2021-02-05 03:54 AM
Hello everyone,
I use a STM32F407VET6 MCU board and I'm trying to implement a Timer 8 Interrupt, every 5u sec. In my code, I also use an ADC interrupt, for ADC conversion purposes. I thought that these 2 interrupts are independent. I observed that when I have both interrupts enabled , Timer misses out and no update interrupt is serviced. I even tried involving DMA but didn't yield appropriate result.
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ADC1_Init();
MX_TIM8_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim8);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
if(startcycle)
{
startcycle=0;
HAL_ADC_Start_IT(&hadc1);
vdiff = setpoint - adcone;
controlleroutput= proportionalgain * vdiff;
timer_value= conv | (__HAL_TIM_GET_COUNTER(&htim8));
comparatoroutput= (controlleroutput > timer_value )?1:0;
/* if(comparatoroutput==1)
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_11, GPIO_PIN_SET);
else
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_11, GPIO_PIN_RESET);*/
}
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 144;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
}
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION_8B;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
static void MX_TIM8_Init(void)
{
/* USER CODE BEGIN TIM8_Init 0 */
/* USER CODE END TIM8_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM8_Init 1 */
/* USER CODE END TIM8_Init 1 */
htim8.Instance = TIM8;
htim8.Init.Prescaler = 0;
htim8.Init.CounterMode = TIM_COUNTERMODE_UP;
htim8.Init.Period = 719;
htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim8.Init.RepetitionCounter = 0;
htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim8) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim8, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM8_Init 2 */
/* USER CODE END TIM8_Init 2 */
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
adcone= HAL_ADC_GetValue(&hadc1);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
// HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_11);
startcycle=1;
}
I came to the conclusion that " there's a conflict between the ADC interrupts and the timer interrupt when i commented the software command of ADC and toggled the PD11 pin in the callback function. I attached the code , clock config and the waveforms.
Please provide some help!
Thanks a lot, in advance!
Kiran
2021-02-05 04:35 AM
hello bharat here;p
2021-02-05 04:41 AM
Only one interrupt handler can run at a time. Higher level interrupts interrupt lower level ones and all interrupt the code in the while loop.
If your goal is doing ADC conversion at a fixed sample rate, you could use a timer trigger event which will trigger ADC in hardware only, without the need of an interrupt handler. This is done by selecting e.g. Timer 8 Trigger Out event as External Trigger Conversion Source in ADC1. In TIM8 you set Trigger Event Selection to Update Event.
When ADC is done, you get the ADC interrupt. This could also be changed to cyclic DMA, i.e. a series of ADC results is automatically transferred to a ring buffer and you have to implement HalfFull and Full handlers for further processing the data in larger chunks.
Combining both approaches frees plenty of CPU power which is currently wasted in your main loop. (Poor indention makes it hardly readable)
hth
KnarfB
2021-02-05 06:09 AM
Hi! thanks for the response and sorry for the indentation. My main goal is , at every start of the 5 us the ADC has to be sampled and it will be computed with some variables only once in the cycle. Let me explain further, I am using Timer8 for generating a sawtooth wave for reference, the period of the sawtooth wave is 5us(200Khz). IN each cycle The ADC has to be sampled and the computation has to be taken place only once and it waits until the next rollover happens and this process continues.
Yes I can use TIM8 Trigger output to trigger the ADC, but keeping in mind that I will be using ADC in Dual regular simultaneous mode (4in ADC1 and 4 inADC2 in scan mode with software trigger with help of DMA) for which i need to have an interrupt. How can I run two interrupts in my program without conflict.
Can I run timer interrupt in blocking mode or nesting of interrupts that can be done. If nesting of interrupts can be done then can someone share that how can that be done in STM32 MCUs.
Thanks,
Kiran
2021-02-05 06:19 AM
Interrupt nesting happens automatically if you choose different priorities (preemption levels). Smaller number --> higher prio. Can configure that in STMCubeIDE or use a CMSIS function https://community.arm.com/developer/ip-products/system/b/embedded-blog/posts/cutting-through-the-confusion-with-arm-cortex-m-interrupt-priorities