Thanks everyone for the feedback! This is indeed more tricky than I had 
thought. 
I'll post back later with a revised implementation 
:)



On Tuesday, October 21, 2014 12:44:05 PM UTC-5, Guy Grotke wrote:
>
> I have not done this with the PRU, but I work with all sorts of other 
> chips that have to use ring buffers.  It is usually easiest to start 
> with head = tail = 0 as the starting (buffer empty) case. Then drop 
> bytes on the sender side if head++ would == tail.  It gets really simple 
> if the head and tail indexes (not pointers) are a data size that equals 
> the size of your ring buffer, for example a 256 byte buffer with 
> unsigned char indexes, because then you just increment the indexes right 
> across the 255=>0 wrap point. 
>
> On 10/21/2014 8:06 AM, Bas Laarhoven wrote: 
> > On 21-10-2014 16:33, Charles Steinkuehler wrote: 
> >> On 10/20/2014 4:05 PM, Rafael Vega wrote: 
> >>> Thanks for the input Peter, you made me realize I had a mistake: 
> >>> 
> >>> The idea here is that ONLY the PRU changes the end pointer (write 
> >>> position 
> >>> pointer) and ONLY the ARM changes the start pointer (read position 
> >>> pointer).  Also, the pointers are updated AFTER the data is read or 
> >>> written 
> >>> (thus the memory barrier on the ARM side). 
> >>> 
> >>> When the ARM is reading/updating the start pointer, the PRU could 
> write 
> >>> messages to fill the buffer, changing the start pointer and 
> >>> corrupting the 
> >>> buffer. To avoid this, I have changed the PRU code as follows. Note 
> >>> that if 
> >>> the buffer is full, new messages will be dropped, you can lower the 
> >>> chances 
> >>> of this happening by making the buffer larger. 
> >>> 
> >>> inline void buffer_write(unsigned int message){ 
> >>>     unsigned int is_full = (*buffer_end == 
> >>> (*buffer_start^buffer_size)); // 
> >>> ^ is orex 
> >>>     if(!is_full){ 
> >>>        shared_ram[*buffer_end & (buffer_size-1)] = message; 
> >>>        *buffer_end = (*buffer_end+1) & (2*buffer_size - 1); 
> >>>     } 
> >>> } 
> >> Careful with the buffer size handling!  It's hard to tell the 
> difference 
> >> between empty and full, since in both cases the read and write pointers 
> >> are identical. 
> >> 
> >> It looks like you're trying to use an extra bit of buffer_end to track 
> >> empty/full, but I don't think your logic is correct.  I don't see how 
> >> the MSB (indicating buffer full) ever gets cleared once set. 
> >> 
> >> I've found it's usually much less hassle to live with a maximum buffer 
> >> size of N-1 (ie: full = 127 elements, not 128) rather than try to 
> >> properly handle the complexity of properly tracking empty/full. Note 
> >> that there are *LOTS * of subtle ways you can mess up the empty/full 
> >> logic (it's even harder to do properly than the basic pointer handling 
> >> for reads/writes), so if you do try to use all buffer elements, be 
> >> *VERY* careful with your code.  I recommend reviewing the Linux kernel 
> >> code if you need a reference implementation. 
> >> 
> > 
> > Rafael, 
> > 
> > This is good advice from Charles! I've been running this n-1 scheme 
> > with my own 
> > PRU code and BeBoPr software for over two years now and it has proven 
> > rock stable. 
> > No concurrency or cache coherency issues, no locking needed and no 
> > data re-ordering 
> > problems! 
> > 
> > You can find the C-code in the following file: 
> > https://github.com/modmaker/BeBoPr/blob/master/pruss_stepper.c 
> > (start with 'pruss_command') 
> > The PRUSS code is not open source, but I think the C-code shows enough 
> > detail. 
> > 
> > Cheers, 
> > -- Bas 
> > 
>
>

-- 
For more options, visit http://beagleboard.org/discuss
--- 
You received this message because you are subscribed to the Google Groups 
"BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to