zoukankan      html  css  js  c++  java
  • STM32技术--存储器映射及位带

    以下以STM32F407ZGT6为例说明。 

    STM32是32位的芯片,意味着有从0x00000000~0xFFFFFFFF 4G也就是32位的寻址空间,在设计芯片的时候,采用的是ARM所设计的架构,ST(意法半导体)公司在基于ARM的对芯片添加了自己的外设。

    注意:这里是一个地址空间存放一个字节,即1Byte

      ARM规定:

    Vendor-specific memory 511MB 存放特定厂商的代码

    Private peripheral bus  1M 物理总线

    External device  1.0GB 片上外设不够用时,外扩在此区域

    Extermal RAM  1.0GB  RAM空间不够用时,外扩在此区域

    peripheral 0.5GB 外设都在此区域 如 GPIO口,定时器等等

    SRAM 0.5GB 用来存放运行时的数据

    Code(Flash) 0.5GB 用来存放相应的代码和数据 

    ST公司又根据ARM的划分添加了相应的外设

     以GPIO口为例:我们操作GPIO口实际上是操作地址为0x40020000~0x400223FF的寄存器

    ST的封装如下:

    GPIO_TypeDef * 是一个结构体指针类型,而这个结构体的地址为各个端口号的基地址,

     

    地址计算为:PERIPH_BASE设备的基地址加上0x00020000的偏移地址为AHB1的地址,AHB1的地址加上各个端口的偏移地址即为各个GPIO口的基地址,再加上每个端口上寄存器的偏移量就得到了该寄存器的地址。

    重写GPIOF的寄存器

    复制代码
    #define GPIOF_BASEADDR   0x40021400
    #define rGPIOF_MODER    *(uint32_t *)(GPIOF_BASEADDR+0x00)
    #define rGPIOF_OTYPER   *(uint32_t *)(GPIOF_BASEADDR+0x04)
    #define rGPIOF_OSPEEDR  *(uint32_t *)(GPIOF_BASEADDR+0x08)
    #define rGPIOF_PUPDR    *(uint32_t *)(GPIOF_BASEADDR+0x0C)
    
    
    void LED_myCOnfig(void)
    {
        RCC->AHB1ENR |= (1<<5);
        rGPIOF_MODER &=~ (3<<12);
        rGPIOF_MODER |= (1<<12);
        rGPIOF_OTYPER &=~ (1<<6);
        rGPIOF_OSPEEDR &=~ (3<<12);
        rGPIOF_OSPEEDR |= (2<<12);
        rGPIOF_PUPDR &=~ (3<<12);
    }
    复制代码

    位带:

     在stm32中因为是对寄存器的位操作,如果我们想要像51单片机那样类似p1=1的位变量操作,就要使用ARM在设计内核架构时留的位带操作。

    什么是位带?

    位带是基于ARM提供的位段机制,将位操作变为字操作的一种操作机制。

    只有0x20000000~0x200FFFFF和0x40000000~0x400FFFFF这两部分有位段的映射,其中0x20000000~0x200FFFFF和0x40000000~0x400FFFFF这两个1MB的空间叫做位段区,0x22000000~0x23FFFFFF和0x42000000~0x43FFFFFF这两部分叫做别名区,位段区的每一个位(1bit)都对应别名区的每一个字(4Byte),我们向别名区相应的字中写入0或1就是向对应的位段区写入0或1.

     

    而位带的使用方法是根据位段区的相应位计算出别名区的地址,然后再通过指针对该地址进行操作即可。

    以PF6为例  GPIOF的基地址为 0x40021414

    计算出GPIOF的基地址相对于位段基地址偏移量  -- 字节

    0x40021414 - 0x40000000 = 0x21414

    再乘以8转换成GPIOF端口的第六个管脚偏移多少位

    0x21414 * 8 + 6

    计算别名区的偏移量

    (0x21414 * 8 + 6)*4

    这里因为是位段区每偏移一位,别名区偏移4个字节,所以得出来的值要乘以4来转换成偏移的字节数

    别名区的地址  --偏移量 + 基地址

    0x42000000 + (0x21414 * 8 + 6)*4 

    换算的公式如下:

    位段区addr  bit

    别名区基地址:

           (Adrr &0xF0000000) +0x2000000

    别名区的偏移量:

           ((Addr & 0xFFFFF)*8 + bit)*4

    别名区地址:

           (Adrr &0xF0000000) +0x2000000 +( (Addr & 0xFFFFF)*8 + bit)*4

    复制代码
    #include "stm32f4xx.h"
    //先计算别名区对应的地址
    #define BITBAND(addr,bit) (((addr&0xf0000000)+0x2000000)+((addr&0xfffff)*8+bit)*4)
    
    //操作别名区
    #define MEM_ADDR(addr,bit)  *(volatile unsigned int *)BITBAND(addr,bit)
        
    //ODR
    #define PAout(bit) MEM_ADDR((unsigned int)&GPIOA->ODR,bit) 
    #define PBout(bit) MEM_ADDR((unsigned int)&GPIOB->ODR,bit)
    #define PCout(bit) MEM_ADDR((unsigned int)&GPIOC->ODR,bit)
    #define PDout(bit) MEM_ADDR((unsigned int)&GPIOD->ODR,bit)
    #define PEout(bit) MEM_ADDR((unsigned int)&GPIOE->ODR,bit)
    #define PFout(bit) MEM_ADDR((unsigned int)&GPIOF->ODR,bit)
    #define PGout(bit) MEM_ADDR((unsigned int)&GPIOG->ODR,bit)
    #define PHout(bit) MEM_ADDR((unsigned int)&GPIOG->ODR,bit)
        
    //IDR
    #define PAin(bit) MEM_ADDR((unsigned int)&GPIOA->IDR,bit)
    #define PBin(bit) MEM_ADDR((unsigned int)&GPIOB->IDR,bit)
    #define PCin(bit) MEM_ADDR((unsigned int)&GPIOC->IDR,bit)
    #define PDin(bit) MEM_ADDR((unsigned int)&GPIOD->IDR,bit)
    #define PEin(bit) MEM_ADDR((unsigned int)&GPIOE->IDR,bit)
    #define PFin(bit) MEM_ADDR((unsigned int)&GPIOF->IDR,bit)
    #define PGin(bit) MEM_ADDR((unsigned int)&GPIOG->IDR,bit)
    #define PHin(bit) MEM_ADDR((unsigned int)&GPIOG->IDR,bit)
    复制代码

    这样,在操作时就可以直接将PF(6)=0使led亮了。

  • 相关阅读:
    flask 需要下载的包
    flask知识点
    移动端网页实现(用百分比进行定位)
    js中的preventDefault
    网页重构面试笔试题
    J2EE课程设计的购物车代码(水平有限,仅供参考)
    JavaScript实现对象克隆函数clone( )的程序及分析
    WEB技术书籍推荐
    2016 Tianjin University Software Testing (lab2)
    Mac下安装npm 、node、ionic和cordova
  • 原文地址:https://www.cnblogs.com/laoxiongzhijia/p/14429761.html
Copyright © 2011-2022 走看看