Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Updating DAC stm32f407 cubemx with timer interrupt went wrong

Status
Not open for further replies.

yefj

Advanced Member level 4
Joined
Sep 12, 2019
Messages
1,180
Helped
1
Reputation
2
Reaction score
3
Trophy points
38
Activity points
7,113
Hello, i am trying to add timer interrupt delay function to my DAC code shown bellow.

At first i used CUBE MX to define dac and used HAL delay and it worked great as shownin the scope photo bellow.

But then i tried to update the code with timer interrupt timer peripehry which is already ON(APB1) its clock is 21Mhz as shown bellow.
So i added manually the code shown bellow and tried to replace hal_delay with delay and the scope gave me absulte noise instead of the starecase shape i had before .the full code shown bellow.



Where did i go wrong?

Reference Manual:


manually added code update for timer delay.
Code:
void delay(unsigned long us)
{
TIM4->CR1|=TIM_CR1_CEN;
myticks=0;
while(myticks<us);
TIM4->CR1&=~TIM_CR1_CEN;

}
void TIM4_IRQHandler(void)
{
myticks++;
TIM4->SR&=~TIM_SR_UIF;
}

int main(void)
{
RCC->APB1ENR|=RCC_APB1ENR_TIM4EN;
TIM4->PSC=0;
TIM4->ARR=21;
TIM4->CR1|=TIM_CR1_URS;
TIM4->DIER|=TIM_DIER_UIE;
TIM4->EGR=TIM_EGR_UG;
NVIC_EnableIRQ(TIM4_IRQn);



FULL CODE
Code:
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
DAC_HandleTypeDef hdac;
unsigned long myticks;
/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DAC_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
    void delay(unsigned long us)
    {
        TIM4->CR1|=TIM_CR1_CEN;
        myticks=0;
        while(myticks<us);
        TIM4->CR1&=~TIM_CR1_CEN;
        
    }
void TIM4_IRQHandler(void)
{
    myticks++;
  TIM4->SR&=~TIM_SR_UIF;
}

int main(void)
{
    RCC->APB1ENR|=RCC_APB1ENR_TIM4EN;
    TIM4->PSC=0;
    TIM4->ARR=21;
    TIM4->CR1|=TIM_CR1_URS;
    TIM4->DIER|=TIM_DIER_UIE;
    TIM4->EGR=TIM_EGR_UG;
    NVIC_EnableIRQ(TIM4_IRQn);




  /* 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_DAC_Init();
  /* USER CODE BEGIN 2 */
HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,1365);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
       HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,0x00000000);
//           HAL_Delay(2);
     delay(10);
           HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,0x00000400);
         //  HAL_Delay(2);
         delay(10);
           HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,0x00000800);
         //  HAL_Delay(2);
        delay(10);
           HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,0x00000C00);
           //HAL_Delay(2);
         delay(10);
    
           HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,0x00000FFF);
          // HAL_Delay(2);
         delay(10);
           HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,0x00000C00);
         //  HAL_Delay(2);
        delay(10);
           HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,0x00000800);
         //  HAL_Delay(2);
             delay(10);
           HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,0x00000400);
          // HAL_Delay(2);
             delay(10);
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
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 = 168;
  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_DIV8;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief DAC Initialization Function
  * @param None
  * @retval None
  */
static void MX_DAC_Init(void)
{

  /* USER CODE BEGIN DAC_Init 0 */

  /* USER CODE END DAC_Init 0 */

  DAC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN DAC_Init 1 */

  /* USER CODE END DAC_Init 1 */
  /** DAC Initialization
  */
  hdac.Instance = DAC;
  if (HAL_DAC_Init(&hdac) != HAL_OK)
  {
    Error_Handler();
  }
  /** DAC channel OUT1 config
  */
  sConfig.DAC_Trigger = DAC_TRIGGER_NONE;
  sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
  if (HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN DAC_Init 2 */

  /* USER CODE END DAC_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PD12 PD13 PD14 PD15 */
  GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
[/URL]
--- Updated ---

1613155759855.png

--- Updated ---

1613155920673.png
 
Last edited:

Hello ,i added the toggle line in my irq_handler and my HOME scope gave me a result as shon bellow.
Its not very accurate,but we see 1Mhz clock signal.
So the Irqhandler works great.
in the delay finction Myticks increasing evey 1microsecond is comparing myticks to us value in a while loop.
I tried to call delay(500000) and put the toggle before and after the loop to see if my led is blinking every half a second.
it didnt blink every half a second it stayed ON ,So for some reason it got stuck in the while loop .
The full code is shown bellow.
Where did i go wrong?
Thanks.
Code:
void delay(unsigned long us)
    {
        HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);
        TIM4->CR1|=TIM_CR1_CEN;
        while(myticks<us);
        myticks=0; //reset my ticks after
        TIM4->CR1&=~TIM_CR1_CEN;
        HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12); 
    }

1613217133092.png


1613217163794.png



Code:
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
DAC_HandleTypeDef hdac;
unsigned long myticks;
/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DAC_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
    void delay(unsigned long us)
    {
        HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_13);
        TIM4->CR1|=TIM_CR1_CEN;
        while(myticks<us);
        myticks=0; //reset my ticks after
        TIM4->CR1&=~TIM_CR1_CEN;
        HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);   
    }
void TIM4_IRQHandler(void)
{
    myticks++;
    //HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);
  TIM4->SR&=~TIM_SR_UIF;
}   
    
int main(void)
{
    RCC->APB1ENR|=RCC_APB1ENR_TIM4EN;
    TIM4->PSC=0;
    TIM4->ARR=21;
    TIM4->CR1|=TIM_CR1_URS;
    TIM4->DIER|=TIM_DIER_UIE;
    TIM4->EGR=TIM_EGR_UG;
    NVIC_EnableIRQ(TIM4_IRQn);
    
    
    
    
  /* 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_DAC_Init();
  /* USER CODE BEGIN 2 */
HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,1365);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
        delay(500000);
    /* USER CODE END WHILE */
       HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,0x00000000);
           HAL_Delay(2);
 //     delay(10000);
           HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,0x00000400);
           HAL_Delay(2);
    //     delay(10000);
           HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,0x00000800);
           HAL_Delay(2);
    //    delay(10000);
           HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,0x00000C00);
           HAL_Delay(2);
    //     delay(10000);
        
           HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,0x00000FFF);
           HAL_Delay(2);
        // delay(10000);
           HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,0x00000C00);
           HAL_Delay(2);
         //delay(10000);
           HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,0x00000800);
           HAL_Delay(2);
        //     delay(10000);
           HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,0x00000400);
           HAL_Delay(2);
            // delay(10000);
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
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 = 168;
  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_DIV8;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief DAC Initialization Function
  * @param None
  * @retval None
  */
static void MX_DAC_Init(void)
{

  /* USER CODE BEGIN DAC_Init 0 */

  /* USER CODE END DAC_Init 0 */

  DAC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN DAC_Init 1 */

  /* USER CODE END DAC_Init 1 */
  /** DAC Initialization
  */
  hdac.Instance = DAC;
  if (HAL_DAC_Init(&hdac) != HAL_OK)
  {
    Error_Handler();
  }
  /** DAC channel OUT1 config
  */
  sConfig.DAC_Trigger = DAC_TRIGGER_NONE;
  sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
  if (HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN DAC_Init 2 */

  /* USER CODE END DAC_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PD12 PD13 PD14 PD15 */
  GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
 

There is sumething with the proccesor which says that ARR=21 is too fast.
so the proccesor loop within the interrupt forever.
I can visualise why its happening?
Can any one help me understand this issue?
Thanks.
 

BTW 'myticks' should be declared 'volatile'.
If you are always in the USR, then the basic problem is that you are triggering the ISR too fast for the number of instructions that are in it (plus the hardware interrupt overhead). That is really telling you that a timer/ISR for a 1MHz signal is not the way to go.
Also how are you making sure that you ARE stuck in the ISR. Are you setting a breakpoint or something? Simply watching an LED can be misleading.
Try using a PWM where everything is handled in hardware and all you need todo in software is to set it up and alter the frequency if you need to.
Susan
 

Hi,

To me it seems you did not understand
* the benefit of an ISR
* how to achieve precision.

What you try is not wrong, but I see no benefit either.
As already mentioned running an ISR with 1MHz isn't the best idea. 1MHz means that the ISR has to be processed every 1 us. But entering the ISR takes time and going back to the main(ore where it came from) takes time .... and for sure processing the ISR itself takes time, too.
Let's imagine this all takes just 500ns. Then it takes 50%of processing time. Means your main loop is slowed down. Not really a big benefit.


Precision ... or do you want accuracy?
What you do:
* Processing some things in main() --> takes some time "m"
* running an ISR controlled delay() --> takes some time "i"
* to enter and leave the ISR takes some overhead time "o"
Your timing form one DAC update to the next is: m + i + o
* if there is some other ISR running or if there is some code in the ISR disabling ISR (like atomic variable access) it may cause additional unknown delay --> jittery DAC output.

m, i, o depend on code, clock freqency, compiler, compiler options....I'd call this rather unknown
So you need to use "trial and error" method to get an accurate DAC update frequency.

If you want to use software to get desired frequency... you need to run a timer/counter all the time, independent whether you are in main or in an ISR.
Then the key for getting accurate frequency is not to restart the timer, but calculate the next compare match.
Only the first time you need to take current counter value.
An example: let's imagine you set up a hardware counter to run at 1MHz. And you want an accurate DAC update rate of 500Hz (2000us)
Then
* only the first time you need to read the actual counter value (let's say it's 12345) then add 2000 meaning you need to update the DAC at 12345 + 2000 = 14345
* all the other timeouts depend on this "14345" value and not the actual counter value. Thus the folowing timeouts are 14345 + 2000 then again + 2000 ....again + 2000 ( getting 16345, 18345, 20345...)
This makes the DAC update frequency absolutely accurate. It does not depend on code, not depend on compiler, not depend on overhead.
There may be delays
* fixed delays don't harm
* variable delays just cause jitter. Unavoidable with software solutions.

Klaus
 

    MD_SHAHRUKH

    Points: 2
    Helpful Answer Positive Rating
Hello Klaus, ISR is interrupt service routine.So calling an interrupt every 1micro second is not possible.
but inside the interrupt handling function i put a toggling gpio and as you can see bellow i get a good 1Mhz signal
So the function is being called every 1us.

You say I should keep the counter running all the time.
Also as Susan mentioned i shouldchange the number of tick into volotile.
Its not about the DAC but creatinga delay function that is based on the interrupt of a timer.
My counter value is a tool i use to reduce the frequency at which we call the interrupt function.
the actual delay is the number of times the interrupt function is being called.


I will try to implement your advices and update with results as soon as possible.
Thanks.

1613426784298.png
 

Hi,

Calling an ISR
Hello Klaus, ISR is interrupt service routine.So calling an interrupt every 1micro second is not possible.
It may be possible or not, it depends on clock frequency and microcontroller. ....But it makes no sense...

but inside the interrupt handling function i put a toggling gpio and as you can see bellow i get a good 1Mhz signal
So the function is being called every 1us.
If you call an ISR every 1us ... and toggle a pin in the ISR
Then the resulting frequency should be perfect 500kHz, since it needs two edges (toggles) for a full period.
500kHz means not 498 or less and not 502 or higher.
But your picture shows 1.445kHz, which is almost 3 times the expectable. This is way OFF.

You say I should keep the counter running all the time.
The emphasis lies on "hardware" counter.

Also as Susan mentioned i shouldchange the number of tick into volotile.
"Volatile" is a compiler keyword for a variable
... that says the variable may be modified externally (ISR, hardware..)
... and disables code optimization (during compilation)

It has nothing to do with "changing the number of tick"

Its not about the DAC but creatinga delay function that is based on the interrupt of a timer.
My counter value is a tool i use to reduce the frequency at which we call the interrupt function.
the actual delay is the number of times the interrupt function is being called.
One does not call an ISR out if mood. The ISR will have a job to do.
In your case: generating delay for DAC output.
--> this is not the way to go.

According your code the staircase period time should be 8x10us = 80us or 125kHz
But it rather looks like 1600us.
A microcontroller is a precision tool. Usually if it is off by more than 1%, then something is wrong.
But yours is off by 2000%.

Klaus
 

Hello Klauss,You were absolutly right.
When i put mytciks as volotile and made prescale by 10 of the counter frequency its started to work by the full code shown bellow.
The thing that i am missing is how to know from the RM of other document the limitations of the ISR?
Could you reccomend me some method of estimating the maximal frequency allowed for the ISR?
Thanks.

Code:
#include "main.h"
#include <stdio.h>
#include "string.h"
#include "stdlib.h"
#include "stdarg.h"
/* Private variables ---------------------------------------------------------*/
DAC_HandleTypeDef hdac;
volatile unsigned long myticks=0;

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DAC_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
    void delay(unsigned long us)
    {
      TIM4->CR1|=TIM_CR1_CEN;  
       
              myticks=0;
        while(myticks<us);
                //HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_15);  
     TIM4->CR1&=~TIM_CR1_CEN;          
     
     
    }
void TIM4_IRQHandler(void)
{
    myticks++;
   
  TIM4->SR&=~TIM_SR_UIF;
}  
   
int main(void)
{
    RCC->APB1ENR|=RCC_APB1ENR_TIM4EN;
    TIM4->PSC=10;
    TIM4->ARR=21;
    TIM4->CR1|=TIM_CR1_URS;
    TIM4->DIER|=TIM_DIER_UIE;
    TIM4->EGR=TIM_EGR_UG;
   
    NVIC_EnableIRQ(TIM4_IRQn);
   HAL_Init();

   SystemClock_Config();

   MX_GPIO_Init();
  MX_DAC_Init();
  /* USER CODE BEGIN 2 */
//HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
//HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_R,1365);

     
   
  while (1)
  {
        delay(100000);
    HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_14);
        //HAL_Delay(500);
         delay(100000);
        HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_14);
       
        //HAL_Delay(500);
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
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 = 168;
  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_DIV8;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief DAC Initialization Function
  * @param None
  * @retval None
  */
static void MX_DAC_Init(void)
{

  /* USER CODE BEGIN DAC_Init 0 */

  /* USER CODE END DAC_Init 0 */

  DAC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN DAC_Init 1 */

  /* USER CODE END DAC_Init 1 */
  /** DAC Initialization
  */
  hdac.Instance = DAC;
  if (HAL_DAC_Init(&hdac) != HAL_OK)
  {
    Error_Handler();
  }
  /** DAC channel OUT1 config
  */
  sConfig.DAC_Trigger = DAC_TRIGGER_NONE;
  sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
  if (HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN DAC_Init 2 */

  /* USER CODE END DAC_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PD12 PD13 PD14 PD15 */
  GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
 

Could you reccomend me some method of estimating the maximal frequency allowed for the ISR?
Wrong question (in my opinion).
Any ISR should operate as quickly as possible and leave any work that requires more than trivial calculations, delays, specific timing etc. to be done in the main code. Often that means the ISR captures any immediate (and possibly changing) information and then sets a flag that is checked in the main loop to start the rest of the processing.
Remember that (in general - it depends on the implementation of the MCU) when in an ISR nothing else happens in the software. Therefore if an ISR is called too often (see Klaus's comment in post #5) then, even if it does nothing, it can slow down everything else.
ISRs are there to respond to something that must be handled 'right now or you lose out'.
At the hardware level, when an interrupt is triggered, the MCU must complete instructions to a point where the interrupt can be recognised - this typically is the end of the current instruction. Then it has to copy information onto the stack - the data sheet tells you exactly what but generally the status and program counter registers at least. It then looks up the address of the ISR and sets the PC to that. All of this is fairly predictable.
Then you need to consider what happens in the ISR itself. If you are writing in assembler then you have complete control, but often C code includes instructors to save additional registers and restore them on either side of your code. That pre/post-amble code can depend on what you have written in the ISR so can be hard to predict. When the ISR is complete then the hardware has to restore the saved registers (status and PC etc.) and start processing your original code - again something that is fairly predictable.
Therefore it can be quite difficult to say how fast an ISR actually completes (even more so if you can have nested interrupts) but looking at the generated code can give you some idea plus the hardware overheads. You can then look at the instruction clock rate and estimate the length of time for each interrupt. Assuming you want nothing else done in your code then that answers your question. However, if you are in the situation where this is important then you need to look for alternative approaches.
Susan
 

Hi,

I agree with Susan.
And: You should not aim for the highest frequency, but the lowest frequency.

But if you want to know about the highest frequency..
It depends. On many things. Microcontroller, your ISR code, your main code other ISR code, clock frequency ... and last but not least: how you define "too often".
Too often maybe is when the processing power for the main loop becomes too low, or an interrupt event is missed, or or or.

I like to work with interrupts. It makes processing more precise in time and makes to react on several events without missing one.
But interrupt and especially an ISR still is a software solution...but assisted by hardware.
But more precise and less processing power consuming is when you can rely on pure hardware options.

So the best is when you define your requirements as precise as possible.

Klaus
 

Hello Klauss,My goal is to create a sinus wave as smooth as possible,
For example i want to build 1KHz frequency,which means 1ms period .
my VDD is 5V ,i want to make it at first 0 to 5V and then filter out the DC thus making the sinus wave run from -2.5V to 2.5V.
STM32 DAC is 12bit so my output voltage range is divided by 2^12=4096 pieces.
This is my basic skeleton
I want to implement it like you said with the most precise method.
" But more precise and less processing power consuming is when you can rely on pure hardware options."

Could you please say what element,properties, terms i need to look at to assemble the requirement peaces?

Thanks.
 
Last edited:

For a start, I really doubt if you need 4096 steps to achieve what you want. To get a full sine wave with 1KHz would require updating the DAC about every 200nSec (or 4MHz interrupt). I would think that 8-bit would be plenty for this application.
If you are already going to use a filter to remove the DC, then create a bandpass filter and remove anything above (say) 4kHz. That also means you can reduce the number of steps - but that is your design challenge.
If it were me, I'd use the one of the two DMA controllers to send the data to the DAC. Set up a table with the values you want to send to the DAC (you only need enough entries for half a cycle) and set up the DMA channel to send those to the DAC. when that is complete, have the DMA interrupt (which for a 1kHz wave will occur every 500uS) that re-sets the DMA channel to send the data from the table in the reverse direction. (I'm not sure about that device but if there are multiple DMA definitions that can be chained, then you can do this without even the interrupt.)
Going back to what you were originally talking about (1MHz outputs) then you probably need to get a separate DDS chip.
Susan
 

Hi,

I'd read datasheet and application notes, design notes, design examples...

I guess there is a DMA option with automatic repeat.
If so then define an array with sample data, fill it with sinewave values

And I guess you can set up a timer to control the DAC..
If so then you neither need an ISR nor continous processing power.

Klaus
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top