2024-11-03 07:00 AM
In a project built using STM32F103, I have used TIM3 for some of my frequent tasks (like LED blinking and setting some flags etc.), which work perfectly. Today when I tried to enable ADC1 using DMA Circular, it looks like the TIM3 Global Interrupt handler is not invoked..
This line of code, stops the TIM3 interrupt.
HAL_ADC_Start_DMA(hadc, adcBuffer, 5)
I don't find any relation between these 2. How ADC1 is related to TIM3? I am not using any channels of TIM3, just using its time elapsed event to do my tasks. Scratching my head.. Please help.
2024-11-03 07:35 AM
If there is an interrupt related to ADC or DMA and it's too lengthy, and the TIM3 interrupt's priority is lower or equal to that interrupt's priority, this may result in behaviour you've described.
One way to debug this is to toggle a pin at the interrupt-in-question's entry and exit and observe on oscilloscope/LA.
JW
2024-11-03 08:19 AM
Yes, I do understand that @waclawek.jan ,
Then what is the way to use TIMER and ADC DMA at the same time?
2024-11-03 09:12 AM
I don't know if what I wrote is the reason for your problem, you have to verify that.
And even if it is, I don't know what are you doing in the mentioned interrupt. If it's a lengthy operation, then try to optimize e.g. switch on compiler optimizations; consider, if the frequency with which you take the ADC readings and process them is necessary, etc. The solutions depend on the problem.
JW
2024-11-03 10:02 AM
DMA larger blocks of data so it's not interrupting continously. Use the TIM to generate fast signals and not have it interrupting at more than a few hundred KHz.
Set priority and preemption levels to accommodate rates and runtime of the handlers.
Lacking a lot of details and specifics about actual requirements and whether those are realistic or not.
2024-11-03 10:20 AM
The ADC, just reads 5 channels and store into the DMA buffer. Right now the interrupt does not do anything more. The TIM3 interrupt only toggles 4 leds on the system depending on their OFF and ON duration settings.
Here is the ADC Handler
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {
if(hadc->Instance == ADC1){
//Doing nothing for now
}
}
Here is the TIM3 Interrupt routine
void toggleLeds() {
uint32_t tick = HAL_GetTick();
if (HAL_GPIO_ReadPin(GPS_LED_GPIO_Port, GPS_LED_Pin) == 1 && ledToggleTiming.ToggleGpsLed == 1) {
//It was ON, turn it OFF
if ((tick - gpsLedLastToggleTime) >= ledToggleTiming.GPSLedOnDuration) {
HAL_GPIO_WritePin(GPS_LED_GPIO_Port, GPS_LED_Pin, GPIO_PIN_RESET);
gpsLedLastToggleTime = tick;
}
} else {
//It was OFF, turn it ON
if ((tick - gpsLedLastToggleTime) >= ledToggleTiming.GPSLedOffDuration) {
HAL_GPIO_WritePin(GPS_LED_GPIO_Port, GPS_LED_Pin, GPIO_PIN_SET);
gpsLedLastToggleTime = tick;
}
}
if (HAL_GPIO_ReadPin(GSM_LED_GPIO_Port, GSM_LED_Pin) == 1 && ledToggleTiming.ToggleGsmLed == 1) {
//It was ON, turn it OFF
if ((tick - gsmLedLastToggleTime) >= ledToggleTiming.GSMLedOnDuration) {
HAL_GPIO_WritePin(GSM_LED_GPIO_Port, GSM_LED_Pin, GPIO_PIN_RESET);
gsmLedLastToggleTime = tick;
}
} else {
//It was OFF, turn it ON
if ((tick - gsmLedLastToggleTime) >= ledToggleTiming.GSMLedOffDuration) {
HAL_GPIO_WritePin(GSM_LED_GPIO_Port, GSM_LED_Pin, GPIO_PIN_SET);
gsmLedLastToggleTime = tick;
}
}
if (HAL_GPIO_ReadPin(SYS_LED_GPIO_Port, SYS_LED_Pin) == 1 && ledToggleTiming.ToggleSysLed == 1) {
//It was ON, turn it OFF
if ((tick - sysledLastToggleTime) >= ledToggleTiming.SYSLedOnDuration) {
HAL_GPIO_WritePin(SYS_LED_GPIO_Port, SYS_LED_Pin, GPIO_PIN_RESET);
sysledLastToggleTime = tick;
}
} else {
//It was OFF, turn it ON
if ((tick - sysledLastToggleTime) >= ledToggleTiming.SYSLedOffDuration) {
HAL_GPIO_WritePin(SYS_LED_GPIO_Port, SYS_LED_Pin, GPIO_PIN_SET);
sysledLastToggleTime = tick;
}
}
}
That's it.. I don't know what happened, I kept playing around with settings and my code and now it seems the ADC DMA interrupt is invoking.
2024-11-03 10:45 AM
Now, I have another question.. Instead of circular dma, I just did it normal dma.. and I call the ADC_Receive_DMA every 2 secs (from my main loop). I have voltage supplied into 2 channels out of 5. Now at every interrupt call, the value of the DMA buffer looks funny... The position of the channel 8 and 9 position keeps changing in the DMA buffer.. Below are 2 screenshots from the live expression..
Here is the adc related code..
uint32_t adcBuffer[5] = { 0 }; //We are reading 5 channels
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {
if(hadc->Instance == ADC1){
//Doing nothing for now
}
}
uint8_t ADC_Read(ADC_HandleTypeDef *hadc) {
if(HAL_ADC_Start_DMA(hadc, adcBuffer, 5) == HAL_OK){
return 1;
}
return 0;
}
The ADC_Read() is called from main loop every 2 seconds..