Generate sine waves with 2 mbeds synchronised. Configurable amplitude and phase. Built for 50 Hz mains simulations.

Dependencies:   MODDMA mbed

Description

Small program based on the MODDMA buffered sine wave example.

This programs reads pin 22 to operate in Master (low) or Slave mode. Then configures pin 21 as output (master) or input (slave), in master mode led2 is on. Use a resistor (100 ohm) between the pin21's of master to slave.

The program then calculates a buffer of sine waves for the DMA with parameters given. And starts the DMA and DAC to generate the sine.

On the callbacks of the dma complete (there are 2) slave waits for a sync and master gives a sync, p21. Master waits a few extra clocks to make sure slave is ready.

Commands can be given over Serial port to modify the parameters on the run. Frequency can be changed for master and slave, but it is better to keep the same. Use "f xx.xx". Phase can be changed for master and slave Amplitude can be changed for master and slave.

Hookup

  • Wire p22 high or low.
  • Serial sr(p9,p10) from master to slave.
  • Wire trigger p21 to p21.
  • Output p18 (analogout)

Information

Do not forget a small RC filter on the DAC output.

Master Commands

<master/slave/frequency> <frequency/phase/amplitude> <space> <number> <line feed>

Example commands for serial:

  • master frequency 50.1 hz
    • mf 50.1\n
  • frequency 50.1 Hz
    • f 50.1\n
  • master phase 3.1415 (or 1.0)
    • mp 1\n
  • slave phase 1.5 pi
    • sp 1.5\n

Or use this GUI

https://dl.dropboxusercontent.com/s/uvwsroyu41vzkwg/2013-06-19%2010_35_52-WaveSim.png

Download, or Download C# Code (Visual Studio 2010)

Files at this revision

API Documentation at this revision

Comitter:
jeroen3
Date:
Fri May 31 14:45:27 2013 +0000
Parent:
1:b97d61d415ff
Child:
3:67b9a01ad7b0
Commit message:
Fixed sine generator bug.; Added command line over USB uart

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
watchdog.h Show annotated file Show diff for this revision Revisions of this file
xIFO.c Show annotated file Show diff for this revision Revisions of this file
xIFO.h Show annotated file Show diff for this revision Revisions of this file
--- a/main.cpp	Thu May 30 21:24:35 2013 +0000
+++ b/main.cpp	Fri May 31 14:45:27 2013 +0000
@@ -6,8 +6,15 @@
 #include "mbed.h"
 #include "MODDMA.h"
 #include <cmath>
+#include "watchdog.h"
+#include "xifo.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
 
 Serial pc(USBTX, USBRX);
+Serial sr(p9, p10);
+Watchdog wdt;
 
 const double PI   = 3.141592653589793238462;
 const float  PI_F = 3.14159265358979f;
@@ -23,37 +30,42 @@
 DigitalOut led2(LED2);
 DigitalOut led3(LED3);
 DigitalOut led4(LED4);
-DigitalIn    modesel(p22);
-DigitalInOut trigger(p21);
-
-DigitalOut timetest(p23);
+DigitalIn    modesel(p22);      // mode selector
+DigitalInOut trigger(p21);  // sync trigger output
  
-int buffer[2][BUFFER_SIZE];
-
-typedef enum {MASTER, SLAVE} modesel_t;
-modesel_t mode;
+uint32_t buffer[3][BUFFER_SIZE];
  
 AnalogOut signal(p18);
  
 MODDMA dma;
-MODDMA_Config *conf0, *conf1;
+MODDMA_Config *conf0, *conf1, *conf2, *conf3;
  
+// Config phase (2*pi is one period)
+double phase_master         = PI * 1;
+double phase_slave          = PI * 1;
+// Config amplitude, x * 3.3 Volt
+double amplitude_master =   1;
+double amplitude_slave  = 1;
+// Config frequency, (if using synchronisation these must be identical)
+double freq_master          = 50;
+double freq_slave               = freq_master;
+// copy calc buffer[2] to ch0/1
+volatile uint32_t toch0 = 0;
+volatile uint32_t toch1 = 0;
+// Mode typedef
+typedef enum {MASTER, SLAVE} modesel_t;
+modesel_t mode;
+// Ringbuffer for cmd
+xifo_t com;
+xifo_pool_t compool[128]; 
+ 
+/* Dma callbacks */
 void TC0_callback(void);
 void ERR0_callback(void);
  
 void TC1_callback(void);
 void ERR1_callback(void);
 
-// Config phase (2*pi is one period)
-double phase_master         = PI * 0;
-double phase_slave          = PI * 0;
-// Config amplitude, x * 3.3 Volt
-double amplitude_master     =   1;
-double amplitude_slave      = 0.5;
-// Config frequency, (if using synchronisation these must be identical)
-double freq_master          = 50;
-double freq_slave           = freq_master;
-
 // Sync function
 void wait_for_sync(){
     switch(mode){
@@ -78,25 +90,37 @@
      // Create a sinewave buffer for testing.           
         switch(mode){
         case MASTER:
-            for (int i =   0; i <=  360; i++) buffer[0][i] =  amplitude_master * (512 * sin((3.14159/180.0 * i) + phase_master)) + 512;                
+            for (int i =   0; i <=  359; i++)
+            {
+                    double rads = (PI/180.0 * i);
+                    buffer[0][i] =  amplitude_master * (512*( sin( rads + phase_master )  ))+512;                
+            }
         break;
         case SLAVE:
-            for (int i =   0; i <=  360; i++) buffer[0][i] =  amplitude_slave * (512 * sin((3.14159/180.0 * i) + phase_slave)) + 512;                
+            for (int i =   0; i <=  359; i++)
+            { 
+                double rads = (PI/180.0 * i);
+                buffer[0][i] =  amplitude_slave * (512 * sin(rads + phase_slave)) + 512;                
+            }
         break;
         }
         
     // Adjust the sinewave buffer for use with DAC hardware.
     for (int i = 0; i < 360; i++) {
-        buffer[0][i] = DAC_POWER_MODE | ((buffer[0][i] << 6) & 0xFFC0);
+                if( buffer[0][i] > 1023 ) buffer[0][i] = 1023;
+        buffer[0][i] = DAC_POWER_MODE | ((buffer[0][i] << 6) & 0xFFC0); 
         buffer[1][i] = buffer[0][i]; // Just create a copy of buffer0 to continue sinewave.
     }
 }
  
+void copycallback(){
+        if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); 
+}
+ 
 // Main
 int main() {
     volatile int life_counter = 0;
         pc.baud(115200);
-        timetest = 0;
         
         if(modesel == 1){
             pc.printf("slave\r\n");
@@ -108,6 +132,11 @@
             trigger.output();
             led2 = 1;
             mode = MASTER;
+                    // Print command set
+        pc.printf("Command descriptions: <[master][slave]><[frequency][amplitude][phase]> <number>\r\n");
+        pc.printf("Commands: <[m][s]><[f][a][p]> <n>\r\n");
+        pc.printf("Min F = 1.02 Hz\r\n");
+        pc.printf("Max F limited to synchronisation and DAC speed (200 Hz with sync, max 1000 Hz without)\r\n");
         }
     
     calculate_sines();
@@ -125,7 +154,6 @@
      ->attach_err    ( &ERR0_callback )     
     ; // config end
     
-    
     // Prepare the GPDMA system for buffer1.
     conf1 = new MODDMA_Config;
     conf1
@@ -138,8 +166,8 @@
      ->attach_tc     ( &TC1_callback )
      ->attach_err    ( &ERR1_callback )     
     ; // config end
- 
-    
+
+                        
     // Calculating the transfer frequency:
     // By default, the Mbed library sets the PCLK_DAC clock value
     // to 24MHz. One complete sinewave cycle in each buffer is 360
@@ -165,12 +193,15 @@
         }
         unsigned int dacdiv = ddacdiv;
     LPC_DAC->DACCNTVAL = dacdiv; // 6500 for 10Hz
+        
+        // Watchdogtimer to reset if sync failed
+        wdt.kick(10.0*(1.0/(dacper/ddacdiv))); 
  
     // Prepare first configuration.
     if (!dma.Prepare( conf0 )) {
         error("Doh!");
     }
-    
+    // Wait period for master (slaves waits for sync)
         if(mode == MASTER){
             wait(0.1);
         }
@@ -180,27 +211,217 @@
     // DBLBUF_ENA as we are using DMA double buffering.
     LPC_DAC->DACCTRL |= (3UL << 2);
     
+        // Disable copy calc buffer flags
+        toch0 = 0; 
+        toch1 = 0;
+        
+        // Create ringbuffer for parsing
+        xifo_init(&com, 128, (uint32_t *)&compool); 
+        xifo_clear(&com);
+        uint32_t do_calc=0;
+
     while (1) {
-        // There's not a lot to do as DMA and interrupts are
-        // now handling the buffer transfers. So we'll just
-        // flash led1 to show the Mbed is alive and kicking.
-        if (life_counter++ > 1000000) {
-            led1 = !led1; // Show some sort of life.
-            life_counter = 0;
+            // There's not a lot to do as DMA and interrupts are
+            // now handling the buffer transfers. So we'll just
+            // flash led1 to show the Mbed is alive and kicking.
+            if (life_counter++ > 1000000) {
+                    led1 = !led1; // Show some sort of life.
+                    life_counter = 0;
+            }
+            
+            /* Do UART data processing */
+            if(mode==MASTER){
+                while(pc.readable()){
+                    xifo_write(&com, pc.getc());
+                }
+                while(sr.readable()){
+                    pc.putc(sr.getc());
+                }
+            }else{
+                while(sr.readable()){
+                xifo_write(&com, sr.getc());
+                }
+            }
+                    
+            
+            
+            {   /* BLOCK with command parsing */
+                uint32_t do_parse=0;
+                // 123456.123456 accurate
+                char number[13] = {0,0,0,0,0,0,0,0,0,0,0,0,0};
+                uint32_t p=0;               
+                // Only parse USB master commands on master mode
+                if(mode==MASTER){
+                    // MASTER mode
+                    if( xifo_read_mr(&com,0) == '\n'){
+                    xifo_pop_mr(&com);
+                        // We have a line
+                        if( xifo_read_lr(&com,0)== 's' ){                                   // Slave
+                            xifo_pop_lr(&com);
+                            pc.printf("Slave ");
+                            // command for slave, forward over serial sr
+                            while(xifo_get_used(&com))
+                            sr.putc(xifo_pop_lr(&com));
+                            sr.putc('\n');
+                            xifo_init(&com, 128, (uint32_t *)&compool); 
+                            xifo_clear(&com);
+                        } else if( xifo_read_lr(&com,0) == 'm' ){                               // Master
+                            xifo_pop_lr(&com);
+                            pc.printf("Master ");
+                            // master
+                            // Parsing
+                            do_parse =1;
+                        } else if( xifo_read_lr(&com,0) == 'f' ){                               // Frequency on MASTER and SLAVE
+                            // Parse data
+                            xifo_pop_lr(&com); // space
+                            // Get number
+                            while( xifo_get_used(&com) && p < sizeof(number))
+                                number[p++] = (char)xifo_pop_lr(&com);
+                            freq_master = strtod(number,0);
+                                int t = dacper / (freq_master);
+                                pc.printf("Master Frequency %f, approximate: %f\nSlave ", freq_master, dacper/t);
+                                sr.printf("f %f\n", freq_master);
+                                do_calc = 1;
+                        } else {
+                            pc.printf("fout ");
+                            while(xifo_get_used(&com))
+                                    pc.putc(xifo_pop_lr(&com));
+                            pc.putc('\n');
+                            xifo_init(&com, 128, (uint32_t *)&compool); 
+                            xifo_clear(&com);
+                        }}
+                }else{
+                    // SLAVE mode
+                    if( xifo_read_mr(&com,0) == '\n'){
+                        xifo_pop_mr(&com);
+                        do_parse = 1;
+                    }
+                }
+                if(do_parse){
+                    do_parse=0;
+                    
+                    // Parse data
+                    char filter = xifo_pop_lr(&com);
+                    xifo_pop_lr(&com) ; // space
+                    // Get number
+                    while( xifo_get_used(&com) && p < sizeof(number))
+                        number[p++] = (char)xifo_pop_lr(&com);
+                    
+                    if(mode==MASTER){   
+                        // frequency
+                        if( filter == 'f' ){
+                            freq_master = strtod(number,0);
+                            int t = dacper / (freq_master);
+                            pc.printf("Frequency %f, approximate: %f\n", freq_master, dacper/t);
+                            do_calc = 1;
+                        }else{
+                        // amplitude
+                        if( filter == 'a'){
+                            amplitude_master = strtod(number,0);
+                            pc.printf("Amplitude %f\n", amplitude_master);
+                            do_calc = 1;
+                        }else{
+                        // phase
+                        if( filter == 'p' ){
+                            phase_master = strtod(number,0) * PI;
+                            pc.printf("Phase %f\n", phase_master);
+                            do_calc = 1;                            
+                        } else{
+                        pc.printf("fout ");
+                        while(xifo_get_used(&com))
+                                pc.putc(xifo_pop_lr(&com));
+                        pc.putc('\n');
+                        xifo_init(&com, 128, (uint32_t *)&compool); 
+                        xifo_clear(&com);
+                        }}}
+                    }else{
+                        // frequency
+                        if( filter == 'f' ){
+                            freq_slave = strtod(number,0);
+                            int t = dacper / (freq_slave);
+                            sr.printf("Frequency %f, approximate: %f\n", freq_slave, dacper/t);
+                            do_calc = 1;
+                        }else{
+                        // amplitude
+                        if( filter == 'a'){
+                            amplitude_slave = strtod(number,0);
+                            sr.printf("Amplitude %f\n", amplitude_slave);
+                            do_calc = 1;
+                        }else{
+                        // phase
+                        if( filter == 'p' ){
+                            phase_slave = strtod(number,0) * PI;
+                            sr.printf("Phase %f\n", phase_slave);
+                            do_calc = 1;                            
+                        } else{
+                        sr.printf("fout ");
+                        while(xifo_get_used(&com))
+                                sr.putc(xifo_pop_lr(&com));
+                        sr.putc('\n');
+                        xifo_init(&com, 128, (uint32_t *)&compool); 
+                        xifo_clear(&com);
+                        }}}
+                    }
+                    }
+            } /* BLOCK with command parsing */
+
+            // recalculate
+            if(do_calc){
+                do_calc = 0;
+                // only continue if previous update is complete
+                if( !toch0 && !toch1 ){
+                    // calc frequency
+                        switch(mode){
+                        case MASTER:
+                            ddacdiv = dacper / (freq_master);
+                            //pc.printf("set dacdiv to %f\n",ddacdiv);
+                        break;
+                        case SLAVE:
+                            ddacdiv = dacper / (freq_slave);
+                        break;
+                        }
+                        unsigned int dacdiv = ddacdiv;
+                        LPC_DAC->DACCNTVAL = dacdiv; // 6500 for 10Hz
+                        wdt.kick(10.0*(1.0/(dacper/ddacdiv)));
+                    // calculate_sines sine
+                    switch(mode){
+                    case MASTER:
+                        for (int i =   0; i <=  359; i++) 
+                        {
+                            double rads = (PI/180.0 * i);
+                            buffer[2][i] =  amplitude_master * (512 * sin( rads + phase_master)) + 512;                     
+                        }
+                    break;
+                    case SLAVE:
+                        for (int i =   0; i <=  359; i++)
+                        {
+                            double rads = (PI/180.0 * i);
+                            buffer[2][i] =  amplitude_slave * (512 * sin( rads + phase_slave)) + 512;                
+                        }
+                    break;
+                    }
+                    // Adjust the sinewave buffer for use with DAC hardware.
+                    for (int i = 0; i < 360; i++) {
+                            if( buffer[2][i] > 1023 ) buffer[2][i] = 1023;
+                            buffer[2][i] = DAC_POWER_MODE | ((buffer[2][i] << 6) & 0xFFC0); 
+                    }
+                toch0 = 1; 
+                toch1 = 1;
+            }
         }
-    } 
+    }
 }
  
 // Configuration callback on TC
 void TC0_callback(void) {
 
-        
     // Just show sending buffer0 complete.
     led3 = !led3; 
     
     // Implement wait for trigger if slave mode
         wait_for_sync();
-    
+        wdt.kick();
+            
     // Get configuration pointer.
     MODDMA_Config *config = dma.getConfig();
     
@@ -212,6 +433,12 @@
  
     // Clear DMA IRQ flags.
     if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); 
+
+        // Copy to channel 0?   
+        if ( toch0 ){
+            for (int i =   0; i <=  359; i++) buffer[0][i] =  buffer[2][i];
+            toch0=0;
+        }
 }
  
 // Configuration callback on Error
@@ -221,24 +448,30 @@
  
 // Configuration callback on TC
 void TC1_callback(void) {
-    
     // Just show sending buffer1 complete.
     led4 = !led4; 
    
     // Implement wait for trigger if slave mode
         wait_for_sync();
+        wdt.kick();
      
     // Get configuration pointer.
     MODDMA_Config *config = dma.getConfig();
-    
-    // Finish the DMA cycle by shutting down the channel.
-    dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
-    
-    // Swap to buffer0
-    dma.Prepare( conf0 );
-    
-    // Clear DMA IRQ flags.
-    if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); 
+
+        // Finish the DMA cycle by shutting down the channel.
+        dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
+        
+        // Swap to buffer0
+        dma.Prepare( conf0 );
+        
+        // Clear DMA IRQ flags.
+        if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();
+      
+        // Copy to channel 1? 
+        if ( toch1 ){
+            for (int i =   0; i <=  359; i++) buffer[1][i] =  buffer[2][i];
+            toch1=0;
+        }
 }
  
 // Configuration callback on Error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/watchdog.h	Fri May 31 14:45:27 2013 +0000
@@ -0,0 +1,19 @@
+// Simon's Watchdog code from
+// http://mbed.org/forum/mbed/topic/508/
+class Watchdog {
+public:
+// Load timeout value in watchdog timer and enable
+    void kick(float s) {
+        LPC_WDT->WDCLKSEL = 0x1;                // Set CLK src to PCLK
+        uint32_t clk = SystemCoreClock / 16;    // WD has a fixed /4 prescaler, PCLK default is /4
+        LPC_WDT->WDTC = s * (float)clk;
+        LPC_WDT->WDMOD = 0x3;                   // Enabled and Reset
+        kick();
+    }
+// "kick" or "feed" the dog - reset the watchdog timer
+// by writing this required bit pattern
+    void kick() {
+        LPC_WDT->WDFEED = 0xAA;
+        LPC_WDT->WDFEED = 0x55;
+    }
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xIFO.c	Fri May 31 14:45:27 2013 +0000
@@ -0,0 +1,287 @@
+
+ /**
+ * @file    xifo.c
+ * @brief   xifo circular buffer
+ * @details xifo supplies object oriented circular buffer with 32 bit size elements. \n
+ *                     To use either as FIFO (First In First Out) or as FILO (First In Last Out)
+ *
+ * @Author    Jeroen Lodder
+ * @Date        April 2013
+ * @version 2
+ *
+ * @{
+ */
+#include "xifo.h"
+
+/**
+ * @brief   Initialise buffer object structure.
+ *
+ * @note    Does not clear memory pool.
+ *
+ * @param[in] c   Pointer to @p xifo_t object used for configuration.
+ * @param[in] s   Number of elements buffer can hold (size).
+ * @param[in] sp  Start of pre-allocated memory pool.
+ */
+void xifo_init(xifo_t *c, uint32_t s, uint32_t *sp){
+    c->startpool        = sp;
+    c->endpool          = &sp[s-1];
+    c->size             = s;
+    c->full             = 0;
+    c->elementcount     = 0;
+    c->read             = sp;
+    c->write            = sp;
+}
+
+/**
+ * @brief   Clear buffer contents
+ *
+ * @note    Must be used on initialised buffer object.
+ *
+ * @param[in] c   Pointer to @p xifo_t object.
+ */
+void xifo_clear(xifo_t *c){
+    c->ptemp = c->startpool;
+    while(c->ptemp <= c->endpool){
+        *c->ptemp++ = 0;        
+    }
+}
+
+/**
+ * @brief   Read from buffer (lr) Least Recent oriented (fifo)
+ *
+ * @note    Buffer state will be preserved
+ *
+ * @warning    Consider this opertaion as atomic!
+ *
+ * @details Read n elements from the oldest element to the most recent.
+ *                    As for index[0] the least recently added element is returned.
+ *                    And for index[elementcount] the most recent element is returned.
+ *                    This makes it possible to peek in fifo.
+ *
+ * @param[in] c           Pointer to @p xifo_t used for configuration.
+ * @param[in] index   Index relative from least recent
+ *
+ * @return    Contents of element or 0 if failed (element can hold 0)
+ */
+uint32_t xifo_read_lr(xifo_t *c, uint32_t index){
+    /* Verify there is valid data to read */
+    if(index+1 > c->elementcount){
+        return 0;    /* Nothing to read there */
+    }
+    /* Calculate index of oldest element */
+    index = (c->elementcount-1) - index;
+    /* Set pointer */
+    c->ptemp = (c->read) - index;
+    if(c->ptemp < c->startpool){
+        /* We exceeded pool boundaries */
+        /* Calculate overshoot (startpool - indexptr) and subtract from end */
+        /* Since one element of overshoot results in end - 1 you would miss the last value */
+        c->ptemp = (c->endpool+1) - (c->startpool - c->ptemp);
+    }
+    /* Read most recent */
+    return *c->ptemp;
+}
+
+/**
+ * @brief   Read from buffer (mr) Most Recent oriented (filo)
+ *
+ * @note    Buffer state will be preserved
+ *
+ * @warning    Consider this opertaion as atomic!
+ *
+ * @details Read n elements back in time.
+ *                    As for index[0] the most recently added element is returned.
+ *                    And for index[elementcount] the oldest element is returned.
+ *                    This makes it possible to keep history. For DSP application.
+ *
+ * @param[in] c           Pointer to @p xifo_t used for configuration.
+ * @param[in] index   Index relative from most recent
+ *
+ * @return    Contents of element or 0 if failed (element can hold 0)
+ */
+uint32_t xifo_read_mr(xifo_t *c, uint32_t index){
+    /* Verify there is valid data to read */
+    if(index+1 > c->elementcount){
+        return 0;    /* Nothing to read there */
+    }
+    /* Set pointer */
+    c->ptemp = (c->read) - index;
+    /* Validate pointer */
+    if(c->ptemp < c->startpool){
+        /* We exceeded pool boundaries */
+        /* Calculate overshoot (startpool - indexptr) and subtract from end */
+        /* Since one element of overshoot results in end - 1 you would miss the last value */
+        c->ptemp = (c->endpool+1) - (c->startpool - c->ptemp);
+    }
+    /* Read most recent */
+    return *c->ptemp;
+}
+
+/**
+ * @brief   Pop (mr) most recent from buffer (filo)
+ *
+ * @note    Buffer state will be altered
+ *
+ * @warning    Consider this opertaion as atomic!
+ *
+ * @details Read and remove the most recently added from the buffer.
+ *                     Using this results in a stack type of buffer.
+ *
+ * @param[in] c           Pointer to @p xifo_t used for configuration.
+ *
+ * @return    Contents of element or 0 if failed (element can hold 0)
+ */
+uint32_t xifo_pop_mr(xifo_t *c){
+    /* Verify there is valid data read */
+    if(c->elementcount == 0){
+        return 0;    /* Nothing to read there */
+    }
+    /* Read */
+    c->temp = *c->read;
+    /* Empty */
+    *c->read = 0;
+    /* Most recent element read, return write pointer */
+    c->write = c->read;
+    /* Decrement read pointer */
+    c->read--;
+    /* Validate pointer */
+    if( c->read < c->startpool ){
+        /* We exceeded pool boundaries */
+        c->read = c->endpool;
+    }
+    /* Reduce elementcount */
+    c->elementcount--;
+    if(c->elementcount < c->size)
+        c->full = 0;
+    return c->temp;
+}
+
+/**
+ * @brief   Pop (lr) least recent from buffer (fifo)
+ *
+ * @note    Buffer state will be altered
+ *
+ * @warning    Consider this opertaion as atomic!
+ *
+ * @details Read and remove the least recently added from the buffer.
+ *                     Using this results in a fifo type of buffer.
+ *
+ * @param[in] c    Pointer to @p xifo_t used for configuration.
+ *
+ * @return    Contents of element or 0 if failed (element can hold 0)
+ */
+uint32_t xifo_pop_lr(xifo_t *c){    
+    /* Verify there is valid data read */
+    if(c->elementcount == 0){
+        return 0;    /* Nothing to read there */
+    }
+    /* Derive least recent buffer element */
+    c->ptemp = c->read+1 - c->elementcount;
+    /* Validate pointer */
+    if(c->ptemp < c->startpool){
+        /* We exceeded pool boundaries */
+        /* Calculate overshoot (startpool - indexptr) and subtract from end */
+        /* Since one element of overshoot results in end - 1 you would miss the last value */
+        c->ptemp = (c->endpool+1) - (c->startpool - c->ptemp);
+    }
+    /* Read oldest buffer element */
+    { /* block with temporary variable to prevent stack use */
+        register uint32_t element;
+        /* Read to temp register */
+        element = *c->ptemp;
+        /* Empty */
+        *c->ptemp = 0;
+        /* Clear temp register */
+        c->temp = element;
+    }
+    /* Reduce elementcount */
+    c->elementcount--;
+    /* Check full flag */
+    if(c->elementcount < c->size)
+        c->full = 0;
+    return c->temp;
+}
+
+/**
+ * @brief   Write to buffer
+ *
+ * @note    Readpointer is automatically set to the last added element.
+ *
+ * @warning    Consider this opertaion as atomic!
+ *                    
+ * @details Adds a value to the buffer.
+ *                    Automatically overwrites oldest elements when full.
+ *
+ * @param[in] c            Pointer to @p xifo_t used for configuration.
+ * @param[in] data    Data to add to buffer
+ *
+ * @return    Number of free buffer elements
+ */
+uint32_t xifo_write(xifo_t *c, uint32_t data){    
+    /* Write data */
+    *c->write = data;
+    /* Update read pointer to most recent element */
+    c->read = c->write;
+    /* Write pointer increment */
+    c->write += 1;
+    /* Validate pointer */
+    if( c->write > c->endpool){
+          /* We exceeded pool boundaries */
+            c->write = c->startpool;
+    }
+    /* Update elementcount */
+    c->elementcount++;
+    /* Verify full */
+    if( c->elementcount >= c->size ){
+        c->full = 1;
+        c->elementcount = c->size;
+    }
+    /* return free elements count */
+    return c->size - c->elementcount;
+}
+
+/**
+ * @brief   Get buffer size
+ *
+ * @param[in] c    Pointer to @p xifo_t used for configuration.
+ *
+ * @return    Size of memory pool in elements
+ */
+uint32_t xifo_get_size(xifo_t *c){
+    return c->size;
+}
+
+/**
+ * @brief   Get number of used elements
+ *
+ * @param[in] c    Pointer to @p xifo_t used for configuration.
+ *
+ * @return    Number of used buffer elements
+ */
+uint32_t xifo_get_used(xifo_t *c){
+    return c->elementcount;
+}
+
+/**
+* @brief   Get number of free elements
+*
+* @param[in] c    Pointer to @p xifo_t used for configuration.
+*
+* @return    Number of free elements
+*/
+uint32_t xifo_get_free(xifo_t *c){
+    return c->size - c->elementcount;
+}
+
+/**
+ * @brief   Get full flag
+ *
+ * @param[in] c    Pointer to @p xifo_t used for configuration.
+ *
+ * @return    1 if full
+ */
+uint32_t xifo_get_full(xifo_t *c){
+    return c->full;
+}
+
+/** @} */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xIFO.h	Fri May 31 14:45:27 2013 +0000
@@ -0,0 +1,92 @@
+ 
+ /**
+ * @file    xifo.h
+ * @brief   xifo circular buffer
+ * @details xifo supplies object oriented circular buffer with 32 bit size elements. \n
+ *                     To use either as FIFO (First In First Out) or as FILO (First In Last Out)
+ *
+ * @author    Jeroen Lodder
+ * @date        April 2013
+ * @version 2
+ *
+ * @{
+ */
+ 
+ /**
+ *    Code has been tested on Cortex M0 (LPC1114)
+ *  Performance table, number of core clocks
+ *    Measured with a timer before and after
+ *    r1 = timer->TC
+ *        test_function 
+ *  r2 = timer->TC
+ *
+ *  Function    Speed        Worst Case
+ *
+ *  write            69            71
+ *  read_mr        59      59
+ *  read_lr        63      70
+ *  pop_mr        76      78
+ *    pop_lr        45      45
+ *
+ */
+
+#ifndef _xifo_H_
+#define _xifo_H_
+
+#include <inttypes.h>
+
+#if defined(__arm__)  || defined(__DOXYGEN__)
+#pragma anon_unions                /**< Allow unnamed unions */
+#endif
+
+/**
+ * @brief   Circular Buffer object.
+ * @details This struct holds the object of a circular buffer
+ */
+typedef struct  {
+/* Pointers: */
+        uint32_t *startpool;  /**< @brief First element in pool */
+        uint32_t *endpool;        /**< @brief Last element in pool */
+        uint32_t *read;                /**< @brief Read pointer */
+        uint32_t *write;            /**< @brief Write pointer */
+/* Variables: */
+        uint32_t full;        /**< @brief Flag indicating buffer is full */
+    uint32_t elementcount;/**< @brief Number of elements used */
+        uint32_t size;                /**< @brief Size of buffer */
+/* Locally used in functions to prevent stack use: */
+        /**< @brief union to prevent lvalue typecasting */  
+        union {                         
+            uint32_t temp;            /**< @brief temp variable and padding for even sized block */
+            uint32_t *ptemp;         /**< @brief temp variable and padding for even sized block */
+        };
+}xifo_t;
+
+/**
+ * @brief   Circular Buffer memory pool type.
+ */
+typedef unsigned int xifo_pool_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* xifo Common */
+void xifo_init(xifo_t *c, uint32_t size, uint32_t *startpool);
+void xifo_clear(xifo_t *c);
+uint32_t xifo_write(xifo_t *c, uint32_t data);
+/* FIFO use */
+uint32_t xifo_read_lr(xifo_t *c, uint32_t index);
+uint32_t xifo_pop_lr(xifo_t *c);
+/* LIFO use */
+uint32_t xifo_read_mr(xifo_t *c, uint32_t index);
+uint32_t xifo_pop_mr(xifo_t *c);
+/* Extractors */
+uint32_t xifo_get_size(xifo_t *c);
+uint32_t xifo_get_used(xifo_t *c);
+uint32_t xifo_get_full(xifo_t *c);
+uint32_t xifo_get_free(xifo_t *c);
+#ifdef __cplusplus
+}
+#endif
+#endif //_xifo_H_
+
+/** @} */