Перейти к содержанию
    

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

Пробую написать программу на 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

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Уточнение: 

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

41 минуту назад, LAS9891 сказал:

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


void HAL_TIM_OC_DelayElapsedCallback (TIM_HandleTypeDef *htim)
{
...

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 minutes ago, jcxz said:

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

CPU clock 400 MHz

APB2 Timer Clocks 200 MHz

4 minutes ago, jcxz said:

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

11 minutes ago, jcxz said:

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

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

11 minutes ago, jcxz said:

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

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

Изменено пользователем LAS9891

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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 должен инициализироваться в последнюю очередь, а не в первую как у вас.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 minutes ago, dimka76 said:

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

 

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

Изменено пользователем LAS9891

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...