Hello,
I'm using the PDB with the differential channel on ADC with the K serie and keil IDE. I'm trying to go from using the adc irq to using the DMA buffer the adc data without success.
I've disabled the ADC_SC1_AIEN (irq) and enabled the ADC_SC2_DMAEN
DMA configuration:
SIM->SCGC7 |= (uint32_t)SIM_SCGC7_DMA_MASK ;
SIM->SCGC6 |= (uint32_t)SIM_SCGC6_DMAMUX0_MASK;
DMA0->CR = DMA_CR_GRP0PRI(3) | DMA_CR_GRP1PRI(3);
DMA0->CR |= (uint32_t) (DMA_CR_EMLM_MASK);
/* DMA_EEI: EEI0=0 */
DMA0->EEI &= (uint32_t)~(uint32_t)(DMA_EEI_EEI0_MASK);
DMA0->INT = DMA_INT_INT0_MASK; // clear interrupt
DMAMUX0->CHCFG[0] = DMAMUX_CHCFG_ENBL_MASK|DMAMUX_CHCFG_SOURCE(41); //DMA source ADC
DMA0->TCD[0].SADDR = (uint32_t) &ADC1->R[0]; //
DMA0->TCD[0].SOFF = 0x00;
DMA0->TCD[0].SLAST = 0x00;
DMA0->TCD[0].DADDR = (uint32_t) &destinationAdr[0];
DMA0->TCD[0].DOFF = 0x02;
DMA0->TCD[0].NBYTES_MLNO = 0x02;
DMA0->TCD[0].DLAST_SGA = -(destinationSize); //32 byte aligned
DMA0->TCD[0].NBYTES_MLOFFNO = DMA_NBYTES_MLOFFNO_NBYTES(2) ;
DMA0->TCD[0].ATTR = DMA_ATTR_SSIZE(1)|DMA_ATTR_DSIZE(1);
DMA0->TCD[0].CSR = DMA_CSR_INTMAJOR_MASK;
NVIC_EnableIRQ(DMA0_DMA16_IRQn);
What am I missing out?
thanks
A
已解决! 转到解答。
I had two problems, configuring the PDB and configuring the channels for mux1. Here one way of doing dma general.
if(!DMA_Init((uint32_t)&ADC0->SC1[CHANNEL_A], (uint32_t)&ADC0->R[CHANNEL_A], (uint8_t*)uc_adc1_mux, NUM_OF_MUX, (uint16_t*)ui_adc1_result, NUM_OF_MUX*NUM_OF_SAMPLES, DMA_MODULE_ADC1_CONFIG, 1, dmaCallback))
printf("DMA INIT SUCCESS\n");
else
printf("DMA INIT FAILED\n");
typedef struct { uint8_t CHLINK, REQLINK, CHREAD, REQREAD, MUX;} tDMA;
#define DMA_MODULE_ADC0_CONFIG \
(tDMA){ \
/* CHLINK */ ADC0_DMA_CHANNEL_ADCONTROL, \
/* REQLINK */ DMA_MUX0_DMA_MUX_1, \
/* CHREAD */ ADC0_DMA_CHANNEL_ADCREAD, \
/* REQREAD */ DMA_MUX0_ADC0, \
DMA_MUX0, \
}
/* Function redefinition */
/***************************************************************************//*!
* @brief DMA initialization function.
* @param LINKAdr - Pointer to module link register (mux)
* @param READAdr - Pointer to module result register
* @param mux - Pointer to mux array
* @param muxSize - Number of channals to mux
* @param destination - Pointer to destination array
* @param destinationSize - Size of destination array (must be 8 aligned)
* @param cfg - DMA module configuration structure.
* @param ip - IRQ Priority
* @param callback - Pointer to DMA_CALLBACK function
* @return 0 - SUCCESS
* @return 1 - ERROR
* @note Implemented as function call.
******************************************************************************/
int DMA_Init ( const uint32_t LINKAdr,
const uint32_t READAdr,
uint8_t * mux,
uint16_t muxSize,
uint16_t * destination,
uint16_t destinationSize,
tDMA cfg, uint8_t ip, DMA_CALLBACK pCallback)
{
float32_t tmp = 0;
if(cfg.CHLINK > DMA_MUX1_CHANNEL_OFFSET || cfg.CHREAD > DMA_MUX1_CHANNEL_OFFSET)
{
//ERROR: ILLEGAL CHANNEL
return 1;
}
tmp = destinationSize/8;
tmp = tmp-(uint16_t)tmp;
if(tmp > 1.0)
{
//ERROR: DESTINATION BUFFER IS NOT 8 BYTE ALIGNED
return 1;
}
// -------------------------------------------------------------------------------------
// DMA channel 'ADCONTROL' used to transfer next ADCx control from RAM to ADCx_SC1A.
// -------------------------------------------------------------------------------------
// Configure this DMA channel to an always enabled request source and enable this channel
if (cfg.MUX)
{
DMAMUX1->CHCFG[cfg.CHLINK] = (DMAMUX_CHCFG_ENBL_MASK | // Enable routing of DMA request
DMAMUX_CHCFG_SOURCE(cfg.REQLINK)); // Channel Activation Source: DMA MUX always enabled
// Attention: DMA MUX1 is routed to DMA channels 16-31 as described in
// Reference manual MK10FX: chapter '3.3.9.1 DMA MUX request sources'
// We have to use a DMA channel offset of 16 during setup of the DMAs
cfg.CHLINK += DMA_MUX1_CHANNEL_OFFSET;
}
else
{
DMAMUX0->CHCFG[cfg.CHLINK] = (DMAMUX_CHCFG_ENBL_MASK | // Enable routing of DMA request
DMAMUX_CHCFG_SOURCE(cfg.REQLINK)); // Channel Activation Source: DMA MUX always enabled
}
DMA0->TCD[cfg.CHLINK].SADDR = (uint32_t) &mux[0]; //mux array
DMA0->TCD[cfg.CHLINK].SOFF = 0x01; //Source address increment, adding "1"
DMA0->TCD[cfg.CHLINK].SLAST = (uint32_t) -muxSize; //Source address decrement after major loop complete
DMA0->TCD[cfg.CHLINK].DADDR = (uint32_t)LINKAdr; //Destination address ADCx mux selector
DMA0->TCD[cfg.CHLINK].DOFF = 0x00; //Destination address increment, adding "0"
DMA0->TCD[cfg.CHLINK].DLAST_SGA = 0x00; //Destination address shift, go to back to [0]
DMA0->TCD[cfg.CHLINK].NBYTES_MLNO = 0x01; //No of bytes minor loop
DMA0->TCD[cfg.CHLINK].BITER_ELINKNO = muxSize; //Major loop step, x num ADC channel are scaning
DMA0->TCD[cfg.CHLINK].CITER_ELINKNO = muxSize; //Major loop step, x num ADC channel are scaning
DMA0->TCD[cfg.CHLINK].ATTR = DMA_ATTR_SSIZE(0)|DMA_ATTR_DSIZE(0); //Source a destination size, 8bit
DMA0->TCD[cfg.CHLINK].CSR = 0x0000; //
if (pCallback != NULL )
{
pCallbackCH[cfg.CHREAD] = pCallback;
NVIC_EnableIRQ(cfg.CHREAD);
}
// -------------------------------------------------------------------------------------
// DMA channel 'ADCREAD' used to transfer ADCx result data from ADCx_RA to RAM.
// -------------------------------------------------------------------------------------
// Configure this DMA channel to use ADCx CoCo as transfer request source and enable this channel
if (cfg.MUX)
{
DMAMUX1->CHCFG[cfg.CHREAD] = (DMAMUX_CHCFG_ENBL_MASK | // Enable routing of DMA request
DMAMUX_CHCFG_SOURCE(cfg.REQREAD)); // Channel Activation Source: ADCx CoCo
// Attention: DMA MUX1 is routed to DMA channels 16-31 as described in
// Reference manual MK10FX: chapter '3.3.9.1 DMA MUX request sources'
// We have to use a DMA channel offset of 16 during setup of the DMAs
cfg.CHREAD += DMA_MUX1_CHANNEL_OFFSET;
}
else
{
DMAMUX0->CHCFG[cfg.CHREAD] = (DMAMUX_CHCFG_ENBL_MASK | // Enable routing of DMA request
DMAMUX_CHCFG_SOURCE(cfg.REQREAD)); // Channel Activation Source: ADCx CoCo
}
//****************************************************************************
//**** DMA channel, use for Read ADC result data, form ADC to SRAM *********
//****************************************************************************
DMA0->TCD[cfg.CHREAD].SADDR = (uint32_t)READAdr; //Source address ADCx result register
DMA0->TCD[cfg.CHREAD].SOFF = 0x00; //Source address increment, adding "0"
DMA0->TCD[cfg.CHREAD].SLAST = 0x00; //Source address decrement after major loop complete
DMA0->TCD[cfg.CHREAD].DADDR = (uint32_t) &destination[0]; //Destination address, ADCx result buffer
DMA0->TCD[cfg.CHREAD].DOFF = 0x02; //Destination address increment, adding "+2"
DMA0->TCD[cfg.CHREAD].DLAST_SGA = (uint32_t) -destinationSize*2; //Destination address decrement after major loop complete
DMA0->TCD[cfg.CHREAD].NBYTES_MLNO = 0x02; //No of bytes minor loop, 16bit ADC result
DMA0->TCD[cfg.CHREAD].BITER_ELINKYES =
DMA_BITER_ELINKYES_ELINK_MASK | DMA_BITER_ELINKYES_LINKCH(cfg.CHLINK) | DMA_BITER_ELINKYES_BITER(destinationSize); //Channel x Link, Channel 0, Major loop step 3 x 4 = 12
DMA0->TCD[cfg.CHREAD].CITER_ELINKYES =
DMA_CITER_ELINKYES_ELINK_MASK | DMA_CITER_ELINKYES_LINKCH(cfg.CHLINK) | DMA_CITER_ELINKYES_CITER(destinationSize); //Channel x Link, Major loop step 3 x 4 = 12
DMA0->TCD[cfg.CHREAD].ATTR = DMA_ATTR_SSIZE(1)|DMA_ATTR_DSIZE(1); //Source a destination size, 16bit
DMA0->SERQ = DMA_SERQ_SERQ(cfg.CHREAD);
DMA0->TCD[cfg.CHREAD].CSR = (DMA_CSR_MAJORLINKCH(cfg.CHLINK)|DMA_CSR_MAJORELINK_MASK)| //Major loop finished start request for Channel 0
DMA_CSR_INTMAJOR_MASK; //|DMA_CSR_INTHALF_MASK; //Irq. enable, full transfer, half complet transfer
return 0;
}
I had two problems, configuring the PDB and configuring the channels for mux1. Here one way of doing dma general.
if(!DMA_Init((uint32_t)&ADC0->SC1[CHANNEL_A], (uint32_t)&ADC0->R[CHANNEL_A], (uint8_t*)uc_adc1_mux, NUM_OF_MUX, (uint16_t*)ui_adc1_result, NUM_OF_MUX*NUM_OF_SAMPLES, DMA_MODULE_ADC1_CONFIG, 1, dmaCallback))
printf("DMA INIT SUCCESS\n");
else
printf("DMA INIT FAILED\n");
typedef struct { uint8_t CHLINK, REQLINK, CHREAD, REQREAD, MUX;} tDMA;
#define DMA_MODULE_ADC0_CONFIG \
(tDMA){ \
/* CHLINK */ ADC0_DMA_CHANNEL_ADCONTROL, \
/* REQLINK */ DMA_MUX0_DMA_MUX_1, \
/* CHREAD */ ADC0_DMA_CHANNEL_ADCREAD, \
/* REQREAD */ DMA_MUX0_ADC0, \
DMA_MUX0, \
}
/* Function redefinition */
/***************************************************************************//*!
* @brief DMA initialization function.
* @param LINKAdr - Pointer to module link register (mux)
* @param READAdr - Pointer to module result register
* @param mux - Pointer to mux array
* @param muxSize - Number of channals to mux
* @param destination - Pointer to destination array
* @param destinationSize - Size of destination array (must be 8 aligned)
* @param cfg - DMA module configuration structure.
* @param ip - IRQ Priority
* @param callback - Pointer to DMA_CALLBACK function
* @return 0 - SUCCESS
* @return 1 - ERROR
* @note Implemented as function call.
******************************************************************************/
int DMA_Init ( const uint32_t LINKAdr,
const uint32_t READAdr,
uint8_t * mux,
uint16_t muxSize,
uint16_t * destination,
uint16_t destinationSize,
tDMA cfg, uint8_t ip, DMA_CALLBACK pCallback)
{
float32_t tmp = 0;
if(cfg.CHLINK > DMA_MUX1_CHANNEL_OFFSET || cfg.CHREAD > DMA_MUX1_CHANNEL_OFFSET)
{
//ERROR: ILLEGAL CHANNEL
return 1;
}
tmp = destinationSize/8;
tmp = tmp-(uint16_t)tmp;
if(tmp > 1.0)
{
//ERROR: DESTINATION BUFFER IS NOT 8 BYTE ALIGNED
return 1;
}
// -------------------------------------------------------------------------------------
// DMA channel 'ADCONTROL' used to transfer next ADCx control from RAM to ADCx_SC1A.
// -------------------------------------------------------------------------------------
// Configure this DMA channel to an always enabled request source and enable this channel
if (cfg.MUX)
{
DMAMUX1->CHCFG[cfg.CHLINK] = (DMAMUX_CHCFG_ENBL_MASK | // Enable routing of DMA request
DMAMUX_CHCFG_SOURCE(cfg.REQLINK)); // Channel Activation Source: DMA MUX always enabled
// Attention: DMA MUX1 is routed to DMA channels 16-31 as described in
// Reference manual MK10FX: chapter '3.3.9.1 DMA MUX request sources'
// We have to use a DMA channel offset of 16 during setup of the DMAs
cfg.CHLINK += DMA_MUX1_CHANNEL_OFFSET;
}
else
{
DMAMUX0->CHCFG[cfg.CHLINK] = (DMAMUX_CHCFG_ENBL_MASK | // Enable routing of DMA request
DMAMUX_CHCFG_SOURCE(cfg.REQLINK)); // Channel Activation Source: DMA MUX always enabled
}
DMA0->TCD[cfg.CHLINK].SADDR = (uint32_t) &mux[0]; //mux array
DMA0->TCD[cfg.CHLINK].SOFF = 0x01; //Source address increment, adding "1"
DMA0->TCD[cfg.CHLINK].SLAST = (uint32_t) -muxSize; //Source address decrement after major loop complete
DMA0->TCD[cfg.CHLINK].DADDR = (uint32_t)LINKAdr; //Destination address ADCx mux selector
DMA0->TCD[cfg.CHLINK].DOFF = 0x00; //Destination address increment, adding "0"
DMA0->TCD[cfg.CHLINK].DLAST_SGA = 0x00; //Destination address shift, go to back to [0]
DMA0->TCD[cfg.CHLINK].NBYTES_MLNO = 0x01; //No of bytes minor loop
DMA0->TCD[cfg.CHLINK].BITER_ELINKNO = muxSize; //Major loop step, x num ADC channel are scaning
DMA0->TCD[cfg.CHLINK].CITER_ELINKNO = muxSize; //Major loop step, x num ADC channel are scaning
DMA0->TCD[cfg.CHLINK].ATTR = DMA_ATTR_SSIZE(0)|DMA_ATTR_DSIZE(0); //Source a destination size, 8bit
DMA0->TCD[cfg.CHLINK].CSR = 0x0000; //
if (pCallback != NULL )
{
pCallbackCH[cfg.CHREAD] = pCallback;
NVIC_EnableIRQ(cfg.CHREAD);
}
// -------------------------------------------------------------------------------------
// DMA channel 'ADCREAD' used to transfer ADCx result data from ADCx_RA to RAM.
// -------------------------------------------------------------------------------------
// Configure this DMA channel to use ADCx CoCo as transfer request source and enable this channel
if (cfg.MUX)
{
DMAMUX1->CHCFG[cfg.CHREAD] = (DMAMUX_CHCFG_ENBL_MASK | // Enable routing of DMA request
DMAMUX_CHCFG_SOURCE(cfg.REQREAD)); // Channel Activation Source: ADCx CoCo
// Attention: DMA MUX1 is routed to DMA channels 16-31 as described in
// Reference manual MK10FX: chapter '3.3.9.1 DMA MUX request sources'
// We have to use a DMA channel offset of 16 during setup of the DMAs
cfg.CHREAD += DMA_MUX1_CHANNEL_OFFSET;
}
else
{
DMAMUX0->CHCFG[cfg.CHREAD] = (DMAMUX_CHCFG_ENBL_MASK | // Enable routing of DMA request
DMAMUX_CHCFG_SOURCE(cfg.REQREAD)); // Channel Activation Source: ADCx CoCo
}
//****************************************************************************
//**** DMA channel, use for Read ADC result data, form ADC to SRAM *********
//****************************************************************************
DMA0->TCD[cfg.CHREAD].SADDR = (uint32_t)READAdr; //Source address ADCx result register
DMA0->TCD[cfg.CHREAD].SOFF = 0x00; //Source address increment, adding "0"
DMA0->TCD[cfg.CHREAD].SLAST = 0x00; //Source address decrement after major loop complete
DMA0->TCD[cfg.CHREAD].DADDR = (uint32_t) &destination[0]; //Destination address, ADCx result buffer
DMA0->TCD[cfg.CHREAD].DOFF = 0x02; //Destination address increment, adding "+2"
DMA0->TCD[cfg.CHREAD].DLAST_SGA = (uint32_t) -destinationSize*2; //Destination address decrement after major loop complete
DMA0->TCD[cfg.CHREAD].NBYTES_MLNO = 0x02; //No of bytes minor loop, 16bit ADC result
DMA0->TCD[cfg.CHREAD].BITER_ELINKYES =
DMA_BITER_ELINKYES_ELINK_MASK | DMA_BITER_ELINKYES_LINKCH(cfg.CHLINK) | DMA_BITER_ELINKYES_BITER(destinationSize); //Channel x Link, Channel 0, Major loop step 3 x 4 = 12
DMA0->TCD[cfg.CHREAD].CITER_ELINKYES =
DMA_CITER_ELINKYES_ELINK_MASK | DMA_CITER_ELINKYES_LINKCH(cfg.CHLINK) | DMA_CITER_ELINKYES_CITER(destinationSize); //Channel x Link, Major loop step 3 x 4 = 12
DMA0->TCD[cfg.CHREAD].ATTR = DMA_ATTR_SSIZE(1)|DMA_ATTR_DSIZE(1); //Source a destination size, 16bit
DMA0->SERQ = DMA_SERQ_SERQ(cfg.CHREAD);
DMA0->TCD[cfg.CHREAD].CSR = (DMA_CSR_MAJORLINKCH(cfg.CHLINK)|DMA_CSR_MAJORELINK_MASK)| //Major loop finished start request for Channel 0
DMA_CSR_INTMAJOR_MASK; //|DMA_CSR_INTHALF_MASK; //Irq. enable, full transfer, half complet transfer
return 0;
}
Hi again,
I ported the AN4590 project IAR proj to keil. I only replaced the mux channels to sample AD05 (my 12V board voltage) AD15 (My 3.3 board Voltage) and the CPU temperatur AD26 (uc_adc_mux). The values doesn't seem to be correct. Must the mux channels come in rising order without gaps? I like to attach the project in this thread. How can I attach an zip file?
best regards
Andreas
Try to keep the ADC_SC1[AIEN] set. When ADC_SC2[DMAEN] = 1, the DMA engine will catch the interrupt. At least, that's the behavior for other peripherals. Quote form the I2C-Module:
"If the DMAEN bit is cleared and the IICIE bit is set, an interrupt condition generates an interrupt request.
If the DMAEN bit is set and the IICIE bit is set, an interrupt condition generates a DMA request instead.
DMA requests are generated by the transfer complete flag (TCF)."
Best regards,
Ulrich Unterhinninghofen
Hi
I am missing seeing where BITER_ELINK and CITER_ELINK are set - they should be (destinationSize/2).
Also enabling the DMA request source in DMA_ERQ may be missing.
There are details of using PBA and ADC in DMA mode at http://www.utasker.com/docs/uTasker/uTaskerADC.pdf
The uTasker project includes a digital delay line based on this operation (as explained in the document) so you can get all code for it at KINETIS Project Code. Furthermore it allows the ADC/PBA/DMA operation to be simulated in Visual Studio so that the operation can be studied and any errors identified.
See also Application note on DMA driven ADC and DAC, using PDB as timebase (the project also records the sampled data as WAV file to an SD card if desired).
Regards
Mark
Hi Mark,
I've added the
DMA0->ERQ |= DMA_ERQ_ERQ0_MASK;
DMA0->TCD[0].BITER_ELINKNO &= ~DMA_BITER_ELINKNO_ELINK_MASK;
DMA0->TCD[0].CITER_ELINKNO &= ~DMA_CITER_ELINKNO_ELINK_MASK;
DMA0->TCD[0].BITER_ELINKYES &= ~DMA_BITER_ELINKYES_ELINK_MASK;
DMA0->TCD[0].CITER_ELINKYES &= ~DMA_CITER_ELINKYES_ELINK_MASK;
DMA0->TCD[0].BITER_ELINKNO |= DMA_BITER_ELINKNO_BITER(destinationSize/2);
DMA0->TCD[0].CITER_ELINKNO |= DMA_CITER_ELINKNO_CITER(destinationSize/2);
DMA0->TCD[0].BITER_ELINKYES |= DMA_BITER_ELINKYES_BITER(destinationSize/2);
DMA0->TCD[0].CITER_ELINKYES |= DMA_CITER_ELINKYES_CITER(destinationSize/2);
I'm still NOT getting the longing DMA Irq...
Is it possible to set the "next pointing address" for the dma to write next sample in the source buffer? I want to adjust so the curve I'm sampling starts in zero or at a peak.
Thanks
A.
Hi
BITER_ELINKYES and BITER_ELINKNO is the same register so you only need to set one of them (same for various registers with multiple meanings/names but same location).
Only ever enable the DMA_ERQ_ERQ0_MASK after the rest has been set up - if it already fires the DMA will not be fully configured, will error and need resetting.
Always check the DMA error register since often teh DMA controller will be trying to do something but can't start/complete due to an illegal configuration or bus error. The error register shows you that something has gone wrong and its details will give a good idea of what it was.
In the other links you will find a working example which you can either use use to work out what is going wrong (eg. check the differences in register configurations) or to have an immediate solution so that you can continue with the application development.
>>Is it possible to set the "next pointing address" for the dma to write next sample in the source buffer?
I am not sure that I understand this sentence. In interrupt mode you could quickly check each sample value and start the DMA operation when you cross a trigger threshold so that the waveform is synchronised to a certain start value.
Regards
Mark