Как правильно реализовать задержку после включения периферийных часов RCC?

Я новичок в микроконтроллерах STM32. Я хотел бы знать, как правильно реализовать задержку в 2 такта после включения периферийных часов RCC.

Раздел 5.2.16 (стр. № 134) https://www.st.com/resource/en/reference_manual/rm0454-stm32g0x0-advanced-armbased-32bit-mcus-stmicroelectronics.pdf

Бит разрешения имеет механизм синхронизации, позволяющий создать тактовую частоту без сбоев для периферийного устройства. После установки бита разрешения существует задержка в 2 тактовых цикла, прежде чем тактовый сигнал станет активным, что программное обеспечение должно учитывать.

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

https://github.com/lab11/stm32l0-base/blob/master/sdk/STM32Cube_FW_LO_V1.5.0/Drivers/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_rcc.c >

Ограничения RCC##### раздел комментариев.

Эта задержка зависит от отображения периферии. Если периферийное устройство подключено к AHB: задержка составляет 2 тактовых цикла AHB. после установки бита разрешения часов в аппаратном регистре Если периферийное устройство сопоставлено с APB: задержка составляет 2 тактовых цикла APB. после установки бита разрешения часов в аппаратном регистре

Я рассматривал пару примеров. В первом примере регистр включения тактовой частоты периферийных устройств RCC считывается обратно.

RCC->AHB1ENR |= (1 << RCC_AHB1ENR_GPIOAEN_Pos);
  
// do two dummy reads after enabling the peripheral clock, as per the errata
volatile uint32_t dummy;
dummy = RCC->AHB1ENR;
dummy = RCC->AHB1ENR;

Во втором примере регистр периферии считывается обратно.

void clock_wait_bus_cycles(enum bus_type bus, uint32_t cycles)
{
    volatile uint32_t unused __attribute__((unused));
    if (bus == BUS_AHB) {
        while (cycles--)
            unused = STM32_DMA1_REGS->isr;
    } else { /* APB */
        while (cycles--)
            unused = STM32_USART_BRR(STM32_USART1_BASE);
    }
}

Какой из подходов правильный?

что ты пытаешься здесь сделать? у шины есть синхронизация, а у периферийного устройства есть синхронизация, и вы можете изменить делитель тактовой частоты шины вниз от системной тактовой частоты. периферийное время — это периферийное время, в течение которого логика занимает некоторое количество тактов, в идеале 1, но не гарантировано, на каждый регистр или задачу и т. д.

old_timer 06.07.2024 19:23

подсчет таких циклов отчасти аналогичен использованию счетчика для мигания. значение вашего счетчика будет меняться просто в зависимости от написанного вами кода и того, что с ним делает компилятор, вы можете изменить код даже не в этом файле и перекомпилировать, и это может резко изменить счетчики, которые вы получаете за некоторую единицу времени, а затем насколько точно вы измеряете свое время, а это еще одна причина, по которой люди допускают ошибки измерения. Будет сложно получить числа, которые имеют какой-либо смысл.

old_timer 06.07.2024 19:25

затем в вашем первом заявлении спрашивается, как сделать задержку. кроме начального приветствия, мир, мигает светодиодом, что вы можете просто сделать с помощью счетчика, больше ничего не нужно трогать. и вы вручную настраиваете это и ожидаете, что оно изменится, когда вы измените код в проекте. Если вам нужна какая-либо точность, вам придется использовать таймер. это не PIC и не что-то еще, где можно считать циклы путем подсчета инструкций.

old_timer 06.07.2024 19:27

поэтому, не зная, что вы спрашиваете, «правильно реализовать задержку» означает, что мы используем таймер, вам не нужно использовать прерывание, прерывания создают свои собственные проблемы. поэтому опрос или прерывание и другие ответы зависят от проблемы, которую вы преследуете.

old_timer 06.07.2024 19:29

Привет, я имею в виду раздел 5.2.16 (страница № 134) st.com/resource/en/reference_manual/…

user2953113 06.07.2024 19:46

Здесь он предупреждает: бит разрешения имеет механизм синхронизации, позволяющий создать тактовую частоту без сбоев для периферийного устройства. После установки бита разрешения существует задержка в 2 тактовых цикла, прежде чем тактовый сигнал станет активным, что программное обеспечение должно учитывать.

user2953113 06.07.2024 19:48

Все, что я хотел бы знать, это как учесть эту задержку в 2 такта. Я видел два разных подхода к этому, как указано в сообщении, и не уверен, какой из них правильный.

user2953113 06.07.2024 19:49

«Я наткнулся на приведенное ниже объяснение…» требуется цитирование — где вы это встретили. Кроме того, STM32 охватывает широкий спектр деталей, которые часто имеют незначительные различия. Например, в руководстве STM34F4xx об этом ничего не сказано. HAL читает ENR только один раз.

Clifford 06.07.2024 20:38

Привет, я обновил сообщение, указав источник, в котором я нашел это объяснение.

user2953113 06.07.2024 20:43

Является ли чтение регистра RCC ENR правильным подходом? Или чтение периферического регистра?

user2953113 06.07.2024 20:47

STM32G0x0, для которого вы процитировали справочное руководство, есть только на шине AHB, а AHBENR нет AHB1ENR, так что, строго говоря, первое неверно для этой конкретной части.

Clifford 06.07.2024 20:52

Да, конкретных примеров для STM32G0x0 я не нашел. Я пытался понять примеры других частей, а затем портировать их на STM32G0x0.

user2953113 06.07.2024 21:09

ST предоставляет «примеры» в виде библиотеки HAL, а для более старых частей STM32 — SPL.

Clifford 06.07.2024 21:43

В микроконтроллерах никогда не бывает одного «лучшего решения», поскольку оно сильно зависит от контекста нескольких типов (конкретного компилятора и его настроек командной строки, микроконтроллера, настроек AHB/APB, рассматриваемого периферийного устройства, памяти, из которой выполняется код... ). Вот еще несколько фрагментов информации (я знаю, это уже сбивает с толку, но это то, что есть) вместе с методологией, которую я использую (по сути, включите все часы в одном месте в начале программы, а затем сделайте что-нибудь еще полезное перед доступом периферийное оборудование).

wek 07.07.2024 13:24
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
14
103
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Первый пример явно относится к части STM32, отличной от STM32G0x0, на которую вы ссылаетесь, поэтому в этом смысле он неверен. STM32G0x0 имеет один AHB, поэтому AHBENR не AHB1ENR, а тактовый сигнал GPIOA в любом случае включается через IOPENR не AHBENR. Однако этот метод является законным, но для того, чтобы он был правильным, он должен быть специфичным для конкретной части.

Функция во втором методе включает в себя накладные расходы на вызов функции и количество циклов ЦП для цикла, поэтому она будет немного длиннее, но это потребует дополнительных усилий. Возможно, это излишне сложно. Выбор периферии для чтения во втором кажется произвольным. Вы также можете прочитать соответствующий регистр включения RCC, как в первом примере. Требуется только прочитать что-то, что будет иметь состояния ожидания, зависящие от соответствующей шины или периферийного устройства, чтобы дальнейшие инструкции не выполнялись до завершения чтения.

ST предоставляет периферийные библиотеки HAL и LL, которые, вероятно, являются хорошими образцами рекомендуемых методов (или, по крайней мере, методов, которые могут быть действительными - и протестированы) - даже если вы решите не использовать сами библиотеки.

HAL STM32G0x0 делает это, например:

#define __HAL_RCC_GPIOA_CLK_ENABLE()           do { \
                                                    __IO uint32_t tmpreg; \
                                                    SET_BIT(RCC->IOPENR, RCC_IOPENR_GPIOAEN); \
                                                    /* Delay after an RCC peripheral clock enabling */ \
                                                    tmpreg = READ_BIT(RCC->IOPENR, RCC_IOPENR_GPIOAEN); \
                                                    UNUSED(tmpreg); \
                                                  } while(0U)

Он считывает только что записанный отдельный бит разрешения, что гарантирует правильность тактового сигнала:

#define READ_BIT(REG, BIT)    ((REG) & (BIT))

Чтение не завершится, пока часы не будут активны, поэтому, я думаю, достаточно одного чтения.

Тот факт, что код в первом примере не будет работать с той частью, которую вы используете, возможно, является аргументом в пользу использования предоставленной ST библиотеки HAL - это позволяет избежать проблем с использованием и переносом кода между несколькими частями STM32, которые значительно различаются в зависимости от серии.

Связано:Архитектура ARM Bus для справки. Это хороший ответ, но было бы полезно сказать, что инструкции по чтению памяти выполняются из-за побочного эффекта. Это время. Вторая проблема заключается в том, что периферийное устройство (на шине) должно иметь активные часы. Во втором примере периферийное устройство uart1 нельзя отключить (чтобы оно функционировало). Вероятно, это загрузочное устройство или что-то в этом роде. Первый пример кажется более надежным, поскольку вы не можете «отключить» RCC (насколько мне известно).

artless noise 11.07.2024 14:04

@artlessnoise. Я сделал смелое предположение, что было понятно, что это были фиктивные чтения для расчета времени. Вопрос об этих, казалось бы, произвольных периферийных устройствах важен. Я могу обновить ответ. Функция будет работать должным образом только в том случае, если это будут первые часы, включенные для каждой шины. Он имеет серьезные недостатки и не просто слишком сложен. Он недостаточно обобщен и будет работать в очень узких обстоятельствах. Я подозреваю, что тот, кто это написал, никогда не заметил этого, потому что одних накладных расходов было достаточной задержкой - если бы тактовая частота шины была >= Sysclk/4, скажем, возможно, это могло бы сработать по глупой удаче.

Clifford 11.07.2024 17:46

Другие вопросы по теме