2022-04-06 07:54 AM
The short version is I'm trying to get a very basic setup working;
STM32L152 using Cube IDE, I want to sample ALL 22 ADC channels continuously into an array using DMA.
I've copied and pasted the 'ADC_MultiChannelSingleConversion' case into my pretty bare-bones project from:
STM32Cube_FW_L1_V1.10.3\Projects\NUCLEO-L152RE\Examples_LL\ADC\ADC_MultiChannelSingleConversion
But although a couple of interrupts fire (AdcDmaTransferComplete_Callback and AdcGrpRegularSequenceConvComplete_Callback get hit) no actual data appears to get transferred by DMA to the data buffer.
I have put the DMA Initialisation before the ADC due to that known bug, other than that my project is basically a copy-paste of the LL example.
The forum won't allow me to paste my code - I'll try in a comment I've pasted the important / relevant bits of the code below - at the moment there's nothing other than SysTick going on anyway.
2022-04-06 07:55 AM
OK let's try to paste the relevant parts of the code...
void Real_MX_DMA_Init(void)
{
/* Init with LL driver */
/* DMA controller clock enable */
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
/* DMA interrupt init */
/* DMA1_Channel1_IRQn interrupt configuration */
NVIC_SetPriority(DMA1_Channel1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),6, 0)); /* DMA IRQ lower priority than ADC IRQ */
NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
void Configure_DMA(void)
{
/* Configure the DMA transfer */
LL_DMA_ConfigTransfer(DMA1,
LL_DMA_CHANNEL_1,
LL_DMA_DIRECTION_PERIPH_TO_MEMORY |
LL_DMA_MODE_CIRCULAR |
LL_DMA_PERIPH_NOINCREMENT |
LL_DMA_MEMORY_INCREMENT |
LL_DMA_PDATAALIGN_HALFWORD |
LL_DMA_MDATAALIGN_HALFWORD |
LL_DMA_PRIORITY_HIGH );
/* Set DMA transfer addresses of source and destination */
LL_DMA_ConfigAddresses(DMA1,
LL_DMA_CHANNEL_1,
LL_ADC_DMA_GetRegAddr(ADC1, LL_ADC_DMA_REG_REGULAR_DATA),
(uint32_t)&aADCxConvertedData[0],
LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
/* Set DMA transfer size */
LL_DMA_SetDataLength(DMA1,
LL_DMA_CHANNEL_1,
ADC_CONVERTED_DATA_BUFFER_SIZE);
/* Enable DMA transfer interruption: transfer complete */
LL_DMA_EnableIT_TC(DMA1,
LL_DMA_CHANNEL_1);
/* Enable DMA transfer interruption: half transfer */
/*
LL_DMA_EnableIT_HT(DMA1,
LL_DMA_CHANNEL_1);
*/
/* Enable DMA transfer interruption: transfer error */
LL_DMA_EnableIT_TE(DMA1,
LL_DMA_CHANNEL_1);
/*## Activation of DMA #####################################################*/
/* Enable the DMA transfer */
LL_DMA_EnableChannel(DMA1,
LL_DMA_CHANNEL_1);
}
void MX_ADC_Init(void)
{
/* USER CODE BEGIN ADC_Init 0 */
/* USER CODE END ADC_Init 0 */
LL_ADC_CommonInitTypeDef ADC_CommonInitStruct = {0};
LL_ADC_InitTypeDef ADC_InitStruct = {0};
LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
/* Peripheral clock enable */
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC1);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOC);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOB);
/**ADC GPIO Configuration
PC0 ------> ADC_IN10
PC1 ------> ADC_IN11
PC2 ------> ADC_IN12
PC3 ------> ADC_IN13
PA0-WKUP1 ------> ADC_IN0
PA1 ------> ADC_IN1
PA2 ------> ADC_IN2
PA3 ------> ADC_IN3
PA4 ------> ADC_IN4
PA5 ------> ADC_IN5
PA6 ------> ADC_IN6
PA7 ------> ADC_IN7
PC4 ------> ADC_IN14
PC5 ------> ADC_IN15
PB0 ------> ADC_IN8
PB1 ------> ADC_IN9
PB12 ------> ADC_IN18
PB13 ------> ADC_IN19
PB14 ------> ADC_IN20
PB15 ------> ADC_IN21
*/
GPIO_InitStruct.Pin = CUR4_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(CUR4_GPIO_Port, &GPIO_InitStruct);
/**
Trimmed for size - other 20 channels in here...
*/
GPIO_InitStruct.Pin = SENS0_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(SENS0_GPIO_Port, &GPIO_InitStruct);
/* ADC DMA Init */
/* ADC Init */
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_LOW);
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_NORMAL);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_HALFWORD);
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_HALFWORD);
/* ADC interrupt Init */
NVIC_SetPriority(ADC1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0));
NVIC_EnableIRQ(ADC1_IRQn);
/* USER CODE BEGIN ADC_Init 1 */
/* USER CODE END ADC_Init 1 */
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
ADC_CommonInitStruct.CommonClock = LL_ADC_CLOCK_ASYNC_DIV1;
LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(ADC1), &ADC_CommonInitStruct);
ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B;
ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;
ADC_InitStruct.LowPowerMode = LL_ADC_LP_AUTOWAIT_NONE|LL_ADC_LP_AUTOPOWEROFF_NONE;
ADC_InitStruct.SequencersScanMode = LL_ADC_SEQ_SCAN_ENABLE;
LL_ADC_Init(ADC1, &ADC_InitStruct);
ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;
ADC_REG_InitStruct.SequencerLength = 22;
ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_CONTINUOUS;//LL_ADC_REG_CONV_SINGLE; // LL_ADC_REG_CONV_CONTINUOUS
ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_UNLIMITED;
LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
LL_ADC_REG_SetFlagEndOfConversion(ADC1, LL_ADC_REG_FLAG_EOC_UNITARY_CONV/*LL_ADC_REG_FLAG_EOC_SEQUENCE_CONV*/); // End of sequence
/** Configure Regular Channel
*/
LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_0);
LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_0, LL_ADC_SAMPLINGTIME_48CYCLES);
/**
Trimmed for size - other 20 channels in here...
*/
/** Configure Regular Channel
*/
LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_21, LL_ADC_CHANNEL_TEMPSENSOR);
LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_TEMPSENSOR, LL_ADC_SAMPLINGTIME_48CYCLES);
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_PATH_INTERNAL_TEMPSENSOR);
/** Configure Regular Channel
*/
LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_22, LL_ADC_CHANNEL_VREFINT);
LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_VREFINT, LL_ADC_SAMPLINGTIME_48CYCLES);
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_PATH_INTERNAL_VREFINT);
/* USER CODE BEGIN ADC_Init 2 */
/* USER CODE END ADC_Init 2 */
}
void Configure_ADC(void)
{
if (LL_ADC_IsEnabled(ADC1) == 0)
{
/* Enable ADC */
LL_ADC_Enable(ADC1);
}
//LL_ADC_EnableIT_EOCS(ADC1);
/* Enable interruption ADC group regular overrun */
LL_ADC_EnableIT_OVR(ADC1);
}
/*
* This triggers ADC conversion and hence subsequent DMA transfer
*/
void service_ADC(void)
{
static uint8_t flag = 0;
/* Wait for ADC conversion and DMA transfer completion to process data */
if(ubDmaTransferStatus != flag)
{
if(flag == 0)
{
ubDmaTransferStatus = 0;
LL_ADC_REG_StartConversionSWStart(ADC1);
flag = 1; // Conversion started
}
return;
}
}
void DMA1_Channel1_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
/* USER CODE END DMA1_Channel1_IRQn 0 */
/* USER CODE BEGIN DMA1_Channel1_IRQn 1 */
/* Check whether DMA transfer complete caused the DMA interruption */
if(LL_DMA_IsActiveFlag_TC1(DMA1) == 1)
{
/* Clear flag DMA transfer complete */
LL_DMA_ClearFlag_TC1(DMA1);
/* Call interruption treatment function */
AdcDmaTransferComplete_Callback();
}
/* Check whether DMA half transfer caused the DMA interruption */
if(LL_DMA_IsActiveFlag_HT1(DMA1) == 1)
{
/* Clear flag DMA half transfer */
LL_DMA_ClearFlag_HT1(DMA1);
/* Call interruption treatment function */
AdcDmaTransferHalf_Callback();
}
/* Check whether DMA transfer error caused the DMA interruption */
if(LL_DMA_IsActiveFlag_TE1(DMA1) == 1)
{
/* Clear flag DMA transfer error */
LL_DMA_ClearFlag_TE1(DMA1);
/* Call interruption treatment function */
AdcDmaTransferError_Callback();
}
/* USER CODE END DMA1_Channel1_IRQn 1 */
}
void ADC1_IRQHandler(void)
{
/* USER CODE BEGIN ADC1_IRQn 0 */
/* USER CODE END ADC1_IRQn 0 */
/* USER CODE BEGIN ADC1_IRQn 1 */
/* Check whether ADC group regular overrun caused the ADC interruption */
if(LL_ADC_IsActiveFlag_OVR(ADC1) != 0)
{
/* Clear flag ADC group regular overrun */
LL_ADC_ClearFlag_OVR(ADC1);
/* Call interruption treatment function */
AdcGrpRegularOverrunError_Callback();
}
else
{
/* Clear flag ADC group regular end of sequence conversions */
LL_ADC_ClearFlag_EOCS(ADC1);
/* Call interruption treatment function */
AdcGrpRegularSequenceConvComplete_Callback();
}
/* USER CODE END ADC1_IRQn 1 */
}
void AdcDmaTransferComplete_Callback(void)
{
/* Update status variable of DMA transfer */
ubDmaTransferStatus = 1;
/* For this example purpose, check that DMA transfer status is matching */
/* ADC group regular sequence status: */
if (ubAdcGrpRegularSequenceConvStatus != 1)
{
AdcDmaTransferError_Callback();
}
/* Reset status variable of ADC group regular sequence */
ubAdcGrpRegularSequenceConvStatus = 0;
}
void AdcDmaTransferError_Callback(void)
{
while(1);
}
void AdcGrpRegularSequenceConvComplete_Callback(void)
{
/* Update status variable of ADC group regular sequence */
ubAdcGrpRegularSequenceConvStatus = 1;
ubAdcGrpRegularSequenceConvCount++;
if(ubAdcGrpRegularSequenceConvCount == ADC_CONVERTED_DATA_BUFFER_SIZE)
{
LL_ADC_DisableIT_EOCS(ADC1);
}
}
void AdcGrpRegularOverrunError_Callback(void)
{
LL_ADC_DisableIT_OVR(ADC1);
}