2025-03-24 2:15 AM - last edited on 2025-03-24 4:08 AM by mƎALLEm
Hello,
I have a problem witht he ADC readings and the timing of reading of the ADC channels.
I am currently using an STM32 U545, both ADCs (1 & 4) configured to read voltage values comming from different sensors that i have on my pcb. The ADC is configured in DMA mode so i can have this reading process runing in parallel and the ADCs are triggered with a timer so that i have full control of the ADC switching. Setting the ADC in continuous/discontinuous conversion mode is not an option for me.
The problem comes when i try to make a function where all the voltage values and temperature values are monitored to check if they are in range so that if they are not the system does not start/stops and informs me which error do i have.
The parameters i try to monitor are the following ones:
void ADC_Calibration(void){
I_BAT = (float)ADC1_VALUES[0] * K_I_BAT + D_I_BAT; // CURRENT VOLTAGE
U_BAT = (float)ADC1_VALUES[1] * K_U_BAT + D_U_BAT; // U_BAT BATTERY VOLTAGE
U_A = (float)ADC1_VALUES[2] * K_U_A + D_U_A; // OUT A VOLTAGE VALUE
U_B = (float)ADC1_VALUES[3] * K_U_B + D_U_B; // OUT B VOLTAGE VALUE
TBAT_1 = (float)ADC4_VALUES[0] * K_TBAT_1 + D_TBAT_1; // TEMPERATURE BAT1
TBAT_2 = (float)ADC4_VALUES[1] * K_TBAT_2 + D_TBAT_2; // TEMPERATURE BAT2
TBAT_3 = (float)ADC4_VALUES[2] * K_TBAT_3 + D_TBAT_3; // TEMPERATURE BAT3
}
The function that monitors the parameters is the following one:
void error(void) {
//if ((TBAT_1 < TEMPERATURE_LIMIT && TBAT_2 < TEMPERATURE_LIMIT && TBAT_3 < TEMPERATURE_LIMIT) &&
//(U_BAT > V_LOWER_LIMIT && U_BAT < V_UPPER_LIMIT) &&
//(I_BAT > I_LIMIT_NEGATIVE && I_BAT < I_LIMIT_POSITIVE)) {
//error_flag = 0;
//return;
//}
// Overcurrent (positive)
if (I_BAT > I_LIMIT_POSITIVE) {
error_flag = 1;
}
// Overcurrent (negative)
else if (I_BAT < I_LIMIT_NEGATIVE) {
error_flag = 2;
}
// Overvoltage
else if (U_BAT > V_UPPER_LIMIT) {
error_flag = 3;
}
// Undervoltage
else if (U_BAT < V_LOWER_LIMIT) {
error_flag = 4;
}
// Overtemperature
else if (TBAT_1 > TEMPERATURE_LIMIT || TBAT_2 > TEMPERATURE_LIMIT || TBAT_3 > TEMPERATURE_LIMIT) {
error_flag = 5;
}
if (error_flag != 0) {
enable_pwm = 0;
setPWM(0);
}
}
The problem im encountering is the following one:
Everytime the ADC starts, the buffer where all the data comming from the sensors goes is filled with 0. So everytime i try to intiate the program it obiously detects that the values are out of range and therefore i cant initiate the program and the error flag instantly pops up.
Is there anyway i can "wait" for the ADC without introducing any kind of blocking mode in the program?
2025-03-24 5:02 AM
Hello,
Possibly the following...
Set up another timer interrupt, with a small value to "wait" until, and then enable it as a single event.
Start timer.
ADC capture initialisation stuff
Go and do something else (i.e. not blocking)
When the interrupt goes off process or check your error values.
2025-03-24 5:15 AM
> I am currently using an STM32 U545, both ADCs (1 & 4) configured to read voltage values comming from different sensors that i have on my pcb. The ADC is configured in DMA mode so i can have this reading process runing in parallel ...
I don't quite understand what do you mean.
Because ADC 1 and 4 are separate peripherals, and (usually) require separate triggers and separate DMA channels. I know of no STM32 MCU that would gather channels frm separate ADCs into one array for you.
Although it might be possible that both could use the same timer as trigger.
I usually configure a TC interrupt event of the DMA, which informs you that an ADC sequence has finished, and all results are transferred.
> Everytime the ADC starts, the buffer where all the data comming from the sensors goes is filled with 0. So everytime i try to intiate the program it obiously detects that the values are out of range and therefore i cant initiate the program and the error flag instantly pops up.
I think you talk about a debugger view window here.
This is not real-time, mind you.
2025-03-24 5:59 AM
Thank you for the fast response...
I have some other timers configured that generate PWMs so i would prefer not to introduce another timer with more interruptions ...
Do you think i can put some code in this part of the code that allows me to wait until i get a good reading of the ADC sensors?
/* USER CODE BEGIN 2 */
// First conversion of values
firsts_ADC_values();
if(HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_OFFSET_LINEARITY, ADC_SINGLE_ENDED)){ // ADC1 Calibration
Error_Handler();
}
if (HAL_ADC_Start_DMA(&hadc1, (uint32_t *)ADC1_VALUES, (ADC1_BUFFER_SIZE)) != HAL_OK){
Error_Handler();
}
if(HAL_ADCEx_Calibration_Start(&hadc4, ADC_CALIB_OFFSET_LINEARITY, ADC_SINGLE_ENDED)){ // ADC4 Calibration
Error_Handler();
}
if (HAL_ADC_Start_DMA(&hadc4, (uint32_t *)ADC4_VALUES, (ADC4_BUFFER_SIZE)) != HAL_OK){
Error_Handler();
}
// deactivate power save mode
HAL_GPIO_WritePin(PS_3V3_GPIO_Port, PS_3V3_Pin, GPIO_PIN_SET);
// activate interrupt timer
HAL_TIM_Base_Start_IT(&htim2);
HAL_TIM_Base_Start(&htim3);
setPWM(0);
// HAL_TIM_Base_Start(&htim1);
// activate timers
CHB_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
CHB_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
CHB_TIM_PWM_Start(&htim8, TIM_CHANNEL_3);
CHB_TIMEx_PWMN_Start(&htim8, TIM_CHANNEL_3);
setPWM(0);
//HAL_TIM_OC_Start(&htim1, TIM_CHANNEL_2);
//HAL_TIM_OC_Start(&htim1, TIM_CHANNEL_4);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4);
/* USER CODE END 2 */
2025-03-24 6:02 AM
Yes, ADC1 and ADC4 are separate peripherals therefore, there are two channels of the DMA for both adcs and two buffers on where to put the data incoming from both sensors but both of them are triggered with the same timer for better synchronization.
Would you consider "real time" if in the debbuging window i go step by step in the program?
2025-03-24 6:47 AM
> Would you consider "real time" if in the debbuging window i go step by step in the program?
I meant the usual "realtime" displays in debugger windows. Their output is usually not synchronized with anything, and is can be described as "best effort".
Single-stepping might not reveal all runtime issues as well.
> Yes, ADC1 and ADC4 are separate peripherals therefore, there are two channels of the DMA for both adcs and two buffers on where to put the data incoming from both sensors but both of them are triggered with the same timer for better synchronization.
You could use the DMA_TC interrupt(s), as mentioned. I don't know if it can be guaranteed that they always appear in the same sequence in each cycle. If not, you would have to sync both event another way.
When both TC events have occured after an ADC trigger, an evaluation of the ADC results is to be started.