Re: How to manipulate a receiving buffer



On Apr 4, 11:47 pm, "Dave Pollum" <vze24...@xxxxxxxxxxx> wrote:
On Apr 3, 10:46 pm, "Steven Woody" <narkewo...@xxxxxxxxx> wrote:



On Apr 4, 3:26 am, David R Brooks <daveb...@xxxxxxxxxxxx> wrote:

Steven Woody wrote:
On 4月4日, 上午1时37分, "Arlet" <usene...@xxxxxxxxxx> wrote:
On Apr 3, 7:13 pm, "Steven Woody" <narkewo...@xxxxxxxxx> wrote:

On 4月4日, 上午12时06分, "Arlet" <usene...@xxxxxxxxxx> wrote:
On Apr 3, 5:11 pm, "John Speth" <johnsp...@xxxxxxxxx> wrote:
__interrupt on_byte_in( void )
{
if ( buffer_len < sizeof( buff ) )
buffer[ buffer_len++ ] = the_byte_in_the_register;
}
flush_receiving_buff( void )
{
for ( size_t i = 0; i < buff_len; ++i ) {
process the buff[ i ];
buff_len = 0; ------------- (a)
}
my question is that, during the execution of statement (a), one or
more new bytes might come in and code above will lost them. if you
folks see the problem, can you please suggest me a solution?
Yes, it's basic. You'll need to disable your receive interrupt during
statement (a) execution. Doing so will prevent the ISR from executing and
changing buff_len while your flush function is also changing it.
It would also be a good idea to declare 'buff_len' as volatile.
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. Powers of two are recommended to
avoid modulo operation. If your compiler doesn't optimize away the
modulo, rewrite it as '& (BUFF_SIZE-1)'. For larger BUFF_SIZE, use a
bigger type.
Arlet,
1, does you ment to say, by letting the on_byte_in wrte only one
variable and letting the flush_receiving_buff write only another
variable, hence the code above don't need to be pretected into a
disable/enable interrupt section?
True. Instead of having a single 'length', this code uses two
variables, and the 'length' is the difference between them. The
interrupt handler only changes head, and the main code only changes
tail, so there's no conflict. It does require atomic reads, though.. On
an 8-bit architecture, where the CPU doesn't have a 16-bit read,
you'll be restricted to 8-bit head/tail counters. For most
applications on an 8-bit platform this is sufficient for a UART
buffer.

thanks for you answer. and, even in a 8-bit architecture, one need to
receive a network packet which may longer than 255 bytes :-( in the
case, data might be lost. am i right?

2, what's the exact functionality of keyword 'volatile', what's the
different if don't use it?
'volatile' tells the compiler not to optimize away memory references.
For example in the while loop:

while( buff_head != buff_tail )

Without the volatile, the compiler could assume that buff_head never
changes, and may therefore load the value in a register before the
while loop, and never read it again. With the 'volatile' keyword, the
buff_head variable will be read from memory before every comparison.
Since buff_tail is not modified in the interrupt handler, it does not
need to be volatile.

thank you very much!

3, can you please answer me another question: will a disabled
interrupt pop up again after it is enabled?
On any sane architecture, yes.

so, if in a disable/enable interrupt secion, there are two bytes comes
in, the first byte will be lost since the interrupt will appear only
once after the enable interrupt instruction. am i righ? ( supposing i
am talking about a UART with only one byte FIFO ).

One thing wasn't clear from the original problem description: will the
fn. flush_receiving_buff() always clear the buffer to empty (for
example, if a complete packet is been received?
If so, you might consider using two receiving buffers, controlled by a
pointer. __interrupt on_byte_in() will load the buffer indicated by the
pointer. Once a full packet is received, the pointer is switched to the
second buffer, & the first is processed at your leisure.
This is the classic double buffer setup. Of course, the actual switching
of the pointer may need protecting as a critical section (eg by
disabling interrupts).

i understand this kind of double buffer setup. but for some reasons i
dont want to put packet recognizing logical into the ISR.

-
woody

I've used double buffering with packet/protocol logic in the ISR, and
that works well. However, if you don't want the packet logic in the
ISR, you could still use double buffering. The ISR could mark a
buffer as ready for the upper level code, and then store more
characters in the _other_ buffer. Ready could be set if the buffer is
full, or if a certain amount of time has passed and no new characters
have been received. The ISR can save the numbers of bytes received in
a variable associated with that buffer (use a struct - see below).
After the upper level code has read all of the chars from the buffer,
it as available. The ISR can then use that buffer again. Disabling
and restoring interrupts aren't needed. This eliminates the need for
both the ISR code and the upper level code to write to the count
(buff_len) variable.

typedef struct {
char nbr_bytes_read; /* 0..255 */
char OK_to_read_buffer; /* T/F */
char buffer[ BUFF_SZ ];
} buffer_stuff;
buffer_stuff *buffer_1;
buffer_stuff *buffer_2;

-Dave Pollum

thank you David.

.



Relevant Pages

  • Re: General Q: Interrupt vs. Polling
    ... An external device writes data to two buffers in my DSP. ... Interrupt DSP ... Write block of data to Buffer B ... DSP processes all data within the ISR ...
    (comp.arch.embedded)
  • Re: ZwWriteFile and buffer reuse
    ... Is it your ISR code???????? ... interrupt routine that ZwWrite routine is completed. ... You cannot touch a buffer passed to NtReadFile/NtWriteFile while it is ...
    (microsoft.public.development.device.drivers)
  • Re: How to manipulate a receiving buffer
    ... ISR, you could still use double buffering. ... characters in the _other_ buffer. ... After the upper level code has read all of the chars from the buffer, ...
    (comp.arch.embedded)
  • Re: How to manipulate a receiving buffer
    ... ISR, you could still use double buffering. ... characters in the _other_ buffer. ... After the upper level code has read all of the chars from the buffer, ... The first buffer is filled and processing starts, ...
    (comp.arch.embedded)
  • Re: Does .S files defines and implements some fuctions for the ISR?
    ... When I write the MC8051 program,there is buffer to recive or send the date ... If the ISR doesn't copy the data from register to buffer, ... interrupt source, disable the specific interrupt and return a SYSINTR ... (l'indirizzo di reply di questo messaggio non ?valido) ...
    (microsoft.public.windowsce.platbuilder)