I'attempting to get ADC channel scanning to work on a MKL17Z256. There are examples of how to do it on a K series but not for the L series which has a different DMA controller.
I'm assuming it is possible in the same way using 2 DMA channels, one loading the ADC channel and the other copying the data out.
Following is what I have but it is not working. I'm not sure if I have the channel linking configured correctly
static void DMA_Callback_0(dma_handle_t *handle, void *userData)
{
uint32_t flags = DMA_GetChannelStatusFlags(DMA0, 0);
PRINTF("Flag 0: %u\r\n", flags);
DMA_ClearChannelStatusFlags(DMA0, 0, kDMA_TransactionsDoneFlag);
static void DMA_Callback_1(dma_handle_t *handle, void *userData)
{
uint32_t flags = DMA_GetChannelStatusFlags(DMA0, 1);
PRINTF("Flag 1: %u\r\n", flags);
if(flags & kDMA_TransactionsDoneFlag)
{
DMA_SubmitTransfer(&g_DMA_Handle_0, &transferConfig_0, kDMA_EnableInterrupt);
DMA_StartTransfer(&g_DMA_Handle_0);
DMA_SubmitTransfer(&g_DMA_Handle_1, &transferConfig_1, kDMA_EnableInterrupt);
DMA_StartTransfer(&g_DMA_Handle_1);
PRINTF("!");
DMA_ClearChannelStatusFlags(DMA0, 1, kDMA_TransactionsDoneFlag);
}
}
void adc_init()
{
//EnableIRQ(ADC0_IRQn);
adc16_config_t adc16ConfigStruct;
adc16_channel_config_t adc16ChannelConfigStruct;
/*
* adc16ConfigStruct.referenceVoltageSource = kADC16_ReferenceVoltageSourceVref;
* adc16ConfigStruct.clockSource = kADC16_ClockSourceAsynchronousClock;
* adc16ConfigStruct.enableAsynchronousClock = true;
* adc16ConfigStruct.clockDivider = kADC16_ClockDivider8;
* adc16ConfigStruct.resolution = kADC16_ResolutionSE12Bit;
* adc16ConfigStruct.longSampleMode = kADC16_LongSampleDisabled;
* adc16ConfigStruct.enableHighSpeed = false;
* adc16ConfigStruct.enableLowPower = false;
* adc16ConfigStruct.enableContinuousConversion = false;
*/
ADC16_GetDefaultConfig(&adc16ConfigStruct);
adc16ConfigStruct.resolution = kADC16_Resolution16Bit;
adc16ConfigStruct.enableContinuousConversion = true;
adc16ConfigStruct.clockSource = kADC16_ClockSourceAlt1;
adc16ConfigStruct.longSampleMode = kADC16_LongSampleCycle24;
adc16ConfigStruct.enableLowPower = true;
ADC16_Init( ADC0, &adc16ConfigStruct);
ADC16_DoAutoCalibration( ADC0 );
ADC16_EnableHardwareTrigger( ADC0, true);
ADC16_EnableDMA( ADC0, true);
adc16ChannelConfigStruct.channelNumber = g_ADC_mux[6];
adc16ChannelConfigStruct.enableInterruptOnConversionCompleted = true; /* Enable the interrupt. */
adc16ChannelConfigStruct.enableDifferentialConversion = false;
ADC16_SetChannelConfig( ADC0, 0, &adc16ChannelConfigStruct);
/* Configure SIM for ADC hw trigger source selection */
SIM->SOPT7 |= 0x8EU; // LPTMR, 1kHz
}
void dma_init()
{
/****************************************
* DMA Config
****************************************/
/* Configure DMAMUX */
DMAMUX_Init(DMAMUX0);
DMAMUX_SetSource(DMAMUX0, DMAChannel_0, 60); /* Channel 0 Source 60: DMA always enabled */
DMAMUX_EnableChannel(DMAMUX0, DMAChannel_0);
DMAMUX_SetSource(DMAMUX0, DMAChannel_1, 40); /* Channel 1 Source 40: ADC COCO trigger */
DMAMUX_EnableChannel(DMAMUX0, DMAChannel_1);
DMA_Init(DMA0);
DMA_CreateHandle(&g_DMA_Handle_0, DMA0, 0);
DMA_SetCallback(&g_DMA_Handle_0, DMA_Callback_0, NULL);
DMA_CreateHandle(&g_DMA_Handle_1, DMA0, 1);
DMA_SetCallback(&g_DMA_Handle_1, DMA_Callback_1, NULL);
DMA_PrepareTransfer(&transferConfig_0,
&g_ADC_mux[0], /* Source Address (ADC channels array) */
1, /* Source width (1 bytes) */
(uint32_t*)(ADC0->SC1),/* Destination Address (ADC_SC1A_ADCH)*/
1, /* Destination width (1 bytes) */
//sizeof(uint8_t), /* Bytes to transfer each minor loop (1 bytes) */
7, /* Total of bytes to transfer (3*1 bytes) */
kDMA_MemoryToPeripheral);/* From ADC channels array to ADCH register */
DMA_PrepareTransfer(&transferConfig_1,
(uint32_t*) (ADC0->R), /* Source Address (ADC0_RA) */
2, /* Source width (2 bytes) */
g_ADC0_resultBuffer, /* Destination Address (Internal buffer)*/
2, /* Destination width (2 bytes) */
//sizeof(uint16_t), /* Bytes to transfer each minor loop (2 bytes) */
B_SIZE * 2, /* Total of bytes to transfer (12*2 bytes) */
kDMA_PeripheralToMemory); /* From ADC to Memory */
DMA_SubmitTransfer(&g_DMA_Handle_0, &transferConfig_0, kDMA_EnableInterrupt);
DMA_SubmitTransfer(&g_DMA_Handle_1, &transferConfig_1, kDMA_EnableInterrupt);
link1.channel1 = 0;
link1.channel2 = 0;
link1.linkType = kDMA_ChannelLinkChannel1;
DMA_SetChannelLinkConfig(DMA0, 1, &link1);
DMA_StartTransfer(&g_DMA_Handle_1);
}
void adc_dma_init()
{
dma_init();
adc_init();
}
Hi
Please consider that as long as this module doesn't have the minor loop, you will be able to only measure one time the ADC channels, this is if you have 3 channels listed in the g_ADC_mux, then only 3 ADC scan can be performed. Following code implement this with uint8_t g_ADC_mux[CHANNELS] ={ VREFL_CH, VREFH_CH, CHANNEL_12 }; and B_SIZE= 3
/****************************************
* DMA Config
****************************************/
dma_transfer_config_t transferConfig_0;
dma_transfer_config_t transferConfig_1;
DMAMUX_Init(DMAMUX0);
DMAMUX_SetSource(DMAMUX0, DMA_CHANNEL0, DMA_SOURCE0);
DMAMUX_SetSource(DMAMUX0, DMA_CHANNEL1, DMA_SOURCE1);
DMAMUX_EnableChannel(DMAMUX0, DMA_CHANNEL0);
DMAMUX_EnableChannel(DMAMUX0, DMA_CHANNEL1);
/* Configure DMA one shot transfer */
DMA_Init(DMA0);
DMA_CreateHandle(&g_DMA_Handle0, DMA0, DMA_CHANNEL0);
DMA_CreateHandle(&g_DMA_Handle1, DMA0, DMA_CHANNEL1);
DMA_SetCallback(&g_DMA_Handle0, DMA_Callback0, NULL);
DMA_SetCallback(&g_DMA_Handle1, DMA_Callback1, NULL);
DMA_PrepareTransfer(&transferConfig_1,
(uint32_t*) (ADC0->R),
sizeof(uint16_t),
g_ADC0_resultBuffer,
sizeof(g_ADC0_resultBuffer[0]), /* Destination width (2 bytes) */
B_SIZE * 2,
kDMA_PeripheralToMemory);
DMA_SubmitTransfer(&g_DMA_Handle1, &transferConfig_1, kDMA_EnableInterrupt);
DMA_PrepareTransfer(&transferConfig_0,
&g_ADC_mux[0],
sizeof(g_ADC_mux[0]),
(uint32_t*)(ADC0->SC1),
sizeof(uint8_t),
CHANNELS,
kDMA_MemoryToPeripheral);
DMA_SubmitTransfer(&g_DMA_Handle0, &transferConfig_0, kDMA_EnableInterrupt);
dma_channel_link_config_t configlink;
configlink.channel1 = DMA_CHANNEL0;
configlink.channel2 = DMA_CHANNEL1;
configlink.linkType = kDMA_ChannelLinkChannel1;
DMA_SetChannelLinkConfig(DMA0, DMA_CHANNEL1, &configlink);
DMA_StartTransfer(&g_DMA_Handle1);
Hope this helps, please let me know if you have any question about this.
Best regards
Jorge Alcala