#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, которое можно увидеть на рисунке ниже:
Однако при запуске кода значения битов GPIOI_MODE_R и GPIOI_OD_R не меняются, что видно на изображении ниже:
Мне нужно, чтобы значения регистров были правильными, чтобы установить светодиодный вывод высоко на моей плате stm32f746ng-discovery.
Я попытался объединить операцию настройки GPIOI_MODE_R в одну: GPIOI_MODE_R = (GPIOI_MODE_R | (1U << 2)) amp; ~(1U << 3)
однако это приводит к тому, что программа теряет связь с отладчиком.
Я использую STM32CubeIDE со следующими настройками компилятора 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, я изначально все писал сам, чтобы лучше понять, как все работает. Тем не менее, теперь у меня есть базовое понимание, и я начал правильно использовать библиотеки холла. Еще раз спасибо за совет. 🙂