stm32f103 непонятки с таймером
- Войдите на сайт для отправки комментариев
Чт, 30/05/2019 - 01:04
Использую следующий скетч:
#define pin_sync (*((volatile unsigned long *) 0x422181A4 )) // PB9 void startHS() { // начало импульса HS, переводится из высокого состояния в низкое pin_sync = 0; } void endHS() { // конец импульса HS pin_sync = 1; } void screenInit() { GPIOB_BASE->CRL = 0xb4444444; // PB7 - альтернативный выход, остальные - вход (не исп.) GPIOB_BASE->CRH = 0x44444434; // PB9 - выход, остальные - вход (не исп.) TIMER4_BASE->CR1 = 0x80; // выключаем таймер TIMER4_BASE->PSC = 0; TIMER4_BASE->CCER = 0x0033; // устанавливаем только 1 и 2 каналы, причем, с инверсией TIMER4_BASE->CCR1 = 1; // 1 - точка отсчета, условный 0, - начало импульса вертикальной синхронизации Timer4.attachCompare1Interrupt(startHS); // начало HS Timer4.attachCompare2Interrupt(endHS); // конец HS TIMER4_BASE->CCR2 = 119; // длительность отрицательного полупериода TIMER4_BASE->ARR = 239; // длительность всего периода TIMER4_BASE->CNT = 0; TIMER4_BASE->CR1 = 0x81; // запускаем таймер } void setup() { screenInit(); } void loop() {}
Пояснения: на пине PB7 аппаратно генерируется отрицательный импульс, на пине PB9 программно в прерываниях генерируется отрицательный импульс.
Осциллограмма (голубой - PB7, желтый - PB9):
Теперь, собственно, два вопроса:
1. Почему на PB7 "0" существенно выше, чем на PB9 и достигает почти одного вольта?
2. Почему запаздывание "программного" импульса относительно аппаратного составляет более мкс, т.е. порядка 80 тактов, тогда как по документации должно быть где-то 12+2 - 12+4?
Насчет уровня 0 - непонятно. Может где подтягивающие резисторы с относительно малым сопротивлением стоят?
А запаздывание - можно посмотреть в какой ассемблерный код все это оттранслировалось? Может там в обработчике прерывания преамбула длинная? Например запихивается куча всего в стек для сохранения состояния.
Что происходит с уровнем когда на PB7 выдается сигнал прямого программного импульса? Пока только одна идея - плохо пропаянная нога. Но это в качестве бреда.
проца не знаю, но смею предположить, что проблема эта вытекает из-за разделения пина PB7 на USART
На WAVGAT имеем именно эту проблему, где-то озвучивал здесь и приводил осциллограммы
andriano, проверил -у меня одинаковые уровни :) По второму вопросу скорее всего да, от входа в __irq_tim4 до выполнения Start_Hs проходит много всяких разных команд и проверок.. Как вариант написать обработчик самостоятельно :)
Стало любопытно, сам попробывал. Всё равно дельта 600nS получается -многовато однако, копаться в портянках генерируемого асм-кода тяжеловато :(
копаться в портянках генерируемого асм-кода тяжеловато :(
А надо бы... иначе - ни о чём... И второе... Зависит от задачи... от желаемого... а то - замутить хардварно и не мучаться...
Поменял местами вывод от таймера и от прерываний: высокое напряжение нуля по прежнему на PB7, следовательно, это аппаратный дефект.
Листинг процедур прерываний такой (вариант после "поменял местами")
вроде ничего лишнего.
Добавил в loop() меандр:
при этом оказалось, что при выбранной частоте прерываний (300 кГц) практически все время камень проводит в прерываниях - частота программно сгенеренного сигнала составила всего 50 кГц, т.е. лишь один проход цикла за 6 прерываний. Уменьшил частоту прерываний до 100 кГц и получил следующее:
внизу - аппаратный таймер, в середине - через прерывания, а вверху - программно сгенеренный в loop() сигнал.
Собственно, видно, что в программно сгенеренном сигнале (примерно 1 МГц) происходят выпадения длительностью по 2 мкс на каждое прерывание (т.е. выпадение происходит вокруг передних и задних фронтов, формируемых прерываниями).
В общем, непонятно, что делает камень 2 мкс (более 140 тактов) в прерывании, состоящем из четырех строчек.
PS. dimax, спасибо: совсем уже было запутался, как взаимодействует таймер и прерывания, но твой код многое для меня прояснил.
Оказывеается, непонятки не ушли - при попытке откомпилировать скетч из сообщения №5:
попытки удалить "С" либо заменить на "С++" приводят к тому, что скетч компилируется, но прерывание не вызывается.
На всякий случай:
У меня стоит 2 ядра под stm32 - одно под блюпилл - под неё не компилится, a ошибки: GPIOB_BASE->CRL = 0xb4444444; error: base operand of '->' is not a pointer ... второе Generic stm32f103c series - под него компилится нормально : Скетч использует 15100 байт (23%) памяти устройства. Всего доступно 65536 байт. Глобальные переменные используют 3088 байт (15%) динамической памяти, оставляя 17392 байт для локальных переменных. Максимум: 20480 байт.
У меня как раз джинерик...
Сейчас попытался на другом компьютере - там, вроде, все то же, только версия AVR 1.6.20. Там откомпилировалось. Теперь надо чесать репу, как перенести все это поближе к осциллографу.
Но, в принципе, раз понятно, что дело в версиях, значит, известно, куда копать.
andriano, подозреваю, что из-за старого IDE (у меня IDE -1.8.9 , SAM Boards 1.6.12 , аддон stm32 -текущий последний.)
Пересчитал свои 600nS в такты -примерно 43, в принципе уже не кажется так чудовищно много. Как минимум 12 тактов забирает NVIC. Осталось понять чем занимается МК ещё 30 тактов, хорошо бы попробывать в кейле, а то к ардуино нет доверия :)
nik182, а какая дельта между фронтами получилась?
Осцилографа пока нет. Через пару дней смогу точно сказать. Я в ИАРе по тактам ядра прерывание смотрел.
nik182, или кинь *.bin, я посмотрю :)
https://cloud.mail.ru/public/x3TR/5iCn2gZLb
По ссылке текст и бинарник. Ноги B6 и B7 выходы первого и второго каналов. В8 программный, В9 меандр из цикла main. Если нужен другой формат - скажи какой. После включения на блюпиле должен загораться диод. У меня получилось меньше 100 наносек.
nick182, к сожалению не получилось залить :( Утилита заливки stlink_cli ругается:
This file type is not supported!
Supported file type are bin, hex, s19 and srec.
Unable to open file!
Смена расширения на bin не помогла. Бутлоадер заливает без ругани, но на выходах ничего нет.
https://cloud.mail.ru/public/51iC/2nGPdtW6P
Этот залился через st-link utility. На моём допотопном С-94 после танцев с внешним запуском сдвиг получился 610 нс. Тоже самое.
Прерывание превратилось в 48 тактов процессора. Без очистки бита прерывания нельзя никак.
Ну его же можно очистить уже после инверсии пина, как бы тоже сокращает время. Вот если бы не было изначальной проверки флага, то тогда бы пришлось тулить барьер или НОПы, а так - сброс флага можно опустить и вниз не боясь.
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka16366.html
Всё может быть в этой жизни. Советуют перенести программу прерывания в RAM, что бы такты задержки чтения флэш на суммировать во время реакции.
И косвенное подтверждение http://we.easyelectronics.ru/STM32/vypolnenie-koda-iz-ozu-v-iar.html
При переводе в RAM крутится быстрее, хотя клок 24МГц. У нас 72.
100 ns это что? Со второй попытки заливка удалась. Снял картинку анализатором.
В общем всё тоже самое. Дырки на сигнале B9 судя по картинке вызваны прерыванием . Просто любопытно, как узнать чем всё таки занимается МК от флажка события таймера до начала импульса в прерывании. Такое ощущение, что ничем, просто стоит и чего-то ждёт :)
Дырки на сигнале B9 судя по картинке вызваны прерыванием . Просто любопытно, как узнать чем всё таки занимается МК от флажка события таймера до начала импульса в прерывании.
Да ничем... ядро то одно... И в доках же всё конкретно расписано... сброс конвейера, вход в прерывание, сохранение контента, выполнение тела прерывания, возврат контента, выход из прерывания... И что такое 1000ns... 72 такта всего... Там только на контенте 12+12=24 такта, как минимум, теряется... остаётся - меньше 48 тактов... И это если нет других более приоритетных прерываний... ДМА и пр. ...
Хотите быстрее... придётся осваивать хардварные решения...