Hi CodeWarriors, I'm using bit fields very extensively in my software. Recently I had a very strange bug: the values of these bit fields were corrupted if there were a lot of interrupts in the same time in the system. It didn't happen at once - sometimes the system worked OK for 10 minutes, sometimes for an hour, but it came over the time for sure. The temporary workaround was that I converted the bitfields into 16-bit variables. It smells like some stack corruption caused by improper register pushing. The question is, why 16-bit variables make a difference? Where sould I look for the bug? I'm using compiler CW5.0 @ DSP56F803; the tests with CW7.0 had the same result. The assembler dump seems to be correct. Any hints, suggestions or your own experiences on bitfields are welcome. BR, Georg Bende |
Using bitfields
Started by ●February 7, 2005
Reply by ●February 7, 20052005-02-07
This is a common problem that occurs with multiple processes in an RTOS
and in code that uses ISRs.
If a background application wants to update a bit field, it operates by
reading, modifying, and writing the new value.
If the ISR routine (or other thread in an RTOS) starts in between the
read and write operations, the ISR's change will be
lost
when the write of the background application
occurs.
Possible solutions include:
1. Don't use bit fields (which required read modify write), which
you already have found out.
2. Disable interrupts before the read and re-enable after the
write.
3. Keep separate variables for bit fields in the application and
ISR.
Another similar problem can occur if variables used by ISRs are not
declared as volatile. This paricularly includes memory mapped I/O
registers.
This can manifest itself when polling a status register and never
seeing it change because a compiler optimized the read of the I/O register and
replaced it with an infinite loop.
Howard
|
Reply by ●February 7, 20052005-02-07
Hi Georg Have you tried wrapping "interrupt-disable" and "restore interrupt level" around the at-risk code? (Just to prove that interrupts are breaking it.) A co-worker also used to use bitfields with CW 5 on DSP56F803 (I think the CW version was 5.1.2). We used it to poke bitfields registers with more-easily-read C code. It was "pretty" code, though very inefficient. When we moved that same code to 56F8357s and CW 6.0, some of the bitfields broke - I forget whether it was Optimization Level 0 or 1. Writing to single-bit-bitfields seemed to be OK. One bitfield was 3bits wide, however, and the 21 lines of ASM generated for that assignment was strange - it set those 3bits wrong and altered other bits than just those 3. We probably had a pointer to a structure to access the register. I tore out the bitfield code, since it behaved differently from one rev of the compiler to the next. My experience was not like yours - mine worked wrong every time it ran, with the CW6 compiler and the 56F8357. It wasn't intermittent, and I had no reason to think it was Interrupt-related. It occurred at setup time when (I think) no interrupts should have been running (but I did not disable interrupts during the setup). I never used the CW6 compiler on the 56F803, or CW5 on the 56F8357. I'm going to wait before moving to CW 7 ... perhaps indefinitely. I don't want to be the one to discover new bugs. I think this is a sample of the code that broke, but it was months ago: //Timer A0 Control Register bit wise structure union TMRACtrlReg0Union { volatile unsigned short *RegAddressVar; struct CtrlReg0Struct { unsigned OutPutMode : 3; /*LSb */ unsigned CoInit : 1; unsigned CounterDir : 1; unsigned CountLengh : 1; unsigned CountOnce : 1; unsigned SecondaryCountSource : 2; unsigned PrimaryCountSource : 4; unsigned CountMode : 3; /*MSb */ }*TMRACtrlReg0Struct; }TMRAcontrolReg0Int; // GatedCount: enum, 011=3 turns TACH PULSE counter ON TMRAcontrolReg0Int.TMRACtrlReg0Struct->CountMode = GatedCount; Rick Corey -----Original Message----- From: Bende Georg [mailto:] Sent: Monday, February 07, 2005 10:32 AM To: Subject: [motoroladsp] Using bitfields Hi CodeWarriors, I'm using bit fields very extensively in my software. Recently I had a very strange bug: the values of these bit fields were corrupted if there were a lot of interrupts in the same time in the system. It didn't happen at once - sometimes the system worked OK for 10 minutes, sometimes for an hour, but it came over the time for sure. The temporary workaround was that I converted the bitfields into 16-bit variables. It smells like some stack corruption caused by improper register pushing. The question is, why 16-bit variables make a difference? Where sould I look for the bug? I'm using compiler CW5.0 @ DSP56F803; the tests with CW7.0 had the same result. The assembler dump seems to be correct. Any hints, suggestions or your own experiences on bitfields are welcome. BR, Georg Bende |
Reply by ●February 7, 20052005-02-07
Hi Georg >> Sad that these DSPs don't support bit fields like microcontrollers do - the generated code is inefficient and slow. << I don't blame the chip, I blame the compiler. I was baffled when I looked at generated ASM code for bitfields (CW6). The chip has BFSET and BFCLR. How about creating a lot of macros, using constants, that just set one bit? The amount of code that is in danger of being stepped on by an ISR is much less. And you could build the interrupt-disable-restore into the macro. Just remember to allow 6 NOPs for the interrupt-disable to take effect. I got this one from some Moto or Metro file, I like their name: #define setRegBits(reg, mask) reg |= mask then I use it: #define SET_GPIO_D( WhichBit ) setRegBits( *GPIO_D_DR, (1<<WhichBit) ); #define LED1_On() (setRegBits( *GPIO_E_DR, 0x0080)) It seems to generate reasonable code for register-poking after the pre-processor digests everything: OFF_USER_LED; P:00040722: E418F3310000 move.l #0xf331,R0 P:00040725: 80400080 bfclr #0x80,X:(R0) SET_GPIO_D( 3 ); P:000480DD: E418F3210000 move.l #0xf321,R0 P:000480E0: 82400008 bfset #8,X:(R0) // D0, D1, D2 and D3 => WhichBits_D_IO == 0x0F - a variable setRegBits(*GPIO_D_PPMODE, WhichBits_D_IO ); // set for 1=OpenDrain (0=PushPullMode) P:00040727: E418F3290000 move.l #0xf329,R0 P:0004072A: F114 move.w X:(R0),B P:0004072B: F01F move.w X:(SP),A // WhichBits comes from the stack P:0004072C: 7819 or.w B,A P:0004072D: D014 move.w A1,X:(R0) Rick Corey -----Original Message----- From: Bende Georg [mailto:] Sent: Monday, February 07, 2005 12:08 PM To: Corey, Rick Cc: Subject: AW: [motoroladsp] Using bitfields Hello, > Have you tried wrapping "interrupt-disable" and "restore interrupt level" > around the at-risk code? (Just to prove that interrupts are breaking it.) I'm not able to do this, since the affected bit fields are referred over 200 times in the software. I did it for the first variable that seemed to be buggy, the problem appeared at the next one, so I gave up this way of troubleshooting quickly. The bitfield referencing on peripheral structures you have mentioned works for me reliable on both CW5.0 and CW7.0. (6.x versions were not tested.) The only thing that broke CW5.0 was when I tried to put these variables in a "while" cycle - in this case the compiled smashed the following error in my face: Error : internal compiler error: File: 'IroNonRegLoopAccesses.c' Line: 559 main.c line 101 } I'll try to isolate the problem more clearly, but right now it appears to be somewhat "mystic" for me. Sad that these DSPs don't support bit fields like microcontrollers do - the generated code is inefficient and slow. Thanks, Georg Bende > -----Ursprgliche Nachricht----- > Von: Corey, Rick [mailto:] > Gesendet: Montag, 7. Februar 2005 17:40 > An: Bende Georg; > Betreff: RE: [motoroladsp] Using bitfields > Hi Georg > > Have you tried wrapping "interrupt-disable" and "restore > interrupt level" > around the at-risk code? (Just to prove that interrupts are > breaking it.) > > A co-worker also used to use bitfields with CW 5 on DSP56F803 > (I think the > CW version was 5.1.2). We used it to poke bitfields registers with > more-easily-read C code. It was "pretty" code, though very > inefficient. > > When we moved that same code to 56F8357s and CW 6.0, some of > the bitfields > broke - I forget whether it was Optimization Level 0 or 1. > > Writing to single-bit-bitfields seemed to be OK. > > One bitfield was 3bits wide, however, and the 21 lines of ASM > generated for > that assignment was strange - it set those 3bits wrong and > altered other > bits than just those 3. We probably had a pointer to a > structure to access > the register. > > I tore out the bitfield code, since it behaved differently > from one rev of > the compiler to the next. > > My experience was not like yours - mine worked wrong every > time it ran, with > the CW6 compiler and the 56F8357. It wasn't intermittent, > and I had no > reason to think it was Interrupt-related. It occurred at > setup time when (I > think) no interrupts should have been running (but I did not disable > interrupts during the setup). I never used the CW6 compiler > on the 56F803, > or CW5 on the 56F8357. > > I'm going to wait before moving to CW 7 ... perhaps > indefinitely. I don't > want to be the one to discover new bugs. > I think this is a sample of the code that broke, but it was > months ago: > > //Timer A0 Control Register bit wise structure > union TMRACtrlReg0Union > { > volatile unsigned short *RegAddressVar; > > struct CtrlReg0Struct { > unsigned OutPutMode : 3; /*LSb */ > unsigned CoInit : 1; > unsigned CounterDir : 1; > unsigned CountLengh : 1; > unsigned CountOnce : 1; > unsigned SecondaryCountSource : 2; > unsigned PrimaryCountSource : 4; > unsigned CountMode : 3; /*MSb */ > }*TMRACtrlReg0Struct; > > }TMRAcontrolReg0Int; > // GatedCount: enum, 011=3 turns TACH PULSE counter ON > TMRAcontrolReg0Int.TMRACtrlReg0Struct->CountMode = GatedCount; > > Rick Corey > -----Original Message----- > From: Bende Georg [mailto:] > Sent: Monday, February 07, 2005 10:32 AM > To: > Subject: [motoroladsp] Using bitfields > > Hi CodeWarriors, > > I'm using bit fields very extensively in my software. Recently I had a > very strange bug: the values of these bit fields were > corrupted if there > were a lot of interrupts in the same time in the system. It didn't > happen at once - sometimes the system worked OK for 10 minutes, > sometimes for an hour, but it came over the time for sure. > The temporary > workaround was that I converted the bitfields into 16-bit variables. > It smells like some stack corruption caused by improper register > pushing. The question is, why 16-bit variables make a > difference? Where > sould I look for the bug? > I'm using compiler CW5.0 @ DSP56F803; the tests with CW7.0 > had the same > result. The assembler dump seems to be correct. > Any hints, suggestions or your own experiences on bitfields > are welcome. > > BR, > Georg Bende > ------------------------ Yahoo! Groups Sponsor > --------------------~--> > In low income neighborhoods, 84% do not own computers. > At Network for Good, help bridge the Digital Divide! > http://us.click.yahoo.com/EpW3eD/3MnJAA/cosFAA/PNArlB/TM > -------------------------- > ------~- > |