LAS9891 0 16 ноября, 2020 Опубликовано 16 ноября, 2020 · Жалоба Пробую написать программу на 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; } Начинаю отлаживать. Пробую сначала работу без второго обработчика прерывания. Вижу следующую картину Верхний сигнал это сигналы TIM3, нижний - сигналы TIM5. Видно два первых импульса, прерывание - когда все таймеры остановлены, и последующие импульсы с меньшим заполнением. Все как хотел. Дальше проверяю с двумя обработчиками прерываний. Устанавливаю точку остановки (break) во втором обработчике прерываний на строчке TIM5->CCR1 = 3. Ожидаю увидеть два первых импульса, прерывание и один импульс с меньшим заполнением. Вижу следующее: Два первых импульса есть, прерывание есть и тишина. Где один импульс с меньшим заполнением? Ниже картина от начала времен без остановки: Виден странный перепад на линии TIM3 и импульсы с изначальным заполнением. Далее картина не лучше: Предположение такое - по какой-то причине второе прерывание возникает сразу после выхода из первого, и короткий импульс не успевает сформироваться. Подскажите в чем проблема? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
LAS9891 0 16 ноября, 2020 Опубликовано 16 ноября, 2020 · Жалоба Уточнение: Первое прерывание возникает по TIM2 по совпадению регистра CNT со значением Pulse в STM32CubeMX. Pulse = 12-1 = 11. На осциллограммах видно что два первоначальных импульса формируются за 12 тактов, после чего формируется прерывание. Второе прерывание должно формироваться по переполнению TIM2. Для TIM2 Counter Period = 18-1 = 17. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 16 ноября, 2020 Опубликовано 16 ноября, 2020 · Жалоба 41 минуту назад, LAS9891 сказал: Обработка прерываний такая: void HAL_TIM_OC_DelayElapsedCallback (TIM_HandleTypeDef *htim) { ... С таким монстроидальным кодом хотите работать с частотами прерываний в 100...200 кГц??? Ну-ну... И какова же частота CPU, позвольте узнать? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
LAS9891 0 16 ноября, 2020 Опубликовано 16 ноября, 2020 · Жалоба 2 minutes ago, jcxz said: И какова же частота CPU, позвольте узнать? CPU clock 400 MHz APB2 Timer Clocks 200 MHz 4 minutes ago, jcxz said: С таким монстроидальным кодом хотите работать с частотами прерываний в 100 кГц??? Ну-ну... Сейчас бы выяснить где косяк в прерываниях Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 16 ноября, 2020 Опубликовано 16 ноября, 2020 · Жалоба И зачем вообще вся эта куча телодвижений по останову и запуску заново таймеров внутри ISR-ов? Обычно таймеры у всех семейств МК имеют возможность на ходу менять значения как регистров сравнения так и регистров периода. Читайте мануал на свой МК - там это описано. Ищите нечто про теневые регистры и как с ними работать. PS: 400МГц - это конечно здОрово, но всё равно вызывает большие сомнения эта куча быдлокода из "библиотечных" вызовов внутри ISR. Да и на кой 400МГц, только для чтобы их все потом угробить на кучу ненужных операций на простейшей задаче?? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
LAS9891 0 16 ноября, 2020 Опубликовано 16 ноября, 2020 (изменено) · Жалоба 11 minutes ago, jcxz said: И зачем вообще вся эта куча телодвижений по останову и запуску заново таймеров внутри ISR-ов? Обычно таймеры у всех семейств МК имеют возможность на ходу менять значения как регистров сравнения так и регистров периода. Читайте мануал на свой МК - там это описано. Ищите нечто про теневые регистры и как с ними работать. Я в курсе. Меня интересует именно работа прерываний, останавливать таймеры или нет - детали. Правильные callback функции я выбрал? Правильно разрешил прерывания? Если - да, то почему работает не как как хотелось? 11 minutes ago, jcxz said: Ищите нечто про теневые регистры и как с ними работать. То о чем вы говорите устанавливается настройкой Output compare preload в значение Disable. При этом как только таймер получил новое значение для сравнения то сразу будет учитывать его. Кстати работоспособность этого можно увидеть на первой осциллограмме - переполнение ещё не наступило, новое значение для сравнение записано, и после прерывания видим импульс с измененным заполнением. Изменено 16 ноября, 2020 пользователем LAS9891 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dimka76 42 16 ноября, 2020 Опубликовано 16 ноября, 2020 · Жалоба 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 должен инициализироваться в последнюю очередь, а не в первую как у вас. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
LAS9891 0 16 ноября, 2020 Опубликовано 16 ноября, 2020 (изменено) · Жалоба 2 minutes ago, dimka76 said: Раз у вас TIM2 и TIM5 тактируются от TIM3, значит TIM3 должен инициализироваться в последнюю очередь, а не в первую как у вас. Учтемс. Хотя эту часть кода генерит STM32CubeMX и эту область предполагается не менять. Изменено 16 ноября, 2020 пользователем LAS9891 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться