Problem with ADC interrupt for DMA

cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with ADC interrupt for DMA

312 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by klaschudi on Fri Jun 28 06:29:17 MST 2013
Hello together,
I'm working with a LPC17569 and try to store the data read by the ADC into an uint32_t array with DMA.
If I understand it right, the ADC module should throw an interrupt which lets the DMA module start transfering the data.
Unfortunately in my implementation the DMA Controller starts the transfer before the ADC finished reading all channels.
Does someone find the faults in my Code?

void ADC_init()
{
 LPC_SC->PCONP |= (1 << PCADC);   // enable power for ADC-unit
 int i;
 for (i = 0; i < ADC_NUM; i++)
 {
  ADCValue = 0;
 }
 // configure ADC-Pins
 LPC_PINCON->PINSEL0 |= ((2 << 4)|(2 << 6));       // AD0.7/P0.2|AD0.6/P0.3
 LPC_PINCON->PINSEL1 |= ((1 << 14)|(1 << 16)|(1 << 18)|(1 << 20));  // AD0.0/P0.23|AD0.1/P0.24|AD0.2/P0.25|AD0.3/P0.26
 LPC_PINCON->PINSEL3 |= ((3 << 28)|(3 << 30));      // AD0.4/P1.30|AD0.5/P1.31
 // configure Pinmodes (no pull up or pull down)
 LPC_PINCON->PINMODE0 |= ((pinmode_nothing <<  4)|(pinmode_nothing << 6));
 LPC_PINCON->PINMODE1 |= ((pinmode_nothing << 14)|(pinmode_nothing << 16)|(pinmode_nothing << 18)|(pinmode_nothing << 20));
 LPC_PINCON->PINMODE3 |= ((pinmode_nothing << 28)|(pinmode_nothing << 30));
 // clock settings (set to 10MHz)
 LPC_SC->PCLKSEL0 &= ~(3 << PCLK_ADC);   // reset clk bits
 LPC_SC->PCLKSEL0 |= (clk_div_4 << PCLK_ADC); // set ADC_CLK to 30MHz
 LPC_ADC->ADCR |=  (0xFF << ADC_SEL)|   // all channels are selected
      (0x2 << ADC_CLKDIV)|  // divide by 2+1 -> ADC_CLK = 10MHz
      (0x0 << ADC_BURST)|   // Burst-Mode -> all channels are consequently read
      (0x1 << ADC_PDN);   // enable ADC
 // Interrupts
 LPC_ADC->ADINTEN &= ~0x1FF;
 LPC_ADC->ADINTEN |= (1 << 8);  // enable Interrupts for all channels
 while (! (LPC_ADC->ADINTEN & (1 << 8)));
 //NVIC_EnableIRQ(ADC_IRQn);  // enable ADC-Interrupt
}
 
 
void ADC_startBurstRead(void)
{
 if (LPC_ADC->ADCR & 0x7) // clear start bits if not already cleared
 {
  LPC_ADC->ADCR &= ~(0x7 << ADC_START);
 }
 LPC_ADC->ADCR &= ~(0xFF << ADC_SEL);// reset sel bits
 LPC_ADC->ADCR |= (0xFF << ADC_SEL); // read all channels
 LPC_ADC->ADCR |= (1 << ADC_BURST);  // start burst read
}
 
void DMA_init(uint32_t src_adr, uint32_t dst_adr)
{
 dmaReady = false;
 DMATCCount = 0;
 DMAErrCount = 0;
 NVIC_DisableIRQ(ADC_IRQn);   // ADC Interrupt needed but no NVIC
 // DMA Controller Initialization --------------------------------------
 LPC_SC->PCONP |= (1 << PCGPDMA);  // enable power for DMA-unit
 LPC_GPDMA->DMACSync = 0xFFFF;   // enable sync (default)
 LPC_SC->DMAREQSEL = 0x0000;   // select UART for DMA Request ???
 LPC_GPDMA->DMACIntTCClear = 0x01;
 LPC_GPDMA->DMACIntErrClr= 0x01;
 LPC_GPDMA->DMACConfig = (1 << DMA_E); // enable DMA
 while (! (LPC_GPDMA->DMACConfig & 0x01));
 NVIC_EnableIRQ(DMA_IRQn);
 // Channel 0 Initialization -------------------------------------------
 LPC_GPDMA->DMACIntTCClear = 0x01;
 LPC_GPDMA->DMACIntErrClr= 0x01;
 LPC_GPDMACH0->DMACCConfig = 0;
 LPC_GPDMACH0->DMACCControl = 0;
 // Ch0 set for P2M transfer from ADC to mempry.
 LPC_GPDMACH0->DMACCSrcAddr = src_adr;
 LPC_GPDMACH0->DMACCDestAddr = dst_adr;
 LPC_GPDMACH0->DMACCControl = (((DMA_SIZE & 0x0FFF) << DMA_TransferSize)|
          (0x0 << DMA_SBSize)|   // src burst size = 1
          (0x0 << DMA_DBSize)|   // dst burst size = 1
          (0x2 << DMA_SWidth)|   // word (32bit) transfer
          (0x2 << DMA_DWidth)|
          (0x1 << DMA_SI)|
          (0x1 << DMA_DI)|
          (0x1 << DMA_I)
         );
 return;
}
void DMA_enableCH0(void)
{
 LPC_GPDMACH0->DMACCConfig = ((0x1 << DMA_E)|     // not enable yet must be done by caller
         (0x4 << DMA_SrcPeripheral)| // ADC as source
         (0x2 << DMA_TransferType)|  // P2M
         (0x1 << DMA_IE)|    // mask error interrupt
         (0x1 << DMA_ITC)    // mask terminal Counter interrupt
        );
}
void DMA_IRQHandler(void)
{
  uint32_t regVal;
  // worked fine
  regVal = LPC_GPDMA->DMACIntTCStat;
  if ( regVal )
  {
 DMATCCount++;
 LPC_GPDMA->DMACIntTCClear = regVal;
 if ( regVal & 0x01 )
 {
   dmaReady = true;
 }
 LPC_ADC->ADCR &= ~(1 << ADC_BURST);  // Disable the BURST mode bit
  }
  // error
  regVal = LPC_GPDMA->DMACIntErrStat;
  if ( regVal )
  {
 DMAErrCount++;
 LPC_GPDMA->DMACIntErrClr = regVal;
 LPC_ADC->ADCR &= ~(1 << ADC_BURST);  // Disable the BURST mode bit
  }
  return;
}
 


In my main-function I first call ADC_init(), the DMA_init() then I start a burst read and end with Enabling the DMA-Channel.

Thanks a lot for your help...
1 Reply

180 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by klaschudi on Fri Jun 28 08:08:49 MST 2013
problem solved...
It had something to do with the Interrupt Enable Register of the ADC. I used the global DONE-Flag as interrupt source there, but it has to be only the Flag of the last Channel (ADINTEN7).