How to manipulate a receiving buffer

r;

----------- (a)

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. Your read routine must check the pointers are not the same before reading (buffer empty) the write routine must check they are not the same after writing (buffer overflow).

Reply to
cbarn24050
Loading thread data ...

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.

For such processors use of an index variable that's fewer bits than a pointer will often work -- I don't know of any popular microprocessors where reading/writing an 8-bit variable isn't an atomic operation (of course that limits your buffer size to

256 bytes).

--
Grant Edwards                   grante             Yow!  What PROGRAM are
                                  at               they watching?
                               visi.com
Reply to
Grant Edwards

This works provided you carefully control the order of operations, and ensure that the read index is advanced only by the read process, and the write index by the write process. Advancing those indices must be modulo buffersize, and so must the comparisons that establish "bufferNotEmpty" and "bufferNotFull". Always keep in mind that one routine may be interrupted to execute the other at any time. Only the read routine can alter the NotFull condition, and only the write routine can alter the NotEmpty condition.

If the buffer size is under 256 bytes, you can usually ensure that the indices (not pointers) read/writes are atomic. Unsigned char are useful here. A buffer of exactly UCHAR_MAX+1 length makes the modulo operations automatic. When these indices get larger you will need to resort to critical sections.

--
Please do not top-post.  Your answer belongs after (or intermixed
with) the quoted material to which you reply, after snipping all
irrelevant material.  See the following links:

  
  
  
    (taming google)
    (newusers)
Reply to
CBFalconer

e or

f you

during

ecuting and

ister;

d to

he

se a

. On

to

he

es.

er

the

n=2E

not

mes

i

the

he

ing

thank you David.

Reply to
Steven Woody

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.

Reply to
Steven Woody

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.

--
Thad
Reply to
Thad Smith
[150 lines of crap deleted]

For kibo's sake trim the quoted material. Was it really necessary to quote 150 lines of old material to add that one single line of new text?

-- Grant Edwards grante Yow! "THE LITTLE PINK at FLESH SISTERS," I saw them visi.com at th' FLUROESCENT BULB MAKERS CONVENTION...

Reply to
Grant Edwards

... snip ...

Bear in mind that the effect of RTS (request-to-send) is not immediate. The sender may well have some number of characters buffered and ready to go. So the receiver has to be able to handle that.

--
 
 
 
 
 "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
Reply to
CBFalconer

Actually, it works as long as the number of possible states can be represented by an unsigned char, or (BUFF_SIZE+1)

Reply to
Arlet

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.

The NS16550 UART chip, was an improvement of the NS16450 UART, adding a 16 level FIFO. If something is written to the FIFO before the hardware flow control is deasserted, the data gets sent without regards to the flow control.

--
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
Reply to
Ulf Samuelsson

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
Reply to
Ulf Samuelsson

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
Reply to
Simon Clubley

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
Reply to
Simon Clubley

Yes, that's what we were describing. It doesn't work on an AVR because pointer read/write operations are not atomic.

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.

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 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??
Reply to
Grant Edwards

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.

--
 
 
 
 
 "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
Reply to
CBFalconer

... snip ...

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.

--
 
 
 
 
 "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
Reply to
CBFalconer

... snip ...

So don't use pointers, use indices, which can be single bytes, and reading or writing must be atomic.

--
 
 
 
 
 "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
Reply to
CBFalconer

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!
Reply to
Grant Edwards

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
Reply to
Thad Smith

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 ..

Reply to
werty

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.