bit band功能,相信大家都比较熟悉了。因为在CM3时,我们就有这个功能,CM4当然也继承了。
下面,我们谈谈M471对应的CM4核的bit band。在规格书里面,新唐并未对其做很多的说明,
仅仅是一带而过。具体感兴趣的,可以去看《Cortex M3与M4权威指南.pdf》,l里面很多CM4
内核相关的,都说的比较清楚~
流程示意:
用BITBANG与不用的区别:
给出的具体转换方法:
有2除寄存器位置可以用bitband:
官方给的例子是操作SRAM的,但是这个现象不是很明显,我们这里操作外设-->GPIO来试一下:
获取GPIO的读写寄存器地址:
我们或得各个PORT对应的读写寄存器地址后,就可以着手程序了:
程序:
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
//#define GPIOA_BASE (AHBPERIPH_BASE + 0x04000UL)
//#define GPIOB_BASE (AHBPERIPH_BASE + 0x04040UL)
//#define GPIOC_BASE (AHBPERIPH_BASE + 0x04080UL)
//#define GPIOD_BASE (AHBPERIPH_BASE + 0x040C0UL)
//#define GPIOE_BASE (AHBPERIPH_BASE + 0x04100UL)
//#define GPIOF_BASE (AHBPERIPH_BASE + 0x04140UL)
//#define GPIOG_BASE (AHBPERIPH_BASE + 0x04180UL)
//#define GPIOH_BASE (AHBPERIPH_BASE + 0x041C0UL)
//#define GPIOI_BASE (AHBPERIPH_BASE + 0x04200UL)
//写寄存器
#define GPIOA_DOUT_Addr (GPIOA_BASE+8) //0x40004008
#define GPIOB_DOUT_Addr (GPIOB_BASE+8) //0x40004048
#define GPIOC_DOUT_Addr (GPIOC_BASE+8) //0x40004088
#define GPIOD_DOUT_Addr (GPIOD_BASE+8) //0x400040C8
#define GPIOE_DOUT_Addr (GPIOE_BASE+8) //0x40004108
#define GPIOF_DOUT_Addr (GPIOF_BASE+8) //0x40004148
#define GPIOG_DOUT_Addr (GPIOG_BASE+8) //0x40004188
#define GPIOH_DOUT_Addr (GPIOH_BASE+8) //0x400041C8
#define GPIOI_DOUT_Addr (GPIOI_BASE+8) //0x40004208
//读寄存器
#define GPIOA_PIN_Addr (GPIOA_BASE+16) //0x40004010
#define GPIOB_PIN_Addr (GPIOB_BASE+16) //0x40004050
#define GPIOC_PIN_Addr (GPIOC_BASE+16) //0x40004090
#define GPIOD_PIN_Addr (GPIOD_BASE+16) //0x400040D0
#define GPIOE_PIN_Addr (GPIOE_BASE+16) //0x40004110
#define GPIOF_PIN_Addr (GPIOF_BASE+16) //0x40004150
#define GPIOG_PIN_Addr (GPIOG_BASE+16) //0x40004190
#define GPIOH_PIN_Addr (GPIOH_BASE+16) //0x400041D0
#define GPIOI_PIN_Addr (GPIOI_BASE+16) //0x40004210
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n) BIT_ADDR(GPIOA_DOUT_Addr,n) //输出
#define PAin(n) BIT_ADDR(GPIOA_PIN_Addr,n) //输入
#define PBout(n) BIT_ADDR(GPIOB_DOUT_Addr,n) //输出
#define PBin(n) BIT_ADDR(GPIOB_PIN_Addr,n) //输入
#define PCout(n) BIT_ADDR(GPIOC_DOUT_Addr,n) //输出
#define PCin(n) BIT_ADDR(GPIOC_PIN_Addr,n) //输入
#define PDout(n) BIT_ADDR(GPIOD_DOUT_Addr,n) //输出
#define PDin(n) BIT_ADDR(GPIOD_PIN_Addr,n) //输入
#define PEout(n) BIT_ADDR(GPIOE_DOUT_Addr,n) //输出
#define PEin(n) BIT_ADDR(GPIOE_PIN_Addr,n) //输入
#define PFout(n) BIT_ADDR(GPIOF_DOUT_Addr,n) //输出
#define PFin(n) BIT_ADDR(GPIOF_PIN_Addr,n) //输入
#define PGout(n) BIT_ADDR(GPIOG_DOUT_Addr,n) //输出
#define PGin(n) BIT_ADDR(GPIOG_PIN_Addr,n) //输入
#define PHout(n) BIT_ADDR(GPIOH_DOUT_Addr,n) //输出
#define PHin(n) BIT_ADDR(GPIOH_PIN_Addr,n) //输入
#define PIout(n) BIT_ADDR(GPIOI_DOUT_Addr,n) //输出
#define PIin(n) BIT_ADDR(GPIOI_PIN_Addr,n) //输入
我们知道PH4对应KEY,PB14对应LED,在正常的GPIO初始化后,我们开始用BITBAND的模式来读取控制:
while(1)
{
if(PHin(4)==0)
{
while(PHin(4)==0){};
PBout(14)=~PBout(14);
}
}
如果按键被按下,等待按键释放后,LED切换状态。
编译,下载,查看:
新唐和其他家的不一样,它的库里面,直接就可以对GPIO PIN 单独操作,如PA5=0 类似的。
这个例子在其他家结合BITBAND 会比较简单些。
我们看看它是具体怎实现的:
先看一个例子:
#define PA0 GPIO_PIN_DATA(0, 0 )
展开定义:
#define GPIO_PIN_DATA(port, pin) (*((volatile uint32_t *)((GPIO_PIN_DATA_BASE+(0x40*(port))) + ((pin)<<2)))) /*!< Pin Data Input/Output \hideinitializer */
再展开:
#define GPIO_PIN_DATA_BASE (AHBPERIPH_BASE + 0x04800UL)
再展开:
#define PERIPH_BASE ((uint32_t)0x40000000) /*!< Peripheral Base Address */
#define AHBPERIPH_BASE PERIPH_BASE
好,现在我们重新从下往上推:
#define GPIO_PIN_DATA_BASE ((uint32_t)0x40000000+ 0x04800UL)
我们查看:
可见 GPIO_PIN_DATA_BASE 对应的是GPIO PA.n Pin Data Input/Output Register
根据表格得,每一个PORT的GPIO_PIN_DATA_BASE 地址相差0x40
对应某一个PORT 的GPIO_PIN_DATA_BASE其内部的0~15 引脚地址关系:在这个地址上再加上0x04*n (n=0~15)
那也就是 ((pin)<<2)) (pin:0~15)
那么:#define PA0 GPIO_PIN_DATA(0, 0 )
这个宏,其实就是定义到对应PORT 对应pin的 PAn_PDIO寄存器上面,我们查看PDIO寄存器:
我去,这个寄存器太好了,直接能读,又能写,比我们之前分开的那个好多了~
ST是没有这个,NXP的有类似的~
好了,bitband就到这了,谢谢观看~
|