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?