Technical discussions about Freescale (Motorola) DSPs (including the DSP56000, DSP56300, DSP56600, 56800 DSPs).
|
Hi Can anyone imagine a way that a modulus operator (%) in the main loop could slow down an ISR? I'm stumped. There's a lot of "div"s in the library function, and two "rtsd"s . I'm using the 6.0.2 CW for 56800E (568357). I turned on Processor Expert to create the project, then turned PE off. Any suggestions or speculation would be appreciated, even if derived from experience with CW 5.1. I had some durable FlexCAN code that broke when I added a modulus operator to my main loop. I just wanted to blink some LEDs so I could see fast TX and RX occur without a scope. The symptom seems to be partial or intermittent blocking of the FlexCAN mailbox interrupt - or possibly slowing down the servicing of that interrupt. If it was only slowing down the main loop, I should never see this symptom. It acts as if it is preventing the FlexCAN ISR from being serviced promptly. I can see a few packets (around 8, instead of 96) go out after a one-second delay that should have fully restored the pool, but despite waiting long enough to TX 7,000 packets, I only find that 8 or so have been clocked out. It seems as if, once this "bad thing" happens, CAN TX is permanently slowed down by a very large factor - maybe around 1,000 times too slow - but not stopped entirely. I normally set up to send almost as fast as the packets can go over the wire. Then I blink an LED every 100 messages (every 300 CAN packets) - in some tests, I also blink other LEDs every 1,000 or 10,000 messages. The symptom is running low on TX packet buffers - as if the ISR is being prevented from running as soon as it should, or as fast as it should. (If the TX ISR ran normally, all the packet buffers would be restored to the pool before I took another 30 buffers out.) Strangely, adding a one-second delay every time I detect "low buffer pool" does not return the chip to full-speed sending, as it should once the pool is full again. Further, the lengths of time it takes to exhaust the pool will be consistent for each test case, but range from 20 seconds to several minutes to overnight. I normally send 30 packets, wait 4 milliseconds, then send another 30. The 4 mSec plus the main loop itself is long enough for the packets to go out - if I count the number of times my ToTxList goes empty, it is equal to the number of batches of packets, so the pool normally gets empty every 4 milliseconds. The test also fails if I run with 10 mSec delays, or 50 mSec - it just takes longer to fail. With the 4 mSec delay and no "%"s, it runs over a weekend. I read the error counters every few packets, and they never exceed "1". I trigger an interrupt and trap on any FCSTATUS error bit. None seen. CODE SAMPLES: Worst case code, with unsigned long, breaks in 20 seconds: if (!(NumMsgsSent % 100)) { LED1_Toggle(); if (!(NumMsgsSent % ONE_K)) { LED2_Toggle(); if (!(NumMsgsSent % TEN_K)) LED3_Toggle(); } } Bad-enough case, even with an unsigned short, it breaks overnight: It also breaks if I use if ( 0 == (NumMsgsSent % 100) ), instead of if (!(NumMsgsSent % 100)) . // not OK with an ushort, either, but it runs for much longer before dying if (!(NumMsgsSent % 100)) LED1_Toggle(); This runs fine overnight, without any "%" modulus: if (NumMsgsSent >= 256) { NumMsgsSent = 0; LED2_Toggle(); } Note that instances of (var % 256) get turned by the compiler into (var & 256), so those don't do any messy math. I've used that for months without problems. LIBRARY CODE, from "mixed source" screen: Here's the asm library function that is JSRed to for if (!(NumMsgsSent % 100)) . I notice that different code is used for % 1,000 or %10,000, but the problem occurs even when I only do % 100 : if (!(NumMsgsSent % 100)) jsr 01238 ARTREMU16Z.asm support/runtime56800E/math_support tst.w y1 ; Check on high bit, should be zero . . . P:00001238: 8F07 tst.w Y1 ; Required carry bit is cleard too! blt High_bit_present ; If bit 15 on, result is either 1 or 0 P:00001239: A51B blt @DummyFn1+0x1d (0x1255) ; 0x000938 P:0000123A: E700 nop lsr16 y0,b ; Copy dividend to b0 no sign extension P:0000123B: 7CD7 lsr16 Y0,B ;;;;;;;;;;;;;;;; 4-bit division ;;;;;;;;;;;;;;;; div y1,b ; form quotient in b0 P:0000123C: 78FF div Y1,B div y1,b P:0000123D: 78FF div Y1,B div y1,b P:0000123E: 78FF div Y1,B div y1,b P:0000123F: 78FF div Y1,B ;;;;;;;;;;;;;;;; 4-bit division ;;;;;;;;;;;;;;;; div y1,b ; form quotient in b0 P:00001240: 78FF div Y1,B div y1,b P:00001241: 78FF div Y1,B div y1,b P:00001242: 78FF div Y1,B div y1,b P:00001243: 78FF div Y1,B ;;;;;;;;;;;;;;;; 4-bit division ;;;;;;;;;;;;;;;; div y1,b ; form quotient in b0 P:00001244: 78FF div Y1,B div y1,b P:00001245: 78FF div Y1,B div y1,b P:00001246: 78FF div Y1,B div y1,b P:00001247: 78FF div Y1,B ;;;;;;;;;;;;;;;; 4-bit division ;;;;;;;;;;;;;;;; div y1,b ; form quotient in b0 P:00001248: 78FF div Y1,B div y1,b P:00001249: 78FF div Y1,B div y1,b P:0000124A: 78FF div Y1,B div y1,b P:0000124B: 78FF div Y1,B ;;;;;;;;;;;;;;;; check sign of quotient and adjust accordingly tst b ; Result sign in N bit of SR P:0000124C: 70BB tst B bge Positive_rem ; if remainder is positive, ok P:0000124D: A403 bge @DummyFn1+0x19 (0x1251) ; 0x00092a P:0000124E: E700 nop Fix_required_remainder: add y1,b ; restored remainder, b is negative P:0000124F: 78F0 add Y1,B P:00001250: E700 nop ; y1-b Positive_rem: rtsd ; delay return after nxt 3 instr P:00001251: E70C rtsd move.w b1,y0 ; move result value into return register P:00001252: 8511 move.w B1,Y0 nop ; filler P:00001253: E700 nop nop ; filler P:00001254: E700 nop ;;;;;;;;;;;;;;; Quotient result is either be 1 (REM = y0-y1) or 0 (REM = y0) High_bit_present: move.w y0,b ; set REM to dividend, y0, for quotient = 0 P:00001255: 8105 move.w Y0,B sub y1,y0 ; REM valid if y0 >= y1 (quotient = 1) P:00001256: 7AF1 sub Y1,Y0 tcc y0,b ; if quotient = 1, REM = y0-y1 P:00001257: 709F tcc Y0,B rtsd ; delay return after nxt 3 instr P:00001258: E70C rtsd move.w b1,y0 ; move REM value into return register P:00001259: 8511 move.w B1,Y0 nop ; filler P:0000125A: E700 nop nop ; filler P:0000125B: E700 nop FWIW, here's what I use for LEDs, borrowed from P.E.: #define LED6_Toggle() (changeRegBits(*GPIO_D_DR,128)) #define LED1_Off() (clrRegBits(*GPIO_C_DR,1)) The inner loop of my delay function reads the timers as often as it can, but does 32-bit arithmetic: while ( NowTick < DoneTick ) TMRD3D2_TICKS_LONG ( NowTick ); where the macro is: #define TMRD3D2_TICKS_LONG( LongVar ) { \ LongVar = (*TMR_D2_CNTR); \ LongVar <<= 16; \ LongVar += (*TMR_D3_HOLD); } Is it conceivable that reading a timer too frequently is somehow stalling an ISR? The HOLD register? Long arithmetic?? Rick Corey Senior Software Engineer DPC Instrument Systems Division |
|
|
|
I've seen something even worse in an earlier version of Code Warrior. I was also attempting to do "simple" math in an ISR. The math in my ISR was written as a standard C expression, but the compiler implemented this as a call to a run-time library function. So far, so good ... but the run-time library function was NOT INTERRUPT SAFE! It corrupted registers which manifested itself as random failures in background code. This was a VERY insidious problem and took quite a while to find. William C. Yochum Microwave Data Systems Inc. Principal Eng./Software 175 Science Parkway Phone: (585) 242-8319 Rochester, NY 14620 FAX: (585) 241-5590 USA -----Original Message----- From: Corey, Rick [mailto:] Sent: Monday, April 05, 2004 5:51 PM To: ' Subject: [Bulk E-Mail] [motoroladsp] modulus (%) affects interrupts? Hi Can anyone imagine a way that a modulus operator (%) in the main loop could slow down an ISR? I'm stumped. There's a lot of "div"s in the library function, and two "rtsd"s . I'm using the 6.0.2 CW for 56800E (568357). I turned on Processor Expert to create the project, then turned PE off. Any suggestions or speculation would be appreciated, even if derived from experience with CW 5.1. I had some durable FlexCAN code that broke when I added a modulus operator to my main loop. I just wanted to blink some LEDs so I could see fast TX and RX occur without a scope. The symptom seems to be partial or intermittent blocking of the FlexCAN mailbox interrupt - or possibly slowing down the servicing of that interrupt. If it was only slowing down the main loop, I should never see this symptom. It acts as if it is preventing the FlexCAN ISR from being serviced promptly. I can see a few packets (around 8, instead of 96) go out after a one-second delay that should have fully restored the pool, but despite waiting long enough to TX 7,000 packets, I only find that 8 or so have been clocked out. It seems as if, once this "bad thing" happens, CAN TX is permanently slowed down by a very large factor - maybe around 1,000 times too slow - but not stopped entirely. I normally set up to send almost as fast as the packets can go over the wire. Then I blink an LED every 100 messages (every 300 CAN packets) - in some tests, I also blink other LEDs every 1,000 or 10,000 messages. The symptom is running low on TX packet buffers - as if the ISR is being prevented from running as soon as it should, or as fast as it should. (If the TX ISR ran normally, all the packet buffers would be restored to the pool before I took another 30 buffers out.) Strangely, adding a one-second delay every time I detect "low buffer pool" does not return the chip to full-speed sending, as it should once the pool is full again. Further, the lengths of time it takes to exhaust the pool will be consistent for each test case, but range from 20 seconds to several minutes to overnight. I normally send 30 packets, wait 4 milliseconds, then send another 30. The 4 mSec plus the main loop itself is long enough for the packets to go out - if I count the number of times my ToTxList goes empty, it is equal to the number of batches of packets, so the pool normally gets empty every 4 milliseconds. The test also fails if I run with 10 mSec delays, or 50 mSec - it just takes longer to fail. With the 4 mSec delay and no "%"s, it runs over a weekend. I read the error counters every few packets, and they never exceed "1". I trigger an interrupt and trap on any FCSTATUS error bit. None seen. CODE SAMPLES: Worst case code, with unsigned long, breaks in 20 seconds: if (!(NumMsgsSent % 100)) { LED1_Toggle(); if (!(NumMsgsSent % ONE_K)) { LED2_Toggle(); if (!(NumMsgsSent % TEN_K)) LED3_Toggle(); } } Bad-enough case, even with an unsigned short, it breaks overnight: It also breaks if I use if ( 0 == (NumMsgsSent % 100) ), instead of if (!(NumMsgsSent % 100)) . // not OK with an ushort, either, but it runs for much longer before dying if (!(NumMsgsSent % 100)) LED1_Toggle(); This runs fine overnight, without any "%" modulus: if (NumMsgsSent >= 256) { NumMsgsSent = 0; LED2_Toggle(); } Note that instances of (var % 256) get turned by the compiler into (var & 256), so those don't do any messy math. I've used that for months without problems. LIBRARY CODE, from "mixed source" screen: Here's the asm library function that is JSRed to for if (!(NumMsgsSent % 100)) . I notice that different code is used for % 1,000 or %10,000, but the problem occurs even when I only do % 100 : if (!(NumMsgsSent % 100)) jsr 01238 ARTREMU16Z.asm support/runtime56800E/math_support tst.w y1 ; Check on high bit, should be zero . . . P:00001238: 8F07 tst.w Y1 ; Required carry bit is cleard too! blt High_bit_present ; If bit 15 on, result is either 1 or 0 P:00001239: A51B blt @DummyFn1+0x1d (0x1255) ; 0x000938 P:0000123A: E700 nop lsr16 y0,b ; Copy dividend to b0 no sign extension P:0000123B: 7CD7 lsr16 Y0,B ;;;;;;;;;;;;;;;; 4-bit division ;;;;;;;;;;;;;;;; div y1,b ; form quotient in b0 P:0000123C: 78FF div Y1,B div y1,b P:0000123D: 78FF div Y1,B div y1,b P:0000123E: 78FF div Y1,B div y1,b P:0000123F: 78FF div Y1,B ;;;;;;;;;;;;;;;; 4-bit division ;;;;;;;;;;;;;;;; div y1,b ; form quotient in b0 P:00001240: 78FF div Y1,B div y1,b P:00001241: 78FF div Y1,B div y1,b P:00001242: 78FF div Y1,B div y1,b P:00001243: 78FF div Y1,B ;;;;;;;;;;;;;;;; 4-bit division ;;;;;;;;;;;;;;;; div y1,b ; form quotient in b0 P:00001244: 78FF div Y1,B div y1,b P:00001245: 78FF div Y1,B div y1,b P:00001246: 78FF div Y1,B div y1,b P:00001247: 78FF div Y1,B ;;;;;;;;;;;;;;;; 4-bit division ;;;;;;;;;;;;;;;; div y1,b ; form quotient in b0 P:00001248: 78FF div Y1,B div y1,b P:00001249: 78FF div Y1,B div y1,b P:0000124A: 78FF div Y1,B div y1,b P:0000124B: 78FF div Y1,B ;;;;;;;;;;;;;;;; check sign of quotient and adjust accordingly tst b ; Result sign in N bit of SR P:0000124C: 70BB tst B bge Positive_rem ; if remainder is positive, ok P:0000124D: A403 bge @DummyFn1+0x19 (0x1251) ; 0x00092a P:0000124E: E700 nop Fix_required_remainder: add y1,b ; restored remainder, b is negative P:0000124F: 78F0 add Y1,B P:00001250: E700 nop ; y1-b Positive_rem: rtsd ; delay return after nxt 3 instr P:00001251: E70C rtsd move.w b1,y0 ; move result value into return register P:00001252: 8511 move.w B1,Y0 nop ; filler P:00001253: E700 nop nop ; filler P:00001254: E700 nop ;;;;;;;;;;;;;;; Quotient result is either be 1 (REM = y0-y1) or 0 (REM = y0) High_bit_present: move.w y0,b ; set REM to dividend, y0, for quotient = 0 P:00001255: 8105 move.w Y0,B sub y1,y0 ; REM valid if y0 >= y1 (quotient = 1) P:00001256: 7AF1 sub Y1,Y0 tcc y0,b ; if quotient = 1, REM = y0-y1 P:00001257: 709F tcc Y0,B rtsd ; delay return after nxt 3 instr P:00001258: E70C rtsd move.w b1,y0 ; move REM value into return register P:00001259: 8511 move.w B1,Y0 nop ; filler P:0000125A: E700 nop nop ; filler P:0000125B: E700 nop FWIW, here's what I use for LEDs, borrowed from P.E.: #define LED6_Toggle() (changeRegBits(*GPIO_D_DR,128)) #define LED1_Off() (clrRegBits(*GPIO_C_DR,1)) The inner loop of my delay function reads the timers as often as it can, but does 32-bit arithmetic: while ( NowTick < DoneTick ) TMRD3D2_TICKS_LONG ( NowTick ); where the macro is: #define TMRD3D2_TICKS_LONG( LongVar ) { \ LongVar = (*TMR_D2_CNTR); \ LongVar <<= 16; \ LongVar += (*TMR_D3_HOLD); } Is it conceivable that reading a timer too frequently is somehow stalling an ISR? The HOLD register? Long arithmetic?? Rick Corey Senior Software Engineer DPC Instrument Systems Division _____________________________________ /groups.php3 <http://www.dsprelated.com/groups.php3 _____ > . |
|
Hi
William
Ouch! I thought
I read somewhere that simple "multiply" is a run-time library function. I wish I could
recall where I read that. I see nothing in the "MSL C" doc. I see 13 "multiply"
instructions listed in family RefMan (which makes sense, for a DSP). IMACUU provides a
32-bit result. Maybe I'm wrong about "*" being a run-time lib function. Hope
so!
The CW online manual
has this to say about "certain computations":
"Intrinsic
functions let you pass in data to perform specific optimized computations. For example, some
calculations may be inefficient if coded in C because the compiler has to follow ANSI C rules
to represent data, and this may cause the program to jump to runtime math routines for certain computations. In such
cases, it probably is better to code these calculations using assembly language instructions
and intrinsic functions. "
The intrinsic multiply
functions I found were all for fractional math, not integer.
I didn't even have the
modulus operator in my ISR - it was in the main loop. I understand that if it isn't
thread-safe, some other math in the ISR could break it ... I would have expected
less-repeatable results.
The "fanciest" math
inside my ISR is:
increment a variable (I think they are all ushorts, but
I'll search for longs)
mask a ushort variable using "var & mask"
mask-and-shift register contents, then assign to another variable (for
byte-swapping)
mask a register value, then use it in a comparison
On a quick
look-through, I don't even see any "multiply"s remaining, but I suppose pointer arithmetic
might use one implicitly. I'll look several more times. I had better look
through the ASM produced to look for calls to lib functions.
I share your
paranoia. Thanks!
Rick
Corey
|
|
|
|
I tried throwing ISR protection around my "modulus code" but that didn't help much. It still died, but maybe took a little longer than it used to. I used the P.E. macros : #define __EI0() { asm(bfclr #0x0300,SR); } /* Enable interrupts of level 0,1,2,3 */ #define __EI3() { asm(bfset #0x0300,SR); } /* Enable interrupts of level 3 only (NMI) */ I _think_ that this rules out the theory that the only problem with modulus is that it isn't interrupt-safe ... but what is left? Rick Corey -----Original Message----- From: Yochum, William [mailto:] Sent: Wednesday, April 07, 2004 11:00 AM To: ' Cc: Corey, Rick Subject: [motoroladsp] RE: modulus (%) affects interrupts? I've seen something even worse in an earlier version of Code Warrior. I was also attempting to do "simple" math in an ISR. The math in my ISR was written as a standard C expression, but the compiler implemented this as a call to a run-time library function. So far, so good ... but the run-time library function was NOT INTERRUPT SAFE! It corrupted registers which manifested itself as random failures in background code. This was a VERY insidious problem and took quite a while to find. William C. Yochum Microwave Data Systems Inc. Principal Eng./Software 175 Science Parkway Phone: (585) 242-8319 Rochester, NY 14620 FAX: (585) 241-5590 USA -----Original Message----- From: Corey, Rick [mailto:] Sent: Monday, April 05, 2004 5:51 PM To: ' Subject: [Bulk E-Mail] [motoroladsp] modulus (%) affects interrupts? Hi Can anyone imagine a way that a modulus operator (%) in the main loop could slow down an ISR? I'm stumped. There's a lot of "div"s in the library function, and two "rtsd"s . I'm using the 6.0.2 CW for 56800E (568357). I turned on Processor Expert to create the project, then turned PE off. Any suggestions or speculation would be appreciated, even if derived from experience with CW 5.1. I had some durable FlexCAN code that broke when I added a modulus operator to my main loop. I just wanted to blink some LEDs so I could see fast TX and RX occur without a scope. The symptom seems to be partial or intermittent blocking of the FlexCAN mailbox interrupt - or possibly slowing down the servicing of that interrupt. If it was only slowing down the main loop, I should never see this symptom. It acts as if it is preventing the FlexCAN ISR from being serviced promptly. I can see a few packets (around 8, instead of 96) go out after a one-second delay that should have fully restored the pool, but despite waiting long enough to TX 7,000 packets, I only find that 8 or so have been clocked out. It seems as if, once this "bad thing" happens, CAN TX is permanently slowed down by a very large factor - maybe around 1,000 times too slow - but not stopped entirely. I normally set up to send almost as fast as the packets can go over the wire. Then I blink an LED every 100 messages (every 300 CAN packets) - in some tests, I also blink other LEDs every 1,000 or 10,000 messages. The symptom is running low on TX packet buffers - as if the ISR is being prevented from running as soon as it should, or as fast as it should. (If the TX ISR ran normally, all the packet buffers would be restored to the pool before I took another 30 buffers out.) Strangely, adding a one-second delay every time I detect "low buffer pool" does not return the chip to full-speed sending, as it should once the pool is full again. Further, the lengths of time it takes to exhaust the pool will be consistent for each test case, but range from 20 seconds to several minutes to overnight. I normally send 30 packets, wait 4 milliseconds, then send another 30. The 4 mSec plus the main loop itself is long enough for the packets to go out - if I count the number of times my ToTxList goes empty, it is equal to the number of batches of packets, so the pool normally gets empty every 4 milliseconds. The test also fails if I run with 10 mSec delays, or 50 mSec - it just takes longer to fail. With the 4 mSec delay and no "%"s, it runs over a weekend. I read the error counters every few packets, and they never exceed "1". I trigger an interrupt and trap on any FCSTATUS error bit. None seen. CODE SAMPLES: Worst case code, with unsigned long, breaks in 20 seconds: if (!(NumMsgsSent % 100)) { LED1_Toggle(); if (!(NumMsgsSent % ONE_K)) { LED2_Toggle(); if (!(NumMsgsSent % TEN_K)) LED3_Toggle(); } } Bad-enough case, even with an unsigned short, it breaks overnight: It also breaks if I use if ( 0 == (NumMsgsSent % 100) ), instead of if (!(NumMsgsSent % 100)) . // not OK with an ushort, either, but it runs for much longer before dying if (!(NumMsgsSent % 100)) LED1_Toggle(); This runs fine overnight, without any "%" modulus: if (NumMsgsSent >= 256) { NumMsgsSent = 0; LED2_Toggle(); } Note that instances of (var % 256) get turned by the compiler into (var & 256), so those don't do any messy math. I've used that for months without problems. LIBRARY CODE, from "mixed source" screen: Here's the asm library function that is JSRed to for if (!(NumMsgsSent % 100)) . I notice that different code is used for % 1,000 or %10,000, but the problem occurs even when I only do % 100 : if (!(NumMsgsSent % 100)) jsr 01238 ARTREMU16Z.asm support/runtime56800E/math_support tst.w y1 ; Check on high bit, should be zero . . . P:00001238: 8F07 tst.w Y1 ; Required carry bit is cleard too! blt High_bit_present ; If bit 15 on, result is either 1 or 0 P:00001239: A51B blt @DummyFn1+0x1d (0x1255) ; 0x000938 P:0000123A: E700 nop lsr16 y0,b ; Copy dividend to b0 no sign extension P:0000123B: 7CD7 lsr16 Y0,B ;;;;;;;;;;;;;;;; 4-bit division ;;;;;;;;;;;;;;;; div y1,b ; form quotient in b0 P:0000123C: 78FF div Y1,B div y1,b P:0000123D: 78FF div Y1,B div y1,b P:0000123E: 78FF div Y1,B div y1,b P:0000123F: 78FF div Y1,B ;;;;;;;;;;;;;;;; 4-bit division ;;;;;;;;;;;;;;;; div y1,b ; form quotient in b0 P:00001240: 78FF div Y1,B div y1,b P:00001241: 78FF div Y1,B div y1,b P:00001242: 78FF div Y1,B div y1,b P:00001243: 78FF div Y1,B ;;;;;;;;;;;;;;;; 4-bit division ;;;;;;;;;;;;;;;; div y1,b ; form quotient in b0 P:00001244: 78FF div Y1,B div y1,b P:00001245: 78FF div Y1,B div y1,b P:00001246: 78FF div Y1,B div y1,b P:00001247: 78FF div Y1,B ;;;;;;;;;;;;;;;; 4-bit division ;;;;;;;;;;;;;;;; div y1,b ; form quotient in b0 P:00001248: 78FF div Y1,B div y1,b P:00001249: 78FF div Y1,B div y1,b P:0000124A: 78FF div Y1,B div y1,b P:0000124B: 78FF div Y1,B ;;;;;;;;;;;;;;;; check sign of quotient and adjust accordingly tst b ; Result sign in N bit of SR P:0000124C: 70BB tst B bge Positive_rem ; if remainder is positive, ok P:0000124D: A403 bge @DummyFn1+0x19 (0x1251) ; 0x00092a P:0000124E: E700 nop Fix_required_remainder: add y1,b ; restored remainder, b is negative P:0000124F: 78F0 add Y1,B P:00001250: E700 nop ; y1-b Positive_rem: rtsd ; delay return after nxt 3 instr P:00001251: E70C rtsd move.w b1,y0 ; move result value into return register P:00001252: 8511 move.w B1,Y0 nop ; filler P:00001253: E700 nop nop ; filler P:00001254: E700 nop ;;;;;;;;;;;;;;; Quotient result is either be 1 (REM = y0-y1) or 0 (REM = y0) High_bit_present: move.w y0,b ; set REM to dividend, y0, for quotient = 0 P:00001255: 8105 move.w Y0,B sub y1,y0 ; REM valid if y0 >= y1 (quotient = 1) P:00001256: 7AF1 sub Y1,Y0 tcc y0,b ; if quotient = 1, REM = y0-y1 P:00001257: 709F tcc Y0,B rtsd ; delay return after nxt 3 instr P:00001258: E70C rtsd move.w b1,y0 ; move REM value into return register P:00001259: 8511 move.w B1,Y0 nop ; filler P:0000125A: E700 nop nop ; filler P:0000125B: E700 nop FWIW, here's what I use for LEDs, borrowed from P.E.: #define LED6_Toggle() (changeRegBits(*GPIO_D_DR,128)) #define LED1_Off() (clrRegBits(*GPIO_C_DR,1)) The inner loop of my delay function reads the timers as often as it can, but does 32-bit arithmetic: while ( NowTick < DoneTick ) TMRD3D2_TICKS_LONG ( NowTick ); where the macro is: #define TMRD3D2_TICKS_LONG( LongVar ) { \ LongVar = (*TMR_D2_CNTR); \ LongVar <<= 16; \ LongVar += (*TMR_D3_HOLD); } Is it conceivable that reading a timer too frequently is somehow stalling an ISR? The HOLD register? Long arithmetic?? Rick Corey Senior Software Engineer DPC Instrument Systems Division _____________________________________ /groups.php3 <http://www.dsprelated.com/groups.php3 _____ > . _____________________________________ /groups.php3 Yahoo! Groups Links |
|
FWIW, I just noticed that my #defined constants for "ONE_K" and "TEN_K"
were #defined as longs ... so the problem I saw may have been with modulus-for-longs. I've run for 5-8 minutes at a time just now with ushorts ... will try overnight. Rick Corey -----Original Message----- From: Corey, Rick Sent: Wednesday, April 07, 2004 3:20 PM To: 'Yochum, William'; ' Cc: Corey, Rick Subject: RE: [motoroladsp] RE: modulus (%) affects interrupts? I tried throwing ISR protection around my "modulus code" but that didn't help much. It still died, but maybe took a little longer than it used to. I used the P.E. macros : #define __EI0() { asm(bfclr #0x0300,SR); } /* Enable interrupts of level 0,1,2,3 */ #define __EI3() { asm(bfset #0x0300,SR); } /* Enable interrupts of level 3 only (NMI) */ I _think_ that this rules out the theory that the only problem with modulus is that it isn't interrupt-safe ... but what is left? Rick Corey -----Original Message----- From: Yochum, William [mailto:] Sent: Wednesday, April 07, 2004 11:00 AM To: ' Cc: Corey, Rick Subject: [motoroladsp] RE: modulus (%) affects interrupts? I've seen something even worse in an earlier version of Code Warrior. I was also attempting to do "simple" math in an ISR. The math in my ISR was written as a standard C expression, but the compiler implemented this as a call to a run-time library function. So far, so good ... but the run-time library function was NOT INTERRUPT SAFE! It corrupted registers which manifested itself as random failures in background code. This was a VERY insidious problem and took quite a while to find. William C. Yochum Microwave Data Systems Inc. Principal Eng./Software 175 Science Parkway Phone: (585) 242-8319 Rochester, NY 14620 FAX: (585) 241-5590 USA -----Original Message----- From: Corey, Rick [mailto:] Sent: Monday, April 05, 2004 5:51 PM To: ' Subject: [Bulk E-Mail] [motoroladsp] modulus (%) affects interrupts? Hi Can anyone imagine a way that a modulus operator (%) in the main loop could slow down an ISR? I'm stumped. There's a lot of "div"s in the library function, and two "rtsd"s . I'm using the 6.0.2 CW for 56800E (568357). I turned on Processor Expert to create the project, then turned PE off. Any suggestions or speculation would be appreciated, even if derived from experience with CW 5.1. I had some durable FlexCAN code that broke when I added a modulus operator to my main loop. I just wanted to blink some LEDs so I could see fast TX and RX occur without a scope. The symptom seems to be partial or intermittent blocking of the FlexCAN mailbox interrupt - or possibly slowing down the servicing of that interrupt. If it was only slowing down the main loop, I should never see this symptom. It acts as if it is preventing the FlexCAN ISR from being serviced promptly. I can see a few packets (around 8, instead of 96) go out after a one-second delay that should have fully restored the pool, but despite waiting long enough to TX 7,000 packets, I only find that 8 or so have been clocked out. It seems as if, once this "bad thing" happens, CAN TX is permanently slowed down by a very large factor - maybe around 1,000 times too slow - but not stopped entirely. I normally set up to send almost as fast as the packets can go over the wire. Then I blink an LED every 100 messages (every 300 CAN packets) - in some tests, I also blink other LEDs every 1,000 or 10,000 messages. The symptom is running low on TX packet buffers - as if the ISR is being prevented from running as soon as it should, or as fast as it should. (If the TX ISR ran normally, all the packet buffers would be restored to the pool before I took another 30 buffers out.) Strangely, adding a one-second delay every time I detect "low buffer pool" does not return the chip to full-speed sending, as it should once the pool is full again. Further, the lengths of time it takes to exhaust the pool will be consistent for each test case, but range from 20 seconds to several minutes to overnight. I normally send 30 packets, wait 4 milliseconds, then send another 30. The 4 mSec plus the main loop itself is long enough for the packets to go out - if I count the number of times my ToTxList goes empty, it is equal to the number of batches of packets, so the pool normally gets empty every 4 milliseconds. The test also fails if I run with 10 mSec delays, or 50 mSec - it just takes longer to fail. With the 4 mSec delay and no "%"s, it runs over a weekend. I read the error counters every few packets, and they never exceed "1". I trigger an interrupt and trap on any FCSTATUS error bit. None seen. CODE SAMPLES: Worst case code, with unsigned long, breaks in 20 seconds: if (!(NumMsgsSent % 100)) { LED1_Toggle(); if (!(NumMsgsSent % ONE_K)) { LED2_Toggle(); if (!(NumMsgsSent % TEN_K)) LED3_Toggle(); } } Bad-enough case, even with an unsigned short, it breaks overnight: It also breaks if I use if ( 0 == (NumMsgsSent % 100) ), instead of if (!(NumMsgsSent % 100)) . // not OK with an ushort, either, but it runs for much longer before dying if (!(NumMsgsSent % 100)) LED1_Toggle(); This runs fine overnight, without any "%" modulus: if (NumMsgsSent >= 256) { NumMsgsSent = 0; LED2_Toggle(); } Note that instances of (var % 256) get turned by the compiler into (var & 256), so those don't do any messy math. I've used that for months without problems. LIBRARY CODE, from "mixed source" screen: Here's the asm library function that is JSRed to for if (!(NumMsgsSent % 100)) . I notice that different code is used for % 1,000 or %10,000, but the problem occurs even when I only do % 100 : if (!(NumMsgsSent % 100)) jsr 01238 ARTREMU16Z.asm support/runtime56800E/math_support tst.w y1 ; Check on high bit, should be zero . . . P:00001238: 8F07 tst.w Y1 ; Required carry bit is cleard too! blt High_bit_present ; If bit 15 on, result is either 1 or 0 P:00001239: A51B blt @DummyFn1+0x1d (0x1255) ; 0x000938 P:0000123A: E700 nop lsr16 y0,b ; Copy dividend to b0 no sign extension P:0000123B: 7CD7 lsr16 Y0,B ;;;;;;;;;;;;;;;; 4-bit division ;;;;;;;;;;;;;;;; div y1,b ; form quotient in b0 P:0000123C: 78FF div Y1,B div y1,b P:0000123D: 78FF div Y1,B div y1,b P:0000123E: 78FF div Y1,B div y1,b P:0000123F: 78FF div Y1,B ;;;;;;;;;;;;;;;; 4-bit division ;;;;;;;;;;;;;;;; div y1,b ; form quotient in b0 P:00001240: 78FF div Y1,B div y1,b P:00001241: 78FF div Y1,B div y1,b P:00001242: 78FF div Y1,B div y1,b P:00001243: 78FF div Y1,B ;;;;;;;;;;;;;;;; 4-bit division ;;;;;;;;;;;;;;;; div y1,b ; form quotient in b0 P:00001244: 78FF div Y1,B div y1,b P:00001245: 78FF div Y1,B div y1,b P:00001246: 78FF div Y1,B div y1,b P:00001247: 78FF div Y1,B ;;;;;;;;;;;;;;;; 4-bit division ;;;;;;;;;;;;;;;; div y1,b ; form quotient in b0 P:00001248: 78FF div Y1,B div y1,b P:00001249: 78FF div Y1,B div y1,b P:0000124A: 78FF div Y1,B div y1,b P:0000124B: 78FF div Y1,B ;;;;;;;;;;;;;;;; check sign of quotient and adjust accordingly tst b ; Result sign in N bit of SR P:0000124C: 70BB tst B bge Positive_rem ; if remainder is positive, ok P:0000124D: A403 bge @DummyFn1+0x19 (0x1251) ; 0x00092a P:0000124E: E700 nop Fix_required_remainder: add y1,b ; restored remainder, b is negative P:0000124F: 78F0 add Y1,B P:00001250: E700 nop ; y1-b Positive_rem: rtsd ; delay return after nxt 3 instr P:00001251: E70C rtsd move.w b1,y0 ; move result value into return register P:00001252: 8511 move.w B1,Y0 nop ; filler P:00001253: E700 nop nop ; filler P:00001254: E700 nop ;;;;;;;;;;;;;;; Quotient result is either be 1 (REM = y0-y1) or 0 (REM = y0) High_bit_present: move.w y0,b ; set REM to dividend, y0, for quotient = 0 P:00001255: 8105 move.w Y0,B sub y1,y0 ; REM valid if y0 >= y1 (quotient = 1) P:00001256: 7AF1 sub Y1,Y0 tcc y0,b ; if quotient = 1, REM = y0-y1 P:00001257: 709F tcc Y0,B rtsd ; delay return after nxt 3 instr P:00001258: E70C rtsd move.w b1,y0 ; move REM value into return register P:00001259: 8511 move.w B1,Y0 nop ; filler P:0000125A: E700 nop nop ; filler P:0000125B: E700 nop FWIW, here's what I use for LEDs, borrowed from P.E.: #define LED6_Toggle() (changeRegBits(*GPIO_D_DR,128)) #define LED1_Off() (clrRegBits(*GPIO_C_DR,1)) The inner loop of my delay function reads the timers as often as it can, but does 32-bit arithmetic: while ( NowTick < DoneTick ) TMRD3D2_TICKS_LONG ( NowTick ); where the macro is: #define TMRD3D2_TICKS_LONG( LongVar ) { \ LongVar = (*TMR_D2_CNTR); \ LongVar <<= 16; \ LongVar += (*TMR_D3_HOLD); } Is it conceivable that reading a timer too frequently is somehow stalling an ISR? The HOLD register? Long arithmetic?? Rick Corey Senior Software Engineer DPC Instrument Systems Division _____________________________________ /groups.php3 <http://www.dsprelated.com/groups.php3 _____ > . _____________________________________ /groups.php3 Yahoo! Groups Links |
|
HI Rick and William, 32-bit multiply instructions take two 16-bit values and generated a 32-bit result. This is not useful by itself for doing 32x32-bit multiplication. This is why a runtime library is called for. 16-bit math is not done in a library. For 5683xx/5685x we have more instruction support and inline much of these user select "optimize for speed". 5680x and 5682x families have a more limited instruction and registers set here. All FP math is done in a library. (no FPU on the processor) Regarding being ISR safe. This is addressed as long as the routine calling these functions have one of the following: 1. "#pragma interrupt" For use only at top level ISR. Recommended when there are not too many subroutine calls 2. "#pragma interrupt saveall" For use only at top level ISR recommended when there will be many subroutine calls 3. "#pragma interrupt called" for use in case #1. Must be placed on C functions called by interrupt routine (unless saveall option was used) One problem you point out is that the compiler does not emit an error if pragma in case 3 is left off. We don not have a solution to offer this shortcoming. If its not guarded by these #pragma's it will clobber volatile registers used by the library. This ABI approach is a solid performance tradeoffs. We have many volatile registers because, it would really slow things down if more were treated as non-volatile. > Hi William > > Ouch! I thought I read somewhere that simple "multiply" is a run-time > library function. I wish I could recall where I read that. I see nothing > in the "MSL C" doc. I see 13 "multiply" instructions listed in family > RefMan (which makes sense, for a DSP). IMACUU provides a 32-bit result. > Maybe I'm wrong about "*" being a run-time lib function. Hope so! > > The CW online manual has this to say about "certain computations": > "Intrinsic functions let you pass in data to perform specific optimized > computations. For example, some calculations may be inefficient if coded in > C because the compiler has to follow ANSI C rules to represent data, and > this may cause the program to jump to runtime math routines for certain > computations. In such cases, it probably is better to code these > calculations using assembly language instructions and intrinsic functions. " > > The intrinsic multiply functions I found were all for fractional math, not > integer. > > I didn't even have the modulus operator in my ISR - it was in the main loop. > I understand that if it isn't thread-safe, some other math in the ISR could > break it ... I would have expected less-repeatable results. > > The "fanciest" math inside my ISR is: > increment a variable (I think they are all ushorts, but I'll search for > longs) > mask a ushort variable using "var & mask" > mask-and-shift register contents, then assign to another variable (for > byte-swapping) > mask a register value, then use it in a comparison > > On a quick look-through, I don't even see any "multiply"s remaining, but I > suppose pointer arithmetic might use one implicitly. I'll look several more > times. I had better look through the ASM produced to look for calls to lib > functions. > > I share your paranoia. Thanks! > > Rick Corey > -----Original Message----- > From: Yochum, William [mailto:] > Sent: Wednesday, April 07, 2004 11:00 AM > To: ' > Cc: Corey, Rick > Subject: RE: modulus (%) affects interrupts? > I've seen something even worse in an earlier version of Code Warrior. > > I was also attempting to do "simple" math in an ISR. > > The math in my ISR was written as a standard C expression, but the compiler > implemented this as a call to a run-time library function. So far, so good > ... but the run-time library function was NOT INTERRUPT SAFE! It corrupted > registers which manifested itself as random failures in background code. > This was a VERY insidious problem and took quite a while to find. > > William C. Yochum Microwave Data Systems Inc. > Principal Eng./Software 175 Science Parkway > Phone: (585) 242-8319 Rochester, NY 14620 > FAX: (585) 241-5590 USA -- Free Download - New Version Released CodeWarrior Development Studio for HC(S)12 Microcontrollers v3.1 Offers "emulator-like" debugging support for HCS12 derivatives http://www.metrowerks.com/MW/Develop/Embedded/HC12/Default.htm Ron Liechty - - http://www.metrowerks.com |
|
Rick Corey wrote: > Can anyone imagine a way that a modulus operator (%) in the main loop could > slow down an ISR? I'm stumped. An ISR will not call any function in the main loop or be affected by it in anyway. The ISR should run to completion before going back to the main loop. The engineers that looked at this are guessing that the time to complete the ISR you wrote might depend on some data structure that could be corrupted by something done in the mainloop. The mod library itself would not do this. It is likely something in your code. Perhaps the modulus operation is just a red herring? Ron -- Free Download - New Version Released CodeWarrior Development Studio for HC(S)12 Microcontrollers v3.1 Offers "emulator-like" debugging support for HCS12 derivatives http://www.metrowerks.com/MW/Develop/Embedded/HC12/Default.htm Ron Liechty - - http://www.metrowerks.com |
|
Hi Ron The modulus problem is not a red herring. I have weeks of testing where: 'without the % it works fine for days" and 20-30 cycles of "add the % and break it - remove the % and it works fine for as long as I run the test". The most recent test is "make both arguments ushorts and run overnight" vs. "if either is a long it will crash very quickly". This is conclusive. The two variables used in the % statement are not used anywhere else in the program and are local to the routine that uses them. It is not a red herring. Rick Corey -----Original Message----- From: MW Ron [mailto:] Sent: Wednesday, April 07, 2004 5:10 PM To: Cc: Corey, Rick Subject: Re: [motoroladsp] modulus (%) affects interrupts? Importance: Low Rick Corey wrote: > Can anyone imagine a way that a modulus operator (%) in the main loop could > slow down an ISR? I'm stumped. An ISR will not call any function in the main loop or be affected by it in anyway. The ISR should run to completion before going back to the main loop. The engineers that looked at this are guessing that the time to complete the ISR you wrote might depend on some data structure that could be corrupted by something done in the mainloop. The mod library itself would not do this. It is likely something in your code. Perhaps the modulus operation is just a red herring? Ron -- Free Download - New Version Released CodeWarrior Development Studio for HC(S)12 Microcontrollers v3.1 Offers "emulator-like" debugging support for HCS12 derivatives http://www.metrowerks.com/MW/Develop/Embedded/HC12/Default.htm Ron Liechty - - http://www.metrowerks.com |
|
|
|
Hi Ron First, I'll just mention that even blocking interrupts entirely around that modulus code did not seem to solve the problem either! I used: "#define __EI3() { asm(bfset #0x0300,SR); }" and "#define __EI0() { asm(bfclr #0x0300,SR); } I added such long delays elsewhere in the main loop that blocking IRQs during the % code wouldn't cause problems. It still died when I used a long constant, and worked when I used a short. Tentatively I would think that this means that "ISR-safety" is not the only issue. Sorry, but I have several points of substantial disagreement with your post: (1) First, you said: "Regarding being ISR safe. This is addressed as long as the routine calling these functions have one of the following: ..." Ron, that means that these are absolutely *NOT* ISR-safe in ANY sense, since they need to have complete ISR protection wrapped around them. You said: "as long as the routine calling these functions have ..." Please tell me how one would add ISR protection like "#pragma interrupt called" to "main", which is where this happened to bite me. Then I could test the theory that "% long" is merely not ISR-safe, as opposed to having other problems as well. I'm also puzzled about how "#pragma interrupt called" can protect the inside of a function, if it does not block IRQs when the function is not called from inside an ISR. It seems to me that the "protected" function (or main, in my case) would save its context, then start running, then reach the math code, then be interrupted by an ISR, and break things. When you put "#pragma interrupt called" around a function that is NOT called from inside an iSR, does it block IRQs as well as SAVEALL? This is puzzling. Even if that is sufficient, are you saying that ANY non-ISR routine that uses any floating point math, or any math function, or any 32-bit multiply needs to have "#pragma interrupt called" around it, even if it is NOT called from inside any ISR? That's a brutal efficiency hit! Would the same rule apply to any function that uses the modulus operator with a long (32-bit) variable? I understand that floating point math will be slow (that's understandable) but not having to save and restore the whole context just to do a 32-bit multiply or modulus! The most scary thing is that these are not explicit library functions like "sin" or "log" ... these are just the ANSII C operators "*" and "%". Modulus isn't ISR-safe with longs in your compiler - or maybe it just occasionally works wrong with longs altogether, I don't know. When I change the "unsigned short" to a "unsigned long" it breaks my code. One excellent consultant we work with pointed to FPE_state as a possible culprit, and I'll test that eventually - he suggests that it should be part of your SAVEALL and RESTOREALL macros for ISRs to work correctly with math. (2) Next, you said: >> 16-bit math is not done in a library. << I think this is incorrect. Here's the ASM you generate: - - - - if (!(NumMsgsSent % 100)) // 0xFF)) P:00000EBA: B57C move.w X:(SP-4),Y0 P:00000EBB: 87470064 move.w #100,Y1 P:00000EBD: E254126D jsr 0x00126d P:00000EBF: 8F05 tst.w Y0 P:00000EC0: A211 bne main+0xd0 (0xed2) ; 0x000772 - - - - The jsr jumps to the following, which the debugger says comes from "C:\program files\Metrowerks\CW6\M56800E Support\math support\Rtrem16\ARTREMU16Z.asm". This looks like a library to me. "Modulus" is math, and both the operands are ushorts (16 bits). It seems to be "16 bit math done in a library" ... but at least it doesn't seem to destroy my code. tst.w y1 ; Check on high bit, should be zero P:0000126D: 8F07 tst.w Y1 ; Required carry bit is cleard too! blt High_bit_present ; If bit 15 on, result is either 1 or 0 P:0000126E: A51B blt @DummyFn1+0x1d (0x128a) ; 0x000953 P:0000126F: E700 nop lsr16 y0,b ; Copy dividend to b0 no sign extension P:00001270: 7CD7 lsr16 Y0,B ;;;;;;;;;;;;;;;; 4-bit division ;;;;;;;;;;;;;;;; div y1,b ; form quotient in b0 P:00001271: 78FF div Y1,B <big snip> ;;;;;;;;;;;;;;; Quotient result is either be 1 (REM = y0-y1) or 0 (REM = y0) High_bit_present: move.w y0,b ; set REM to dividend, y0, for quotient = 0 P:0000128A: 8105 move.w Y0,B sub y1,y0 ; REM valid if y0 >= y1 (quotient = 1) P:0000128B: 7AF1 sub Y1,Y0 tcc y0,b ; if quotient = 1, REM = y0-y1 P:0000128C: 709F tcc Y0,B rtsd ; delay return after nxt 3 instr P:0000128D: E70C rtsd move.w b1,y0 ; move REM value into return register P:0000128E: 8511 move.w B1,Y0 nop ; filler P:0000128F: E700 nop nop ; filler P:00001290: E700 nop - - - - - - (3) Finally, you said: "If its not guarded by these #pragma's it will clobber volatile registers used by the library. This ABI approach is a solid performance tradeoffs. We have many volatile registers because, it would really slow things down if more were treated as non-volatile." I never heard that, before, as a reason to ship non-re-entrant math libraries for a microcontroller. The tendency to use those with interrupts usually makes re-entrancy an absolute requirement for usability. How could making your libraries re-entrant slow things down as much as forcing the user to wrap "SAVEALL" and "RESTOREALL" around every single routine that uses any math? Rick Corey -----Original Message----- From: MW Ron [mailto:] Sent: Wednesday, April 07, 2004 5:06 PM To: Subject: Re: [motoroladsp] RE: modulus (%) affects interrupts? Importance: Low HI Rick and William, 32-bit multiply instructions take two 16-bit values and generated a 32-bit result. This is not useful by itself for doing 32x32-bit multiplication. This is why a runtime library is called for. 16-bit math is not done in a library. For 5683xx/5685x we have more instruction support and inline much of these user select "optimize for speed". 5680x and 5682x families have a more limited instruction and registers set here. All FP math is done in a library. (no FPU on the processor) Regarding being ISR safe. This is addressed as long as the routine calling these functions have one of the following: 1. "#pragma interrupt" For use only at top level ISR. Recommended when there are not too many subroutine calls 2. "#pragma interrupt saveall" For use only at top level ISR recommended when there will be many subroutine calls 3. "#pragma interrupt called" for use in case #1. Must be placed on C functions called by interrupt routine (unless saveall option was used) One problem you point out is that the compiler does not emit an error if pragma in case 3 is left off. We don not have a solution to offer this shortcoming. If its not guarded by these #pragma's it will clobber volatile registers used by the library. This ABI approach is a solid performance tradeoffs. We have many volatile registers because, it would really slow things down if more were treated as non-volatile. > Hi William > > Ouch! I thought I read somewhere that simple "multiply" is a run-time > library function. I wish I could recall where I read that. I see nothing > in the "MSL C" doc. I see 13 "multiply" instructions listed in family > RefMan (which makes sense, for a DSP). IMACUU provides a 32-bit result. > Maybe I'm wrong about "*" being a run-time lib function. Hope so! > > The CW online manual has this to say about "certain computations": > "Intrinsic functions let you pass in data to perform specific optimized > computations. For example, some calculations may be inefficient if coded in > C because the compiler has to follow ANSI C rules to represent data, and > this may cause the program to jump to runtime math routines for certain > computations. In such cases, it probably is better to code these > calculations using assembly language instructions and intrinsic functions. " > > The intrinsic multiply functions I found were all for fractional math, not > integer. > > I didn't even have the modulus operator in my ISR - it was in the main loop. > I understand that if it isn't thread-safe, some other math in the ISR could > break it ... I would have expected less-repeatable results. > > The "fanciest" math inside my ISR is: > increment a variable (I think they are all ushorts, but I'll search for > longs) > mask a ushort variable using "var & mask" > mask-and-shift register contents, then assign to another variable (for > byte-swapping) > mask a register value, then use it in a comparison > > On a quick look-through, I don't even see any "multiply"s remaining, but I > suppose pointer arithmetic might use one implicitly. I'll look several more > times. I had better look through the ASM produced to look for calls to lib > functions. > > I share your paranoia. Thanks! > > Rick Corey > -----Original Message----- > From: Yochum, William [mailto:] > Sent: Wednesday, April 07, 2004 11:00 AM > To: ' > Cc: Corey, Rick > Subject: RE: modulus (%) affects interrupts? > I've seen something even worse in an earlier version of Code Warrior. > > I was also attempting to do "simple" math in an ISR. > > The math in my ISR was written as a standard C expression, but the compiler > implemented this as a call to a run-time library function. So far, so good > ... but the run-time library function was NOT INTERRUPT SAFE! It corrupted > registers which manifested itself as random failures in background code. > This was a VERY insidious problem and took quite a while to find. > > William C. Yochum Microwave Data Systems Inc. > Principal Eng./Software 175 Science Parkway > Phone: (585) 242-8319 Rochester, NY 14620 > FAX: (585) 241-5590 USA -- Free Download - New Version Released CodeWarrior Development Studio for HC(S)12 Microcontrollers v3.1 Offers "emulator-like" debugging support for HCS12 derivatives http://www.metrowerks.com/MW/Develop/Embedded/HC12/Default.htm Ron Liechty - - http://www.metrowerks.com _____________________________________ /groups.php3 Yahoo! Groups Links |
|
|
|
Corey, Rick wrote: > Hi Ron > > The modulus problem is not a red herring. I have weeks of testing where: > 'without the % it works fine for days" and 20-30 cycles of "add the % and > break it - remove the % and it works fine for as long as I run the test". > The most recent test is "make both arguments ushorts and run overnight" vs. > "if either is a long it will crash very quickly". This is conclusive. The > two variables used in the % statement are not used anywhere else in the > program and are local to the routine that uses them. It is not a red > herring. Please open a Service Request on this and let me know when you do. We need a reproducible case. Ron > > -----Original Message----- > From: MW Ron [mailto:] > Sent: Wednesday, April 07, 2004 5:10 PM > To: > Cc: Corey, Rick > Subject: Re: [motoroladsp] modulus (%) affects interrupts? > Importance: Low > Rick Corey wrote: > >> Can anyone imagine a way that a modulus operator (%) in the main loop > could >> slow down an ISR? I'm stumped. > > An ISR will not call any function in the main loop or be affected by it in > anyway. The ISR should run to completion before going back to the main loop. > > The engineers that looked at this are guessing that the time to complete the > ISR you wrote might depend on some data structure that could be corrupted by > something done in the mainloop. The mod library itself would not do this. > It is likely something in your code. Perhaps the modulus operation is just > a red herring? > > Ron > > -- > Free Download - New Version Released > CodeWarrior Development Studio for HC(S)12 Microcontrollers v3.1 > Offers "emulator-like" debugging support for HCS12 derivatives > http://www.metrowerks.com/MW/Develop/Embedded/HC12/Default.htm > Ron Liechty - - http://www.metrowerks.com > > > _____________________________________ > /groups.php3 > > Yahoo! Groups Links -- Free Download - New Version Released CodeWarrior Development Studio for HC(S)12 Microcontrollers v3.1 Offers "emulator-like" debugging support for HCS12 derivatives http://www.metrowerks.com/MW/Develop/Embedded/HC12/Default.htm Ron Liechty - - http://www.metrowerks.com |
|
Fundamentally, you have to save any registers used in the execution of an ISR in order to save the context of the interrupted code. If you are writing in assembly you simply push onto the stack whatever you intend to use in the ISR and then pop the stack to restore the values. If you write your ISRs in C then Codewarrior provides #pragma interrupt and #pragma interrupt saveall for your ISR (the code launched from the vector table) and #pragma interrupt called for any code called from the ISR. #pragma interrupt..... Context saved Return For ------------------------- --------------------- ------ -------- #pragma interrupt only registers used RTI ISR #pragma interrupt saveall all registers RTI ISR #pragma interrupt called only registers used RTS non ISR If you have a simple ISR that doesn't call many routines then #pragma interrupt is sufficient. You then have to protect any subroutines launched out of the ISR with #pragma interrupt called. If you find yourself doing a lot of #pragma interrupt called for a particular ISR then it is more efficient to save the entire context once with a #pragma interrupt saveall for the ISR than saving many partial contexts for the ISR and all the called routines. |
|
|
|
> If you have a simple ISR that doesn't call many routines
then
> #pragma interrupt is sufficient. This is fundamentally
correct, but I do think it is a compiler defect when an ISR routine written in "C",
which does not explicitly call a subroutine, fails because the compiler implicitly
substitutes a run-time library routine which is not interrupt safe.
This is the case if you
perform certain types of math in your ISR.
-----Original
Message-----
From: Michael W. Mann [mailto:M...@Motorola.Com] Sent: Friday, April 09, 2004 7:51 PM To: m...@yahoogroups.com Subject: [motoroladsp] Re: modulus (%) affects interrupts? Fundamentally, you have to save any registers used in the execution |
|
Hi All, I was wondering. If you have a C function that you want to use as an ISR but also call from the main loop does "#pragma interrupt" work for both? Does it require 2 different functions? What are the implications. Thanks, Pete --- In , "Michael W. Mann" <Michael.W.Mann@M...> wrote: > Fundamentally, you have to save any registers used in the execution > of an ISR in order to save the context of the interrupted code. If > you are writing in assembly you simply push onto the stack whatever > you intend to use in the ISR and then pop the stack to restore the > values. > > If you write your ISRs in C then Codewarrior provides #pragma > interrupt and #pragma interrupt saveall for your ISR (the code > launched from the vector table) and #pragma interrupt called for any > code called from the ISR. > > #pragma interrupt..... Context saved Return For > ------------------------- --------------------- ------ -------- > #pragma interrupt only registers used RTI ISR > #pragma interrupt saveall all registers RTI ISR > #pragma interrupt called only registers used RTS non ISR > > If you have a simple ISR that doesn't call many routines then > #pragma interrupt is sufficient. You then have to protect any > subroutines launched out of the ISR with #pragma interrupt called. > > If you find yourself doing a lot of #pragma interrupt called for a > particular ISR then it is more efficient to save the entire context > once with a #pragma interrupt saveall for the ISR than saving many > partial contexts for the ISR and all the called routines. |
|
|
|
I'm not even doing the
math (%) inside the ISR - the % is in main.
Rick
Corey
|
|
--- In , "Pete Becher" <pbecher@d...> wrote: > Hi All, > > I was wondering. If you have a C function that you want to use as an > ISR but also call from the main loop does "#pragma interrupt" work > for both? Does it require 2 different functions? What are the > implications. There are times you can get away with calling a routine that is "#pragma interrupt" enabled from outside of an ISR processing thread. Basically when you call such a routine you are needlessly saving and restoring the core's registers. This is just inefficient. But at the return you are also enabling interrupts. That is the difference between an RTI (return from interrupt) instead RTS (return from subroutine). The #pragma enabled routine will return via RTI. If enabling interrupts at that time causes on harm to your application then you can get away with it. But be sure that it doesn't renable interrupts when you desire to keep them masked. If you don't want this risk then you can code up two separate routines in C. You can also code the routine in assembly and check the SR to see if interrupts are enabled or masked. Then you can save or not save context accordingly. > > Thanks, > Pete |
|
Correct me
if I'm wrong, but strictly speaking the difference between an "RTI" and an "RTS" is restoration
of the SR register. This MIGHT reenable interrupts, but it doesn't necessarily do
so, right?
If a
"#pragma interrupt" routine was called from the main loop it would simply restore the interrupt
status that was active at that time. If interrupts were off they should remain
off.
-----Original
Message-----
From: Michael W. Mann [mailto:M...@Motorola.Com] Sent: Tuesday, April 13, 2004 2:50 PM To: m...@yahoogroups.com Subject: [motoroladsp] Re: #pragma interrupt / modulus (%) affects interrupts? --- In m...@yahoogroups.com, "Pete Becher" <pbecher@d...> |
|
Hi
RTI usually restores
the SR by popping it off the stack.
If you encounter an
RTI, but you never pushed the SR onto the stack in a matching "go to ISR" mechanism, the RTI
should break the stack most fatally.
Maybe you could set up
a "callback function" (non-ISR, with no RTI). Have the ISR itself do nothing but call the
callback function. Since the ISR shell would contain the RTI, main could call it,
too, without blowing the stack.
Of course the callback
function would have to be re-entrant or have ISR protection.
(Maybe callback is the
wrong term if it is called directly from inside the ISR.)
Rick
Corey
|