2024-04-09 02:28 PM
Given:
STM32CubeIDE:
Version: 1.14.1
Build: 20064_20240111_1413 (UTC)
STM32CubeMX:
Version: 6.10.0-RC9
Build: 20231120-2037 (UTC)
OS:
Linux Lmint21
Initialization Code in Main for ADC: Scanning three internal values
static void MX_ADC3_Init(void)
{
/* USER CODE BEGIN ADC3_Init 0 */
/* USER CODE END ADC3_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC3_Init 1 */
hadc3.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
/* USER CODE END ADC3_Init 1 */
/** Common config
*/
hadc3.Instance = ADC3;
hadc3.Init.Resolution = ADC_RESOLUTION_16B;
hadc3.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc3.Init.EOCSelection = ADC_EOC_SEQ_CONV;
hadc3.Init.LowPowerAutoWait = DISABLE;
hadc3.Init.ContinuousConvMode = DISABLE;
hadc3.Init.NbrOfConversion = 3;
hadc3.Init.DiscontinuousConvMode = DISABLE;
hadc3.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc3.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
hadc3.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc3.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
hadc3.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc3) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_16CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
sConfig.OffsetSignedSaturation = DISABLE;
if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_VBAT;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Rank = ADC_REGULAR_RANK_3;
if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC3_Init 2 */
/* USER CODE END ADC3_Init 2 */
}
Note: I had to add the clock pre-scale to the beginning user code since this is still not available to select in CubeMX.
The system clock config is set to pass 50MHz to the ADC,
I did verify the ADC clock was being set in HAL_ADC_MspInit()
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
if(hadc->Instance==ADC3)
{
/* USER CODE BEGIN ADC3_MspInit 0 */
/* USER CODE END ADC3_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_ADC3_CLK_ENABLE();
The code to perform the scan is in a thread (AZURE RTOS):
typedef struct ADCvalues{
uint16_t Raw[3];
double IntSensTmp;
double int_ref;
double vbat;
} adcval_t;
adcval_t ADC;
void ADC_Thread_entry(ULONG thread_input)
{
(void) thread_input;
tx_thread_sleep(500);
HAL_ADC_Start_DMA(&hadc3, (uint32_t*)ADC.Raw, 3);
while(1){
tx_semaphore_get(&ADC_Semaphore, TX_WAIT_FOREVER);
tx_thread_sleep(500);
HAL_ADC_Start_DMA(&hadc3, (uint32_t*)ADC.Raw, 3);
}
}
void HAL_ADC_ConvCpltCallback (ADC_HandleTypeDef *hadc)
{
HAL_ADC_Stop_DMA(hadc);
tx_semaphore_put(&ADC_Semaphore); // let system know the FPGA is done loading
}
and the interrupt handlers are in the stm32h7xx_it.c as:
void ADC3_IRQHandler(void)
{
/* USER CODE BEGIN ADC3_IRQn 0 */
/* USER CODE END ADC3_IRQn 0 */
HAL_ADC_IRQHandler(&hadc3);
/* USER CODE BEGIN ADC3_IRQn 1 */
/* USER CODE END ADC3_IRQn 1 */
}
/**
* @brief This function handles BDMA channel0 global interrupt.
*/
void BDMA_Channel0_IRQHandler(void)
{
/* USER CODE BEGIN BDMA_Channel0_IRQn 0 */
/* USER CODE END BDMA_Channel0_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_adc3);
/* USER CODE BEGIN BDMA_Channel0_IRQn 1 */
/* USER CODE END BDMA_Channel0_IRQn 1 */
}
The CubeMX Mode and params are set up as:
and
NVIC settings:
with DMA settings:
Also Register Callbacks are set to enable for ADC.
So what did I miss?
This did work a little as I was debugging and setting breakpoints. Pausing at the first HAL_ADC_Start_DMA call and stepping into the Hal code to verify parameters being passed, I then pushed play and hit the break point in the callback. However, continuing past the break point in the callback, I did not get anymore passes through the callback. Then, for reasons unknown this would not occur anymore after code changes that I cannot recall the sequence of. Now it does not work at all.
The code operation is intended to wait in the thread until a semaphore indicates a completed conversion. Then sleep for 5 seconds after which another conversion is started. There is no processing of the ADC values yet. I was going to add those later once I actually have data to process.
Solved! Go to Solution.
2024-04-10 12:53 AM
Hello,
BDMA, DMA1 and DMA2 do not have access to the DTCM memory. BDMA has access to SRAM4 in D3 only. Please refer to the reference manual.
2024-04-09 05:04 PM
I made a change that did not change any behavior.
I created a DTCM_section in the linker script and set the attribute of the ADC data structure to point to that section with:
__attribute__((section(".DTCMRAM_section"))) adcval_t ADC;
The debugger confirms the ADC structure is pointing to 0x20000000 (DTCM RAM).
Then I made another change that seems to have had some effect. I changed the Overrun behavior to Overrun data overwritten.
Now, I hit the break points at the first call HAL_ADC_Start_DMA(&hadc3, (uint32_t*)ADC.Raw, 3); followed by the second call HAL_ADC_Start_DMA(&hadc3, (uint32_t*)ADC.Raw, 3); five seconds later in the while loop after the tx_semaphore_get. But then, running the program further generates no more interrupts and hence no more hits to the HAL_ADC_ConvCpltCallback (ADC_HandleTypeDef *hadc) routine.
2024-04-10 12:53 AM
Hello,
BDMA, DMA1 and DMA2 do not have access to the DTCM memory. BDMA has access to SRAM4 in D3 only. Please refer to the reference manual.
2024-04-10 08:50 AM
Setting the DMA to DMA1 fixes the issue. Thought I had tried this before and failed, but I must have had other issues in the setup.
Thank You SofLit