'taking care of the circularity of the Pointer to the Buffer'.
int buf[1024];
int ptr;
x = buf[ptr&0x3ff];
x = buf[(ptr+7)&0x3ff];
x = buf[(ptr-5)&0x3ff];
That sounds very interesting.Add another pointer, and you've got FIFO
That is the most efficent solution for circular buffer. Well, you can get rid of the AND only if you use 8-bit index variable and 256 size buffer.. or 16 bit index and 2^16 size buffer. That way the variable rolls over "naturally".I assume you don't mind the extra 'AND' operation cycles?C:x = buf[ptr&0x3ff];
#define BUFFER_SIZE 20;
#define NEXT_INDEX(idx) ((idx) ? (idx--) : (idx) = ((BUFFER_SIZE)-1))
static uint16_t ring_buffer[BUFFER_SIZE];
static uint8_t index;
void
ring_buffer_put(uint16_t data)
/* Writes one data entry in ring buffer */
{
ring_buffer[buffer_index] = data; /* write data */
NEXT_INDEX(index); /* move index by one */
}
That sounds very interesting.
Could you explain that please?
You know FIFO - it's a buffer with 2 pointers - Tail and Head. You put things at Tail and read then from the Head.
NorthGuy said:You know FIFO - it's a buffer with 2 pointers - Tail and Head. You put things at Tail and read then from the Head.
Got you! thanks!misterT said:FIFO = First In First Out (ring buffer, for example)
LIFO = Last In First Out (stack)
That is the most efficent solution for circular buffer. Well, you can get rid of the AND only if you use 8-bit index variable and 256 size buffer.. or 16 bit index and 2^16 size buffer. That way the variable rolls over "naturally".
I just wrote a simple ring-buffer, but I needed more flexibility for the buffer size. So I wrote a macro that calculates the next index. You can see that you need to check the index everytime you modify it. It can roll over at any time.
C:#define BUFFER_SIZE 20; #define NEXT_INDEX(idx) ((idx) ? (idx--) : (idx) = ((BUFFER_SIZE)-1)) static uint16_t ring_buffer[BUFFER_SIZE]; static uint8_t index; void ring_buffer_put(uint16_t data) /* Writes one data entry in ring buffer */ { ring_buffer[buffer_index] = data; /* write data */ NEXT_INDEX(index); /* move index by one */ }
Hi T,
I think that the Macro you're using costs few cycles that one may prefer to spare, dont you think?
I like to write "good code" rather that highly optimized code.
Just wondering. What is your definition of "good code"?
That depends on the problem..
It is more of a good modular design where most of the code is "vanilla C", rather than using fancy tricks to squeeze out one instruction. Of course if you need to squeeze out one instruction, then you may have to sacrifice good style over performance (or think of a better design). The original problem description of this thread does sound like a poor design.
That all makes sense. However, you didn't tell what is your definitition of the "good style".
// see if porta.0 is clear and turn led on
if (!(PORTA & 1)) PORTB |= 4;
#define sbi(b,n) (b |= (1<<n)) /* Set bit number n in byte b */
#define cbi(b,n) (b &= (~(1<<n))) /* Clear bit number n in byte b */
#define fbi(b,n) (b ^= (1<<n)) /* Flip bit number n in byte b */
#define rbi(b,n) (b & (1<<n)) /* Read bit number n in byte b */
#define bit_is_clear(combo) !rbi(combo)
#define BUTTON (PORTA),(0)
#define led_on() sbi(PORTB,4)
if (bit_is_clear(BUTTON))
/* User has pressed the button */
{
led_on();
}
Yes, readability is first goal towards "good code and style".
compare this:
C:// see if porta.0 is clear and turn led on if (!(PORTA & 1)) PORTB |= 4;
to this:
You can read the latter almost like a book.C:#define sbi(b,n) (b |= (1<<n)) /* Set bit number n in byte b */ #define cbi(b,n) (b &= (~(1<<n))) /* Clear bit number n in byte b */ #define fbi(b,n) (b ^= (1<<n)) /* Flip bit number n in byte b */ #define rbi(b,n) (b & (1<<n)) /* Read bit number n in byte b */ #define bit_is_clear(combo) !rbi(combo) #define BUTTON (PORTA),(0) #define led_on() sbi(PORTB,4) if (bit_is_clear(BUTTON)) /* User has pressed the button */ { led_on(); }
if (is_bit_clear(black_button_port, black_button_bit) {
/* Normally, the pin is pulled high by the pull-up resiostor,
but when user presses the button, the pin goes low
We do not need debouncing because we have a low
pass filter, which performs hardware debouncing.
Keep in mind that the capacitor slows
down the reaction.
*/
set_bit(green_led_port, green_led_bit);
}
if (is_button_pressed(black_button) {
// no comments necessary at this level of abstraction
// all problems are solved in "is_button_pressed" and
// "turn_on_led"
turn_on_led(green_led);
}
Well, I just have to disagree.. and besides that, the example was meant to demonstrate readability only. Not any other aspect of "good programming".I have to somewhat agree with NG here.
if(is_button_pressed(black_button){
// no comments necessary at this level of abstraction
// all problems are solved in "is_button_pressed" and
// "turn_on_led"
turn_on_led(green_led);
}
Well, I just have to disagree.. and besides that, the example was meant to demonstrate readability only. Not any other aspect of "good programming".
And I do use different levels of abstraction between inputs and outputs.. comes from experience.
sbi, cbi macros are the same name as the asm instructions they translate to.. fbi and rbi are very common macros also.
One file: "global_flags.h"As you say in your code the names would be directly meaningful to a person working on that block on that processor but if the 'new' guy needed to port the C code to a different architecture after you are retired and are living in a nice villa, the what/why of it's meaning might be lost on that person without good comments.
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?