Ttelmah Guest
|
Re: Buffer help please |
Posted: Wed Apr 21, 2004 4:39 am |
|
|
billy jones wrote: | Hi all.
Im new to PICs and C programming and I was wondering if anyone would be kind enough to explain to me how the buffer in the file EX_SISR.C works as Im having trouble understanding.
Thanks
Billy |
Ouch!...
Ok. Let's split it up a little. Imagine you have an array of storage locations, callled 'buffer', and these are 'addressable', using a number. So:
buffer[0] refers to the first location,
while
buffer[n] is the n+1'th location (arrays in C are 'zero referenced').
Now you have characters arriving from an external source, that need to be temporarily stored, and retrieved in the same order. So you have a pair of 'indexes' to the array, called 'in', and 'out'.
Now initially, you can just add characters to the array, by using:
buffer[in] = chr; //put 'chr' into the address 'in'
Then incrementing 'in', to point to the next location.
However, since the buffer cannot be of infinite size, you have to also handle the condition that 'in' can get to the end of the buffer. This is done by:
in = (++in % size);
where 'size' is the size of the buffer. The '%' symbol, means to generate the remainder, when the first number is divided by the second. So if the 'size' was 8, and in was 6, then the result would be:
6+1 = 7
7/8, = 0 remainder 7
So the result would be '7'.
However the next time the function is called, the maths goes:
7+1 = 8
8/8 = 1 remainder 0
So the result now is '0'.
Hence using this function makes 'in' (and 'out'), increment through the sequence:
0 1 2 3 4 5 6 7 0 1 2 3 4 ....
So now, the address used to store the character, will 'wrap' back to the start of the storage area, when it reaches the end.
The 'retrieval' operation, uses the 'out' address. When the first character is added, 'in' increments. Now the 'out' value and the 'in' value differ. This is used to detect that there is a character in the buffer. Hence you can test at any time for the buffer containing data, by coding:
if (in != out) - here the buffer has got data.
Alternatively if you want to wait till data arrives (as is done in the 'getc' function), if you code as:
while (in==out) - the code will wait here till a character arrives.
The two addresses 'chase' each other round the addresses allowed (hence such buffers are often called 'ring' buffers).
When you increment the 'in' value, if it 'catches up' with the output value, then the buffer is full. The CCS code handles this, by setting 'in' back to the last value if this happens, throwing away the newest character. I often handle this the opposite way, throwing away the 'oldest' character instead.
The operation to do this, is:
buff[in] = chr;
in = ++in % size;
if (in==out) out = ++out % size;
Now the use of the '%' operation, allows the buffer to be any size (5, 10, 20 characters etc.), but has the 'downside', that this involves more arithmetic than some alternatives.
The obvious alternative, is the binary '&' operation. If the buffer 'size' is only allowed to be a direct 'binary' power (so 2, 4, 8, 16, 32 bytes), then you can instead use:
in = ++in & (size-1);
This codes as just a couple of instructions, making for faster buffer handling. The '&' operator, only returns bits in the output, where bits are present in both input values. So, with 'size' = 8:
size-1 = 7 = 00000111
6 = 00000110 & 00000111 = 00000110 = 6
7 = 00000111 & 00000111 = 00000111 = 7
8 = 00001000 & 00000111 = 00000000 = 0
Giving the same 'wrap' effect.
If you do a search on 'ring buffers', you should find a lot more about this.
Best Wishes |
|