2022-08-13 10:09 AM
snippet from main code->
uint32_t a=0;
uint32_t ADC_VAL[100];
ADC_VAL[0]=0;
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_VAL, 1);
HAL_Delay(10);
a=ADC_VAL[0]; <- set a breakpoint at this point to view the value in 'a'
<-
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_MultiModeTypeDef multimode = {0};
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc1.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure the ADC multi-mode
*/
multimode.Mode = ADC_MODE_INDEPENDENT;
if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
The initialization routine sets the ADC resolution to 12 bit, the code should read one 32 bit byte from the ADC over DMA . The value is copied into variable 'a' just so that I can set a breakpoint and view the value.
The value of a rolls over above 255 to zero, I assume that the HAL call is returning an 8 bit byte into ADC_VAL[0]?
Am I making a basic mistake here?
Thanks
2022-08-13 11:14 PM
Isn't DMA handling 16 bit ADC quantities? Have you tried to first make a non DMA one shot convertion to pin point the root cause? Usually the nucleo of the corresponding mcu has adc examples to check and compare.
2022-08-14 06:28 AM
That's a good approach, I'll try it, like you, I suspect it is something to do with the DMA transfer. Do you see anything wrong with the way I have coded it?
2022-08-15 06:39 AM
Thanks for the suggestion, the following works perfectly and returns values greater than 8 bits, so it must be something to do with DMA. Quite what , I have no idea however.
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion (&hadc1, 10);
//HAL_Delay(100);
ADC_VAL[0]=HAL_ADC_GetValue (&hadc1);
2022-08-15 08:56 AM
Buffers touched by DMA clearly need to be volatile, and you need to explicitly wait for completion. Use the callbacks, or query the peripheral. Arbitrary delays are a bad habit
2022-08-15 12:57 PM
So I have to declare ADC_VAL as volatile ? I agree with your comment about delays, I just added them for debug thinking there was a timing issue.
2022-08-15 01:13 PM
>>So I have to declare ADC_VAL as volatile ?
Loading outside the purview of program flow, or the MCU, would seem like the poster child case for use of volatile
Memory altered in IRQ, or DMA.
Similarly the entire peripheral register space, which is combinatorial logic, and not memory cells. Each read can return a different value, potentially from a different register.
For out-bound DMA you'd need to ensure write buffers get flushed to memory.
On CM7 you'd need to further worry about cache coherency.
2022-08-15 11:18 PM
> Buffers touched by DMA clearly need to be volatile
Actually no. Modifying such buffers has a side effect and for these adding a sequence point is enough.
https://en.wikibooks.org/wiki/C_Programming/Side_effects_and_sequence_points
These are probably the least known important concepts of the C programming...
The volatile is much "stronger" attribute. It forces accessing the actual memory every single time - even the same memory location within a simple loop without any function calls. And it forces keeping the order relatively to other volatile accesses. The sequence points don't do any of this.