STM32F446xx使用解除引用的指针和结构之间的外围寄存器访问差异

问题描述 投票:1回答:1

我正在尝试简单地点亮一个外部LED(连接到STM32F446RE的端口C引脚10)。我正在为编译器的Windows使用gcc-arm-none-eabi 8-2019-q3-update,并使用Keil uVision5 IDE来刷新/调试板(Keil IDE还使用GCC编译器处理编译)。

在下面的代码中,当使用结构引用GPIO和RCC外设寄存器(main的第二个“部分”)时,一切正常。 RCC->AHB1ENRGPIOC->MODER写入线正确更新了相关存储器地址上的值,并且LED确实亮了。

但是,当使用取消引用的指针(main的第一个“部分”时,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端口的时钟信号,然后进行了存储器写操作,而工作不正常的“部分”尝试进行了存储器写操作,然后启用了时钟信号。我在这里假设,但是似乎该内存区域是时钟门控的,或者在未启用对该区域的时钟的情况下尝试从该区域读取/写入该区域的操作将导致零读/写忽略。

c gcc arm embedded cortex-m
1个回答
0
投票

您必须先启用外围设备,然后才能与之交谈。

© www.soinside.com 2019 - 2024. All rights reserved.