At 06:38 AM 2/19/04 +1100, you wrote: > > FIFO. When you get an interrupt you can sit in a loop and stuff the FIFO > > full before returning. That nicely lowers the interrupt overhead by a > > factor of 15 or 16. On the down side the main service body will take > > longer, maybe not a full 15x longer but longer so that each individual > > interrupt may be longer and increase your latency. If you just put in one > > character and exit the interrupt it will probably act just as you say. > >How do you then know when the FIFO is full ? There is nothing >accessible to tell you. >Do you maintain a counter loop that lets you only write up to 16 chars >in the FIFO ? >The description on page 89 is really ambiguous, it implies that if 2 or more >chars are in the FIFO _and_ the shiftregister has just flushed out a char, >that THRE will set too. >THRE when FIFO empty "provided" certain init conditions have been met. >Is this referring to the char delay so no INTs will issue straight away at >start up ? >I guess so. I don't see another way than maintaining a counter. From National's data sheet pg 19 When the XMIT FIFO and transmitter interrupts are enabled (FCR0e1, IER1e1), XMIT interrupts will occur as follows: A. The transmitter holding register interrupt (02) occurs when the XMIT FIFO is empty; it is cleared as soon as the transmitter holding register is written to (1 to 16 characters may be written to the XMIT FIFO while servicing this interrupt) or the IIR is read. B. The transmitter FIFO empty indications will be delayed 1 character time minus the last stop bit time whenever the following occurs: THREe1 and there have not been at least two bytes at the same time in the transmit FIFO, since the last THREe1. The first transmitter interrupt after changing FCR0 will be immediate, if it is enabled. Character timeout and RCVR FIFO trigger level interrupts have the same priority as the current received data available interrupt; XMIT FIFO empty has the same priority as the current transmitter holding register empty interrupt. It's a little easier to follow in the datasheet. " 'Freedom' has no meaning of itself. There are always restrictions, be they legal, genetic, or physical. If you don't believe me, try to chew a radio signal. " Kelvin Throop, III |
UART TX FIFO and INTs problem
Started by ●February 17, 2004
Reply by ●February 18, 20042004-02-18
Reply by ●February 18, 20042004-02-18
Thanks Robert, I had downloaded it in the meantime, and had gone through it. Bitmaps etc. seemed identical to LPC2000, so I guess it's a true 16C550 "industry-standard" like the datasheet claims. BTW : Maybe I should clarify that when I mentioned about disabling global INTs instead of U0IER.THRE, that I was referring to the IRQs of course. The program that caused resets before has been running for over an hour now, and no problems anymore. It might also pay to note that I use the ldr pc, [pc,-0xFF0] instruction for immediate vectoring. I really studied the VIC part, and there was no mention anywhere that you can't disable/re-enable specific IRQs the way I did. Still got more studying to do I guess, if anyone has any ideas why this was happening, I'd love to hear about it. Re. doign prologue/epilogue in ASM, I totally agree that it's a good way to learn the ins and outs better of the CPU. That was going to be the next thing I did. -- Kris ----- Original Message ----- From: "Robert Adsett" <> To: <> Sent: Thursday, February 19, 2004 7:34 AM Subject: Re: [lpc2000] UART TX FIFO and INTs problem > At 06:38 AM 2/19/04 +1100, you wrote: > > > FIFO. When you get an interrupt you can sit in a loop and stuff the FIFO > > > full before returning. That nicely lowers the interrupt overhead by a > > > factor of 15 or 16. On the down side the main service body will take > > > longer, maybe not a full 15x longer but longer so that each individual > > > interrupt may be longer and increase your latency. If you just put in one > > > character and exit the interrupt it will probably act just as you say. > > > >How do you then know when the FIFO is full ? There is nothing > >accessible to tell you. > >Do you maintain a counter loop that lets you only write up to 16 chars > >in the FIFO ? > >The description on page 89 is really ambiguous, it implies that if 2 or more > >chars are in the FIFO _and_ the shiftregister has just flushed out a char, > >that THRE will set too. > >THRE when FIFO empty "provided" certain init conditions have been met. > >Is this referring to the char delay so no INTs will issue straight away at > >start up ? > >I guess so. > > I don't see another way than maintaining a counter. From National's data > sheet pg 19 > > When the XMIT FIFO and transmitter interrupts are enabled > (FCR0e1, IER1e1), XMIT interrupts will occur as follows: > > A. The transmitter holding register interrupt (02) occurs > when the XMIT FIFO is empty; it is cleared as soon as > the transmitter holding register is written to (1 to 16 characters > may be written to the XMIT FIFO while servicing > this interrupt) or the IIR is read. > > B. The transmitter FIFO empty indications will be delayed 1 > character time minus the last stop bit time whenever the > following occurs: THREe1 and there have not been at > least two bytes at the same time in the transmit FIFO, > since the last THREe1. The first transmitter interrupt after > changing FCR0 will be immediate, if it is enabled. > > Character timeout and RCVR FIFO trigger level interrupts > have the same priority as the current received data available > interrupt; XMIT FIFO empty has the same priority as > the current transmitter holding register empty interrupt. > > It's a little easier to follow in the datasheet. > > " 'Freedom' has no meaning of itself. There are always restrictions, > be they legal, genetic, or physical. If you don't believe me, try to > chew a radio signal. " > > Kelvin Throop, III > > -- ------ > Yahoo! Groups Links > > a.. To |
|
Reply by ●February 18, 20042004-02-18
I just uploaded a ZIP file containing my UART and elapsed system timer code. It is a simple program which uses some very helpful support routines. The code is configured for the Nohau LPC2106 TESTER eval board but is easily reconfigurable for other LPC processors. Regards -Bill Knight R O SoftWare |
Reply by ●February 22, 20042004-02-22
Hi all, This s a hairy one - ARM Gurus, please read this !!! (Bill, this will cause a problem in your UART package too, since you set VicDefVectAddr to the Reset Vector, and you also use a RMW operation on UxIER) I figured out why I was getting "resets" while UART0 is TXing interrupt driven. The problem only occurs when I disable the THE interrupt by masking : U0IER &= ~ 0x02; /* Disable THE */ ...... U0IER |= 0x02; When I disable and then re-enable THE interrupts with a direct write : U0IER = 0x01; /* Disable THE, leave RDA enabled */ ..... U0IER = 0x03; /* Reenable THE */ I didn't get these "resets". This is the problem : ----------------------- I didn't have VicDefVectAddr specified, so it was set to its default 0x00000000 address. (All IRQs are disabled, except for VIC Channel # 6) While U0IER &= ~ 0x02 is executing, there MUST be a few cycles where the THE is disabled, BUT the interrupt asserts at the right moment, hence causing a non-vectored assertion.... (which of course vectors to 0x000000, and ultimately results in a RESET) Is this a known problem on the VIC ? Is this normal on the VIC ? I put in a "dummy" function default_IRQ_handler() so I can break on it, and when it hits that function, VicRawIntr reads 0x3008. If I merely indicate on a LED when that function is hit, but then return from interrupt, the execution happpily picks up after the U0IER &=~0x02; statement, and things run as good as gold. NO TX interrupts were missed by the looks of it, since the non-vectored dummy function doesn't service or alter anything, the pending interrupt must be serviced when THE is re-emabled. Are there any ARM gurus here that can shed some light on this ? I've been just about driven to tears over this problem. I can't just use a direct write (I have an interrupt on the other UART in RX, and that operates on a CRC function, the RF transmit function needs to operate on the same CRC function, so I need masking of the Interrupt Enables, rather than directly setting/clearing all INT sources on UxIER) As far as I'm concerned this classifies as a silicon BUG, since UxIER bits cannot assert themselves, and it is indeed a R/W register. BTW : How do I work out with VicRawIntr (0x3008 in my case) which Slot/Int is asserted ? I can't find a bitmap on it. Best regards, Kris |
|
Reply by ●February 22, 20042004-02-22
> BTW : How do I work out with VicRawIntr (0x3008 in my case) which
Slot/Int is asserted ? > I can't find a bitmap on it. Thinking about this again, I presume that the bit # in VicRawIntr corresponds to the VIC Slot # ? That would mean that ARM Core, Embedded ICE - DbgCommTX and PLL Locl, RTCCIF are always asserted when I have the break point in the Default IRQ handler ? -- Kris |
Reply by ●February 22, 20042004-02-22
Kris Thanks for spotting this. It's the old spurious interrupt problem. The fix is to disable global interrupts around the first read-modify-write instruction. Doing the direct write (U0IER = xxx) can still allow the problem to happen. What happens is the interrupt occurs and is recognized while the masking instruction is executing but before it has completed. Then when the instruction does complete, the interrupt can't find the vector so uses the default. So to fix: Disable global interrupts mask interrupt Enable global interrupts do your stuff unmask interrupt NOTE: I don't think this last modification of the mask register needs protection. Someone correct me if I am wrong. Regards -Bill Knight R O SoftWare On Mon, 23 Feb 2004 02:09:38 +1100, microbit wrote: Hi all, This s a hairy one - ARM Gurus, please read this !!! (Bill, this will cause a problem in your UART package too, since you set VicDefVectAddr to the Reset Vector, and you also use a RMW operation on UxIER) I figured out why I was getting "resets" while UART0 is TXing interrupt driven. The problem only occurs when I disable the THE interrupt by masking : U0IER &= ~ 0x02; /* Disable THE */ ...... U0IER |= 0x02; When I disable and then re-enable THE interrupts with a direct write : U0IER = 0x01; /* Disable THE, leave RDA enabled */ ..... U0IER = 0x03; /* Reenable THE */ I didn't get these "resets". This is the problem : ----------------------- I didn't have VicDefVectAddr specified, so it was set to its default 0x00000000 address. (All IRQs are disabled, except for VIC Channel # 6) While U0IER &= ~ 0x02 is executing, there MUST be a few cycles where the THE is disabled, BUT the interrupt asserts at the right moment, hence causing a non-vectored assertion.... (which of course vectors to 0x000000, and ultimately results in a RESET) Is this a known problem on the VIC ? Is this normal on the VIC ? I put in a "dummy" function default_IRQ_handler() so I can break on it, and when it hits that function, VicRawIntr reads 0x3008. If I merely indicate on a LED when that function is hit, but then return from interrupt, the execution happpily picks up after the U0IER &=~0x02; statement, and things run as good as gold. NO TX interrupts were missed by the looks of it, since the non-vectored dummy function doesn't service or alter anything, the pending interrupt must be serviced when THE is re-emabled. Are there any ARM gurus here that can shed some light on this ? I've been just about driven to tears over this problem. I can't just use a direct write (I have an interrupt on the other UART in RX, and that operates on a CRC function, the RF transmit function needs to operate on the same CRC function, so I need masking of the Interrupt Enables, rather than directly setting/clearing all INT sources on UxIER) As far as I'm concerned this classifies as a silicon BUG, since UxIER bits cannot assert themselves, and it is indeed a R/W register. BTW : How do I work out with VicRawIntr (0x3008 in my case) which Slot/Int is asserted ? I can't find a bitmap on it. Best regards, Kris |
|
Reply by ●February 22, 20042004-02-22
Hi Bill, Thanks for the prompt response. This has actually been my main problem. It's not my "style" when I develop to just change my SW, and go "oh, yeah, well it works like that but not like that, so what". If I write code a particular way, then I expect it to work a particular way, and if it doesn't - I want to know why ! Anywho, I'm glad I persisted with this. I had indeed noticed that I didn't have this weird problems either when I used Gloabl enable/disable on IRQ. Bah,what a pain. I'll use your workaround, it sounds plausible. I can't believe that this problem didn't show up when just printing away with printf(), but ONLY when running the BASIC interpreter, and with a specific program running ! Do you think I should maintain a Default_IRQ handler (I don't plan to use non-vectored INTs), case this happens again ? I'm naturally concerned that if I write to ViCVectAddr at end of Default_IRQ handler, that I'll miss actual INTs, as opposed to spurious INTs. Your summary must be dead-on, because I found that different optimisations would exhibit the problem or not. Thanks a lot ! Kris Bill wrote : > Kris > Thanks for spotting this. It's the old spurious interrupt problem. > The fix is to disable global interrupts around the first read-modify-write > instruction. Doing the direct write (U0IER = xxx) can still allow the problem > to happen. What happens is the interrupt occurs and is recognized while > the masking instruction is executing but before it has completed. Then > when the instruction does complete, the interrupt can't find the vector > so uses the default. So to fix: > > Disable global interrupts > mask interrupt > Enable global interrupts > > do your stuff > unmask interrupt > > NOTE: I don't think this last modification of the mask register needs > protection. Someone correct me if I am wrong. > Regards > -Bill Knight > R O SoftWare > > On Mon, 23 Feb 2004 02:09:38 +1100, microbit wrote: > > Hi all, > > This s a hairy one - ARM Gurus, please read this !!! > (Bill, this will cause a problem in your UART package too, since you > set VicDefVectAddr to the Reset Vector, and you also use a RMW > operation on UxIER) > > I figured out why I was getting "resets" while UART0 is TXing > interrupt driven. > The problem only occurs when I disable the THE interrupt by masking : > > U0IER &= ~ 0x02; /* Disable THE */ > ...... > U0IER |= 0x02; > > When I disable and then re-enable THE interrupts with a direct write : > > U0IER = 0x01; /* Disable THE, leave RDA enabled */ > ..... > U0IER = 0x03; /* Reenable THE */ > > I didn't get these "resets". > > This is the problem : > ----------------------- > > I didn't have VicDefVectAddr specified, so it was set to its default 0x00000000 > address. (All IRQs are disabled, except for VIC Channel # 6) > While U0IER &= ~ 0x02 is executing, there MUST be a few cycles where the THE > is disabled, BUT the interrupt asserts at the right moment, hence causing a non-vectored > assertion.... (which of course vectors to 0x000000, and ultimately results in a RESET) > Is this a known problem on the VIC ? > Is this normal on the VIC ? > > I put in a "dummy" function default_IRQ_handler() so I can break on it, and when it hits > that function, VicRawIntr reads 0x3008. > If I merely indicate on a LED when that function is hit, but then return from interrupt, the > execution happpily picks up after the U0IER &=~0x02; statement, and things run as good as gold. > NO TX interrupts were missed by the looks of it, since the non-vectored dummy function doesn't > service or alter anything, the pending interrupt must be serviced when THE is re-emabled. > > Are there any ARM gurus here that can shed some light on this ? > I've been just about driven to tears over this problem. > I can't just use a direct write (I have an interrupt on the other UART in RX, and that operates on > a CRC function, the RF transmit function needs to operate on the same CRC function, so I need > masking of the Interrupt Enables, rather than directly setting/clearing all INT sources on UxIER) > > As far as I'm concerned this classifies as a silicon BUG, since UxIER bits cannot assert themselves, > and it is indeed a R/W register. > > BTW : How do I work out with VicRawIntr (0x3008 in my case) which Slot/Int is asserted ? > I can't find a bitmap on it. > > Best regards, > Kris > -- ------ > Yahoo! Groups Links > > a.. To |
|
Reply by ●February 22, 20042004-02-22
Version 2 of the UART, Blinky LED codeis now posted. I went ahead and protected the code which re-enables the uart interrupt in addition to when it is disabled. While the demo code does not have a preemptive OS, if it did, it would be possible (not probable) for another process to sneak in during the execution of the RMW sequence and modify the mask. The protection closes that possibility. As a side note. The disabling and restoring of the global interrupt flag in the cpsr can has a similar problem. It has to do with the processor actually having multiple psr's and preemptive processes doing the same thing to it while the main line code thinks it is either enabling or disabling the current IRQ bit. However, without preemptive processes or ISR's which muck with the interrupt flag bits, I don't believe there is a problem. For more info on this, Atmel has an APP note discribing it on their web site in the AT91 ARM7 section. Regards -Bill Knight R O SoftWare |
|
Reply by ●February 22, 20042004-02-22
I don't think using the default handler to mask the problem is the answer. You might however, use it to inform the user &/or yourself of an internal error so it can be corrected in the next release of your code. -Bill On Mon, 23 Feb 2004 03:04:05 +1100, microbit wrote: Hi Bill, Thanks for the prompt response. This has actually been my main problem. It's not my "style" when I develop to just change my SW, and go "oh, yeah, well it works like that but not like that, so what". If I write code a particular way, then I expect it to work a particular way, and if it doesn't - I want to know why ! Anywho, I'm glad I persisted with this. I had indeed noticed that I didn't have this weird problems either when I used Gloabl enable/disable on IRQ. Bah,what a pain. I'll use your workaround, it sounds plausible. I can't believe that this problem didn't show up when just printing away with printf(), but ONLY when running the BASIC interpreter, and with a specific program running ! Do you think I should maintain a Default_IRQ handler (I don't plan to use non-vectored INTs), case this happens again ? I'm naturally concerned that if I write to ViCVectAddr at end of Default_IRQ handler, that I'll miss actual INTs, as opposed to spurious INTs. Your summary must be dead-on, because I found that different optimisations would exhibit the problem or not. Thanks a lot ! Kris Bill wrote : > Kris > Thanks for spotting this. It's the old spurious interrupt problem. > The fix is to disable global interrupts around the first read-modify-write > instruction. Doing the direct write (U0IER = xxx) can still allow the problem > to happen. What happens is the interrupt occurs and is recognized while > the masking instruction is executing but before it has completed. Then > when the instruction does complete, the interrupt can't find the vector > so uses the default. So to fix: > Disable global interrupts > mask interrupt > Enable global interrupts > do your stuff > unmask interrupt > NOTE: I don't think this last modification of the mask register needs > protection. Someone correct me if I am wrong. > Regards > -Bill Knight > R O SoftWare > On Mon, 23 Feb 2004 02:09:38 +1100, microbit wrote: > Hi all, > This s a hairy one - ARM Gurus, please read this !!! > (Bill, this will cause a problem in your UART package too, since you > set VicDefVectAddr to the Reset Vector, and you also use a RMW > operation on UxIER) > I figured out why I was getting "resets" while UART0 is TXing > interrupt driven. > The problem only occurs when I disable the THE interrupt by masking : > U0IER &= ~ 0x02; /* Disable THE */ > ...... > U0IER |= 0x02; > When I disable and then re-enable THE interrupts with a direct write : > U0IER = 0x01; /* Disable THE, leave RDA enabled */ > ..... > U0IER = 0x03; /* Reenable THE */ > I didn't get these "resets". > This is the problem : > ----------------------- > I didn't have VicDefVectAddr specified, so it was set to its default 0x00000000 > address. (All IRQs are disabled, except for VIC Channel # 6) > While U0IER &= ~ 0x02 is executing, there MUST be a few cycles where the THE > is disabled, BUT the interrupt asserts at the right moment, hence causing a non-vectored > assertion.... (which of course vectors to 0x000000, and ultimately results in a RESET) > Is this a known problem on the VIC ? > Is this normal on the VIC ? > I put in a "dummy" function default_IRQ_handler() so I can break on it, and when it hits > that function, VicRawIntr reads 0x3008. > If I merely indicate on a LED when that function is hit, but then return from interrupt, the > execution happpily picks up after the U0IER &=~0x02; statement, and things run as good as gold. > NO TX interrupts were missed by the looks of it, since the non-vectored dummy function doesn't > service or alter anything, the pending interrupt must be serviced when THE is re-emabled. > Are there any ARM gurus here that can shed some light on this ? > I've been just about driven to tears over this problem. > I can't just use a direct write (I have an interrupt on the other UART in RX, and that operates on > a CRC function, the RF transmit function needs to operate on the same CRC function, so I need > masking of the Interrupt Enables, rather than directly setting/clearing all INT sources on UxIER) > As far as I'm concerned this classifies as a silicon BUG, since UxIER bits cannot assert themselves, > and it is indeed a R/W register. > BTW : How do I work out with VicRawIntr (0x3008 in my case) which Slot/Int is asserted ? > I can't find a bitmap on it. > Best regards, > Kris > > -- ------ > Yahoo! Groups Links > a.. To Yahoo! Groups Links |
Reply by ●February 22, 20042004-02-22
Bill Knight wrote: > Kris > Thanks for spotting this. It's the old spurious interrupt problem. > The fix is to disable global interrupts around the first read-modify-write > instruction. Doing the direct write (U0IER = xxx) can still allow the > problem > to happen. What happens is the interrupt occurs and is recognized while > the masking instruction is executing but before it has completed. Then > when the instruction does complete, the interrupt can't find the vector > so uses the default. So to fix: > [snip] Why should the direct write cause this problem? The issue with read-modify-write makes perfect sense, but the write should be an atomic operation. How would you get an interrupt between <nothing> and the write? --jc |
|