承接上一篇学习笔记,这次开始实际运行例程。每学习一个新的DSP都是从点灯开始,这次也不例外。TI的官方帮助文档[1]可以在C:\ti\c2000\C2000Ware_2_01_00_00\device_support\f28004x\docs\F28004x_DEV_USER_GUIDE.pdf找到。里面为新人提供了step by step的入门指南以及所有例程的说明。TI提供了两套例程,其中寄存器编程的例程在C:\ti\c2000\C2000Ware_2_01_00_00\device_support\f28004x,库函数编程的例程在C:\ti\c2000\C2000Ware_2_01_00_00\driverlib\f28004x\examples。本次实验参考的例程是Led_ex1_blinky。未来学习其他型号的DSP也可以按此步骤开始。
在文献[1]中有这样的描述
在CCS9.3中对应的设置为:
这个设置的目的是为了匹配不同的硬件。对于两款处理器28379D和280049C,TI分别发布了ControlCARD和LaunchPad,他们的晶振和引脚配置等各不相同。例程是针对ControlCARD开发的,如果想将其应用到LaunchPad上,自然需要更改引脚映射。具体的代码可以在devices.h中找到,部分截图如下:
需要说明的是,如果完全自己从零开始定义引脚,开发程序,并不需要理会这部分条件编译指令。
这小节给出来自官方文件夹的Led闪烁实验的两份例程,第一份是库函数编程版本的,第二份是寄存器编程的。可以看出在初始化函数的调用部分有显著差别。
280049C LaunchPad的Led部分电路图如下:
库函数版:
#include "driverlib.h"
#include "device.h"
# define LOOP_COUNT 10
void main(void)
{
// 初始化时钟和外设 Initialize device clock and peripherals
Device_init();
// 初始化GPIO并设置为推挽输出 Initialize GPIO and configure the GPIO pin as a push-pull output
Device_initGPIO();
GPIO_setPadConfig(DEVICE_GPIO_PIN_LED1, GPIO_PIN_TYPE_STD); // Push-pull output or floating input
GPIO_setDirectionMode(DEVICE_GPIO_PIN_LED1, GPIO_DIR_MODE_OUT);
// 初始化PIE并清空PIE寄存器,关闭CPU中断
// Initialize PIE and clear PIE registers. Disables CPU interrupts.
Interrupt_initModule();
// 初始化PIE向量表
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
Interrupt_initVectorTable();
// Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
EINT;
ERTM;
// Loop Forever
for(;;)
{
// Turn on LED
// 硬件电路设计是GPIO输出低电平时LED亮
GPIO_writePin(DEVICE_GPIO_PIN_LED1, 0);
// 延迟0.5s Delay for a bit.
DEVICE_DELAY_US(500000);
// Turn off LED
GPIO_writePin(DEVICE_GPIO_PIN_LED1, 1);
// Delay for a bit.
DEVICE_DELAY_US(500000);
}
}
寄存器版:
#include "F28x_Project.h"
#define DEVICE_GPIO_PIN_LED1 31
void main(void)
{
// Initialize device clock and peripherals
InitSysCtrl();
// Initialize GPIO and configure the GPIO pin as a push-pull output
InitGpio();
GPIO_SetupPinMux(DEVICE_GPIO_PIN_LED1, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(DEVICE_GPIO_PIN_LED1, GPIO_OUTPUT, GPIO_PUSHPULL);
// Initialize PIE and clear PIE registers. Disables CPU interrupts.
DINT;
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
InitPieVectTable();
// Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
EINT;
ERTM;
// Loop Forever
for(;;)
{
// Turn on LED
GPIO_WritePin(DEVICE_GPIO_PIN_LED1, 0);
// Delay for a bit.
DELAY_US(500000);
// Turn off LED
GPIO_WritePin(DEVICE_GPIO_PIN_LED1, 1);
// Delay for a bit.
DELAY_US(500000);
}
}
讨论寄存器编程的文章比较多,这里参考[4]进行总结。
第二份代码主函数后第一条语句就是InitSysCtrl(),对芯片进行初始化,该函数的声明在f28004x_sysctrl.c中。
芯片在上电或复位后会自动使能看门狗,所以初始化函数的第一句是将其关闭,具体代码如下:
void DisableDog(void)
{
volatile Uint16 temp;
EALLOW;
//
// Grab the clock config so we don't clobber it
//
temp = WdRegs.WDCR.all & 0x0007;
WdRegs.WDCR.all = 0x0068 | temp;
EDIS;
}
这个代码写的比过去的版本好很多,没有直接赋值,而是采用或的方式,避免了破坏其他时钟设置。
在[5]的3.1节有对EALLOW进行讨论。
在3.14.23.4节有对寄存器的每一位给出详细的解释
根据手册,关闭看门狗对应的二进制是0000 0000 0110 1000,也就是十六进制的0068
剩下的部分就是初始化Flash。以目前的水平看这部分代码还比较困难,暂时跳过。
在这部分,280049C会涉及到一个叫DCC的名词,全称是Dual-Clock Comparator,主要是为了增强时钟信号的可靠性的,在[5]的第6章有论述。
[5]的3.7节对系统时钟做了较详细的介绍,如果阅读有困难可以先参考[7]的相关章节。
280049C的时钟需要从下列时钟源选择
之后就是配置锁相环了,结构如图所示:
LaunchPad和ControlCARD的晶振是20MHz,默认100MHz主频的软件配置是:
//
// PLLSYSCLK = (XTAL_OSC) * (IMULT + FMULT) / (PLLSYSCLKDIV)
// 100MHz=20MHz*(10+0)/2
InitSysPll(XTAL_OSC,IMULT_10,FMULT_0,PLLCLK_BY_2);
280049C的锁相环配置十分自由。这里的时钟配置可以玩儿很多花样,比如把时钟超频到240MHz……
另外似乎没有高速时钟的概念了,仅保留了低速时钟。