On Wed, 19 Feb 2003, Tony Nixon wrote:
{Quote hidden}> Tony Harris wrote:
> >
> > That is really vague and hard to search on. I'm not sure if you do any
> > programming in the gaming arena, but double buffers are frequently used for
> > page flipping to create smooth graphics, if you search on double buffer
> > memory, just about every link you get will be either graphic card
> > specifications, double buffer programming, page flipping, double buffer
> > scrolling, direct X back buffers, etc.
> >
> > Do you know of any specific material relating to implementation with a pic?
>
> The basic idea is quite simple.
>
> One approach would be to split he RAM into two halves.
>
> The first half begins to fill with data being aquired by the system.
>
> The system uses the second half of RAM to display contents, transmit it,
> or what ever.
>
> When the first half fills up, the system swaps it's access to each half,
> such that the second half now starts filling with data, while the first
> is used as mentioned before.
>
> When the second half fills etc etc etc
>
> If it takes longer to process data from one buffer than it takes to fill
> the other, then just stop aquiring data after it is full until ready to
> start again.
In my opinion, a better approach is one (circular) buffer and two
pointers. Of course, it depends on the type of data one receives and how
it is processed (and may be totally inappropriate for the particular
application the original poster is interested in [but I didn't see that
part of the thread]). But for communication links, data comes in a
byte-at-time and is handled as a stream. If a large chunk needs to be
processed at once then I still think that a circular buffer with two
pointers is useful.
For the 18f family, I reserve FSR2 for interrupts and FSR0 and FSR1 for
non-interrupts. Here's an example of one of my interrupt handlers for
receiving data from the usart:
check_USART_RX_interrupt: ;
BTFSC PIR1,RCIF ;
BTFSS PIE1,RCIE ;
BRA check_next_interrupt ;
;
LFSR 2,RxBuffer ; *** Rx Interrupt ***
INCF RxIndexInt,W ;
ANDLW RX_INDEX_MASK ; We just received a byte in the
MOVWF RxIndexInt ;UART. This byte gets stored in
MOVFF RCREG,PLUSW2 ; RxBuffer[RxIndexInt] = RCREG
...
Then the main loop will call a function
RCALL RxProcessOneByte
Which does this:
RxProcessOneByte:
MOVF RxIndexInt,W ;Did we receive a byte? If the Rx
; Indices
XORWF RxIndex,W ;for the interrupt and
; non-interrupt code
BNZ rpob1 ;are different then we have a
;byte.
RETURN ;Otherwise we don't...
;
rpob1:
INCF RxIndex,W ;Advance the non-interrupt index
ANDLW RX_INDEX_MASK ;using roll-over arithmetic
MOVWF RxIndex ;and get the byte that the
LFSR 0,RxBuffer ;interrupt routine placed into
MOVFF PLUSW0,RxNextByte ;the RxBuffer.
CLRF PLUSW0 ;Wipe out the byte in the RxBuffer
;so that
;we don't get fooled later when
;the pointer
;wraps around
The two pointers are "RxIndex" and "RxIndexInt". Everytime the interrupt
routine receives a byte, "RxIndexInt" is advanced by one (and the new byte
is placed into the buffer). The non-interrupt code compares these two
indices. When they're different, the next byte is "processed".
With a single circular buffer you'll probably be able to make it bigger
than one of the two ping-pong buffers. With a larger buffer, there's less
risk of buffer overflow. Buffer overflow sucks.
Scott
--
http://www.piclist.com hint: The PICList is archived three different
ways. See http://www.piclist.com/#archives for details.