AvrX Real Time Kernel

Home
Up
AvrX Fifo
Overview
Theory
Getting Started
AvrX 2.6
AvrX 2.3 IAR
Mail

Sept, 14, 2005
AvrXFifo requires AvrX 2.6f or newer.
AvrX 2.6f contains some significant changes to support AvrXFifo's.  The changes
should be 100% backward compatible to previous 2.6 versions.  The change primarily 
allows interrupt handler to directly call AvrXSetSemaphore().  Older versions of AvrX 
probably will work, but an extra context will be temporarily pushed onto the kernel 
stack during the Set Semaphore processing.
Files:
	AvrXFifo.h
	AvrXFifo.c
Notes on declaration & usage of AvrXFifo's:
	Maximum fifo size is 255 bytes.  Most practical systems only need a few
	bytes to buffer interrupt handlers or protocols (e.g. large enough for
	the biggest outgoing packet, for example).   If this limit is too small,
	see "Future Expansion" below.
	The user can declare and initialize Fifo's explicitly, in code, or use
	some handy #define MACROs to do the job.  To do this manually follow
	this template:
	Outside of your code (e.g. global data memory)
		uint8_t SomeBuffer[sizeof(AvrXFifo) + DesiredBufferSize];
		static const pAvrXFifo FifoName = (pAvrXFifo)SomeBuffer;
	Or use the macro
		AVRX_DECL_FIFO(FifoName, FifoSize);
	or if external
		extern uint8_t SomeBuffer[];
		static const pAvrXFifo FifoName = (pAvrXFifo)SomeBuffer;
	Or use the macro
		AVRX_EXT_FIFO(FifoName);
	In your code, initialize the fifo:
		FifoName->size = DesiredBufferSize;
		AvrXFlushFifo(FifoName);
	Or use the macro
		AVRX_INIT_FIFO(FifoName);
	To use the fifo:
	int retc = AvrXPutFifo(FifoName, data);	// Place data in fifo
	int foo = AvrXPullFifo(FifoName);		// Get data from fifo
	AvrXWaitPutFifo(FifoName, data);	// Place data in fifo, blocks if full
	int foo = AvrXWaitPullFifo(FifoName);	// Get data from fifo, blocks if empty
	int size = AvrXPeekFifo(FifoName);	// Check size of fifo
	AvrXFlushFifo(FifoName);		// Flush fifo & release producer.
	int foo = AvrXDelFifo(FifoName);		// Remove last item placed in fifo
	Return Values:
		FIFO_ERR (-1)	fifo full or empty and operation can't be completed
		FIFO_OK  (0)	operation successful
		unsigned int	Char data, zero extended for successful removal
	GCC produces poor AVR code when comparing to literal 0 (there are reasons
	why this is correct behavior).  GCC generates good AVR code when testing results
	for < 0. e.g.
	if ((c = AvrXPullFifo(FifoName)) < FIFO_OK)	// rather than ==
	    // empty...
	else
	    // Do something with c which is unsigned char data.
	Because the pointer to the FIFO is declared as a static const value, no
	actual storage is used.  The compiler is smart enough to just use the
	address of the byte buffer when referencing the FIFO.  Optimal code is
	generated.
Macros:
	Macros hide the need to record the size for initialization, otherwise are identical 
	to the explicit C code.  The only caveat is that the init macro needs to be in the 
	same file as the declaration macro.  This is also good programming practice to 
	keep declarations and initialization in one file.  Also the External declaration macro 
	cannot be used in the same file as the declaration macro.
Synchronization:
	AvrXFifo's have built in synchronization between producers (put) and
	consumers (pull).  Producers and consumers can be either tasks or
	interrupt handlers.  Interrupt handlers, of course, cannot use the
	blocking FIFO API.
	When blocked, the producer/consumer will be come unblocked when the
	opposite side either removes or adds a data item (respectively).  There
	is no mechanism to notify an interrupt handler that something has been
	added or removed from a FIFO.  See the example of the buffered serial
	I/O to see how that is handled.	In short, it is up to the task end of
	the FIFO to manage coordination with the interrupt handler.
Future expansion possibilities:
	By using the FIFO code as a starting point some interesting things could
	be added:
	1. FIFO could be defined as word or even arbitrary data size buffers.
	The size could be declared as multiples of the data and new get/put
	routines defined that remove the data item.  This could be made generic
	by adding the element size to the FIFO data structure, at the expense of
	more code for the simple case.
	2. Routine addresses could be added to the FIFO structure as call-backs
	for interrupt handlers when the FIFO fills or empties.  This would allow
	a FIFO to be put between two interrupt handlers.  Say a serial to serial
	buffer.  Simple tasks between handlers could be written as entirely
	kernel context code avoiding the overhead of task switching.
	3. FIFO size could be expanded beyond 255 by changing the internal size,
	in and out from uint8_t to uint16_t and modifying the FIFO code
	appropriately (internal temporary values).  Also, race conditions in
	loading pointers must be taken into account.  With byte pointers CPU
	reads are atomic and no critical sections are needed.
	The current byte size data was chosen as a compromise between small
	system code and decent sized buffers.
CAVEATS:
	The FIFO code has not been tested with a buffer size of 255.  It should work.
	There might be race conditions
Last  update  16-Mar-2007 .