[英]STM32F446xx Peripheral Register Access Difference Between Using Dereferenced Pointers and Structs
我試圖簡單地點亮一個外部 LED(連接到我的 STM32F446RE 的端口 C 引腳 10)。 我正在將 gcc-arm-none-eabi 8-2019-q3-update 用於我的編譯器的 windows 和 Keil uVision5 IDE 用於刷新/調試電路板(Keil IDE 還使用 GCC 編譯器處理編譯)。
在以下代碼中,當使用結構引用 GPIO 和 RCC 外設寄存器(main 的第二個“部分”)時,一切正常。 RCC->AHB1ENR
和GPIOC->MODER
寫入線正確更新相關存儲器地址處的值,並且 LED 確實亮起。
但是,當使用取消引用的指針(主的第一個“部分”)時,LED 不亮。 調試此問題時,在執行*GPIOC_MODER
和*RCC_AHB1ENR
行后,不會寫入所有寄存器的內存位置。
這兩種方法有什么區別,為什么一種有效,另一種無效? 我已經使用 STM32F446xx 數據表 ( https://www.st.com/content/ccc/resource/technical/document/reference_manual/4d/ed/bc/89/b5/70/40/dc /DM00135183.pdf/files/DM00135183.pdf/jcr:content/translations/en.DM00135183.pdf ),即使地址不正確,基於結構的方法也不應該起作用。
#include <stdint.h>
/* General Purpose Input Output Registers, Address Range 0x4002 0000 - 0x4002 1FFF */
typedef struct
{
uint32_t volatile MODER; /* Offset: 0x00 (R/W) Mode Register */
uint32_t volatile OTYPER; /* Offset: 0x04 (R/W) Output Type Register */
uint32_t volatile OSPEEDR; /* Offset: 0x08 (R/W) Output Speed Register */
uint32_t volatile PUPDR; /* Offset: 0x0C (R/W) Pull-up/Pull-down Register */
uint32_t volatile IDR; /* Offset: 0x10 (R/W) Input Data Register */
uint32_t volatile ODR; /* Offset: 0x14 (R/W) Output Data Register */
uint32_t volatile BSRR; /* Offset: 0x18 (R/W) Bit Set/Reset Register */
uint32_t volatile LCKR; /* Offset: 0x1C (R/W) Configuration Lock Register */
uint32_t volatile AFRL; /* Offset: 0x20 (R/W) Alternate Function Low Register */
uint32_t volatile AFRH; /* Offset: 0x24 (R/W) Alternate Function High Register */
} GPIO_t;
#define GPIOA ((GPIO_t *)0x40020000)
#define GPIOB ((GPIO_t *)0x40020400)
#define GPIOC ((GPIO_t *)0x40020800)
#define GPIOD ((GPIO_t *)0x40020C00)
#define GPIOE ((GPIO_t *)0x40021000)
#define GPIOF ((GPIO_t *)0x40021400)
#define GPIOG ((GPIO_t *)0x40021800)
#define GPIOH ((GPIO_t *)0x40021C00)
/* Reset and Clock Control Registers (RCC), Address Range: 0x4002 3800 - 0x4002 3BFF */
typedef struct
{
uint32_t volatile CR; /* Offset: 0x00 (R/W) Clock Control Register */
uint32_t volatile PLLCFGR; /* Offset: 0x04 (R/W) PLL Configuration Register */
uint32_t volatile CFGR; /* Offset: 0x08 (R/W) Clock Configuration Register */
uint32_t volatile CIR; /* Offset: 0x0C (R/W) Clock Interrupt Register */
uint32_t volatile AHB1RSTR; /* Offset: 0x10 (R/W) AHB1 Peripheral Reset Register */
uint32_t volatile AHB2RSTR; /* Offset: 0x14 (R/W) AHB2 Peripheral Reset Register */
uint32_t volatile AHB3RSTR; /* Offset: 0x18 (R/W) AHB3 Peripheral Reset Register */
uint32_t volatile reserved0;
uint32_t volatile APB1RSTR; /* Offset: 0x20 (R/W) APB1 Peripheral Reset Register */
uint32_t volatile APB2RSTR; /* Offset: 0x24 (R/W) APB2 Peripheral Reset Register */
uint32_t reserved1[2];
uint32_t volatile AHB1ENR; /* Offset: 0x30 (R/W) AHB1 Peripheral Clock Enable Register */
uint32_t volatile AHB2ENR; /* Offset: 0x34 (R/W) AHB2 Peripheral Clock Enable Register */
uint32_t volatile AHB3ENR; /* Offset: 0x38 (R/W) AHB3 Peripheral Clock Enable Register */
uint32_t reserved2;
uint32_t volatile APB1ENR; /* Offset: 0x40 (R/W) APB1 Peripheral Clock Enable Register */
uint32_t volatile APB2ENR; /* Offset: 0x44 (R/W) APB1 Peripheral Clock Enable Register */
uint32_t reserved3[2];
uint32_t volatile AHB1LPENR; /* Offset: 0x50 (R/W) AHB1 Peripheral Clock Enable Lower Power Mode Register */
uint32_t volatile AHB2LPENR; /* Offset: 0x54 (R/W) AHB2 Peripheral Clock Enable Lower Power Mode Register */
uint32_t volatile AHB3LPENR; /* Offset: 0x58 (R/W) AHB3 Peripheral Clock Enable Lower Power Mode Register */
uint32_t reserved4;
uint32_t volatile APB1LPENR; /* Offset: 0x60 (R/W) APB1 Peripheral Clock Enable Lower Power Mode Register */
uint32_t volatile APB2LPENR; /* Offset: 0x64 (R/W) APB2 Peripheral Clock Enable Lower Power Mode Register */
uint32_t reserved5[2];
uint32_t volatile BDCR; /* Offset: 0x70 (R/W) Backup Domain Control Register */
uint32_t volatile CSR; /* Offset: 0x74 (R/W) Clock Control & Status Register */
uint32_t reserved6[2];
uint32_t volatile SSCGR; /* Offset: 0x80 (R/W) Spread Spectrum Clock Generation Register */
uint32_t volatile PLLI2SCFGR; /* Offset: 0x84 (R/W) PLLI2S Configuration Register */
uint32_t volatile PLLSAICFGR; /* Offset: 0x88 (R/W) PLLSAI Configuration Register */
uint32_t volatile DCKCFGR; /* Offset: 0x8C (R/W) Dedicated Clocks Configuration Register */
uint32_t volatile CKGATENR; /* Offset: 0x90 (R/W) Clocks Gated Enabled Register */
uint32_t volatile DCKCFGR2; /* Offset: 0x94 (R/W) Dedicated Clocks Configuration Register 2 */
} RCC_t;
#define RCC ((RCC_t *)0x40023800)
void main()
{
/* This section doesn't work */
uint32_t volatile * const GPIOC_MODER = (uint32_t *)0x40020800;
uint32_t volatile * const GPIOC_ODR = (uint32_t *)0x40020814;
uint32_t volatile * const RCC_AHB1ENR = (uint32_t *)0x40023830;
*GPIOC_MODER &= ~(0x1 << 21); //!# Enable clock to GPIO Port C
*GPIOC_MODER |= 0x1 << 20; //!# Clear bit 21 to put pin 10 into general purpose output mode
*RCC_AHB1ENR |= 0x1 << 2; //!# Set bit 20 to put pin 10 into general purpose output mode
while (1) {
*GPIOC_ODR |= 0x1 << 10; //!# Write a 1 to bit 10 (port 10) of GPIO Port C
}
/* This section does work */
RCC->AHB1ENR |= 0x1 << 2; //!# Enable clock to GPIO Port C
GPIOC->MODER &= ~(0x1 << 21); //!# Clear bit 21 to put pin 10 into general purpose output mode
GPIOC->MODER |= 0x1 << 20; //!# Set bit 20 to put pin 10 into general purpose output mode
while (1) {
GPIOC->ODR |= 0x1 << 10; //!# Write a 1 to bit 10 (port 10) of GPIO Port C
}
}
更新:事實證明,這是指令的順序,這就是為什么一個“部分”可以工作而一個“部分”沒有的原因。 工作“部分”啟用到該 GPIO 端口的時鍾信號,然后進行內存寫入,而不工作的“部分”嘗試進行內存寫入,然后啟用時鍾信號。 我在這里假設,但似乎該內存區域是時鍾門控的,或者在未啟用該區域的時鍾時嘗試從該區域讀取/寫入該區域的內容將導致讀取為零/寫入忽略.
您必須先啟用外圍設備,然后才能與之交談。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.