I am trying to read ADC values from an arduino shield connected to my board. The Arduino shield is an already tested custom board which sends data when a contact between a sensor and a finger is detected.
I developed a program using STM32Cube IDE to be able to read these values and display it periodically. This program is based on STemWin example. Unfortunately, after first read from the program, the value is not updated and the rest of the features are not working anymore. The program is stuck. If I comment the code which periodically reads data from ADC then the program works normally.
Here is the content of my main :
/* Configure the MPU attributes */
MPU_Config();
/* Invalidate I-Cache : ICIALLU register */
SCB_InvalidateICache();
/* Enable branch prediction */
SCB->CCR |= (1 << 18);
__DSB();
/* Invalidate I-Cache : ICIALLU register */
SCB_InvalidateICache();
/* Enable I-Cache */
SCB_EnableICache();
SCB_InvalidateDCache();
SCB_EnableDCache();
/* STM32F7xx HAL library initialization:
- Configure the Flash ART accelerator on ITCM interface
- Configure the Systick to generate an interrupt each 1 msec
- Set NVIC Group Priority to 4
- Global MSP (MCU Support Package) initialization
*/
HAL_Init();
/* Configure the system clock @ 200 Mhz */
SystemClock_Config();
/* Init GPIO */
MX_GPIO_Init();
/* Init ADC3 */
MX_ADC3_Init();
/* Configure the board */
k_BspInit();
/* Initialize RTC */
k_CalendarBkupInit();
/* Create GUI task */
osThreadDef(GUI_Thread, GUIThread, osPriorityNormal, 0, 2 * 1024);
osThreadCreate(osThread(GUI_Thread), NULL);
/* Add Modules*/
k_ModuleInit();
/* Link modules */
k_ModuleAdd(&audio_player_board);
k_ModuleAdd(&redfrog_loader_board);
k_ModuleAdd(&redfrog_workstation_board);
#if !defined ( __GNUC__ )
k_ModuleAdd(&video_player_board);
#endif
/*k_ModuleAdd(&audio_recorder_board);
k_ModuleAdd(&vnc_server);
k_ModuleAdd(&gardening_control_board);
k_ModuleAdd(&home_alarm_board);
k_ModuleAdd(&games_board);
k_ModuleAdd(&settings_board);*/
/* Start scheduler */
osKernelStart();
/* We should never get here as control is now taken by the scheduler */
for (;;)
;
Here is the content of MX_ADC3_Init and MX_GPIO_Init functions :
/**
* @brief ADC3 Initialization Function
* @param None
* @retval None
*/
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 */
__HAL_RCC_ADC3_CLK_ENABLE()
;
/* USER CODE END ADC3_Init 1 */
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc3.Instance = ADC3;
hadc3.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc3.Init.Resolution = ADC_RESOLUTION_12B;
hadc3.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc3.Init.ContinuousConvMode = ENABLE;
hadc3.Init.DiscontinuousConvMode = DISABLE;
hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc3.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc3.Init.NbrOfConversion = 1;
hadc3.Init.DMAContinuousRequests = ENABLE;
hadc3.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc3) != HAL_OK) {
printf("NOK");
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK) {
printf("NOK");
}
/* USER CODE BEGIN ADC3_Init 2 */
/* USER CODE END ADC3_Init 2 */
}
static void MX_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = { 0 };
__HAL_RCC_GPIOA_CLK_ENABLE()
;
/*Configure GPIO pin : PA0 */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_NVIC_SetPriority(ADC_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(ADC_IRQn);
}
And finally here is the GUIThread function which is called as a thread in main function.
/**
* @brief Start task
* @param argument: pointer that is passed to the thread function as start argument.
* @retval None
*/
static void GUIThread(void const *argument) {
/* Initialize Storage Units */
k_StorageInit();
/* Initialize GUI */
GUI_Init();
WM_MULTIBUF_Enable(1);
GUI_SetLayerVisEx(1, 0);
GUI_SelectLayer(0);
GUI_SetBkColor(GUI_WHITE);
GUI_Clear();
/* Set General Graphical proprieties */
k_SetGuiProfile();
/* Demo Startup */
k_StartUp();
/* Create Touch screen Timer */
osTimerDef(TS_Timer, TimerCallback);
lcd_timer = osTimerCreate(osTimer(TS_Timer), osTimerPeriodic, (void*) 0);
/* Start the TS Timer */
osTimerStart(lcd_timer, 100);
/* Show the main menu */
k_InitMenu();
WM_HWIN hItem = TEXT_CreateEx(350, 100, 80, 15, WM_GetDesktopWindowEx(0),
WM_CF_SHOW, 0, 33, "0");
TEXT_SetFont(hItem, GUI_FONT_13B_ASCII);
TEXT_SetTextColor(hItem, GUI_BLACK);
HAL_ADC_Start(&hadc3);
HAL_StatusTypeDef res;
/* Gui background Task */
while (1) {
uint32_t InitTick = 0;
GUI_Exec(); /* Do the background work ... Update windows etc.) */
res = HAL_ADC_PollForConversion(&hadc3,
HAL_MAX_DELAY);
switch (res) {
case HAL_OK:
if ((WM_IsVisible(hItem))
&& ((osKernelSysTick() - InitTick) > 500)) {
g_ADCValue = HAL_ADC_GetValue(&hadc3);
g_MeasurementNumber++;
hItem = WM_GetDialogItem(WM_GetDesktopWindowEx(0), 33);
char str[12];
sprintf((char*) str, "%lu", g_ADCValue);
TEXT_SetText(hItem, str);
WM_InvalidateWindow(hItem);
WM_Update(hItem);
}
break;
case HAL_ERROR:
printf("ERROR");
break;
case HAL_BUSY:
printf("BUSY");
break;
case HAL_TIMEOUT:
printf("TIMEOUT");
break;
}
osDelay(20); /* Nothing left to do for the moment ... Idle processing */
}
}
The while loop at the end contains the code that should allow me to read values periodically from GPIOPin0/ADC3Channel0. It works a first time since when I reset the board the value is changing. But then the program is stuck. I need your help to understand what I am doing wrong. Thank you very much.
The ADC only converts one sample.
This is caused by your call of res = HAL_ADC_PollForConversion(&hadc3, HAL_MAX_DELAY);
This function will stop the ADC after the conversion is finished, so next time you come to this call your program get blocked since the EOC flag is never set.
Simply add a HAL_ADC_Start(&hadc3);
within your while(1)
loop and you will always get new values.
Later you could change your code to use DMA and the ADC could run without waiting :)