20 ADC Chanel0 vakues to Memory, DMA driven?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

20 ADC Chanel0 vakues to Memory, DMA driven?

479 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by elgarbe on Sun Apr 13 08:20:39 MST 2014
Hi, I need to continuosly read ADC chanel 0 and transfer the result to an array. I need to make 20 readings befor DMA make an interrupt. So I write this code:

adc.c
void ADCInit(void){
LPC_SC->PCONP |= (1 << 12);// Enable CLOCK into ADC controller */

LPC_PINCON->PINSEL1 &= ~(2<<14);// P0.23 -> AD0.0, function 01
LPC_PINCON->PINSEL1 |= 1<<14;

LPC_ADC->ADCR = ( 1 << 0 ) | // SEL=1,select channel 0 on ADC0
( 4 << 8 ) |  // 100MHz/4 (PCKL_ADC default) = 25MHz / 5 = 5MHz
( 1 << 16 ) | // BURST = 1, BURST mode, continuos covertion
( 1 << 21 ) |  // PDN = 1, normal operation
( 0 << 24 ) |  // START = 0 A/D conversion stops
( 0 << 27 );// EDGE = 0 (CAP/MAT singal falling,trigger A/D conversion)
LPC_ADC->ADINTEN |= 1<<0;// Enable Chanel 0 interrupt request
NVIC_DisableIRQ(ADC_IRQn);            // Register ADC Interrupt Handler
}


dma.c
void DMAInit(){
LPC_SC->PCONP |= 1 << 29; // Power up DMA

LPC_GPDMACH0->DMACCConfig = 0; // stop ch0 dma

LPC_GPDMACH0->DMACCSrcAddr = (uint32_t) &(LPC_ADC->ADDR0); // ADC Chanel 0
LPC_GPDMACH0->DMACCDestAddr = (uint32_t) &arrRSSI; // Array
LPC_GPDMACH0->DMACCLLI = 0;
LPC_GPDMACH0->DMACCControl = ADC_CANT_SAMPLE // Transferencia de 20 word
| (0 << 12) // 1 burst
| (0 << 15) // 1 burst
| (2 << 18) // Word width
| (2<< 21) // Word width
| (0 << 26 ) // Source no increment.
| (1 << 27 ) // Destination increment.
| (1 << 31 );// Enable Terminal Count Interrupt

LPC_GPDMACH0->DMACCConfig = ( 4 << 1 )// Set ADC as source DMA request
| ( 2 << 11 ) // Peripheral to Memory
| ( 1 << 15 ); // Terminal count interrupt mask. 1 = unmasked

LPC_GPDMA->DMACIntErrClr |= 0xff;//Clear all DMA interrupts
LPC_GPDMA->DMACIntTCClear |= 0xff;
NVIC_EnableIRQ(DMA_IRQn);// Register DMA Interrupt Handler

//LPC_GPDMACH0->DMACCConfig |= 1; // enable ch0
LPC_GPDMA->DMACConfig |= 1; // enable DMA
}

void DMA_IRQHandler (void){
uint8_t i;
int adcSuma=0;
for (i=0;i<=ADC_CANT_SAMPLE;i++){
adcSuma += (arrRSSI[0] >> 4) & 0xFFF;
}
adcRSSI = (float)adcSuma / ADC_CANT_SAMPLE;
adcRSSI = adcRSSI * 3.3 / 4096;
LPC_GPDMA->DMACIntTCClear |= 0xff;
}

void DMACh0_Ena(){
LPC_GPDMACH0->DMACCConfig |= 1; //enable ch0
}
void DMACh0_Dis(){
LPC_GPDMACH0->DMACCConfig = 0; // stop ch0 dma
}


and main.c

#include <cr_section_macros.h>
#include "adc.h"
#include "dma.h"

volatile float adcRSSI;

int main(void) {

DMAInit();
ADCInit();

DMACh0_Ena();

    while(1) {
    }
}


With this code I pause on DMA_IRQ and see what arrRSSI have. I see this:
arrRSSI[0]uint32_t2147516752
arrRSSI[1]uint32_t33104
arrRSSI[2]uint32_t33104
arrRSSI[3]uint32_t33104
arrRSSI[4]uint32_t33104
arrRSSI[5]uint32_t33104
arrRSSI[6]uint32_t33104
arrRSSI[7]uint32_t33104
arrRSSI[8]uint32_t33104
arrRSSI[9]uint32_t33104
arrRSSI[10]uint32_t33104
arrRSSI[11]uint32_t33104
arrRSSI[12]uint32_t33104
arrRSSI[13]uint32_t33104
arrRSSI[14]uint32_t33104
arrRSSI[15]uint32_t33104
arrRSSI[16]uint32_t33104
arrRSSI[17]uint32_t33104
arrRSSI[18]uint32_t33104
arrRSSI[19]uint32_t33104


as you can see only first convertion as an 1 on DONE bit so I think the other values are not correct.

So how do I configure DMA chanel to read 20 adc chanel 0 readings after a TC interrupt fire?

Regards!
Labels (1)
0 Kudos
1 Reply

444 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by elgarbe on Sun Apr 13 17:50:51 MST 2014
I think that maybe the previouse value from ADC where correct, so i configure the DMA transfer size to 1000 and I obtain this:

arrRSSI[0]uint32_t3221258592
arrRSSI[1]uint32_t33120
arrRSSI[2]uint32_t33120
arrRSSI[3]uint32_t33120
arrRSSI[4]uint32_t33120
arrRSSI[5]uint32_t33120
arrRSSI[6]uint32_t33120
arrRSSI[7]uint32_t33120
arrRSSI[8]uint32_t33120
arrRSSI[9]uint32_t33120
arrRSSI[10]uint32_t33120
arrRSSI[11]uint32_t33120
arrRSSI[12]uint32_t33120
arrRSSI[13]uint32_t33120
arrRSSI[14]uint32_t33120
arrRSSI[15]uint32_t33120
arrRSSI[16]uint32_t33120
arrRSSI[17]uint32_t33120
arrRSSI[18]uint32_t33120
arrRSSI[19]uint32_t33120
arrRSSI[20]uint32_t33120
arrRSSI[21]uint32_t33120
arrRSSI[22]uint32_t33120
arrRSSI[23]uint32_t33120
arrRSSI[24]uint32_t33120
arrRSSI[25]uint32_t33120
arrRSSI[26]uint32_t33120
arrRSSI[27]uint32_t33120
arrRSSI[28]uint32_t2147516768
arrRSSI[29]uint32_t33120
arrRSSI[30]uint32_t33120


So, only position 0 and 28 of the array is valid ADC value. Another valid value is on position 63 and 99 and so on.

I think that maybe the way to make it work is with Linked List and scatter and gather, so I change my code to this:

dma.c
typedef struct LLI{
uint32_t SourAddr;
uint32_t DestAddr;
struct LLI *nextLLI;
uint32_t  Control;
}dmaLLI;

struct LLI adcLLI[4];

extern volatile float adcRSSI;
uint32_t arrRSSI[1000];

void DMAInit(){
adcLLI[0].SourAddr = (uint32_t) &(LPC_ADC->ADDR0); // ADC Chanel 0
adcLLI[0].DestAddr = (uint32_t) &arrRSSI[2]; // ADC Chanel 0
adcLLI[0].nextLLI = &adcLLI[1];
adcLLI[0].Control =1 // Transferencia de 20 half word
| (0 << 12) // 1 burst
| (0 << 15) // 1 burst
| (2 << 18) // Word width
| (2 << 21) // Word width
| (0 << 26 ) // Source no increment.
| (0 << 27 ) // Destination increment.
| (0 << 31 );// Enable Terminal Count Interrupt

adcLLI[1].SourAddr = (uint32_t) &(LPC_ADC->ADDR0); // ADC Chanel 0
adcLLI[1].DestAddr = (uint32_t) &arrRSSI[4]; // ADC Chanel 0
adcLLI[1].nextLLI = 0;
adcLLI[1].Control =1 // Transferencia de 20 half word
| (0 << 12) // 1 burst
| (0 << 15) // 1 burst
| (2 << 18) // Word width
| (2 << 21) // Word width
| (0 << 26 ) // Source no increment.
| (0 << 27 ) // Destination increment.
| (1 << 31 );// Enable Terminal Count Interrupt

LPC_SC->PCONP |= 1 << 29; // Power up DMA

LPC_GPDMACH0->DMACCConfig = 0; // stop ch0 dma

LPC_GPDMACH0->DMACCSrcAddr = (uint32_t) &(LPC_ADC->ADDR0); // ADC Chanel 0
LPC_GPDMACH0->DMACCDestAddr = (uint32_t) &arrRSSI[0]; // Array
LPC_GPDMACH0->DMACCControl = 1 // Transferencia de 20 half word
| (0 << 12) // 1 burst
| (0 << 15) // 1 burst
| (2 << 18) // Word width
| (2 << 21) // Word width
| (0 << 26 ) // Source no increment.
| (1 << 27 ) // Destination increment.
| (0 << 31 );// Enable Terminal Count Interrupt
LPC_GPDMACH0->DMACCConfig = ( 4 << 1 )// Set ADC as source DMA request
| ( 2 << 11 ) // Peripheral to Memory
| ( 1 << 15 ); // Terminal count interrupt mask. 1 = unmasked
//LPC_GPDMACH0->DMACCLLI = 0;
LPC_GPDMACH0->DMACCLLI = (uint32_t)&adcLLI[0];

LPC_GPDMA->DMACIntErrClr |= 0xff;//Clear all DMA interrupts
LPC_GPDMA->DMACIntTCClear |= 0xff;
NVIC_EnableIRQ(DMA_IRQn);// Register DMA Interrupt Handler

//LPC_GPDMACH0->DMACCConfig |= 1; // enable ch0
LPC_GPDMA->DMACConfig |= 1; // enable DMA
}

void DMA_IRQHandler (void){
uint8_t i;
int adcSuma=0;
for (i=0;i<=ADC_CANT_SAMPLE;i++){
adcSuma += (arrRSSI[0] >> 4) & 0xFFF;
}
adcRSSI = (float)adcSuma / ADC_CANT_SAMPLE;
adcRSSI = adcRSSI * 3.3 / 4096;
LPC_GPDMA->DMACIntTCClear |= 0xff;
}

void DMACh0_Ena(){
LPC_GPDMACH0->DMACCConfig |= 1; //enable ch0
}
void DMACh0_Dis(){
LPC_GPDMACH0->DMACCConfig = 0; // stop ch0 dma
}


As you can see I configure 3 transfer. The first is on DMA Chanel 0 config regiter, the other 2 are on LLI. Take a look at destination address: &arrRSSI[0], &arrRSSI[2] and &arrRSSI[4]. That is to test Scater and gather. So my result is:

arrRSSI[0]uint32_t2147516784
arrRSSI[1]uint32_t0
arrRSSI[2]uint32_t33136
arrRSSI[3]uint32_t0
arrRSSI[4]uint32_t33136
arrRSSI[5]uint32_t0
arrRSSI[6]uint32_t0


So scater and gather is working ok. But it seems that DMA fires BEFORE ADC conversion finish.... maybe I have to clear Interrupt request from ADC after each transfer... but if it is ok, then I can't transfer several conversion without intervention... I don't like this...

Any idea?
0 Kudos