xintrea 0 May 3 Posted May 3 (edited) · Report post Привет, народ! Заметил такую странность, которую не знаю как объяснить. Плата STM32F103C8T6 (Blue Pill) Я хотел сделать мигание светодиодом на ноге A0 при инициализации контроллера на 72MHz. Взял сделанный ранее проект и стал его упрощать. И вот когда оставил в проекте, по-сути, только: - инициализацию на 72Mhz - включение тактирования портов - настройку пина A0, то заметил, что код мигания стал работать медленнее! Т. е. мигание, сделанное в бесконечном цикле, стало в 1.5-2 раза медленнее, чем было до. Я стал разбираться, что могло на это повлиять. И вернул вызов ненужной функции, в которой инициализировались пины A8, A9, B3, B4, B6, B7. И о чудо, мигание стало опять быстрым! Повторюсь, в этой функции делается только инициализация пинов, и она вызывается один раз в начале программы, ничего более. Вот полный код: https://pastebin.com/Z7d0LZif А вот код функции, которая "разгоняет" выполнение кода: // Настройка пинов A8, A9, B3, B4, B6, B7 void otherPortInit(void) { // Для начала сброс конфигурации всех используемых портов в ноль GPIOA->CRH &= ~(GPIO_CRH_MODE8 | GPIO_CRH_CNF8); GPIOA->CRH &= ~(GPIO_CRH_MODE9 | GPIO_CRH_CNF9); GPIOB->CRL &= ~(GPIO_CRL_MODE3 | GPIO_CRL_CNF3); GPIOB->CRL &= ~(GPIO_CRL_MODE4 | GPIO_CRL_CNF4); GPIOB->CRL &= ~(GPIO_CRL_MODE6 | GPIO_CRL_CNF6); GPIOB->CRL &= ~(GPIO_CRL_MODE7 | GPIO_CRL_CNF7); uint32_t mode; uint32_t cnf; mode=0b11; // Режим выхода, с максимальной частотой 50 МГц cnf=0b00; // Режим push-pull GPIOA->CRH |= (mode << GPIO_CRH_MODE8_Pos) | (cnf << GPIO_CRH_CNF8_Pos); GPIOA->CRH |= (mode << GPIO_CRH_MODE9_Pos) | (cnf << GPIO_CRH_CNF9_Pos); mode=0b00; // Режим входа cnf=0b01; // Режим плавающего входа, подтяжки нет GPIOB->CRL |= (mode << GPIO_CRL_MODE3_Pos) | (cnf << GPIO_CRL_CNF3_Pos); GPIOB->CRL |= (mode << GPIO_CRL_MODE4_Pos) | (cnf << GPIO_CRL_CNF4_Pos); GPIOB->CRL |= (mode << GPIO_CRL_MODE6_Pos) | (cnf << GPIO_CRL_CNF6_Pos); GPIOB->CRL |= (mode << GPIO_CRL_MODE7_Pos) | (cnf << GPIO_CRL_CNF7_Pos); } Я не могу эту вещь объяснить. Почему настройки пинов, которые не используются в коде, так странно влияют на скорость выполнения программы контроллером? Мало того, в базовом проекте, на точно таком же коде я обнаружил обратный эффект: вызов этой функции инициализации портов замедляет мигание, а комментирование ее вызова - ускоряет. В общем, я в недоумении. Я вообще не ожидал, что такое поведение возможно. Это тормозит разработку домашнего проекта, потому то в нем критична реакция на сигналы длительностью ~500нс, и тут я вижу, что тупой бесконечный цикл работает с разной скоростью в зависимости от инициализации неиспользуемых портов. Вопрос 1: Как единственный вызов этой функции может влиять на скорость выполнения основного цикла? Вопрос 2: Почему вызов этой функции может давать строго обратный эффект? Edited May 3 by xintrea Quote Share this post Link to post Share on other sites More sharing options...
adnega 2 May 3 Posted May 3 · Report post Сравните листинги функций msDelay для разных сборок. От того, как компилятор их реализует многое будет зависеть. Quote Share this post Link to post Share on other sites More sharing options...
xintrea 0 May 3 Posted May 3 · Report post 16 minutes ago, adnega said: Сравните листинги функций msDelay для разных сборок. От того, как компилятор их реализует многое будет зависеть. Опции компиляции всех проектов у меня одинаковые. Оптимизация везде -Os и все. Или хотите сказать, что в разном окружающем коде компилятор будет по-разному компилировать msDelay? Quote Share this post Link to post Share on other sites More sharing options...
adnega 2 May 3 Posted May 3 · Report post 21 минуту назад, xintrea сказал: Опции компиляции всех проектов у меня одинаковые. Оптимизация везде -Os и все. Или хотите сказать, что в разном окружающем коде компилятор будет по-разному компилировать msDelay? Я другого объяснения придумать не могу, и это легко проверить. Кста, про скорость, вроде -03, а -Os это про размер. Quote Share this post Link to post Share on other sites More sharing options...
xintrea 0 May 3 Posted May 3 (edited) · Report post 1 hour ago, adnega said: Сравните листинги функций msDelay для разных сборок. От того, как компилятор их реализует многое будет зависеть. В общем, проверил. Функция msDelay() в обеих случаях закомпилилась одинаково, байт в байт: 24 minutes ago, adnega said: Кста, про скорость, вроде -03, а -Os это про размер. Я же для микроконтроллера компилю, по дефолту оптимизация по размеру. Edited May 3 by xintrea Quote Share this post Link to post Share on other sites More sharing options...
aaarrr 3 May 3 Posted May 3 · Report post 22 minutes ago, xintrea said: Функция msDelay() в обеих случаях закомпилилась одинаково, байт в байт Вот только адреса разные. Скорость выполнения зависит от смещения кода в 64 (или 128?) битном блоке. Quote Share this post Link to post Share on other sites More sharing options...
k155la3 3 May 3 Posted May 3 · Report post Проверяйте настройку тактовой системы. ф. int clockInit(void) даже возвращает ошибки, обработку которых я не увидел. Тем более на предельных режимах тактовой. Неплохо было бы убедиться аппаратно, что тактовая реально установилась на 72MHz. Возможно "играет рояль" то, что комментируемая строка вносит задержку после кода инициализации. В цикле мигалки уменьшите или увеличьте значения задержек в 2 раза, проконтролируйте что частота мигания также увеличилась (уменьшилась) в 2 раза. Используйте осциллограф на светодиоде, тк может оказаться, что "мигание" это ШИМ. ps 1 hour ago, xintrea said: . . . Это тормозит разработку домашнего проекта, потому то в нем критична реакция на сигналы длительностью ~500нс, и тут я вижу, что тупой бесконечный цикл работает с разной скоростью в зависимости от инициализации неиспользуемых портов. . . . Я конечно сильно извиняюсь, не мое это дело, но Вы собираетесь события с порядком "длительности" 500ns фиксировать методом опроса ? Quote Share this post Link to post Share on other sites More sharing options...
xintrea 0 May 3 Posted May 3 · Report post 48 minutes ago, k155la3 said: Проверяйте настройку тактовой системы. ф. int clockInit(void) даже возвращает ошибки, обработку которых я не увидел. Тем более на предельных режимах тактовой. Неплохо было бы убедиться аппаратно, что тактовая реально установилась на 72MHz. Да, там реально 72MHz устанавливается. Функция инициализации такая же как и здесь: https://webhamster.ru/mytetrashare/index/mtb0/1649356037vhemuctihu и на ноге 12 в этом коде реально 60нс на осциллографе видно. 48 minutes ago, k155la3 said: Возможно "играет рояль" то, что комментируемая строка вносит задержку после кода инициализации. Где про обязательность задержки можно прочитать? Что-то в даташите не нашел таких ограничений. 48 minutes ago, k155la3 said: В цикле мигалки уменьшите или увеличьте значения задержек в 2 раза, проконтролируйте что частота мигания также увеличилась (уменьшилась) в 2 раза. Да, частота видимых миганий изменяется в двое. 48 minutes ago, k155la3 said: Используйте осциллограф на светодиоде, тк может оказаться, что "мигание" это ШИМ. Ну какой ШИМ, там же просто включется-выключется нога с задержкой. 48 minutes ago, k155la3 said: Я конечно сильно извиняюсь, не мое это дело, но Вы собираетесь события с порядком "длительности" 500ns фиксировать методом опроса ? Можете предложить другой метод? На таком оборудовании через прерывания ловить события не получится, потому что только на вход в прерывание больше 500нс уходит. Если приплюсовать сюда выход и задержку прохода сигнала прерывания, то получится что с прирываниями работать вообще не вариант. А методом опроса можно ловить события, и еще 15-25 тактов останется на логику, а мне больше и не надо. Quote Share this post Link to post Share on other sites More sharing options...
adnega 2 May 3 Posted May 3 · Report post 6 минут назад, xintrea сказал: Можете предложить другой метод? А что за сигнал/обработка? Таймеры/FPGA/CPLD/рассыпуха ? Quote Share this post Link to post Share on other sites More sharing options...
jcxz 7 May 4 Posted May 4 · Report post 8 часов назад, xintrea сказал: Или хотите сказать, что в разном окружающем коде компилятор будет по-разному компилировать msDelay? Учитесь использовать таймер для учёта и выдержки временных интервалов. Иначе всё время будете спотыкаться о такие "чудеса". 5 часов назад, xintrea сказал: Можете предложить другой метод? Пока не расскажете о решаемой задаче, никто ничего путного предложить не сможет. Судя по вашему описанию - движетесь в неверном направлении. Quote Share this post Link to post Share on other sites More sharing options...
Eddy_Em 1 May 4 Posted May 4 · Report post 8 hours ago, xintrea said: методом опроса можно ловить события Лучше уж таймер настроить в режиме измерения длительности входного импульса. Запустил, через миллисекунду проверил. Если ноль - события не было... А еще лучше - правильно сформулировать свою задачу. Возможно, ее можно решить простым способом. Quote Share this post Link to post Share on other sites More sharing options...
k155la3 3 May 4 Posted May 4 · Report post 9 hours ago, xintrea said: Где про обязательность задержки можно прочитать? Что-то в даташите не нашел таких ограничений. Это не "обязательность", а симптом вашей проблемы. Все-таки, как с кодом результата работы ClockInit(), то что в Вашей ссылке // Настройка тактирование системы от внешнего кварца // через PLL на максимально возможных частотах. // Внешний кварц должен быть на 8МГц // Возвращает: // 0 - завершено успешно // 1 - не запустился кварцевый генератор // 2 - не запустился PLL // Итоговая настройка делается на 72МГц int ClockInit(void) Если уж решать задачу "тупо и в лоб", залазите в otherPortInit() и блочно/построчно отлавливаете что влияет на "симптом". То что "функция инициализации такаяже как здесь" не гарантирует, что она корректно работает. На какой пин процессора подключен светодиод ? (проверить прозвонкой) д.б. на PC13 пин процессора 2. Другой метод можно предложить, но для этого нужно, как писали выше, описание входных сигналов - а именно частота их возникновения и длительность. Ну, и количество линий. А использовать такой процессор в режиме опроса "негуманно". Ну, еслиб это был у вас 8-разрядный контроллер с 64 бит RAM и 256 байт программной памяти ... без прерываний .... без таймера .... тогда может быть да, режим "опроса" со-скрипом подходит. Quote Share this post Link to post Share on other sites More sharing options...
xintrea 0 May 4 Posted May 4 (edited) · Report post 18 hours ago, jcxz said: Пока не расскажете о решаемой задаче, никто ничего путного предложить не сможет. Я пытаюсь сделать эмулятор ПЗУ для клона Радио-86РК. Он подключается в разъем, на который выведена ША а ШД этого компьютера, и еще несколько системных сигналов. Под подключаемые внешние модули (эмулятор ПЗУ-это и есть внешний модуль) в компьютере отведено адресное пространство 8000h-BFFFh (объем 16Кб). Задача эмулятора ПЗУ - держать пины ШД, к котором подключен контроллер STM, в высокоимпендансном состоянии, и следить за адресом на ША. Если адрес попадает в обслуживаемый эмулятором диапазон, и приходит сигнал на чтение, пины ШД переводятся в состояние выхода и на них выставляется нужный байт. Длительность сигнала на чтение - 500нс. Все. 14 hours ago, k155la3 said: Ну, еслиб это был у вас 8-разрядный контроллер с 64 бит RAM и 256 байт программной памяти ... без прерываний .... без таймера .... тогда может быть да, режим "опроса" со-скрипом подходит. Такой контроллер не подойдет, одна только эмулируемая прошивка будет занимать 16Кб программной памяти. Edited May 4 by xintrea Quote Share this post Link to post Share on other sites More sharing options...
Edit2007 0 May 5 Posted May 5 · Report post Можно использовать двухпортовое ОЗУ (или гибрид SPI - параллельная шина). С одной стороны МК грузит прошивку (легко обновлять), с другой стороны ее вычитывает клон (минимальные аппаратные издержки). Quote Share this post Link to post Share on other sites More sharing options...
jcxz 7 May 5 Posted May 5 · Report post 10 часов назад, xintrea сказал: Задача эмулятора ПЗУ - держать пины ШД, к котором подключен контроллер STM, в высокоимпендансном состоянии, и следить за адресом на ША. Если адрес попадает в обслуживаемый эмулятором диапазон, и приходит сигнал на чтение, пины ШД переводятся в состояние выхода и на них выставляется нужный байт. Длительность сигнала на чтение - 500нс. Все. Имхо: идея использовать для этого МК - не самая удачная. Почему простое параллельное ОЗУ/ППЗУ не использовать? Если нужно - совместно с МК (для управления). У вас МК, во время такой эмуляции, больше ничего не будет успевать делать. Иначе пропустит такты обращения. Это если цикл делать. Можно попробовать сделать на DMA, но довольно сложно будет и не факт что получится. Но даже если делать циклом, то всё равно: цикл с использованием сигналов прерываний должен быстрее работать, чем обычный цикл поллинга GPIO. 43 минуты назад, Edit2007 сказал: Можно использовать двухпортовое ОЗУ 2-портовое не нужно. Ведь ТС не собирается на лету (во время эмуляции) прошивку обновлять? А значит: во время обновления отключаем РК86 от эмулятора (тем или иным способом, например - подачей сигнала HALT в системную шину РК86), подключаемся к шине своим МК и обновляем. Так что подойдёт любое параллельное ОЗУ/FLASH/FRAM. Quote Share this post Link to post Share on other sites More sharing options...