AT91SAM7 Circular Data Buffer

I’m not very experienced with ARM7 and am using the YAGARTO toolchain. I’m looking for some tips on creating a circular data buffer to store parallel data (8 bit) being read off the PIO that needs to be sent out RS232 on UART0.

I’m using the AT91SAM7S64 with 16,384 bytes of ram, of which I would like to use as much as possible as a buffer. If i’m not mistaken, RAM starts at 0x00200000 and ends at 0x00204000. In looking at the main.map file from the program I have already constructed the _end = . is 0x0020001c. Can a buffer safely be constructed after this address to the last ram address?

Also, what’s the best way to write a circular buffer in C? Thanks for any help!

Here’s a simple example of mine:

/*
** queue.c
** circular buffer program
*/

#include <stdio.h>

char buffer[20];

int head, tail = 0;
int length = 20;


int main(void)
{
	enqueue(1);
	enqueue(2);
	printf("%d\n", dequeue());
	printf("%d\n", dequeue());
	
}

enqueue(c)
unsigned char c;
{
	buffer[tail] = c;
	if (tail == length)
		tail = 0;
	else
		tail++;
}

dequeue()
{
	unsigned char c;

	c = buffer[head];
	if (head == length)
		head = 0;
	else
		head++;
	return c;
}

It needs more stuff like testing for buffer full and so on, but you should get the idea.

Leon

This is an example of a circular buffer.

/* Queue structure */
typedef struct {
  /** Pointer to the queue buffer (base).*/
  uint8_t           *q_buffer;
  /** Pointer to the first location after the buffer (top).*/
  uint8_t           *q_top;
  /** Write pointer.*/
  uint8_t           *q_wrptr;
  /** Read pointer.*/
  uint8_t           *q_rdptr;
  /** Counter, number of bytes in the queue.*/
  uint32_t          q_cnt;
} Queue;

If you want to see the full code you can follow the link in my signature, look into the chqueues.c file. Probably you will not need all of it but you can use it as a starting point.

Edit: this could help too: http://en.wikipedia.org/wiki/Circular_buffer

regards,

Giovanni

leon_heller:
Here’s a simple example of mine:

/*

** queue.c
** circular buffer program
*/

#include <stdio.h>

char buffer[20];

int head, tail = 0;
int length = 20;

int main(void)
{
enqueue(1);
enqueue(2);
printf(“%d\n”, dequeue());
printf(“%d\n”, dequeue());

}

enqueue(c)
unsigned char c;
{
buffer[tail] = c;
if (tail == length)
tail = 0;
else
tail++;
}

dequeue()
{
unsigned char c;

c = buffer[head];
if (head == length)
	head = 0;
else
	head++;
return c;

}




It needs more stuff like testing for buffer full and so on, but you should get the idea.



Leon

Your soft isn’t completly good, you will have memory conflict error. As your buffer is 20 char length, you may use index 0 to 19, but not the 20’.

And also it’s could be good to check to not overwrite data.

=> and do not care about your memory allocation in main.map, because in “c”, it will be automatically allocated with your ```
char Buffer[1024];

I said it needed more work. :sunglasses:

Leon

Thanks for the replies. I forgot about not having to address the buffer, i’m used to ASM :slight_smile: . One thing I did notice thought, is I can make the buffer larger that the available RAM and there is no error generated.

C doesn’t stop you doing things like that.

Leon

The best way to make a circular buffer is to make it’s size a power of two, so you don’t have to test for overflow at all. Here’s my implementation; I use only 16 bytes buffer here (it’s the AVR implementation) but the principle is the same for bigger ones.

class Circular16
{
public:
	uint8_t m_fill : 4;
	uint8_t	m_done : 4;
	uint8_t	m_buf[16];
	
	void init()
	{
		m_fill = m_done = 0;
	}
	bool done()  const
	{
		return m_fill == m_done;
	}
	bool	add(uint8_t b)
	{
		uint8_t nx = (m_fill + 1) & 0xf, 
				dn = m_done;	// don't overflow
		if (nx == dn)
			return false;
		m_buf[m_fill] = b;
		m_fill = nx;
		return true;
	}
	bool	get(uint8_t * b)
	{
		if (m_done == m_fill)
			return false;
		*b = m_buf[m_done++];
		return true;
	}
};