• stm32存储器映像和标准库中定义外设地址的方法


    结合存储器映像理解stm32标准库中定义外设地址的方法。

    stm32f103zet6是32位的。它所能访问的地址空间范围为2^32=4GB,把4GB分为8个block,分别为block0-block-7。把这8个block用于不同的用途。

    block0-block7的用途

    图1

    ————————————————————————————————————————————————————————

    图2

     从上面的图2中可以看到block2作为外设的地址,也就是说我们操作的外设都在block2中。block2的起始地址是0x4000 0000。这些外设包括哪些?看下面图3上,所有APB1、APB2、AHB上的外设都在这个block2中。

    #define PERIPH_BB_BASE        ((uint32_t)0x42000000) /*!< Peripheral base address in the bit-band region */
    //标准库中定义了外设起始地址(block2的起始地址)

      

    图3

     ————————————————————————————————————————————————————————

    我们操作的外设都在block2中,而外设又必定在APB1、APB2、AHB中的某一条总线上。那APB1、APB2、AHB在block2中怎么排布?图4上列出来3条总线的地址,可以看到APB1总线的起始地址和block2的起始地址是一样的。

    #define APB1PERIPH_BASE       PERIPH_BASE        //APB1的起始地址是block2的起始地址
    #define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000) //APB2的起始地址是在block2的地址上偏移得到的
    #define AHBPERIPH_BASE        (PERIPH_BASE + 0x20000) //AHB的起始地址是0x4001 8000(SDIO的地址),标准库中AHBPERIPH_BASE是0x4002 000(DMA1外设)
    
    

     

     

    图4

     从图5中列出了APB1总线上的外设。观察发现APB1总线上的第一个外设是TIM2定时器。

    #define TIM2_BASE             (APB1PERIPH_BASE + 0x0000) //标准库中定义的定时器2的地址,+0x0000是因为tim2地偏移地址是0,
                                      //比如,APB1总线上第二给外设是tim3,偏移地址0x0400,它的写法就是
    #define TIM3_BASE             (APB1PERIPH_BASE + 0x0400)

     

     图5

    经过上面的外设基地址+偏移地址得到了TIM2的起始地址,TIM2这个外设有很多寄存器,第一个寄存器偏移地址是0x00。每个寄存器的偏移地址都是0x04。这里没有再用上面的宏定义的方法去通过基地址+偏移地址去计算每个外设的寄存器的地址,通过一种更巧妙的方法。

    因为寄存器是32位的,也就是4个字节。寄存器都是内存对齐的(寄存器用不了32位的,剩多少保留多少),用结构体的方式去强制转换一TIM2的起始地址。这个利用了结构体中变量对齐和外设寄存器对齐的方式。

    #define TIM2                ((TIM_TypeDef *) TIM2_BASE)
    

     结构体内部:

    typedef struct
    {
      __IO uint16_t CR1;
      uint16_t  RESERVED0;
      __IO uint16_t CR2;
      uint16_t  RESERVED1;
      __IO uint16_t SMCR;
      uint16_t  RESERVED2;
      __IO uint16_t DIER;
      uint16_t  RESERVED3;
      __IO uint16_t SR;
      uint16_t  RESERVED4;
      __IO uint16_t EGR;
      uint16_t  RESERVED5;
      __IO uint16_t CCMR1;
      uint16_t  RESERVED6;
      __IO uint16_t CCMR2;
      uint16_t  RESERVED7;
      __IO uint16_t CCER;
      uint16_t  RESERVED8;
      __IO uint16_t CNT;
      uint16_t  RESERVED9;
      __IO uint16_t PSC;
      uint16_t  RESERVED10;
      __IO uint16_t ARR;
      uint16_t  RESERVED11;
      __IO uint16_t RCR;
      uint16_t  RESERVED12;
      __IO uint16_t CCR1;
      uint16_t  RESERVED13;
      __IO uint16_t CCR2;
      uint16_t  RESERVED14;
      __IO uint16_t CCR3;
      uint16_t  RESERVED15;
      __IO uint16_t CCR4;
      uint16_t  RESERVED16;
      __IO uint16_t BDTR;
      uint16_t  RESERVED17;
      __IO uint16_t DCR;
      uint16_t  RESERVED18;
      __IO uint16_t DMAR;
      uint16_t  RESERVED19;
    } TIM_TypeDef;
    

      

    总结一下:

    stm32中,标准库中定义一个外设地址的方法是,外设起始地址(block2起始地址)+总线偏移地址(APB1、APB2、AHB)+具体外设偏移地址(TIM、GPIO等)。最后把具体外设偏移地址通过结构体类型强制转换成结构体变量。

  • 相关阅读:
    nullptr和NULL
    tmux用于恢复远程屏幕
    如何改变git的默认路径
    scp拷贝文件
    C++头文件<bits/stdc++.h>
    MAME模拟器使用简单教程
    typescript接口扩展
    Typescript中的可索引接口 类类型接口
    typescript函数类型接口
    typescript静态属性 静态方法 抽象类 多态
  • 原文地址:https://www.cnblogs.com/1024E/p/13208011.html
Copyright © 2020-2023  润新知