Fifo example in USB device soft framework Avrstudio5

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

Has anyone used the fifo example? I am getting strange results!
like if I use the fifo_get_used_size() function or the fifo_get_free_size() I get wrong values...

I am using a buffer of 2048 size and after placing 24 bytes I get used size of 63720!!!

It seems:
2024 in binary is 111 1110 1000
63720 in binary is 1111 1000 1110 1000

Does this mean anything??

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

I abandoned using the fifo that came with the application framework. I am now using my own fifo code...which I think is very similar to the application framework code....however i see for some reason the the application framework code has read write indexes being ANDed with (2*SIZE-1).

It makes more sense to have them ANDed with (SIZE-1) where SIZE is the 2s power number, eg: 2, 4, 8, 16, 32 etc...(size of the fifo buffer).

Essentially what it is doing is causing a circular bounds using modular arithmatics.

for example if a fifo size of 64 is desired then as the write index is incremented by 1 it can go beyond 64 and when it does all you have to do is do wr_index = wr_index % 64.

And doing modular arithmatic with a 2s power number is equivalant to doing an AND operation with the (2s power number -1).

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

Are you talking about the common\services\fifo one? As far as I can tell from the documentation of fifo_init(), it's a FIFO for at most _128_ elements. 2048 would be way out of bounds.

Also, fifo_get_used_size() and fifo_get_free_size() are defined to return uint8_t, so I don't understand how you can get anything larger than 255.

Do you have any code to share with us?

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

luvocean1 wrote:
I abandoned using the fifo that came with the application framework. I am now using my own fifo code...which I think is very similar to the application framework code....however i see for some reason the the application framework code has read write indexes being ANDed with (2*SIZE-1).

It makes more sense to have them ANDed with (SIZE-1) where SIZE is the 2s power number, eg: 2, 4, 8, 16, 32 etc...(size of the fifo buffer).

Essentially what it is doing is causing a circular bounds using modular arithmatics.

for example if a fifo size of 64 is desired then as the write index is incremented by 1 it can go beyond 64 and when it does all you have to do is do wr_index = wr_index % 64.

And doing modular arithmatic with a 2s power number is equivalant to doing an AND operation with the (2s power number -1).

The reason of this "ANDed with (2*SIZE-1)" is that this gives you the possibility to use 100% of the fifo. for example, if you have a fifo of 16 elements, you can store 16 elements, not 15 (max minus one), which is the case when you usually "ANDed with (SIZE-1)".

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

hhm... then why didnt the code from atmel framework work properly? hhm...

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

luvocean1 wrote:
hhm... then why didnt the code from atmel framework work properly? hhm...

... because the max fifo size in the fifo driver in the ASF is 128 elements. If you look at the return value from fifo_init(), you will get a FIFO_ERROR error.

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

yes i know that...actually max size was 64 for my buffer example... i had modified it to suit my size but still didnt work. anyways here is the code I have done up... it seems to work..

//for header file


//! Error codes used by FIFO driver.
enum {
	FIFO_OK = 0,          // Normal operation.
	FIFO_ERROR_OVERFLOW,  // Attempt to push something in a FIFO that is full.
	FIFO_ERROR_UNDERFLOW, // Attempt to pull something from a FIFO that is empty
	FIFO_ERROR
};



//sutrcture holding information for processing a FIFO buffer
typedef struct FIFO_Buffer FIFO_Buffer;
struct FIFO_Buffer
{
	unsigned char *Buffer;		//pointer to the actual buffer
	unsigned short Size;		//size of the buffer, a power of 2
	unsigned short WriteIndex;
	unsigned short ReadIndex;	
};


#define FIFO_RX_LEN			4096
#define FIFO_TX_LEN			4096

//variable


//FIFO variables
extern FIFO_Buffer  FifoRxDesc;
extern FIFO_Buffer  FifoTxDesc;
extern unsigned char FifoRx[FIFO_RX_LEN];
extern unsigned char FifoTx[FIFO_TX_LEN];

//function definitions
unsigned char FifoInit(FIFO_Buffer *fifoBuffer, unsigned char *buffer, unsigned short size);



//INLINED functions
//get used size of the buffer
static inline unsigned short FifoUsedSize(FIFO_Buffer *fifoBuffer)
{
	signed short diff = fifoBuffer->WriteIndex - fifoBuffer->ReadIndex;	
	return (diff % fifoBuffer->Size);
}


//get how much space is left in the buffer
static inline uint16_t FifoFreeSize(FIFO_Buffer *fifoBuffer)
{
	return (fifoBuffer->Size - FifoUsedSize(fifoBuffer));
}


//check if a fifo is empty
static inline Bool FifoIsEmpty(FIFO_Buffer *fifoBuffer)
{
	return (fifoBuffer->WriteIndex == fifoBuffer->ReadIndex);
}

//check if a fifo is full
static inline Bool FifoIsFull(FIFO_Buffer *fifoBuffer)
{
	return (((fifoBuffer->WriteIndex + 1) & (fifoBuffer->Size - 1)) == fifoBuffer->ReadIndex);
}


//push a byte into the fifo buffer.
//any calling function should first find out if the buffer has space
//before calling this function.
static inline void FifoPushByte(FIFO_Buffer *fifoBuffer, unsigned char data)
{
	fifoBuffer->Buffer[fifoBuffer->WriteIndex & (fifoBuffer->Size - 1)] = data;
	fifoBuffer->WriteIndex = (fifoBuffer->WriteIndex + 1) & (fifoBuffer->Size - 1);
}


//pull a byte from the fifo buffer.
//any calling function should first find out if the buffer is empty of not.
//if the buffer is not empty then the following function could be called.
static inline void FifoPullByte(FIFO_Buffer *fifoBuffer, unsigned char *data)
{
	*data = fifoBuffer->Buffer[fifoBuffer->ReadIndex & (fifoBuffer->Size - 1)];
	fifoBuffer->ReadIndex = (fifoBuffer->ReadIndex + 1) & (fifoBuffer->Size - 1);	
}



//flush the fifo
static inline void FifoFlush(FIFO_Buffer *fifoBuffer)
{
	//empty the fifo
	fifoBuffer->ReadIndex = fifoBuffer->WriteIndex = 0;
}
//for C file
//initialize the fifo
//buffer size is expected to be a power of 2.
unsigned char FifoInit(FIFO_Buffer *fifoBuffer, unsigned char *buffer, unsigned short size)
{
	unsigned short tmp;

	// Check the size parameter. It must be a 2-power.
	tmp = size >> ctz(size);
	if (tmp != 1) {
		return FIFO_ERROR;
	}
	
	fifoBuffer->ReadIndex = fifoBuffer->WriteIndex = 0;	//Fifo starts empty.	
	fifoBuffer->Size = size;		//Save the size parameter.	
	fifoBuffer->Buffer = buffer;	//Save the buffer pointer

	return FIFO_OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

it seems the above code has some issues as well. I am baffled...seems to do with gcc? The following will show what I mean.

unsigned short x = 4176;
unsigned short size = 4096;
x = x & (size - 1);     //equivalent to mod 4096, ie: x = x % 4096

unsigned short y = 2784;

unsigned short result = (x-y) % size;

printing the above code gives 62832!
How is that possible????

But if I do the following:

unsigned short x = 4176;
unsigned short size = 4096;
x = x & (size - 1);

unsigned short y = 2784;

unsigned short result = (x-y) & (size - 1);

it gives me 1392...which is as expected!

Any idea?

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

so according to the 2nd result...the code I showed above for fifo should be corrected.

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

Quote:

printing the above code gives 62832!

Printing how? In 16bits 62832 could also be -2704 simply depending on signed/unsigned interpretation.

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

its not posting :(
oh may be cos I had the "sprint"??server didnt like it?

here it is again:
I was doing:

sprintf(msg, "result d\r\n", result);<br />
UsartString(msg);

for reason I cant put the percent sign in the above, before d? avrfreaks wont let me post with that.

Well regardless of printing whatever value... I had a functiont that does FifoUsedSize() which basically returns the result value. and depending on that I run a for loop to copy of the received data to another buffer...and sure enough it was running 62K times... so it wasnt anything to do with printing.

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

OK so taking your non-working case:

unsigned short x = 4176;
unsigned short size = 4096;
x = x & (size - 1);  // here result is 80

unsigned short y = 2784;

unsigned short result = (x-y) % size; 
// that's the equivalent of:
unsigned short result = (80-2784) % 4096; 

80-2784 is -2704 which is 62832 when treated unsigned.

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

I have tested your 2 small codes with IAR and here are the results:

First code:

unsigned short result = (x-y) % size;

The compiler will use the DIVS instruction which performs the integer division in Rd and put the reminder in Rd+1. This is a way to perform the modulo.

DIVS Rd, -2704, 4096

The result will be:
Rd = 0
Rd+1 = -2704

Then, the compiler use this value as an unsigned 16-bits value, which gives the 62832 result.

I think that the issue is that the compiler is lost since you are doing a soustraction of 2 unsigned values. The compiler should use a DIVU is this case.

For exemple, if you do:

unsigned short result = (x-y); 
result = result1 % size;

you will have:
result = 1392 (the correct value you are looking for)

Second code:

unsigned short result = (x-y) & (size - 1);

Here, the compiler is using a simple AND (size-1) and the result is correct.

You should either do:

unsigned short result = (unsigned short)((signed short)x-y) % size; 

in order to help the compiler in using the appropriate operations

unsigned short result3 = (size + x-y) % size;

in order to always have a positive result in the substraction

Last Edited: Wed. Aug 17, 2011 - 12:50 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have just discovered that you can not use the 'modulo' or 'percent' caracter in the forum: it will not be posted, unless put under Code token. :lol:

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

Quote:

I have just discovered that you can not use the 'modulo' or 'percent' caracter in the forum: it will not be posted, unless put under Code token. Laughing

Use % whenever you need to post a % sign here - it's a fault in the BBS software that has existed for several years now.

Moderator

BTW % on it's own or followed immediately by a digit such as %02X works without any changes.