第一章 创建CCS项目
1.1 28335_RAM_lnk.cmd文件作用
随便在B站上找个视频学着创建CCS工程,在最后选择项目模板和样例(Project templates and examples)时,选择带有main.c的选项。创建完成后,左侧会一些文件生成,其中28335_RAM_lnk.cmd文件的作用就是进行RAM存储空间的配置,从命名中的RAM和lnk(表示link)也能看出些端倪,这个文件是对随机存储器RAM操作。可以理解通过这个文件完成了代码中的虚拟地址向物理地址进行映射等操作。在前期调试过程中,借助这个文件,通过仿真器将代码存放在RAM中进行调试。根据存储器基础知识可知,RAM内的内容,断电后就会消失,但读写速度快,适合调试过程。当调试完成后需要借助另一个cmd配置文件,将其烧录进不易失ROM中。由于现在包括DSP在内的嵌入式都采用Flash ROM,有时也会用flash来表示嵌入式的ROM。
具体CMD完成了哪些事情,双击文件后,查看它的代码,然后通过《手把手教你学DSP基于MS320F28335》4.1章F28335存储空间配置进行辅助学习,书中图4.1就是CMD中MEMORY{}代码段做的事。
1.2 头文件
虽然在创建项目时,CCS在Includes生成一些头文件,但这只是最基本的,以所使用的嵌入式芯片型号无关的头文件,涉及特定芯片型号烧录ROM的cmd和一些外设(例如CAN总线、ECAN等)以及延时函数的头文件需要在TI公司,或者开发板的经销商打包的资料里去找。
1.3 完整工程所需要的其他基础文件
1.3.1 BIOS或nonBIOS.cmd
除了1.1节提到了调试和烧写进Flash时需要的cmd文件,还有根据嵌入式设备是否有操作系统所需的BIOS配置文件。当嵌入式设备没有操作系统时,使用nonBIOS.cmd,需要操作系统时使用BIOS.cmd。
1.3.2 芯片的目标配置文件.ccxml
可以理解为,需要这个文件,宿主机和目标机之间才能建立联系。
1.3.3 芯片内核及外设.c源文件及相应.h头文件
比如DSP28335_Gpio.C、DSP28335_PieCtrl.c(中断源文件)等。那么这些源文件对应的头文件也应当包含进工程的基础文件中。
1.4 系统时钟
任何一种芯片不仅是CPU,包括外设的芯片都需要时钟信号作为基础单元为其工作,因为芯片的主频决定了执行一条基本指令所花费的时间。根据原理图,该开发板采用的是频率为32.768kHz的晶体,但是F28335芯片的最高主频为150MHz,为了充分发挥芯片性能,我们希望芯片主频工作在最高主频。
通过内部锁相环(PLL)对内部或外部时钟源信号进行分频和倍频。从时钟域锁相环控制电路原理图可以看到,时钟源信号经过异或门后成为OSCCLK(振荡器时钟信号),该信号受到锁相环寄存器(PLLSTS)的OSCOFF位控制,当该开关闭合后,OSCCLK信号会分为两路,一路直接经过0倍频(不加倍数)直接进入分频环节;另一路进入锁相环模块(PLL),当使用锁相环模块时,需通过PLLOFF位将其使能。OSCCLK经过PLL模块后得到相位更为稳定的VCOCLK时钟信号,PLLCR寄存器控制倍频器倍数,当倍数设置为10时,30MHz的VCOCLK将会增长为300MHz,经过DIVSEL位选择分频数后降为150MHz的CLKIN给到CPU。
在备考计算机三级嵌入式的学习中,我们了解到,嵌入式系统还会分为两种方式提供给外设时钟,一种是快速;一种是慢速。我们都通过下图能看到,黑实线的系统时钟为150MHz,会各道很多寄存器有些不经过分频,但有些比如eCAN-A/B就需要经过2分频。
第二章 点亮LED
2.1 功能说明
通过GPIO点亮两个LED。
2.2 硬件电路分析
通过查看硬件电路原理图,LED模块(非核心板)中有D1和D2两个LED,采用的是共阳极接法,控制端分别是PWM7和PWM8。
通过核心板双排针模块能找到PWM7和PWM8分别对应PWM4A和PWM4B的别名,这个别名对应就是芯片的引脚名。
在核心板原理图的芯片管脚中找到了对应PWM4A和PWM4B,又分别对应的GPIO6和GPIO7。至此,我们知道了,如果要点亮D1和D2两个LED,必须使得GPIO6和GPIO7输出低电平。28335的GPIO引脚有GPIO0~GPIO87,共88个,其中GPIO0~GPIO31为A组,GPIO32~GPIO63为B组,GPIO64~GPIO87为C组。后续,我们将使用A组的相关寄存器去控制GPIO6和GPIO7。
2.3 GPIO初始化
在使用GPIO之前先要对GPIO进行初始化,包括对GPIO功能选择和GPIO外设时钟等初始化。
2.3.1 GPIO时钟使能(初始化)
首先对外设GPIO时钟进行使能,外设时钟统一由外设时钟控制寄存器PCLCCR0、1、3来控制,通过查找其功能定义表,发现GPIO时钟使能位在寄存器PCLCCR3的第13位。TI提供的编译库文件中,将寄存器用C语言结构体的方式封装好了,使用PCLCCR3.GPIOINENCLK=1就能将其使能。
外设时钟控制寄存器PCLCCR3各位定义
在将TI提供时钟操作程序源文件DSP2833x_SysCtrl.c放入项目文件夹中,在这里,我采用新建Source文件夹存放。
通过点开DSP2833x_SysCtrl.c文件左侧的三角符号可以看到,该源程序包含有7个函数、2个引用的头文件。头文件图标左下角侧有黄色感叹号,这是因为该源文件所引用的头文件并未包含在该项目列表中,在这里,我通过再新建一个INCLUDE文件夹存放这些支撑函数所涉及到头文件,就不将其放入CCS系统的编译器库中,即Includes文件夹路径。具体系统库路径可翻看前面1.2章节截图。将这些头文件放在项目文件夹而不是系统文件夹下的好处在于,当将整个项目文件夹复制到另一台电脑运行时,避免了其CCS系统库中没有对应头文件的尴尬。
但是,当你再次点开新建的INCLUDE文件夹里的DSP2833x_Device.h文件,会发现它们所引用的头文件同样缺乏,所以一劳永逸的方法就是将所有头文件直接复制过来。复制完后,编译(工具栏中锤子图标)一下,看看有无报错。
再次编译后,出现报错,根据报错信息,是在DSP2833x_SysCtrl.obj的文件中存在无法解析的符号。而包含这些无法解析的符号的文件也在TI或者经销商提供的资料包里。
找到压缩包中的以下文件,其中DSP2833x_SysCtrl.c是我们最开始使用的系统时钟源文件。将所有文件复制进项目文件夹。
再次编译,将没有报错。
经过配置系统时钟文件的操作,我们以大致了解,缺乏哪些文件将会出现报错的情况,熟悉了各种文件之间的联系,在以后的使用中,我们将直接把所有配置文件、源文件和头文件复制进项目文件夹, 不再逐个查看。
在main函数,我们调用函数InitSysCtrl()初始化系统时钟,命名中Init的含义就是Initial,最初的,开始的意思,这在很多程序中很常见,表示初始化某个模块。通过按住Ctrl再左键点击函数就能直接进入该函数所在源文件中,进行查看该函数以及其他函数的详细信息。
在InitSysCtrl()中,又包含了关闭看门狗、初始化PLL控制器和初始化外部时钟函数。
先看InitPll()函数,该函数有DSP28_PLLCR和DSP28_DIVSEL这2个实参,其值就是锁相环控制电路中的倍频系数和分频系数,通过Ctrl+左键的方式查看传入的实参,其值是通过宏定义确定的,后续标注中的列写了倍频系数和分频系数所能设置的值,设置时将其取消标注就行。经过10倍频和2分频后,目前系统时钟为150MHz。
InitPeripheralClocks() 函数中首先通过结构体SysCtrlRegs.HISPCP.all和SysCtrlRegs.LOSPCP.all分别设置的外设高速时钟和低速时钟的分频系数。其中0x????中的?表示1位十六进制数,1位十六进制对应4位二进制,4个十六进制正好对16位的外设时钟寄存器。0x0001表示(0000 0000 0000 0001)B,根据高速外设时钟分频寄存器分配表,低3位为有效位,即001表示系统时钟频率需经过2分频提供给高速外设时钟,150MHz的系统时钟经过2分频后为75MHz。低速时钟依次类推。
同时,能在该函数体的最后看到,GPIO的时钟使能已经打开。至此,关于系统时钟和外设时钟设置所涉及的部分已经完成。
2.3.2 GPIO
GPIO的控制涉及到一下几个寄存器:GPxMux、GPxDIR、GPxDAT、GPxSET、GPxCLEAR和GPxTOOGLE。其中“GPx…”中的“x”表示GPIO分组当中的A、B或C。GPxMux寄存器控制每个GPIO引脚的功能,分别有普通I/O口功能和外设专用功能,当选择作为普通I/O功能后,还需要通过GPxDIR寄存器设置是作为输入(Input)还是输出(Output)。
第三章 编写程序和测试结果
3.1 main函数程序解释
由于在对GPIO进行初始化会涉及对GPIO结构体的操作,通常都会需要DSP2833x_Device.h和DSP2833x_Examples.h两个头文件,就如同在终端中的stdio.h一样。
EALLOW和EDIS两个命令是对控制寄存器进行保护功能的操作,作用在于防止程序中对控制寄存器的误操作。注意!仅限于控制寄存器,对数据寄存器没有保护功能。EALLOW为关闭写保护,在对控制寄存器进行操作之前必须使用该命令;EDIS为打开写保护,设置完控制寄存器后必须使用该命令。
结构体变量GpioCtrlRegs中有元素GPxMUX、GPxDIR、GPxPUD等,其中“Ctrl”表示“控制”,“Regs”表示“寄存器”,由于GPIO6和GPIO7在A组,并且GPAMUX1控制其中的GPIO0~GPIO15,GPAMUX2控制GPIO16~GPIO31。
GPxPUD为上拉功能控制寄存器,其中“PU”表示为“PULL UP”,该寄存器功能为:当设备上电启动开始后,程序运行到I/O口功能之前,对GPIO引脚的电平进行控制。由于D1和D2是对应I/O口低电平点亮,那么在上电启动后,I/O应为高电平。
对GPIO进行输出时,采用的是数据寄存器GpioDataRegs。在对GPIODAT寄存器进行控制时,与之前按位控制不同,这次采用全位控制(我自己瞎编的)。由于A组数据寄存器是32位的,从低到高每一位对应GPIO0~GPIO31引脚,当要GPIO6和GPIO7要输出低电平“0”时,那么GPADAT寄存器位应该为(1111 1111 1111 1111 1111 1111 0011 1111)B=(FFFFFF3F)H,采用按位与的方式进行设置。同理,熄灭时按位或的方式控制。这部分寄存器位的含义在《手把手教你学DSP基于MS320F28335》中没有,需寻找随开发板的文件手册。
/**
* main.c
*/
#include "DSP2833x_Device.h"
#include "DSP2833x_Examples.h"
int main(void)
{
InitSysCtrl(); //初始化系统时钟
EALLOW; //关闭写保护
GpioCtrlRegs.GPAMUX1.bit.GPIO6=0; //GPIO6设置为普通I/O功能
GpioCtrlRegs.GPADIR.bit.GPIO6=1; //GPIO6设置为输出
GpioCtrlRegs.GPAPUD.bit.GPIO6=0; //GPIO6上拉使能
GpioCtrlRegs.GPAMUX1.bit.GPIO7=0;
GpioCtrlRegs.GPADIR.bit.GPIO7=1;
GpioCtrlRegs.GPAPUD.bit.GPIO7=0;
EDIS; //打开写保护
// GpioDataRegs.GPADAT.all=GpioDataRegs.GPADAT.all | 0x000000C0; //D1和D2都熄灭
GpioDataRegs.GPADAT.all=GpioDataRegs.GPADAT.all & 0xFFFFFF3F; //D1和D2都点亮
return 0;
}
3.2 烧录和测试
将开发板通过仿真器与宿主机连接后,按工具栏中的Debug(小虫子图标)烧录到RAM中进行调试。
烧录完成后,按工具栏中的Resume键运行。底板处的D1和D2已点亮。