CC3220学习笔记---点亮LED寄存器版

xiaoxiao2021-02-28  115

CC3220SF开发板到货,拍照留念

两兄弟,右边这块是CC3220SF,大一些。 相比51单片机,ARM的MCU复杂得多,再加上N层的抽象,复杂度更是高得多。更可怕的是,所有文档还是英文的,这东西看中文都很吃力。所以,没办法,只能从最底层搞起,抽丝剥茧,慢慢搞清楚了。 CC3220到货,先搞个类似51单片机的程序,直接控制寄存器来点亮LED。 先查阅CC3220技术参考手册,的第五章【General-Purpose Input/Outputs (GPIOs)】介绍了GPIO的相关内容。 5.4 初始化和配置 配置指定端口的GPIO引脚: 通过设置 GPIO0CLKEN、c、GPIO2CLKEN、GPIO3CLKEN和GPIO4CLKEN寄存器中合适的位来使能指定port的时钟。通过GPIODIR寄存器编程设置GPIO port引脚的方向。置1表示输出,置0表示输入。 之后中讲的是配置DMA和中断,此处省略。也就是说,如果要点亮LED,需要做的初始化工作首先要配置时钟,然后设置引脚方向性。 查找三盏灯所接引脚: CC3220的引脚被分为4组,分别是为Port A0、Port A1、Port A2、Port A3。首先我们找到CC3220SF开发板的三盏LED灯所对就的GPIO口,查电路图:

看看实物图:

D8  :绿灯,接GPIO_11 D9  :黄灯,接GPIO_10 D10:红灯,接GPIO_9 查找三盏灯所接GPIO口所对应的port 还是同一章,找到GPIO映射表:

D8  :绿灯,接GPIO_11   ---GPIOA1  的第3位引脚 D9  :黄灯,接GPIO_10   ---GPIOA1  的第2位引脚 D10:红灯,接GPIO_9     ---GPIOA1  的第1位引脚(从0开始) 也就是说,三盏灯同属GPIOA1,那么,我们只需打开GPIO1CLKEN即可。 寻找GPIO1CLKEN寄存器地址 首先寻找时钟管理的基地址,【2.2.3 Memory Model】这一节的【Table 2-4  Memory Map】中可以找到时钟管理基地址,如图:

找到时钟管理基地址,0x4402.5000 接下来【15.6.16 GPIO1CLKEN Register】

DSLPCLKEN:深度睡眠 SLPCLKEN:睡眠 RUNCLKEN:正常运行 由图可看到偏移量offset = 58h,重启默认值reset = 0h。我们需要的是正常运行状态,也就是把RUNCLKEN置1即可打开GPIOA1时钟。 最终结果:[0x44025000+0x58]寄存器值设为0x01 寻找GPIODIR寄存器地址 翻到【5.5 GPIO Registers】,看到以下内容:

前面已经说过,CC3220把所有GPIO分为4组,A0~A3,上面列出了每个组的基地址。而每个组都有自己的寄存器。Table 5-3列出的是每组自身所拥有的寄存器,Offset列就是各组寄存器针对各组基地址位移。 上面特意声明,在这些寄存器可以访问前,每个GPIO的模块时钟必须首先开启,在开启后的延时3个系统时钟方能访问这些寄存器。 接下来点GPIODIR寄存器右边链接转到5.5.2节,如下图:

前面我们看过Table 5-14 GPIO Mapping,可观察到 4组GPIO,每组管8个引脚。而GPIODIR寄存器的DIP字段正好占8个位,每个位对应一个引脚。那么根据前面所查资料,可以得知三盏LED由上图红框的3个位所控制。只要把它们都置1,三盏LED的引脚都会变为输出方向。 那么GPIO Port A1基地址0x40005000,GPIODIR寄存器地址偏移400h。得出结论 最终结果:[0x40005000+0x400] = 0x0E 引脚复用 相比51单片机,CC3220是一块高级芯片,大部分引脚经过配置,都可以实现不同的功能,如I2C、SPI、UART或GPIO。接下来我们就需要将3盏LED所连接的引脚配置为GPIO。 首先翻到【16.7 Functional Pin Mux Configurations】,找到GPIO9、GPIO10、GPIO11三个引脚复用数据,如下图: GPIO9:

GPIO10、GPIO11:

注意红色方框标注处。可注意到,只要将三个引脚所对应的寄存器名称和地址分别为: GPIO_PAD_CONFIG_9   :0x4402E0C4 GPIO_PAD_CONFIG_10 :0x4402E0C8 GPIO_PAD_CONFIG_11  :0x4402E0CC 只需将它们的ConfigMode配置为0,即可用为GPIO。 接下来翻到【16.8.1.1 Pad Mux and Electrical Configuration Register Bit Definitions】,如下图:

GPIO_PAD_CONFIG_x寄存器占用12个位。[3:0]用于ConfigMode,如上所述,这里设为0就是GPIO。[7:5]用于驱动强度,我们把它设为001 = 2mA即可。[3:0]=0,[7:5]=001,得出数字0x20。 最终结果: [0x4402E0C4] = 0x20 [0x4402E0C8] = 0x20  [0x4402E0CC] = 0x20 控制引脚高低电平 不要急,还没完。配置是结束了,点亮或熄灭LED灯还需控制GPIO的高低电平,这是一个非常复杂难懂的过程。 还是翻到【5.5 GPIO Registers】看Table 5-3的内容,

如上表所示,GPIODATA的地址范围从0h~3FFh,总共占用1024个字节。而每组GPIO共8个引脚,一个字节即可表示完成。下面看看关于GPIODATA寄存器的描述,翻到【5.5.1 GPIODATA Register (offset = 0h) [reset = 0h]】,图5-4:

考虑到MCU为32位总线,那么需要4个字节来控制一组GPIO口(只使用了前8位)。为何留了1024个字节来控制8个引脚呢? 实际上CC3220将这1024个字节分为256个区域(即256个别名,1024/4=256),每个区域正好存放控制一组GPIO口所需的32个位。第一个区地址偏移量为0x00,第二个区地址偏移量为0x04,最后一个区地址偏移量为0x3FC。在不同的区域读写GPIO得到的是不同的效果。翻到【5.2.1.2 Data Register Operation】。 1、先看看写操作

如上图所示: 第一行方块表示地址偏移量 第二行方块表示要写的值 第三行方块表示GPIODATA的结果值 在偏移量为0x098这个地址上写GPIO。0x098的第2到第9位可作为写操作掩码,把0x098用二进制来看,3、4、7位的值为1,表示对这三位的写操作可以成功。剩下的5位对它们进行任何写操作都不会改变GPIODATA的值。 换句话说,如果想用一个数字同时操作一组GPIO的8个引脚,就应当在偏移量为0x3FC的地址上写。如果在偏移量为0x000的地址上写,则不会有任何效果。 2、再来看读操作

如上图所示: 第一行方块表示地址偏移量 第二行方块表示GPIODATA的当前值 第三行方块表示读操作返回值 上图的地址偏移量为0x04C,表示只会返回GPIODATA中第2、6、7这三个位的结果,其它位的值不会返回。 这样做的好处翻译一下:软件驱动可在一个单周期指令内完成对单个GPIO引脚的修改,而不影响其它引脚的状态。相对于传统方法的读-改-写操作去设置或清除单个GPIO引脚,此方法更具效率。 下面可以推断出,三盏LED所在GPIO Port A1基地址0x40005000;我们打算象51单片机那样同时控制3盏灯,3盏灯处于A口的第1、2、3位。为不影响其它GPIO口,偏移量应设计为二进制的(0000111000),即16进制的0x038。 最终结果:[0x40005000 + 0x00E] = xx 好,该讲的讲完了,不容易啊!下面可以写程序了。这回写最底层的象51单片机一样的程序。 例一:三盏灯同时闪烁: 首先单击菜单【Project】-->【New CCS Project】,弹出新建项目窗体,画红框的地方按图进行设置,Project name可以自己起。

接下来在自动生成的main.c文件输入如下代码:

//延时函数 void delay(int temp) { int i = 0; for (i = 0; i < temp; i++); } int main(void) { //开启GPIOA1时钟 *((volatile unsigned long *)(0x44025000 + 0x58)) = 0x01; //设置3个LED引脚为输出方向 *((volatile unsigned long *)(0x40005000 + 0x400)) |= 0x0E; //配置3个LED引脚为GPIO,电流强度为2mA *((volatile unsigned long *)(0x4402E0C4)) = 0x20; *((volatile unsigned long *)(0x4402E0C8)) = 0x20; *((volatile unsigned long *)(0x4402E0CC)) = 0x20; while(1) { //同时点亮3盏LED *((volatile unsigned long *)(0x40005000 + 0x038)) = 0x0E; delay(0x2fffff); //同时熄灭3盏LED *((volatile unsigned long *)(0x40005000 + 0x038)) = 0x00; delay(0x2fffff); } }

这程序牛啊,未引用任何头文件! 单击绿色甲壳虫按钮(Debug),烧进开发板后按绿色三角(Resume)按钮,观察开发板,三盏灯同时闪烁。大功告成,走到这一步不容易啊! 心情好,再来个跑马灯: void delay(int temp) { int i = 0; for (i = 0; i < temp; i++); } int main(void) { //开启GPIOA1时钟 *((volatile unsigned long *)(0x44025000 + 0x58)) = 0x01; //设置3个LED引脚为输出方向 *((volatile unsigned long *)(0x40005000 + 0x400)) |= 0x0E; //配置3个LED引脚为GPIO,电流强度为2mA *((volatile unsigned long *)(0x4402E0C4)) = 0x20; *((volatile unsigned long *)(0x4402E0C8)) = 0x20; *((volatile unsigned long *)(0x4402E0CC)) = 0x20; int flag = 2; while(1) { *((volatile unsigned long *)(0x40005000 + 0x038)) = flag; flag = (flag == 8) ? 2 : flag << 1; delay(0x2fffff); } } 本文参考了 阿汤哥的文章 ,没他的文章我是肯定没办法写出这程序的,有部分内容他没讲清楚,我这也算是补全了吧。

转载请注明原文地址: https://www.6miu.com/read-62115.html

最新回复(0)