Jump to content
    

Скорость работы пина зависит от других пинов. Это нормально?

Привет, народ!

 

Заметил такую странность, которую не знаю как объяснить. Плата 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 by xintrea

Share this post


Link to post
Share on other sites

Сравните листинги функций msDelay для разных сборок. От того, как компилятор их реализует многое будет зависеть.

Share this post


Link to post
Share on other sites

16 minutes ago, adnega said:

Сравните листинги функций msDelay для разных сборок. От того, как компилятор их реализует многое будет зависеть.

Опции компиляции всех проектов у меня одинаковые. Оптимизация везде -Os и все.

Или хотите сказать, что в разном окружающем коде компилятор будет по-разному компилировать msDelay?

Share this post


Link to post
Share on other sites

21 минуту назад, xintrea сказал:

Опции компиляции всех проектов у меня одинаковые. Оптимизация везде -Os и все.

Или хотите сказать, что в разном окружающем коде компилятор будет по-разному компилировать msDelay?

Я другого объяснения придумать не могу, и это легко проверить.

Кста, про скорость, вроде -03, а -Os это про размер.

Share this post


Link to post
Share on other sites

 

1 hour ago, adnega said:

Сравните листинги функций msDelay для разных сборок. От того, как компилятор их реализует многое будет зависеть.

В общем, проверил. Функция msDelay() в обеих случаях закомпилилась одинаково, байт в байт:

 

2022-05-03-23-03-26.png

 

24 minutes ago, adnega said:

Кста, про скорость, вроде -03, а -Os это про размер.

Я же для микроконтроллера компилю, по дефолту оптимизация по размеру.

Edited by xintrea

Share this post


Link to post
Share on other sites

22 minutes ago, xintrea said:

Функция msDelay() в обеих случаях закомпилилась одинаково, байт в байт

Вот только адреса разные. Скорость выполнения зависит от смещения кода в 64 (или 128?) битном блоке.

Share this post


Link to post
Share on other sites

Проверяйте настройку тактовой системы. 

ф. int clockInit(void) даже возвращает ошибки, обработку которых я не увидел. Тем более на предельных режимах тактовой.

Неплохо было бы убедиться аппаратно, что тактовая реально установилась на 72MHz.

Возможно "играет рояль" то, что комментируемая строка вносит задержку после кода инициализации.

В цикле мигалки уменьшите или увеличьте значения задержек в 2 раза, проконтролируйте что частота мигания также увеличилась (уменьшилась) в 2 раза.

Используйте осциллограф на светодиоде, тк может оказаться, что "мигание" это ШИМ.

ps

1 hour ago, xintrea said:

. . .  Это тормозит разработку домашнего проекта, потому то в нем критична реакция на сигналы длительностью ~500нс, и тут я вижу, что тупой бесконечный цикл работает с разной скоростью в зависимости от инициализации неиспользуемых портов. . . .

Я конечно сильно извиняюсь, не мое это дело, но Вы собираетесь события с порядком "длительности" 500ns фиксировать методом опроса ?

Share this post


Link to post
Share on other sites

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 тактов останется на логику, а мне больше и не надо.

Share this post


Link to post
Share on other sites

6 минут назад, xintrea сказал:

Можете предложить другой метод?

А что за сигнал/обработка? Таймеры/FPGA/CPLD/рассыпуха ?

Share this post


Link to post
Share on other sites

8 часов назад, xintrea сказал:

Или хотите сказать, что в разном окружающем коде компилятор будет по-разному компилировать msDelay?

Учитесь использовать таймер для учёта и выдержки временных интервалов. Иначе всё время будете спотыкаться о такие "чудеса".

5 часов назад, xintrea сказал:

Можете предложить другой метод?

Пока не расскажете о решаемой задаче, никто ничего путного предложить не сможет.

Судя по вашему описанию - движетесь в неверном направлении.

Share this post


Link to post
Share on other sites

8 hours ago, xintrea said:

методом опроса можно ловить события

Лучше уж таймер настроить в режиме измерения длительности входного импульса. Запустил, через миллисекунду проверил. Если ноль - события не было...

А еще лучше - правильно сформулировать свою задачу. Возможно, ее можно решить простым способом.

Share this post


Link to post
Share on other sites

9 hours ago, xintrea said:

Где про обязательность задержки можно прочитать? Что-то в даташите не нашел таких ограничений.

Это не "обязательность", а симптом вашей проблемы. Все-таки, как с кодом результата работы ClockInit(), то  что в Вашей ссылке

// Настройка тактирование системы от внешнего кварца
// через PLL на максимально возможных частотах.
// Внешний кварц должен быть на 8МГц
// Возвращает:
//  0 - завершено успешно
//  1 - не запустился кварцевый генератор
//  2 - не запустился PLL
// Итоговая настройка делается на 72МГц
int ClockInit(void)

Если уж решать задачу "тупо и в лоб", залазите в otherPortInit() и блочно/построчно отлавливаете что влияет на "симптом".

То что "функция инициализации такаяже как здесь" не гарантирует, что она корректно работает.

На какой пин процессора подключен светодиод ? (проверить прозвонкой) д.б. на PC13 пин процессора 2.

Другой метод можно предложить, но для этого нужно, как писали выше, описание входных сигналов - а именно частота их возникновения и длительность. Ну, и количество линий. А использовать такой процессор в режиме опроса "негуманно". Ну, еслиб это был у вас 8-разрядный контроллер с 64 бит RAM и 256 байт программной памяти ... без прерываний .... без таймера ....  тогда может быть да, режим "опроса" со-скрипом подходит.

 

 

 

 

Share this post


Link to post
Share on other sites

18 hours ago, jcxz said:

Пока не расскажете о решаемой задаче, никто ничего путного предложить не сможет.

Я пытаюсь сделать эмулятор ПЗУ для клона Радио-86РК. Он подключается в разъем, на который выведена ША а ШД этого компьютера, и еще несколько системных сигналов.

Под подключаемые внешние модули (эмулятор ПЗУ-это и есть внешний модуль) в компьютере отведено адресное пространство 8000h-BFFFh (объем 16Кб). Задача эмулятора ПЗУ - держать пины ШД, к котором подключен контроллер STM, в высокоимпендансном состоянии, и следить за адресом на ША. Если адрес попадает в обслуживаемый эмулятором диапазон, и приходит сигнал на чтение, пины ШД переводятся в состояние выхода и на них выставляется нужный байт. Длительность сигнала на чтение - 500нс. Все.

14 hours ago, k155la3 said:

Ну, еслиб это был у вас 8-разрядный контроллер с 64 бит RAM и 256 байт программной памяти ... без прерываний .... без таймера ....  тогда может быть да, режим "опроса" со-скрипом подходит.

Такой контроллер не подойдет, одна только эмулируемая прошивка будет занимать 16Кб программной памяти.

Edited by xintrea

Share this post


Link to post
Share on other sites

Можно использовать двухпортовое ОЗУ (или гибрид SPI - параллельная шина). С одной стороны МК грузит прошивку (легко обновлять), с другой стороны ее вычитывает клон (минимальные аппаратные издержки).

Share this post


Link to post
Share on other sites

10 часов назад, xintrea сказал:

Задача эмулятора ПЗУ - держать пины ШД, к котором подключен контроллер STM, в высокоимпендансном состоянии, и следить за адресом на ША. Если адрес попадает в обслуживаемый эмулятором диапазон, и приходит сигнал на чтение, пины ШД переводятся в состояние выхода и на них выставляется нужный байт. Длительность сигнала на чтение - 500нс. Все.

Имхо: идея использовать для этого МК - не самая удачная. Почему простое параллельное ОЗУ/ППЗУ не использовать? Если нужно - совместно с МК (для управления).

У вас МК, во время такой эмуляции, больше ничего не будет успевать делать. Иначе пропустит такты обращения. Это если цикл делать. Можно попробовать сделать на DMA, но довольно сложно будет и не факт что получится.

 

Но даже если делать циклом, то всё равно: цикл с использованием сигналов прерываний должен быстрее работать, чем обычный цикл поллинга GPIO.

 

43 минуты назад, Edit2007 сказал:

Можно использовать двухпортовое ОЗУ

2-портовое не нужно. Ведь ТС не собирается на лету (во время эмуляции) прошивку обновлять? А значит: во время обновления отключаем РК86 от эмулятора (тем или иным способом, например - подачей сигнала HALT в системную шину РК86), подключаемся к шине своим МК и обновляем.

Так что подойдёт любое параллельное ОЗУ/FLASH/FRAM.

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.

×
×
  • Create New...