1
\$\begingroup\$

I am using dsPIC33EP512MU810 to simultaneous sample 4 signals from a mic and display the samples on the on-board tft screen on the EasyPIC Fusion v7 development board.

I was successful in acheiving my goal of doing this task without DMA, but now have come to a dead end when using DMA.

Furthermore, I am using the in-built TFT display library available in MikroC for dsPIC compiler. It's Link.

The screen is showing 0 for all four channels (no data is being read from the ADC). I have gone through the connections and datasheets many times but can't seem to understand what I am doing wrong.

Can someone please go through my code to find the 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
}

Edit 1:

Changed ADC1CON4 = 0x0100;

It did enable the dma, but now the lcd screen keeps on blinking and is unable to display anything. The reason I think is the constant interrupts occurring and keeping the cpu occupied.

I am using 8MHz crystal and internal PLL circuitory to generate a 80Mhz clock.

Can someone guide me how I should select Timer3 timeout, dma buffer size and how do I calculate the maximum ammount of sample rate I can work with, without overloading the MCU?

\$\endgroup\$
  • \$\begingroup\$ Welcome to EE.SE! You've just dumped a whole design in your question and haven't explained your approach. To get the best answer, you should provide some explanation of your intention and what debugging results you have. \$\endgroup\$ – user2943160 Jun 30 '16 at 3:26
  • \$\begingroup\$ I have added additional details for my work and tried my best to explain my approach. I will answer any follow up questions as well. \$\endgroup\$ – Mohsin Anees Jun 30 '16 at 6:24
0
\$\begingroup\$

In the INitADC fuction, you do not enable the DMA in control register 4.

Try

AD1CON4bits.ADDMAEN = 1;

-OR-

AD1CON4 = 0x0100; 

See page 424 dsPIC33EP512MU810 userguide / ref manual.

\$\endgroup\$
  • \$\begingroup\$ Thank you it really was a mistake. But this has lead to another major problem. The LCD screen keeps on turning on and off and cannot display anything at all. I think it is because of constant interrupts occuring and continously occupying the cpu. Can you please guide me how I should select Timer3 timeout and BUFFER size for the DMA? \$\endgroup\$ – Mohsin Anees Jun 30 '16 at 6:31
  • \$\begingroup\$ @MohsinAnees if this is a modification of your question then you should edit your above question, otherwise (more likely, in this case) you should start a new question detailing your new issues. \$\endgroup\$ – user2943160 Jun 30 '16 at 13:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.