Jump to content

    
Sign in to follow this  
LAS9891

РАБОТА ПРЕРЫВАНИЙ в HAL библиотеках.

Recommended Posts

Пробую написать программу на STM32 используя HAL библиотеки. В программе инициализируются три таймера номер 3 (TIM3) , номер 5 (TIM5), номер 2 (TIM2).

TIM3 тактируется от внутреннего источника (от шины), работает в режиме ШИМ и формирует на выходе меандр с частотой 1,2 МГц.

 

TIM5 тактируется от TIM3, работает в режиме ШИМ.

 

TIM2 тактируется от TIM3, работает в режиме сравнения.

 

Как хотелось бы чтобы работало:

Таймеры запускаются одновременно. Разрешается прерывание по TIM2 по значению Pulse в STM32CubeMX. TIM2 отсчитывает интервал времени в течение которого TIM5 сформирует на выходе два импульса ШИМ с заданной частотой и заполнением. Когда TIM2 досчитывает до конца временного интервала (значение Pulse в STM32CubeMX), формируется прерывание.

В обработчике прерывания меняется заполнение импульсов, которые формирует TIM5. Запрещается прерывание TIM2 по значению Pulse и разрешается прерывание TIM2 по переполнению.

Далее таймеры продолжают считать. TIM5 формирует один импульс с измененным заполнением и возникает переполнение по переполнению TIM2.

В обработчике прерывания меняется заполнение импульсов, которые формирует TIM5, на изначальное значение. Запрещается прерывание TIM2 по переполнению, разрешается прерывание TIM2 по значению Pulse.

И так по кругу... TIM5 на выходе должен формировать последовательность импульсов: два с одинаковым заполнением, один с меньшим, опять два с одинаковым, опять один с меньшим и т.д.

 

Написал такой код main.c:

  MX_GPIO_Init();
  MX_TIM3_Init();
  MX_TIM2_Init();
  MX_TIM5_Init();

  HAL_TIM_PWM_Start  (&htim2, TIM_CHANNEL_1);
  HAL_TIM_PWM_Start  (&htim2, TIM_CHANNEL_2);
  HAL_TIM_OC_Start_IT(&htim2, TIM_CHANNEL_3);
  HAL_TIM_PWM_Start  (&htim5, TIM_CHANNEL_1);
  HAL_TIM_PWM_Start  (&htim3, TIM_CHANNEL_1);

  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

 

 

Обработка прерываний такая:

void HAL_TIM_OC_DelayElapsedCallback (TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM2)
    {
    if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3) // Необходимо сформировать последний в кадре импульс INT.
      {
      HAL_TIM_PWM_Stop   (&htim3, TIM_CHANNEL_1);
        
      HAL_TIM_PWM_Stop   (&htim2, TIM_CHANNEL_1); // Выключение таймера. Таймер работал в режиме работы с формированием прерывания.
      HAL_TIM_PWM_Stop   (&htim2, TIM_CHANNEL_2); // Выключение таймера. Таймер работал в режиме работы с формированием прерывания.
      HAL_TIM_OC_Stop_IT (&htim2, TIM_CHANNEL_3); // Выключение таймера. Таймер работал в режиме работы с формированием прерывания.
      HAL_TIM_PWM_Stop   (&htim5, TIM_CHANNEL_1);     // Выключение таймера. Таймер работал в режиме работы без формированием прерывания.

      TIM5->CCR1 = 4;

      __HAL_TIM_ENABLE_IT(&htim2, TIM_IT_UPDATE);
      HAL_TIM_PWM_Start  (&htim2, TIM_CHANNEL_1);
      HAL_TIM_PWM_Start  (&htim2, TIM_CHANNEL_2);
      HAL_TIM_OC_Start   (&htim2, TIM_CHANNEL_3);
      HAL_TIM_PWM_Start  (&htim5, TIM_CHANNEL_1);
            
      HAL_TIM_PWM_Start  (&htim3, TIM_CHANNEL_1);
      }
    else
      return;
    }
}


//---Прерывание по переполнению счетчика--------------------------------------------------------------------------------------------
void HAL_TIM_PeriodElapsedCallback (TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM2)
    {
    HAL_TIM_PWM_Stop   (&htim3, TIM_CHANNEL_1);
    HAL_TIM_PWM_Stop   (&htim2, TIM_CHANNEL_1); // Выключение таймера. Таймер работал в режиме работы с формированием прерывания.
    HAL_TIM_PWM_Stop   (&htim2, TIM_CHANNEL_2); // Выключение таймера. Таймер работал в режиме работы с формированием прерывания.
    HAL_TIM_OC_Stop    (&htim2, TIM_CHANNEL_3); // Выключение таймера. Таймер работал в режиме работы с формированием прерывания.
    HAL_TIM_PWM_Stop   (&htim5, TIM_CHANNEL_1); // Выключение таймера. Таймер работал в режиме работы без формированием прерывания.
    __HAL_TIM_DISABLE_IT (&htim2, TIM_IT_UPDATE );
        
    TIM5->CCR1 = 3;
            
    HAL_TIM_PWM_Start  (&htim2, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start  (&htim2, TIM_CHANNEL_2);
    HAL_TIM_OC_Start_IT(&htim2, TIM_CHANNEL_3);
    HAL_TIM_PWM_Start  (&htim5, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start  (&htim3, TIM_CHANNEL_1);
    }
else return;
    
}

 

Начинаю отлаживать. Пробую сначала работу без второго обработчика прерывания. Вижу следующую картину

1932111311_(16_11.202013-39-07).thumb.jpg.df56ce09165d069b0b4c7f829b69cecb.jpg

 

Верхний сигнал это сигналы TIM3, нижний - сигналы TIM5. Видно два первых импульса, прерывание - когда все таймеры остановлены, и последующие импульсы с меньшим заполнением. Все как хотел. Дальше проверяю с двумя обработчиками прерываний. Устанавливаю точку остановки (break) во втором обработчике прерываний на строчке TIM5->CCR1 = 3. Ожидаю увидеть два первых импульса, прерывание и один импульс с меньшим заполнением.

Вижу следующее:

490570660_(16_11.202013-47-46).thumb.jpg.fc22068d694438757f78541f8d0f73d7.jpg

 

Два первых импульса есть, прерывание есть и тишина. Где один импульс с меньшим заполнением?

 

Ниже картина от начала времен без остановки:

517729376_(16_11.202013-50-29).thumb.jpg.f6f32c4d120352e5ba293651806738cb.jpg

 

Виден странный перепад на линии TIM3 и импульсы с изначальным заполнением.

 

Далее картина не лучше:

1163188954_(16_11.202013-55-17).thumb.jpg.9867b83b588123ab72a9073fa0c4e551.jpg

 

Предположение такое - по какой-то причине второе прерывание возникает сразу после выхода из первого, и короткий импульс не успевает сформироваться.

Подскажите в чем проблема?

Share this post


Link to post
Share on other sites

Уточнение: 

Первое прерывание возникает по TIM2 по совпадению регистра CNT со значением Pulse в STM32CubeMX. Pulse = 12-1 = 11. На осциллограммах видно что два первоначальных импульса формируются за 12 тактов, после чего формируется прерывание. Второе прерывание должно формироваться по переполнению TIM2. Для TIM2 Counter Period = 18-1 = 17.

 

Share this post


Link to post
Share on other sites
41 минуту назад, LAS9891 сказал:

Обработка прерываний такая:


void HAL_TIM_OC_DelayElapsedCallback (TIM_HandleTypeDef *htim)
{
...

 

С таким монстроидальным кодом хотите работать с частотами прерываний в 100...200 кГц??? Ну-ну... :unknw:

И какова же частота CPU, позвольте узнать?

Share this post


Link to post
Share on other sites
2 minutes ago, jcxz said:

И какова же частота CPU, позвольте узнать?

CPU clock 400 MHz

APB2 Timer Clocks 200 MHz

4 minutes ago, jcxz said:

С таким монстроидальным кодом хотите работать с частотами прерываний в 100 кГц??? Ну-ну... :unknw:

Сейчас бы выяснить где косяк в прерываниях

Share this post


Link to post
Share on other sites

И зачем вообще вся эта куча телодвижений по останову и запуску заново таймеров внутри ISR-ов? Обычно таймеры у всех семейств МК имеют возможность на ходу менять значения как регистров сравнения так и регистров периода. Читайте мануал на свой МК - там это описано. Ищите нечто про теневые регистры и как с ними работать.

 

PS: 400МГц - это конечно здОрово, но всё равно вызывает большие сомнения эта куча быдлокода из "библиотечных" вызовов внутри ISR. Да и на кой 400МГц, только для чтобы их все потом угробить на кучу ненужных операций на простейшей задаче??

Share this post


Link to post
Share on other sites
11 minutes ago, jcxz said:

И зачем вообще вся эта куча телодвижений по останову и запуску заново таймеров внутри ISR-ов? Обычно таймеры у всех семейств МК имеют возможность на ходу менять значения как регистров сравнения так и регистров периода. Читайте мануал на свой МК - там это описано. Ищите нечто про теневые регистры и как с ними работать.

Я в курсе. Меня интересует именно работа прерываний, останавливать таймеры или нет - детали. Правильные callback функции я выбрал? Правильно разрешил прерывания? Если - да, то почему работает не как как хотелось?

11 minutes ago, jcxz said:

Ищите нечто про теневые регистры и как с ними работать.

То о чем вы говорите устанавливается настройкой Output compare preload в значение Disable. При этом как только таймер получил новое значение для сравнения то сразу будет учитывать его. Кстати работоспособность этого можно увидеть на первой осциллограмме - переполнение ещё не наступило, новое значение для сравнение записано, и после прерывания видим импульс с измененным заполнением.

Edited by LAS9891

Share this post


Link to post
Share on other sites
1 hour ago, LAS9891 said:

TIM3 тактируется от внутреннего источника (от шины), работает в режиме ШИМ и формирует на выходе меандр с частотой 1,2 МГц.

TIM5 тактируется от TIM3, работает в режиме ШИМ.

TIM2 тактируется от TIM3, работает в режиме сравнения.

Написал такой код main.c:


  MX_GPIO_Init();
  MX_TIM3_Init();
  MX_TIM2_Init();
  MX_TIM5_Init();

  HAL_TIM_PWM_Start  (&htim2, TIM_CHANNEL_1);
  HAL_TIM_PWM_Start  (&htim2, TIM_CHANNEL_2);
  HAL_TIM_OC_Start_IT(&htim2, TIM_CHANNEL_3);
  HAL_TIM_PWM_Start  (&htim5, TIM_CHANNEL_1);
  HAL_TIM_PWM_Start  (&htim3, TIM_CHANNEL_1);

  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

 

Раз у вас TIM2 и TIM5 тактируются от TIM3, значит TIM3 должен инициализироваться в последнюю очередь, а не в первую как у вас.

 

Share this post


Link to post
Share on other sites
2 minutes ago, dimka76 said:

Раз у вас TIM2 и TIM5 тактируются от TIM3, значит TIM3 должен инициализироваться в последнюю очередь, а не в первую как у вас.

 

Учтемс. Хотя эту часть кода генерит STM32CubeMX и эту область предполагается не менять. 

Edited by LAS9891

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this