ADC con DMA no funciona

1

Estoy usando dsPIC33EP512MU810 para muestrear simultáneamente 4 señales de un micrófono y mostrar las muestras en la pantalla tft integrada en la placa de desarrollo EasyPIC Fusion v7.

Tuve éxito en lograr mi objetivo de realizar esta tarea sin DMA, pero ahora he llegado a un punto muerto cuando uso DMA.

Además, estoy usando la biblioteca de pantallas TFT incorporada disponible en MikroC para el compilador dsPIC. Es el Link .

La pantalla muestra 0 para los cuatro canales (no se están leyendo datos del ADC). He revisado las conexiones y las hojas de datos muchas veces, pero parece que no entiendo lo que estoy haciendo mal.

¿Puede alguien revisar mi código para encontrar el error?

// TFT module connections
char TFT_DataPort at LATE;
sbit TFT_RST at LATD7_bit;
sbit TFT_BLED at LATD2_bit;
sbit TFT_RS at LATD9_bit;
sbit TFT_CS at LATD10_bit;
sbit TFT_RD at LATD5_bit;
sbit TFT_WR at LATD4_bit;
char TFT_DataPort_Direction at TRISE;
sbit TFT_RST_Direction at TRISD7_bit;
sbit TFT_BLED_Direction at TRISD2_bit;
sbit TFT_RS_Direction at TRISD9_bit;
sbit TFT_CS_Direction at TRISD10_bit;
sbit TFT_RD_Direction at TRISD5_bit;
sbit TFT_WR_Direction at TRISD4_bit;
// End TFT module connections

void init_MCU();
void init_LCD();
void load_background();
void draw_pulse();
void refresh_axis();
void readAdc(adcResults);
void int_ADC();
void init_DMA();
void DMA5Interrupt();

int ch_incr[4] = {60, 120, 180, 240};

int New_X[4], New_Y[4], Adc_Values[4];
int Curr_X[4] = {0,0,0,0};
int Curr_Y[4] = {60, 120, 180, 240};
int i = 0, j = 0, k;
int Curr_Val[4] = {0}, Scaled_Val[4];
int ADCValues[4] = {0, 0, 0, 0};

struct adcResults {
  unsigned int Adc1Ch0[8];
  unsigned int Adc1Ch1[8];
  unsigned int Adc1Ch2[8];
  unsigned int Adc1Ch3[8];
}BufferA, BufferB;

typedef struct adcResults ADCResults;
ADCResults *ptr;


void main() {
  init_MCU();
  init_LCD();
  int_ADC();
  init_DMA();
  load_background();

  while(1) {
    draw_pulse();
  }
}

void init_MCU() {
  // PLL settings
  CLKDIVbits.PLLPRE = 0;      // PLLPRE<4:0> = 0  ->  N1 = 2    8MHz / 2 =   4MHz
                              // (must be within 0.8 MHz to 8 MHz range)
  PLLFBD =   38;              // PLLDIV<8:0> = 48 ->  M = 40    4MHz * 40 = 160MHz
                              // (must be within 100 MHz to 200 MHz range)
  CLKDIVbits.PLLPOST = 0;     // PLLPOST<1:0> = 0 ->  N2 = 2    160MHz / 2 = 80MHz
                              // (must be within 12.5 MHz to 80 MHz range)

  ANSELD = 0xFF;          // Set All pins as digital
  ANSELE = 0xFF;
  ANSELC = 0xFF;
}

void init_LCD() {
  TFT_BLED_Direction = 0;
  TFT_Set_Default_Mode();
  TFT_Init_ILI9341_8bit(320, 240);
  TFT_BLED = 1;
}
void load_background() {
  // Enable gradient from black to white color, left-right orientation
  TFT_Set_Brush(1, CL_BLACK, 1, TOP_TO_Bottom, CL_BLACK, CL_WHITE);
  TFT_Fill_Screen(CL_BLACK);
  TFT_Set_Brush(0, 0, 1, LEFT_TO_RIGHT, CL_BLACK, CL_WHITE);
  TFT_Set_Pen(CL_GRAY, 1);
  TFT_H_Line(10, 310, 60);                       //x-start, x-stop, y-axis
  TFT_H_Line(10, 310, 120);                       //x-start, x-stop, y-axis
  TFT_H_Line(10, 310, 180);                       //x-start, x-stop, y-axis
  TFT_H_Line(10, 310, 240);                       //x-start, x-stop, y-axis
}

void draw_pulse() {

  for(k=0; k<4; k++) {
    Scaled_Val[k] = ch_incr[k] - ((ceil(Curr_Val[k])/1023)* 60);
  }

  for(k=0; k<4; k++) {
    New_X[k] = i;
    New_Y[k] = Scaled_Val[k];
  }

  if(i < 318) {
  TFT_Set_PEN(CL_BLACK, 1);
  TFT_V_Line(0,240,i+1);
  TFT_Set_PEN(CL_RED, 1);
  TFT_V_Line(0,240,i+2);
  }
  else if(i == 319){
  TFT_Set_PEN(CL_BLACK, 2);
  TFT_V_Line(0,240,i+1);
  }


  TFT_Set_Pen(CL_RED, 2);
  TFT_Line(Curr_X[0], Curr_Y[0], New_X[0], New_Y[0]);
  TFT_Set_Pen(CL_BLUE, 2);
  TFT_Line(Curr_X[1], Curr_Y[1], New_X[1], New_Y[1]);
  TFT_Set_Pen(CL_GREEN, 2);
  TFT_Line(Curr_X[2], Curr_Y[2], New_X[2], New_Y[2]);
  TFT_Set_Pen(CL_YELLOW, 2);
  TFT_Line(Curr_X[3], Curr_Y[3], New_X[3], New_Y[3]);

  for(k=0; k<4; k++) {
    Curr_Y[k] = New_Y[k];
    Curr_X[k] = New_X[k];
    if(Curr_X[k] == 320) {
      Curr_X[k] = 0;
    }
  }

  if(i == 320) {
   i = 0;
  TFT_Set_PEN(CL_BLACK, 1);
  TFT_V_Line(0,240,i);
  }
  i++;
}

void int_ADC() {
  /* Initialize and enable ADC module */
     AD1CON1 = 0x004C;               // Enable simultaneous sampling and auto-sample
     AD1CON2 = 0x0300;               // Sample 4 channels
     AD1CON3 = 0x003F;
     AD1CON4 = 0x0100;
     AD1CSSH = 0x0000;
     AD1CSSL = 0x0000;
     AD1CHS0bits.CH0SA = 3;          // Select AN3 for CH0 +ve input
     AD1CHS0bits.CH0NA = 0;          // Select Vref- for CH0 -ve input
     AD1CHS123bits.CH123SA = 0;      // Select AN0 for CH1 +ve input
                                     // Select AN1 for CH2 +ve input
                                     // Select AN2 for CH3 +ve input
     AD1CHS123bits.CH123NA = 0;
                                     // Select Vref- for CH1/CH2/CH3 -ve inputs

     //Set up Timer3 to trigger ADC1 conversions:
     TMR3 = 0x0000;
     PR3 = 4999; // Trigger ADC1 every 125usec
     IFS0bits.T3IF = 0; // Clear Timer3 interrupt
     IEC0bits.T3IE = 0; // Disable Timer3 interrupt
     T3CONbits.TON = 1; //Start Timer3

     //Set up ADC1 for DMA operation:
     AD1CON1bits.ADDMABM = 0; // DMA buffers are built in scatter/
     AD1CON2bits.SMPI = 3; // 4 ADC buffers
     AD1CON4bits.DMABL = 3; // Each buffer contains 8 words
     IFS0bits.AD1IF = 0; // Clear the A/D interrupt flag
     IEC0bits.AD1IE = 0; // Do Not Enable A/D interrupt
     AD1CON1bits.ADON = 1; // Turn on the A/D converter

}

void readAdc(ADCResults *p)
{
  Curr_Val[0] = p->Adc1Ch0; // Read the AN0 conversion result
  Curr_Val[1] = p->Adc1Ch1; // Read the AN1 conversion result
  Curr_Val[2] = p->Adc1Ch2; // Read the AN2 conversion result
  Curr_Val[3] = p->Adc1Ch3; // Read the AN3 conversion result
}

void init_DMA(void)
{
  //Set up DMA Channel 5 for Peripheral Indirect Addressing:

  DMA5CONbits.AMODE = 2; // Configure DMA for Peripheral indirect mode
  DMA5CONbits.MODE = 2; // Configure DMA for Continuous Ping-Pong mode
  DMA5PAD = (volatile unsigned int)&ADC1BUF0; // Point DMA to ADC1BUF0
  DMA5CNT = 31; // 32 DMA request (4 buffers, each with 8 words)
  DMA5REQ = 13; // Select ADC1 as DMA Request source
  DMA5STAH = 0x0000;
  DMA5STAL = 0x0000;
  DMA5STAH = 0x0000;
  DMA5STAL = 0x1000;
  IFS3bits.DMA5IF = 0; //Clear the DMA interrupt flag bit
  IEC3bits.DMA5IE = 1; //Set the DMA interrupt enable bit
  DMA5CONbits.CHEN=1; // Enable DMA
}

//Set up DMA Channel 5 Interrupt Handler:
unsigned int DmaBuffer = 0;
void DMA5Interrupt()
{
  // Switch between Primary and Secondary Ping-Pong buffers
  if(DmaBuffer == 0) {
    ptr = &BufferA;
    readADC(ptr);
  }
  else {
    ptr = &BufferB;
    readADC(ptr);
  }
  DmaBuffer = ~DmaBuffer;
  IFS3bits.DMA5IF = 0; //Clear the DMA5 Interrupt Flag
}

Edición 1:

Se modificó ADC1CON4 = 0x0100;

Sí habilitó el dma, pero ahora la pantalla lcd sigue parpadeando y no puede mostrar nada. Creo que la razón es la constante interrupción y la ocupación de la CPU.

Estoy utilizando un circuito de 8MHz de cristal y PLL interno para generar un reloj de 80Mhz.

¿Alguien me puede guiar en cómo debo seleccionar el tiempo de espera del temporizador 3, el tamaño del búfer dma y cómo calculo la cantidad máxima de frecuencia de muestreo con la que puedo trabajar, sin sobrecargar la MCU?     

pregunta Mohsin Anees

1 respuesta

0

En la función INitADC, no habilita el DMA en el registro de control 4.

Probar

AD1CON4bits.ADDMAEN = 1;

-OR-

AD1CON4 = 0x0100; 

Consulte la página 424 dsPIC33EP512MU810 manual de usuario / referencia.

    
respondido por el pgvoorhees

Lea otras preguntas en las etiquetas