Значение бита выходного регистра GPIO не обновляется

#c #stm32f7

Вопрос:

Я только начал изучать встроенные системы, и у меня возникли некоторые проблемы с правильной настройкой светодиодного вывода на моей плате stm32f746ng-discovery. Я не уверен, правильно ли я набираю текст или у меня неправильный адрес для pin-кода, однако я считаю, что все решил правильно, и я не вижу изменения значения для регистра выходных данных GPIO в окне просмотра, что наводит меня на мысль, что с моим кодом может быть проблема.

Чтобы определить регистры и их соответствующие адреса, я использовал именно такой подход:

 //Referring to STM32F746xx Memory Map and Register Boundary Addresses:
#define PERIPH_BASE             (0x40000000UL)

#define AHB1PERIPH_OFFSET       (0x00020000UL)
#define AHB1PERIPH_BASE         (PERIPH_BASE   AHB1PERIPH_OFFSET)

#define GPIOI_OFFSET            (0x2000UL)
#define GPIOI_BASE              (AHB1PERIPH_BASE   GPIOI_OFFSET)

#define RCC_OFFSET              (0x3800UL)
#define RCC_BASE                (AHB1PERIPH_BASE   RCC_OFFSET)

#define RCC_AHB1EN_R_OFFSET     (0x30UL)
#define RCC_AHB1EN_R            (*(volatile unsigned int *)(RCC_BASE   RCC_AHB1EN_R_OFFSET)) //register

#define MODE_R_OFFSET           (0x00UL)
#define GPIOI_MODE_R            (*(volatile unsigned int *)(GPIOI_BASE   MODE_R_OFFSET)) //register

#define OD_R_OFFSET             (0x14UL)
#define GPIOI_OD_R              (*(volatile unsigned int *)(GPIOI_BASE   OD_R_OFFSET)) //register

#define GPIOIEN                 (1U << 0)

#define PIN_1                   (1U << 1)
#define LED_PIN                 PIN_1
 

Вышеуказанные шестнадцатеричные адреса я нашел в таблице/карте памяти таблицы данных stm32f746xx и справочном руководстве RM0385 для stm32f74xxx.

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

 int main(void)
{
    /* 1. Enable clock access for GPIOI.*/
    /* 1.1 I use the OR operator to only change the first bit instead of the whole 32bit chain. */
    RCC_AHB1EN_R |= GPIOIEN;

    /* 2. Sets PIN_1 as output.*/
    GPIOI_MODE_R |= (1U << 2);
    GPIOI_MODE_R amp;=~(1U << 3);

    while(1)
    {
        /* 3. Sets PIN_1 high */
        GPIOI_OD_R |= LED_PIN;

    }
}
 

Проблема, с которой я сталкиваюсь, заключается в том, что значение бита для регистра GPIOI_OD_R обновляется неправильно и устанавливается на 00 вместо 01, что является необходимым значением для вывода GPIOI Pin_1 (светодиод), который должен быть установлен в режим вывода общего назначения.

Вышеуказанные параметры я получил из справочного руководства RM0385 для stm32f74xxx, которое можно увидеть на рисунке ниже:

Регистр режима GPIO

Однако при запуске кода значения битов GPIOI_MODE_R и GPIOI_OD_R не меняются, что видно на изображении ниже:

GPIO регистрирует отсутствие изменения значения

Мне нужно, чтобы значения регистров были правильными, чтобы установить светодиодный вывод высоко на моей плате stm32f746ng-discovery.

Я попытался объединить операцию настройки GPIOI_MODE_R в одну: GPIOI_MODE_R = (GPIOI_MODE_R | (1U << 2)) amp; ~(1U << 3) однако это приводит к тому, что программа теряет связь с отладчиком.

Я использую STM32CubeIDE со следующими настройками компилятора MCU GCC: Настройки компилятора MCU GCC

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

Ответ №1:

Я нашел проблему и понял, что обращался к неправильному значению бита для GPIOIEN. Вместо того, чтобы смотреть на битовый адрес для GPIOIEN с: #define GPIOIEN (1U << 8) я допустил ошибку, посмотрев на битовый адрес для GPIOAEN с: #define GPIOIEN (1U << 0) . введите описание изображения здесь

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

Окончательное кодовое решение, которое я прикрепил ниже:

 //Referring to STM32F746xx Memory Map and Register Boundary Addresses:
#define PERIPH_BASE             (0x40000000UL)

#define AHB1PERIPH_OFFSET       (0x00020000UL)
#define AHB1PERIPH_BASE         (PERIPH_BASE   AHB1PERIPH_OFFSET)

#define GPIOI_OFFSET            (0x2000UL)
#define GPIOI_BASE              (AHB1PERIPH_BASE   GPIOI_OFFSET)

#define RCC_OFFSET              (0x3800UL)
#define RCC_BASE                (AHB1PERIPH_BASE   RCC_OFFSET)

#define RCC_AHB1EN_R_OFFSET     (0x30UL)
#define RCC_AHB1EN_R            (*(volatile unsigned int *)(RCC_BASE   RCC_AHB1EN_R_OFFSET))

#define MODE_R_OFFSET           (0x00UL)
#define GPIOI_MODE_R            (*(volatile unsigned int *)(GPIOI_BASE   MODE_R_OFFSET))

#define OD_R_OFFSET             (0x14UL)
#define GPIOI_OD_R              (*(volatile unsigned int *)(GPIOI_BASE   OD_R_OFFSET))

#define GPIOIEN                 (1U << 8) // updated from (1U << 0)

#define PIN_1                   (1U << 1)
#define LED_PIN                 PIN_1

int main(void)
{
    /* 1. Enable clock access for GPIOI.*/
    /* 1.1 I use the OR operator to only change the first bit instead of the whole 32bit chain. */
    RCC_AHB1EN_R |= GPIOIEN;

    /* 2. Sets PIN_1 as output.*/
    GPIOI_MODE_R |= (1U << 2);
    GPIOI_MODE_R amp;=~(1U << 3);

    while(1)
    {
        /* 3. Sets PIN_1 high */
        GPIOI_OD_R |= LED_PIN;

    }
}
 

Комментарии:

1. PS: это уже упоминалось в комментарии к вашему вопросу, но лучше объединить обе двоичные операции GPIOI_MODE_R в одном операторе, например GPIOI_MODE_R = (GPIOI_MODE_R | (1U << 2)) amp; ~(1U << 3) . Это позволяет избежать промежуточного (возможно, недопустимого) состояния. (PS: Лично я бы предпочел GPIOI_MODE_R = (GPIOI_MODE_R amp; ~0xC) | 0x4; сначала написать, чтобы очистить, а затем установить все MODER1 биты, но эффект, конечно, был бы тот же).

2. @wovano, спасибо за комментарий, я обновлю проект со своей стороны и обязательно объединю двоичные операции, когда это возможно, чтобы избежать потенциальных недопустимых состояний в будущем. Кроме того, я просто хотел проверить, когда вы сказали, что лично будете использовать GPIOI_MODE_R = (GPIOI_MODE_R amp; ~0xC) | 0x4 это, потому что это правильный стандарт и правильный способ реализации? Я только начал учиться и хочу убедиться, что код, который я создаю, соответствует правильному стандарту. Еще раз спасибо за совет, который я очень ценю.

3. Это просто для того, чтобы сделать код более понятным. Вместо 2 операций над (казалось бы) произвольными битами более четко указано, что вы выполняете операцию над битами 2 и 3 регистра. Для этого довольно часто создается переменная» маска » (или определение). Посмотрите, как это делает STM32F7 HAL: строка 231-235 из stm32f7xx_hal_gpio.c (вы также заметите, что они используют временную переменную, чтобы избежать 2-х записей в регистр). Маски определены в stm32f746xx.h.

4. PS: Если бы вы использовали эти файлы заголовков, это позволило бы избежать вашей опечатки. Я не уверен, что вы все пишете сами, потому что хотите научиться и понять это, но в целом я бы рекомендовал использовать библиотеки, так как они уже выполнили для вас довольно много работы 🙂

5. Спасибо, @wovano, я изначально все писал сам, чтобы лучше понять, как все работает. Тем не менее, теперь у меня есть базовое понимание, и я начал правильно использовать библиотеки холла. Еще раз спасибо за совет. 🙂