【CC3200 评测】CC3200-LAUNCHXL开发板使用心得分享 -CC3200外设之GPIO深入篇(库函数和寄存器)By CUG_Xiao

       大家好,我是cug-xiao,今天为大家带来的是CC3200外设之GPIO详解

       首先呢,我们先来了解一下如何开发CC3200的外设。毫无疑问的,两种方式:寄存器和库函数。

       咱们首先来说简单的库函数,ti官方有提供driverlib,咱们只需要在include里面添加好驱动库的路径,在使用时只需要include相应头文件就可以愉快的使用库函数了。

       首先咱们来建立工程,直接File -> New -> CCS Project,取好名字点Finsh即可。新建好工程模板之后我们还需要修改cmd文件(可直接从官方例程复制)和新建一个ccxml文件(可直接从官方例程复制),这俩文件是用来Debug的。

       然后呢我们需要在include下添加驱动库路径,右键工程名选择最下方的Properties会弹出如下窗口。

       咱们点击ARM Compiler下的include Options,点击加号即可选择我们的驱动库路径,官方例程中的common文件路径可以不用添加,因为这个是专门为CC3200这个开发板写的接口,若是我们以后自己用CC3200绘制板子做应用,这个接口就用不到了,这种接口我们一般将其称之为BSP(Board Support Package,即板级支持包),不是通用接口,像driverlib这种底层一点的驱动库才是我们需要的。

       好了,将驱动库路径添加好之后不要着急关闭这个页面,因为我们还有一步需要完成,点击ARM Linker,选择File Search Path,添加driverlib.a这个文件,这是告诉编译器去哪找头文件相对应的源文件,如果没有这一步是无法编译通过的哟(提示无法找到函数定义)。添加好后如下图。

       好啦,工程模板建好了,下面就要开始愉快的编码了。本来以为是挺简单的一个过程(如果很简单的话就没有这个帖子了~~),结果还是有许多坑的。

       首先咱们看看官方怎么写的,嗯,相比于我们的工程多了pinmux文件和gpio_if文件。不用多说,pinmux是引脚配置文件,将与LED相连的机构引脚配置为输出模式,这个文件可以使用我们之前提到的Pin Mux Tool这个工具来直接生成;gpio_if这个文件呢是官方BSP里面的,可以看到我们的LED驱动就只在这一个文件夹里实现的,咱们自己实现的话,最好不要使用这个文件,当然可以用来参考。不过我个人觉得这个驱动实现的有点七拐八绕的,不容易看明白具体如何实现的,特别是在CC3200的GPIO分组奇奇怪怪的情况下。

       接下来咱们来聊一聊CC3200的GPIO,作为一个第一次接触ti的开发板的开发者来讲,这个板子(我不知道其他的开发板是不是也是这样)的GPIO实在是有点奇怪,在程序中即用到了芯片的引脚号(PIN_01~PIN_64),也用到了GPIO编号(GPIO00~GPIO31),还用到了GPIO组号(GPIO_A0~A3,GPIO_PIN_00~07),而且在使用库函数时这三个参数都需要使用到。而这其中的对应关系,说实话阻隔了我一段时间。

       这其中的映射关系我们有一下几种方式了解到:

①    查表,在pin.c下有这么一个表,存放的就是PIN至GPIO的映射关系。

②    看官方数据手册(72页的),从第8页开始,也可以找到对应关系

③    使用Pin Mux Tool这个工具,添加GPIO后就可以直接看到对应关系,配置需要使用到的GPIO就可以直接生成配置函数。值得一提的是这个工具生成的函数GPIO_PIN入口参数竟然是数字,作为一个个读程序的人来说,纯数字是没有任何意义的(大大的吐槽一下),而且驱动库里明明有相应的宏定义,官方却没有使用。

       好了,通过以上几种方式我们知道了芯片引脚编号和GPIO引脚的映射关系了,就差GPIO的分组了,这个就稍微简单一点,GPIO00~31共32个IO(能用的没这么多)可以分4组(其实有5组),后面的编号对8取模就是组号,取余就是对于引脚号(这个算法可以在官方BSP中gpio_if.c中找到),比如GPIO00就对应GPIOA0,GPIO_PIN0,GPIO09就对应GPIOA1,GPIO_PIN1。

       到此为止终于是弄清了这个映射关系,终于可以愉快的写代码了,首先咱们让我们板子上的led闪烁起来:首先外部声明全局向量表和BoardInit这俩直接从官方例程复制即可,咱们只需要编写GPIO_Init和main函数即可,GPIO的初始化首先要使能相应GPIO组的时钟,通过前面的方式我们只知道板子上的LED7为PIN_64对应GPIO09,对应GPIOA1,GPIO_PIN_1,设置引脚模式,和输入输出方向即可成功初始化,这里我们初始化之后默认输出0,再在主循环里翻转GPIO的输出电平即可达到LED闪烁效果。

       下面是驱动板子上的LED代码

       代码写好了,我们来试试Debug(注意,需要验证代码时我们只需要Debug即可,没有必要每次都烧写到flash里面,毕竟烧写是比较麻烦的,咱们直接下载到RAM里调试即可,这个我们直接Debug,cmd文件官方已经写好,我们无需修改。需要Debug时直接右键工程名选择Debug As -> CCDS,进入调试界面后可以一直运行或者单步运行等等,包括断点等等调试手段都是有的),点击一直运行后可以发现板子上的LED闪烁起来了,不过复位或者掉电之后就啥也没有了。

下面我们来试试其他IO行不行,其他IO没接东西,想知道他的状态咱们可以使用read函数读取。可以看到也是可以的。

       OK,以上就是使用库函数点灯的方式,下面咱们来讲一讲更底层的寄存器(有兴趣的朋友可以继续看下去)。

       首先呢咱们使用寄存器开发的话得需要更详细的资料,咱们可以去找CC3200的寄存器手册(swru367,572页),刚才的数据手册(72页)就没多大作用了。

       这次呢,同样的使LED7闪烁起来,只不过是直接使用寄存器实现的。

       初始化GPIO,即使能GPIO相应端口的时钟,咱们使用到的GPIO为GPIOA1的GPIO_PIN_1,所以呢咱们翻到手册第487页,需要使能GPIO1的时钟

可以看到想要使能时钟需要将GPIO1CLKEN寄存器的最低位置1,即使能时钟在运行模式,那么这个寄存器的地址是多少呢?首先这个寄存器是属于PRCM(Power,Reset and Clock Management)寄存器组的,我们得知道他的基地址,见下图可看出PRCM基地址为0x44025000,而上面的土中则可以看到GPIO1CLKEN的偏移地址为0x58,所以呢,GPIO1CLKEN的最终地址为0x44025058。

       时钟使能之后呢,咱们需要配置引脚,寄存器地址如下

Config寄存器地址知道了,怎么配置呢,见下图

可以看到低4位用来决定该引脚是用来干什么的,具体哪个值对应哪个功能呢,见下图

这个寄存器我们还需要设置的是位【4】是否开漏输出,咱们驱动LED不需要,位【7】~【5】,设置驱动电流,一般为2mA,后面的则是一些无关紧要的寄存器,后面需要用到再说,

       引脚配置好之后呢咱们就可以配置GPIO这个外设了,在此之前咱们首先来看看寄存器表

       咱们驱动LED的话只需要使用以上两个寄存器即可,其他寄存器都是用来配置中断的,首先咱们配置GPIO方向

咱们把相应为配置为1即可输出。输入输出模式配好之后就可以控制GPIO输出高低电平啦,那怎么控制呢,见下图

DATA里的8位数据分别控制8个IO口的电平,那前面这一堆英文是什么意思呢,这就需要看手册了

乍一看还是比较复杂难懂,在看了半天代码后终于有一点明悟了,对于写GPIODATA来说,0x098代表什么意思?意思是说我只想让GPIO_PIN_5、2、1改变,其他GPIO就算你往里写1也不会改变,那为什么不直接使用低8位来表示,而要左移两位呢,因为我们的GPIO的的引脚数值是递增1的(原本可以是位【0】代表GPIO0,位【1】代表GPIO1),但是我们的DATA寄存器却是32位的,每加1,地址需要往后移4个字节,所以就造成了需要左移两位的情况,就是说现在是这样的,8个GPIO哪个需要改变哪个不需要改变总共有256中排列组合(2的8次方),所以呢我们的ti工程师就在这一片地址空间里总共设置了256个地址,每个地址都可以独立配置,这样做可以方便软件(这样的硬件真贴心),如何方便呢,可能你还没有明白,简单举个例子,比如地址(偏移)为0x000,就是每个GPIO都不想改变,你往这个地址里写任何值GPIO的电平都不会有变化,那地址(偏移)为0x004呢(低2位必须为0 ,因为我们的寄存器是32位的,一下得增加4字节),就是只想改变GPIO_PIN_0,就算你往里写0xff,也只会把GPIO_PIN_0写成1,其他GPIO原来是什么电平现在就是什么电平,丝毫不为所动,这下大家懂了吧。

       评价一下这种读写配置方式,嗯虽然对于软件的编写来说是方便了点,不过这个文档看起来就略微有点费劲了,而且感觉有点浪费地址。不过呢地址空间够大(32位机最大能用4个G的地址空间),浪费一点也没啥关系。好了下面咱们开始愉快的编写代码吧。

       编码的时候就很简单了,直接往寄存器里写值就好了,写好的代码如下图

       可以看到我们往寄存器里写值是这样的*((volatile unsigned long *)值),有些同学可能不知道这是什么意思啊,我稍微解释一下,(volatile unsigned long *)这个是强制转化,转换成什么呢,可变的无符号长整型指针,这个指针指向的地址就是这个“值”,然后我们使用*来引用这个指针,往里写值或者读取这个地址里的值。怎么样,是不是感觉很简单。

       OK,既然代码写好了,下面咱们来debug一下(Debug的时候板子上的跳线帽保持出厂时候的样子就行了,不像烧写代码的时候一样要插一个跳冒),右键工程名选择Debug As -> CCDS,进入调试状态,点击一直运行就可以看到板子上的LED7欢快的闪烁起来啦。

       好了,以上就是今天的全部内容,谢谢大家!!

 

13 个回复