EmbeddedRelated.com
Forums
Memfault Beyond the Launch

How to manipulate a receiving buffer

Started by Steven Woody April 3, 2007
>> First set up your buffer, setup 2 pointers to it, the serial interrupt >> uses one of them to write each byte, incrementing each time (ie a >> circular pointer). Ditto for your reading routine (use the other >> pointer). To flush the buffer set both pointers to the same number. >> You will not need to disable the serial interrupt. > > That's true as long as you know that reading/writing a pointer > is an atomic operation. That's not true for all > microprocessors. For example, on the AVR, reading/writing a > pointer isn't atomic -- a MAJOR flaw in any processor that's > intended for use with C -- one of the reasons I dislice the AVR > ISA. >
Use a Producer/Consumer with separate pointers. I.E Receive interrupt subroutine writes data to the Software FIFO and updates its write pointer. This is an atomic operation because the main loop will not interrupt the interrupt. The main loop can disable interrupts while accessing the pointer. In Embedded C++, you can probably define a "++" operator which operates on circular buffers which handles everything for you. -- Best Regards, Ulf Samuelsson This is intended to be my personal opinion which may, or may not be shared by my employer Atmel Nordic AB
In article <1175738083.526529.80590@l77g2000hsb.googlegroups.com>, "Steven Woody" <narkewoody@gmail.com> writes:
> > only a little confusing: in the Linux-Serial-HOWTO, i saw that > negating RTS is used to stop incoming flow and raising RTS is used to > resume the incoming flow. >
Sorry for not been clear; I was thinking of the signals as presented at the device that you want to stop sending you data when I wrote my response, which is why I talked about CTS and not RTS. The document is correct in that it's usually the case that the RTS pin on the device running the interrupt handler is connected to the CTS pin on the device whose data transmission you want to control (the HOWTO is obviously looking at it from the viewpoint of the device running the interrupt handler). Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980's technology to a 21st century world
In article <ev2i1i$qhh$2@aioe.org>, "Ulf Samuelsson" <ulf@a-t-m-e-l.com> writes:
> > Hope everyone is aware that the RTS/CTS is to be considered > a recommendation to the other end to try to stop its babbling. > > You must expect to get AT LEAST 16 more incoming characters > if you want to be PC compliant. >
Interesting. I must admit that I was looking at it from the viewpoint of microcontroller/unbuffered device to microcontroller communication. In your example therefore, if the OP's talking to a device using buffered UART controllers, then he simply can't have interrupts off for an extended period, unless his UART also does buffering. Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980's technology to a 21st century world
On 2007-04-05, Ulf Samuelsson <ulf@a-t-m-e-l.com> wrote:

>>> First set up your buffer, setup 2 pointers to it, the serial >>> interrupt uses one of them to write each byte, incrementing >>> each time (ie a circular pointer). Ditto for your reading >>> routine (use the other pointer). To flush the buffer set both >>> pointers to the same number. You will not need to disable the >>> serial interrupt. >> >> That's true as long as you know that reading/writing a pointer >> is an atomic operation. That's not true for all >> microprocessors. For example, on the AVR, reading/writing a >> pointer isn't atomic -- a MAJOR flaw in any processor that's >> intended for use with C -- one of the reasons I dislice the >> AVR ISA. > > Use a Producer/Consumer with separate pointers.
Yes, that's what we were describing. It doesn't work on an AVR because pointer read/write operations are not atomic.
> I.E Receive interrupt subroutine writes data to the Software > FIFO and updates its write pointer. This is an atomic > operation because the main loop will not interrupt the > interrupt.
But reading the pointer is not an atomic operation. It doesn't matter if only one of the read/write operations is non-atomic. The algorithm only works without disabling interrupts if _both_ reading and writing the pointer is atomic.
> The main loop can disable interrupts while accessing the pointer.
No it can't. We were discussing methods where there was no disabling of interrupts. That only works if reading and writing the buffer positions are both atomic operations. If you use pointers on an AVR, reading/writing them is not an atomic operation and therefore can not be done without disabling interrupts.
> In Embedded C++, you can probably define a "++" operator > which operates on circular buffers which handles everything for you.
In other words, "You can use the 'producer consumer' model without disabling interrupts. All you have to do is disable interrupts?" -- Grant Edwards grante Yow! I'm losing my at hair...did it go to visi.com ATLANTIC CITY??
Simon Clubley wrote:
> "Ulf Samuelsson" <ulf@a-t-m-e-l.com> writes: >> >> Hope everyone is aware that the RTS/CTS is to be considered >> a recommendation to the other end to try to stop its babbling. >> >> You must expect to get AT LEAST 16 more incoming characters >> if you want to be PC compliant. > > Interesting. I must admit that I was looking at it from the > viewpoint of microcontroller/unbuffered device to microcontroller > communication. > > In your example therefore, if the OP's talking to a device using > buffered UART controllers, then he simply can't have interrupts > off for an extended period, unless his UART also does buffering.
What you do know is that sender buffered data will be sent at full speed. Therefore you only need to inhibit the sending with RTS and wait for a limited period, say enough to transmit 16 chars. Now you don't have to inhibit that interrupt (although you may do so). Your receiving UART may be able to hardware buffer that many characters before interrupting anyhow, mitigating the problem of enforcing a delay. -- <http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt> <http://www.securityfocus.com/columnists/423> <http://www.aaxnet.com/editor/edit043.html> "A man who is right every time is not likely to do very much." -- Francis Crick, co-discover of DNA "There is nothing more amazing than stupidity in action." -- Thomas Matthews -- Posted via a free Usenet account from http://www.teranews.com
Arlet wrote:
>
... snip ...
> > Of course, the mod may be unacceptably slow, so in that case > BUFF_SIZE needs to be restricted to a constant power of two (with > 128 being the highest number that meets the requirements), so it > can be implemented by a bitwise 'and'. Any decent compiler will do > the optimization automatically. Using the mod is still possible if > it meets the timing requirements, and if there's a need for > special buffer sizes.
After proper initialization you don't need a mod operation. The code can take the faster form: if (BUFF_SIZE == ++index) index = 0; eliminating the need for a power of two. -- <http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt> <http://www.securityfocus.com/columnists/423> <http://www.aaxnet.com/editor/edit043.html> "A man who is right every time is not likely to do very much." -- Francis Crick, co-discover of DNA "There is nothing more amazing than stupidity in action." -- Thomas Matthews -- Posted via a free Usenet account from http://www.teranews.com
Grant Edwards wrote:
> On 2007-04-05, Ulf Samuelsson <ulf@a-t-m-e-l.com> wrote: >
... snip ...
> >> I.E Receive interrupt subroutine writes data to the Software >> FIFO and updates its write pointer. This is an atomic >> operation because the main loop will not interrupt the >> interrupt. > > But reading the pointer is not an atomic operation. It doesn't > matter if only one of the read/write operations is non-atomic. > The algorithm only works without disabling interrupts if _both_ > reading and writing the pointer is atomic.
So don't use pointers, use indices, which can be single bytes, and reading or writing must be atomic. -- <http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt> <http://www.securityfocus.com/columnists/423> <http://www.aaxnet.com/editor/edit043.html> "A man who is right every time is not likely to do very much." -- Francis Crick, co-discover of DNA "There is nothing more amazing than stupidity in action." -- Thomas Matthews -- Posted via a free Usenet account from http://www.teranews.com
On 2007-04-07, CBFalconer <cbfalconer@yahoo.com> wrote:
> Grant Edwards wrote: >> On 2007-04-05, Ulf Samuelsson <ulf@a-t-m-e-l.com> wrote: >> > ... snip ... >> >>> I.E Receive interrupt subroutine writes data to the Software >>> FIFO and updates its write pointer. This is an atomic >>> operation because the main loop will not interrupt the >>> interrupt. >> >> But reading the pointer is not an atomic operation. It doesn't >> matter if only one of the read/write operations is non-atomic. >> The algorithm only works without disabling interrupts if _both_ >> reading and writing the pointer is atomic. > > So don't use pointers, use indices, which can be single bytes, and > reading or writing must be atomic.
Yes, I know. I already said that. Then ULF said that it didn't matter that pointer accesses weren't atomic on the AVR because you could use a "producer consumer pattern". -- Grant Edwards grante Yow! ANN JILLIAN'S HAIR at makes LONI ANDERSON'S visi.com HAIR look like RICARDO MONTALBAN'S HAIR!
Arlet wrote:
> On Apr 5, 4:45 am, Thad Smith <ThadSm...@acm.org> wrote: > >>Arlet wrote: >> >>>Alternatively, you could use something similar to this, and leave >>>interrupts enabled: >> >>>static unsigned char buff[ BUFF_SIZE ]; >>>static volatile unsigned char buff_head; >>>static unsigned char buff_tail; >> >>>__interrupt on_byte_in( void ) >>>{ >>> if ( (unsigned char) (buff_head - buff_tail) < BUFF_SIZE ) >>> buff[ buff_head++ % BUFF_SIZE ] = the_byte_in_the_register; >> >>>} >> >>>flush_receiving_buff( void ) >>>{ >>> while( buff_head != buff_tail ) >>> process the buff[ buff_tail++ % BUFF_SIZE ]; >>>} >> >>>This works only if BUFF_SIZE < 256. >> >>It only works if BUFF_SIZE divides evenly into UCHAR_MAX+1. In order to >>fix this, store the incremented indexes after mod reduction (which >>normally works faster by comparison, rather than mod operator). Also, >>you have BUF_SIZE+1 states to distinguish: 0 through BUF_SIZE stored >>characters. They can't be uniquely distinguished by the comparisons >>shown in the code. The standard approach is to either use a separate >>state variable or to eliminate the all full state by storing a max of >>BUF_SIZE-1 characters. > > > Actually, it works as long as the number of possible states can be > represented by an unsigned char, or (BUFF_SIZE+1) <= (UCHAR_MAX+1). In > theory, BUFF_SIZE could be as high as 255. The fact that the > comparison is done _before_ the mod reduction makes sure that we still > have the complete state information available.
Let's assume BUFF_SIZE = UCHAR_MAX = 255. At initialization buff_head and buff_tail = 0. We get 255 insertions into buff[0] to buff[254] without removals, leaving buff_head = 255. We know that another insertion will be refused if there is no removal. Let's take out one byte, leaving buff_tail = 1. Now we get another insertion, which is allowed since (255-1) < 255, and put it in buff[255%255] = buff[0]. OK so far. buff_head is incremented to 0. Remove the second byte from buff[1], leaving buff_tail = 2. Do another insertion, which is allowed since (unsigned char)(0-2) < 255. We place the character into buff[0%255] = buff[0], which overwrites the previously stored (and unfetched) character. It's broken. -- Thad
 If all code is structured , you have a

  2nd choice , to poll the serial port .

  If the kernel is structured , it can keep

 track of all the critical tasks , easily .

  If you ask the kernel to do an important

 task , is it important enuf to ignore

 the serial port ?

 Maybe , you are the programmer .

   In my machine , i am getting critical

  data from the old RS232 , i am

 using a modern mcu , with 16 char

 buffer .  This gives kernel enuf

 time to execute any task ( structure allows

 you to time it perfectly )

  and never overrun the ser' buffer .

   Its much faster to write a kernel from

 scatch , if you structure it with low level

 primatives , then mid-levels ( looks like

 a list of lists ) .

  C/C++ wont help you do this .



   My project is a ARM pocket PC .

  I will not use anyones code , i will not

 study any books , nor use the English

 language , nor ASCII text .

  It will be a tiny G.U.I. in 8 KB .

  Then expand it to 32Kb ....then

 to 1 megabyte ..





Memfault Beyond the Launch