Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

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

Вт май 03, 2022 21:47:08

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

Заметил такую странность, которую не знаю как объяснить. Плата 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: Почему вызов этой функции может давать строго обратный эффект?

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

Ср май 04, 2022 05:22:36

Открываем листинг и смотрим. Чудес не бывает.

PS: И не скорость работы пина у вас зависит, а результат работы кода в целом.

PPS: Для генерации и измерения временных интервалов в контролере есть развитая система таймеров. Без них у вас всё будет от фазы луны зависеть.

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

Ср май 04, 2022 05:50:33

Как написали, так оно и работает.
Ну и msDelay вовсе не в миллисекундах считает. Она считает просто в величинах, пропорциональных числу тактов на выполнение этой ф-ции. Счет до 1000 на 72 МГц пролетает очень быстро, а вы наблюдаете просто визуальный строб-эффект.

"Режим выхода, с максимальной частотой 50 МГц" - это просто формирователь крутизны фронтов.

И для F1 издревле конфиг портов пишется в виде
GPIOA->CRL = (GPIOA->CRL & ~(GPIO_CRL_CNF0 | GPIO_CRL_CNF1)) | GPIO_CRL_MODE0 | GPIO_CRL_MODE1;
то есть в одном месте. Хотя тут каждый выдумывает свою идеологию, как ему кажется, более удобную. Кто-то вообще наворачивает тонны портянок, кто-то прям цифрами пишет, посчитав на калькуляторе. Но самое важное - банально не ошибиться.

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

Ср май 04, 2022 07:34:32

Посмотрел листинг на соседнем форуме. Разница только в расположении кода в памяти. Выравнивание одинаковое, выполняться должно с одинаковой скоростью.

Я бы для начала вывел тактовую частоту процессора на MCO и сравнил. По листингу цикл с nop выполняется на глаз около 12 тактов. Плюс/минус. 1 мс там может быть разве что на тактовой 8 МГц.

Добавлено after 27 minutes 17 seconds:
Re: Скорость работы пина зависит от других пинов. Это нормально?
Небольшое замечание по коду - не надо просто так от души разбрасываться volatile (_IO тоже). Это не бесплатная опция. Взять хотя бы вашу функцию задержки. Там директива asm сама по себе volatile и оптимизатор цикл с ней никогда не выкинет. Делать ещё и счётчик volatile не надо. Посмотрите в листинге разницу

Спойлер
Код:
//void msDelay(int ms)
//{
_Z7msDelayi:
        SUB      SP,SP,#+4     
//  while (ms-- > 0) {
??msDelay_0:
        SUBS     R0,R0,#+1     
        BLT.N    ??msDelay_1   
//  volatile int x=500;
        MOV      R1,#+500       
        STR      R1,[SP, #+0]   
//  while (x-- > 0)
??msDelay_2:
        LDR      R1,[SP, #+0]   
        SUBS     R2,R1,#+1     
        STR      R2,[SP, #+0]   
        BLT.N    ??msDelay_0   
//    __asm("nop");
        nop
        B.N      ??msDelay_2   
//  }
//}
??msDelay_1:
        ADD      SP,SP,#+4     
        BX       LR     


//void msDelay(int ms)
//{
//  while (ms-- > 0) {
_Z7msDelayi:
??msDelay_0:
        SUBS     R0,R0,#+1     
        BLT.N    ??msDelay_1   
//    int x=500;
        MOV      R1,#+500       
//    while (x-- > 0)
??msDelay_2:
        SUBS     R1,R1,#+1     
        BLT.N    ??msDelay_0   
//    __asm("nop");
        nop
        B.N      ??msDelay_2   
//  }
//}
??msDelay_1:
        BX       LR


ЗЫ: Замечания по коду снимаются, он скопипизженый полностью.

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

Чт май 05, 2022 01:04:59

Посмотрел листинг на соседнем форуме. Разница только в расположении кода в памяти. Выравнивание одинаковое, выполняться должно с одинаковой скоростью.


Видимо, выравнивание таки было неодинаковым.

Вот здесь разбор полетов: https://www.linux.org.ru/forum/development/16860172

Вроде как в теории если msDelay() выровнять на 8, то должно работать быстро. На деле оказалось что быстро работает при выравнивании 32 или при перемещении кода функции с FLASH на ОЗУ.

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

Чт май 05, 2022 16:33:11

Вроде как в теории если msDelay() выровнять на 8, то должно работать быстро. На деле оказалось что быстро работает при выравнивании 32 или при перемещении кода функции с FLASH на ОЗУ.
Пока не освоите таймеры, то так и дальше у вас всё будет работать - в зависимости от фазы луны. :dont_know:
Ответить