Real Time FIR Filter - Distinctive Excellence award winner :)

Dependencies:   mbed

Revision:
0:b3e50e98acac
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.c	Sat Aug 13 17:35:52 2011 +0000
@@ -0,0 +1,200 @@
+/*
+==============================================================================================
+ Name                        : QuiPad
+ Contest Registration Number : NXP3854
+ Description                 : Real time FIR filter controlled by a touchpad
+==============================================================================================
+*/
+
+#include "mbed.h"
+#include "cr_dsplib.h"
+#include "filters.h"
+#include "dma.h"
+#include "adc_dac.h"
+#include "timer.h"
+#include "config.h"
+#include "touchpad.h"
+#include "leds_mbed.h"
+
+
+#define init_ahb_ram0 0x2007c000
+#define mid_ahb_ram0 0x2007DE00
+#define init_ahb_ram1 0x20080000
+#define mid_ahb_ram1 0x20081E00
+
+/*Los buffers y listas de guardan en la memoria AHB SRAM*/
+/*Esto es porque esta seccion de la memoria tiene menor tiempo de accesso*/
+/*Los buffer del DAC tienen 3 muestras extra por un detalle del algoritmo de filtrado */
+/*Esas tres muestras son descartadas luego al ser ignoradas por el DMA */
+int dac_buff_ping[BLOCKSIZE+3] __attribute__ ((at(init_ahb_ram0))); /*Buffers de datos para el DAC*/
+int dac_buff_pong[BLOCKSIZE+3] __attribute__ ((at(init_ahb_ram1)));
+int adc_buff_ping[(COEFF_AMOUNT-1)+BLOCKSIZE] __attribute__ ((at(mid_ahb_ram0))); /*Buffers de datos para el ADC*/
+int adc_buff_pong[(COEFF_AMOUNT-1)+BLOCKSIZE] __attribute__ ((at(mid_ahb_ram1)));
+/* Los buffers estan distribuidos de tal forma que el filtrado de datos se realice solo en una
+ * memoria SRAM a la vez y no estorbe la otra. De la misma forma, el DMA usa la otra memoria unicamente.
+ * Asi logro que el DMA y el filtrado no compitan por la memoria y acelero el filtrado.
+ */
+
+int main(void)
+{
+    tS_blockfir32_Coeff filter_pad;
+
+    int i;
+
+    /* La declaro como static para que se almacene en RAM */
+    static int filterRAM[256];
+
+    /* Estructura para obtencion de coordenadas */
+    touchpad_position current_position, prev_position, valid_position;
+
+    valid_position.pos_x = 0;
+    valid_position.pos_y = 0;
+
+    /* Inicializacio DMA */
+
+    static dmaLinkedListNode DACdmaList[2];    /*Lista del DMA del DAC*/
+    static dmaLinkedListNode ADCdmaList[2];    /*Lista del DMA del ADC*/
+
+    dmaLinkedListNode *pNodeDACping = &(DACdmaList[0]);
+    dmaLinkedListNode *pNodeDACpong = &(DACdmaList[1]);
+    dmaLinkedListNode *pNodeADCping = &(ADCdmaList[0]);
+    dmaLinkedListNode *pNodeADCpong = &(ADCdmaList[1]);
+
+    /* Configuro los nodos de las listas de los canales DMA */
+
+    /* Nodos del DMA que copia de la memoria al DAC */
+    pNodeDACping->sourceAddr = (unsigned int) dac_buff_ping; /*Direccion inicial de lectura del buffer DAC*/
+    pNodeDACping->destAddr = (unsigned int) &(LPC_DAC->DACR); /*Direccion del DAC*/
+    pNodeDACping->nextNode = (unsigned int) pNodeDACpong; /*Proximo nodo de la lista*/
+    pNodeDACping->dmaControl =  (unsigned int)BLOCKSIZE  | /*Numero de transferencias en total (BLOCKSIZE)*/
+                               ((unsigned int)0x0 << 12) | /*Numero de transferencias por burst de origen (1)*/
+                               ((unsigned int)0x0 << 15) | /*Numero de transferencias por burst de destino (1)*/
+                               ((unsigned int)0x2 << 18) | /*Ancho de bus de origen de 32 bits */
+                               ((unsigned int)0x2 << 21) | /*Ancho de bus de destino de 32 bits */
+                               ((unsigned int)0x0 << 24) | /*Reservado*/
+                               ((unsigned int)0x1 << 26) | /*Incrementar source address luego de cada transferencia*/
+                               ((unsigned int)0x0 << 27) | /*No incrementar el destination address luego de cada transferencia*/
+                               ((unsigned int)0x0 << 28) | /*No usado en el LPC17xx*/
+                               ((unsigned int)0x0 << 29) | /*No usado en el LPC17xx*/
+                               ((unsigned int)0x0 << 30) | /*No usado en el LPC17xx*/
+                               ((unsigned int)0x0 << 31);  /*Deshabilito interrupcion de "transferencia completa"*/
+
+    pNodeDACpong->sourceAddr = (unsigned int) dac_buff_pong; /*Direccion inicial de lectura del buffer DAC*/
+    pNodeDACpong->destAddr = (unsigned int) &(LPC_DAC->DACR); /*Direccion del DAC*/
+    pNodeDACpong->nextNode = (unsigned int) pNodeDACping; /*Proximo nodo de la lista*/
+    pNodeDACpong->dmaControl =  (unsigned int)BLOCKSIZE  | /*Numero de transferencias en total (BLOCKSIZE)*/
+                               ((unsigned int)0x0 << 12) | /*Numero de transferencias por burst de origen (1)*/
+                               ((unsigned int)0x0 << 15) | /*Numero de transferencias por burst de destino (1)*/
+                               ((unsigned int)0x2 << 18) | /*Ancho de bus de origen de 32 bits */
+                               ((unsigned int)0x2 << 21) | /*Ancho de bus de destino de 32 bits */
+                               ((unsigned int)0x0 << 24) | /*Reservado*/
+                               ((unsigned int)0x1 << 26) | /*Incrementar source address luego de cada transferencia*/
+                               ((unsigned int)0x0 << 27) | /*No incrementar el destination address luego de cada transferencia*/
+                               ((unsigned int)0x0 << 28) | /*No usado en el LPC17xx*/
+                               ((unsigned int)0x0 << 29) | /*No usado en el LPC17xx*/
+                               ((unsigned int)0x0 << 30) | /*No usado en el LPC17xx*/
+                               ((unsigned int)0x0 << 31);  /*Deshabilito interrupcion de "transferencia completa"*/
+
+    /* Nodos del DMA que copia del ADC a la memoria */
+    pNodeADCping->sourceAddr = (unsigned int) &(LPC_ADC->ADDR0); /*Direccion de los datos de salida del ADC*/
+    pNodeADCping->destAddr = (unsigned int) &(adc_buff_ping[(COEFF_AMOUNT-1)]) ; /*Direccion del buffer del ADC*/
+    pNodeADCping->nextNode = (unsigned int) pNodeADCpong; /*Proximo nodo de la lista*/
+    pNodeADCping->dmaControl =  (unsigned int)BLOCKSIZE  | /*Numero de transferencias en total (BLOCKSIZE)*/
+                               ((unsigned int)0x0 << 12) | /*Numero de transferencias por burst de origen (1)*/
+                                  ((unsigned int)0x0 << 15) | /*Numero de transferencias por burst de destino (1)*/
+                                  ((unsigned int)0x2 << 18) | /*Ancho de bus de origen de 32 bits */
+                                  ((unsigned int)0x2 << 21) | /*Ancho de bus de destino de 32 bits */
+                                  ((unsigned int)0x0 << 24) | /*Reservado*/
+                                  ((unsigned int)0x0 << 26) | /*No Incrementar source address luego de cada transferencia*/
+                                  ((unsigned int)0x1 << 27) | /*Incrementar el destination address luego de cada transferencia*/
+                                  ((unsigned int)0x0 << 28) | /*No usado en el LPC17xx*/
+                                  ((unsigned int)0x0 << 29) | /*No usado en el LPC17xx*/
+                                  ((unsigned int)0x0 << 30) | /*No usado en el LPC17xx*/
+                                  ((unsigned int)0x1 << 31);  /*Habilito interrupcion de "transferencia completa"*/
+
+    pNodeADCpong->sourceAddr = (unsigned int) &(LPC_ADC->ADDR0); /*Direccion de los datos de salida del ADC*/
+    pNodeADCpong->destAddr = (unsigned int) &(adc_buff_pong[(COEFF_AMOUNT-1)]) ; /*Direccion del buffer del ADC*/
+    pNodeADCpong->nextNode = (unsigned int) pNodeADCping; /*Proximo nodo de la lista*/
+    pNodeADCpong->dmaControl =  (unsigned int)BLOCKSIZE  | /*Numero de transferencias en total (BLOCKSIZE)*/
+                                  ((unsigned int)0x0 << 12) | /*Numero de transferencias por burst de origen (1)*/
+                                  ((unsigned int)0x0 << 15) | /*Numero de transferencias por burst de destino (1)*/
+                                  ((unsigned int)0x2 << 18) | /*Ancho de bus de origen de 32 bits */
+                                  ((unsigned int)0x2 << 21) | /*Ancho de bus de destino de 32 bits */
+                                  ((unsigned int)0x0 << 24) | /*Reservado*/
+                                  ((unsigned int)0x0 << 26) | /*No Incrementar source address luego de cada transferencia*/
+                                  ((unsigned int)0x1 << 27) | /*Incrementar el destination address luego de cada transferencia*/
+                                 ((unsigned int)0x0 << 28) | /*No usado en el LPC17xx*/
+                                  ((unsigned int)0x0 << 29) | /*No usado en el LPC17xx*/
+                                  ((unsigned int)0x0 << 30) | /*No usado en el LPC17xx*/
+                                  ((unsigned int)0x1 << 31);  /*Habilito interrupcion de "transferencia completa"*/
+
+    /* Inicializo perifericos */
+    init_touchpad();
+    initADC();
+    initDAC();
+    initDMAs(pNodeADCping , pNodeDACping);
+    init_timer();
+
+    /* Una vez inicializado el sistema, se tienen que atender las interrupciones generadas por el
+     * DMA (cuando se llenan los buffer) y llamar a la funcion de filtrado FIR. */
+
+     /* Loop infinito. */
+    while(1)
+    {
+        if(BufferTransferCompleted == TRUE)
+        {
+            BufferTransferCompleted = FALSE;
+
+            /* Obtengo posicion del touchpad */
+            current_position = get_position();
+
+            /* Aplico filtrado al valor de posicion para evitar ruido */
+            /* Verifico que la misma posicion se haya registrado dos veces seguidas */
+            /* En caso negativo, la descarto */
+            if ((prev_position.pos_x == current_position.pos_x) && (prev_position.pos_y == current_position.pos_y))
+            {
+                valid_position.pos_x = current_position.pos_x;
+                valid_position.pos_y = current_position.pos_y;
+            }
+
+            prev_position.pos_x = current_position.pos_x;
+            prev_position.pos_y = current_position.pos_y;
+
+            show_number_on_leds(valid_position.pos_y);
+
+            /* Copio el filtro a utilizar a la RAM (mejora el tiempo de filtrado) */
+            for(i = 0; i < 256; i++)
+            {
+                /* filterRAM[i] = filters[valid_position.pos_x][valid_position.pos_y][i]; */
+                /* Por ahora, a modo de ejemplo, solo utilizo la coordenada Y */
+                filterRAM[i] = filters[valid_position.pos_y][i];
+            }
+
+            filter_pad.NTaps = filter_length;
+            filter_pad.pi_Coeff = filterRAM;
+
+            if(BufferToProcess == PING)
+            {
+                /* Copio las ultimas (COEFF-1) muestras del buffer ping al buffer pong */
+                for(i=0; i < COEFF_AMOUNT-1; i++)
+                {
+                    adc_buff_pong[i] = adc_buff_ping[BLOCKSIZE + i];
+                }
+                /* Proceso el buffer adc_buff_ping y guardo resultados en dac_buff_ping */
+                vF_dspl_blockfir32(dac_buff_ping, adc_buff_ping, &filter_pad, (COEFF_AMOUNT-1)+BLOCKSIZE);
+            }
+            else
+            {
+                /* Copio las ultimas (COEFF-1) muestras del buffer pong al buffer ping */
+                for(i=0; i < COEFF_AMOUNT-1; i++)
+                {
+                    adc_buff_ping[i] = adc_buff_pong[BLOCKSIZE + i];
+                }
+                /* Proceso el buffer adc_buff_pong y guardo resultados en dac_buff_pong */
+                vF_dspl_blockfir32(dac_buff_pong, adc_buff_pong, &filter_pad, (COEFF_AMOUNT-1)+BLOCKSIZE);
+            }
+           }
+    }
+
+    return 1 ; /* Si se llego aqui, hay un problema! */
+}