uint8_t indexing in 256b ring buffer. What are disadvantages to using int overflow?

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've decided to use a ring buffer (FIFO) for my SPI communications, however I am unsure if I specify that my buffer is only every going to be 256 bytes large, if using 8 bit integer overflow is a good idea. I will be using a standard head and tail for the buffer.

I did a simulation to see what Status Flags are set when I overflow, is there anything bad that could occur from triggering the carry flag and half carry?

 

Any tips or reasons I shouldn't?

Last Edited: Wed. May 6, 2015 - 08:20 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I gather we're talking about assembler.
The technique you describe is common. As for 'triggering' flags, that's up to your code if and how it treats them. Many instructions change the flags based on the result of the instruction.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

8 bit unsigned char in C.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am actually using just standard C with an atmega644PA. Perhaps I should've asked if the c compilier would do anything with these flags when using this method.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

This is a "General Programming" topic - nothing specifically to do with AVR.

 

The advantage of using a power-of-two length is that the "wrap-around" from the end of the ring back to the beginning can be done with a simple mask, not requiring any arithmetic at all - thus giving the fastest, most compact code possible.

 

In the special case of a 256-byte buffer and 8-bit index, you don't even need a mask - the index just automatically wraps from 255 to 0.

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Wed. May 6, 2015 - 05:39 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

You use a C compiler to take care of the low level details like flags. Assuming the compiler does the right thing, you don't need to worry about them.
Many operations will set/clear the carry flag - this is quite normal.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And just to be clear. If you are simply using uint8_t overflow to handle the wrap then obviously you get no choice about the buffer size - it has to be 256. For all but the largest AVRs that's a fair chunk of RAM and probably far more than you actually need to buffer. The usual technique of an AND mask simply means the buffer has to be a binary multiple so you can pick a more "sensible" size like 16, 32, 64 or similar...

$ cat avr.c
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>

uint8_t buffer[16];
uint8_t idx;

int main(void) {
}

ISR(SPI_STC_vect) {
  buffer[idx] = SPDR;
  idx = ++idx & 0x0F;
}
$ avr-gcc -mmcu=atmega16 -Os -save-temps avr.c -o avr.elf
$ cat avr.s
	.file	"avr.c"
__SREG__ = 0x3f
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__CCP__ = 0x34
__tmp_reg__ = 0
__zero_reg__ = 1
	.text
.global	main
	.type	main, @function
main:
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
/* epilogue start */
	ret
	.size	main, .-main
.global	__vector_10
	.type	__vector_10, @function
__vector_10:
	push __zero_reg__
	push r0
	in r0,__SREG__
	push r0
	clr __zero_reg__
	push r24
	push r25
	push r30
	push r31
/* prologue: Signal */
/* frame size = 0 */
/* stack size = 7 */
.L__stack_usage = 7
	lds r24,idx
	in r25,47-32
	ldi r30,lo8(buffer)
	ldi r31,hi8(buffer)
	add r30,r24
	adc r31,__zero_reg__
	st Z,r25
	subi r24,lo8(-(1))
	andi r24,lo8(15)
	sts idx,r24
/* epilogue start */
	pop r31
	pop r30
	pop r25
	pop r24
	pop r0
	out __SREG__,r0
	pop r0
	pop __zero_reg__
	reti
	.size	__vector_10, .-__vector_10
	.comm buffer,16,1
	.comm idx,1,1
.global __do_clear_bss

The index increment/wrap there is about as "tight" as you might hope to get it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

  idx = ++idx & 0x0F;

This statement has undefined behavior.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You sure? I deliberately used pre-increment to ensure it happened first - is that not the case then? I was just trying to avoid the additional typing involved in:

idx = (idx + 1) & 0x0F;

Now you aren't going to tell me that is undefined too are you?!? cheeky

 

BTW it might be undefined but at least the compiler knew what I meant wink...

	lds r24,idx
...
	subi r24,lo8(-(1))
	andi r24,lo8(15)
	sts idx,r24

EDIT: ah ha - I think I see the point you are making:

 

http://en.cppreference.com/w/c/l...

 

Is it because of them both being level 2 and right to left associativity?

Last Edited: Thu. May 7, 2015 - 02:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Between sequence points, one is not allowed to assign to the same object, e.g. idx, twice.

Precedence has nothing to do with it.

Note that the result is undefined, not unspecified.

Nasal demons are allowed.

 

Edit: sequence points

Moderation in all things. -- ancient proverb

Last Edited: Fri. May 8, 2015 - 01:43 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nasal demons are allowed.

You had me scratching my head at that one.  Luckily Google instantly knows...

 

Top Definition

nasal demons

Recognized shorthand on the Usenet group comp.std.c for any unexpected behavior of a C compiler on encountering an undefined construct. During a discussion on that group in early 1992, a regular remarked "When the compiler encounters a given undefined construct it is legal for it to make demons fly out of your nose" (the implication is that the compiler may choose any arbitrarily bizarre way to interpret the code without violating the ANSI C standard). Someone else followed up with a reference to "nasal demons", which quickly became established.

http://www.urbandictionary.com/d...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.