DSP28335代码学习

更新时间:2024-03-05 05:02:02 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

1.2、外设位域结构体方法综述 1.2.1、传统#define的方法

C代码访问寄存器的传统方法是使用#define宏为每一个寄存器分配一个地址。例如: #define CPUTIMER0_TIM (volatile unsigned long *) 0x0c00 #define CPUTIMER0_PRD (volatile unsigned long *) 0x0c02 #define CPUTIMER0_TCR(volatile unsigned long *) 0x0c04 #define CPUTIMER0_TPR (volatile unsigned long *) 0x0c06 …..

同样的#define方法将在每一个外设寄存器上不断重复 弊端:

不容易访问寄存器中的位域部分 不容易在CCS观察窗口显示位域的值 不能利用CCS的自动完成功能

对于重复的外设,头文件的开发者不能获得重复利用的便利。

1.2.2、位域及结构体的方法

位域及结构体方法采用C代码的结构体方式,将属于某个指定外设的所有寄存器组成一个集合。通过链接器,每个C代码结构体就是外设寄存器的内存映射。这一映射允许编译器通过使用CPU数据页指针(DP)直接访问外设寄存器。另外,多数寄存器都定义了位域,从而使编译器能够读取或者操作某一个寄存器中的单个位域。 (1)下面代码是

下面代码示例是一个DSP28335的CPU定时器存器对应的C代码结构体类型。 // CPU Timer Register File: //

struct CPUTIMER_REGS {

union TIM_GROUP TIM; // Timer counter register union PRD_GROUP PRD; // Period register union TCR_REG TCR; // Timer control register Uint16 rsvd1; // reserved

union TPR_REG TPR; // Timer pre-scale low union TPRH_REG TPRH; // Timer pre-scale high };

该结构体类型包括6个成员组成,前后顺序与他们在内存中的顺序相同。CPUTIMER_REGS代表了一个结构体类型。他和系统已经定义的标准类型如int,char等一样可以用来作为定义变量的类型。 注意:

1、寄存器名字出现的顺序必须与他们在内存中被安排的顺序相同

2、在结构体中,通过使用保留变量rsvd1等来预留内存中的保留位置。这种保留结构体仅仅用以预留内存中的空间 3、Uint16 是无符号16位数类型定义,相应的类型定义申明由DSP2833x_Device.h文件建立。 (2)申明可访问寄存器的变量

寄存器结构类型可被用来申明一个可访问寄存器的变量,对器件的每个外设都采用这一相同的做法,同一种外设的复用外设可以采用同样的结构体类型定义。例如一个器件上有3个CPU-timer,可以创建如下所示的3个具有struct CPUTIMER_REGS结构体类型的变量。

volatile struct CPUTIMER_REGS CpuTimer0Regs ; // 定义CpuTimer0Regs是一个具有CPUTIMER_REGS类型的变量 volatile struct CPUTIMER_REGS CpuTimer1Regs ; volatile struct CPUTIMER_REGS CpuTimer2Regs ;

关键字volatile在变量声明中十分重要。它告诉编译器,这些变量的内容可由硬件改变,并且编译器无需优化使用volatile变量的代码。

(3)分配专用的数据区

单有上面的两个定义还不够,还必须为3个CPU定时器分配数据区。分配某个定时器在数据区的起始地址必须与系统定义的该定时器的内存地址一致。在DSP2833x_GlobalVariableDefs.c文件中,通过使用编译器的#pragma DATA_SECTION指令,与外设寄存器结构体类型相对应的每一个变量分配一个专用的数据区。任何使用DSP2833x外设头文件的项目都必须包含这个源文件。该文件时外设寄存器结构体变量及数据区分配的一个声明,在source目录中建立。下面代码为定时器0,1,2分配的数据区。 // FILE: // TITLE:

DSP2833x_GlobalVariableDefs.c// 全局变量默认文件 DSP2833x Global Variables and Data Section Pragmas.//

//########################################################################### // $TI Release: DSP2833x/DSP2823x C/C++ Header Files V1.31 $ // $Release Date: August 4, 2009 $

//########################################################################### #include \ // DSP2833x Headerfile Include File //--------------------------------------------------------------------------- // Define Global Peripheral Variables: //----------------------------------------

#ifdef __cplusplus // 用于C++代码 #pragma DATA_SECTION(\#else

#pragma DATA_SECTION(CpuTimer0Regs,\ // 用于C代码 #endif

volatile struct CPUTIMER_REGS CpuTimer0Regs;

//---------------------------------------- #ifdef __cplusplus

#pragma DATA_SECTION(\#else

#pragma DATA_SECTION(CpuTimer1Regs,\#endif

volatile struct CPUTIMER_REGS CpuTimer1Regs;

//---------------------------------------- #ifdef __cplusplus

#pragma DATA_SECTION(\#else

#pragma DATA_SECTION(CpuTimer2Regs,\#endif

volatile struct CPUTIMER_REGS CpuTimer2Regs; 注:

#ifdef #else #endif 为预处理器条件编译指令。对器件的每个外设寄存器结构体变量,都会重复这一数据区分配操作。 (4)映射到外设寄存器

当每个结构体都分配到自身的数据区以后,通过使用链接命令文件DSP2833x_Header_nonBIOS.cmd ,

FILE: DSP2833x_Headers_nonBIOS.cmd

// TITLE: DSP2833x Peripheral registers linker command file // DESCRIPTION:

// This file is for use in Non-BIOS applications. // Linker command file to place the peripheral structures // used within the DSP2833x headerfiles into the correct memory // mapped locations.

// This version of the file includes the PieVectorTable structure.

// For BIOS applications, please use the DSP2833x_Headers_BIOS.cmd file // which does not include the PieVectorTable structure.

//########################################################################### MEMORY /*定义存储区域*/ {

PAGE 0: /* Program Memory */ PAGE 1: /* Data Memory */

CPU_TIMER0 : origin = 0x000C00, length = 0x000008 /* CPU Timer0 registers */

CPU_TIMER1 : origin = 0x000C08, length = 0x000008 /* CPU Timer0 registers (CPU Timer1 & Timer2 reserved TI use)*/ CPU_TIMER2 : origin = 0x000C10, length = 0x000008 /* CPU Timer0 registers (CPU Timer1 & Timer2 reserved TI use)*/ }

SECTIONS /*分配存储区域*/ {

CpuTimer0RegsFile : > CPU_TIMER0, PAGE = 1 /* 将CpuTimer0RegsFile段分配到CPU_TIMER0区域*/ CpuTimer1RegsFile : > CPU_TIMER1, PAGE = 1 CpuTimer2RegsFile : > CPU_TIMER2, PAGE = 1 }

通过把变量直接映射到外设寄存器的同一内存地址,用户采用C代码对寄存器进行访问,只需要通过访问变量中所需的成员即可。例如对CpuTimer0 TCR寄存器进行写操作,只需访问CpuTimer0Regs变量中的TCR成员,如以下代码所示: CpuTimer0Regs.TCR.all = TSS_MASK;

上面的操作是对CpuTimer0Regs.TCR整体赋值操作,可以通过添加位域结构体,直接访问某位。 1.2.3 添加位域结构体 (1)增加位域定义

我们经常需要直接访问寄存器中的某一位,C2833x C头文件及外设示例所涉及的位域结构体方法,为多数片上外设寄存器提供了位域定义。例如CPU_Timer控制寄存器的位域定义如下 // CPU Timer Register Bit Definitions: // TCR: Control register bit definitions:

struct TCR_BITS { // bits description Uint16 rsvd1:4; // 3:0 reserved Uint16 TSS:1; // 4 Timer Start/Stop Uint16 TRB:1; // 5 Timer reload Uint16 rsvd2:4; // 9:6 reserved

Uint16 SOFT:1; // 10 Emulation modes Uint16 FREE:1; // 11

Uint16 rsvd3:2; // 12:13 reserved Uint16 TIE:1; // 14 Output enable

Uint16 TIF:1; // 15 Interrupt flag };

然后通过共用体进行申明,以便访问位域结构体定义的各个成员或者16位或32位寄存器的值。例如,定时器的控制寄存器共用体如下所示:

// FILE: DSP2833x_CpuTimers.h

union TCR_REG // 定义共用体类型TCR_REG(不是变量) {

Uint16 all;

struct TCR_BITS bit; //bit是一个具有TCR_BITS结构体类型的变量 }; 还例如:

// TPR: Pre-scale low bit definitions:

struct TPR_BITS { // bits description Uint16 TDDR:8; // 7:0 Divide-down low Uint16 PSC:8; // 15:8 Prescale counter low };

union TPR_REG { Uint16 all; struct TPR_BITS bit; };

// TPRH: Pre-scale high bit definitions:

struct TPRH_BITS { // bits description

Uint16 TDDRH:8; // 7:0 Divide-down high Uint16 PSCH:8; // 15:8 Prescale counter high };

union TPRH_REG { Uint16 all; struct TPRH_BITS bit; };

等等,一旦每个寄存器的位域结构体和共用体的定义都建立起来了,则在CPU定时器(CPU-Timer)的寄存器结构体类型中,各个成员可以通过采用共用体定义的形式写。如前文所给的示例: // FILE: DSP2833x_CpuTimers.h // CPU Timer Register File: struct CPUTIMER_REGS {

union TIM_GROUP TIM; // Timer counter register union PRD_GROUP PRD; // Period register union TCR_REG TCR; // Timer control register Uint16 rsvd1; // reserved

union TPR_REG TPR; // Timer pre-scale low union TPRH_REG TPRH; // Timer pre-scale high };

到此,我们就可以既能访问CPUTimer寄存器中的某位,也可以对整个寄存器进行访问: CpuTimer0Regs.TCR.bit.TSS = 1;

CpuTimer0Regs.TCR.all =TSS _MASK;

注意:对没有位域结构体和共用体定义的寄存器,不能使用*.bit或*.all名称进行访问。 2.3、关于ConfigCpuTimer()函数的说明

在DSP2833x_CpuTimers.c中,包含了两个函数:一个是定时器初始化函数InitCpuTimers(),另一个是CPU定时器的配置函数ConfigCpuTimer()。

1、对指令 Timer->RegsAddr->TCR.bit.TRB = 1; 的注解 “struct CPUTIMER_VARS *Timer”

*为指针运算符,Timer是一个具有CPUTIMER_VARS结构体类型的指针变量,它指向结构体CPUTIMER_VARS。通过

(*Timer).xxx可以访问CPUTIMER_VARS结构体中的xxx成员。在C语言中,为使用方便和使之直观,可以把(*Timer).xxx用Timer->xxx来代替。“->”是成员选择指针。看下面指令:

Timer->RegsAddr->TCR.bit.TRB = 1;

为了弄清楚前面两个指针的的含义,先引入结构体CPUTIMER_VARS有关定义。

// CPU Timer Support Variables: //

struct CPUTIMER_VARS //该函数由DSP2833x_CpuTimers.h文件建立 {

volatile struct CPUTIMER_REGS *RegsAddr; Uint32 InterruptCount; float CPUFreqInMHz; float PeriodInUSec; };

这个结构体列出了CPU定时器所支持的变量,其第一个成员是一个包含CPU定时器所有专用寄存器的结构体(CPUTIMER_REGS),RegsAddr是一个具有CPUTIMER_REGS结构体类型的指针变量,InterruptCount是定时器中断计算器,另外两个的乘积构成定时器的周期。

现在再引入CPU定时器寄存器结构体CPUTIMER_REGS的有关定义: // CPU Timer Register File: //

struct CPUTIMER_REGS // 该定义由由DSP2833x_CpuTimers.h文件建立 {

union TIM_GROUP TIM; // Timer counter register union PRD_GROUP PRD; // Period register union TCR_REG TCR; // Timer control register Uint16 rsvd1; // reserved

union TPR_REG TPR; // Timer pre-scale low 定时器预定标计数低位 union TPRH_REG TPRH; // Timer pre-scale high };

这个结构体声明有6个成员,除第4个成员保留外,其余5个均属于CPU定时器专用寄存器,其中“union TCR_REG TCR;”声明TCR_REG是一种共用体类型,同时定义相应的共用体变量TCR,以便引用。下面列出TCR_REG共用体类型定义及TCR控制寄存器位域结构体(TCR_BITS)定义。

// CPU Timer Register Bit Definitions: // TCR: Control register bit definitions:

struct TCR_BITS //该定义由由DSP2833x_CpuTimers.h文件建立 { // bits description

Uint16 rsvd1:4; // 3:0 reserved

SYSCLKOUT或采样窗限制之外,还可以是异步的。 1、 输入异步

该模式仅用于不需要输入同步的外设或外设自身具有信号同步功能,如通信端口SCI、SPI、eCAN和IIC。如果引脚是GPIO引脚,则异步功能失效。 2、 仅与SYSCLKOUT同步

这是所有引脚复位时默认的输入限制模式。在该模式中,输入信号仅与SYSCLKOUT同步。因为引入的信号不同步,所以需要1个SYSCLKOUT的延迟。 3、 采用采样窗限制

在该模式中,输入信号首先与系统时钟同步(SYSCLKOUT同步),然后在允许输入改变之前通过特定的数个周期进行限制。需要指定两种参数:采样周期、采样数。 3.2程序实例

3.2.1、GPIO切换测试程序(GpioToggle.c) 1、GpioToggle.c文件要点 (1)内容:GPIO切换测试程序

(2)条件:本程序需要DSP2833Xv1.00头文件支持,另外还需要配置成“boot to H0”操作方式。除了boot方式配置之外,不需要其他的硬件配置。

(3)说明:这里包含了(数据寄存器方式、置位/清除寄存器方式、切换寄存器方式),可在编译前通过对程序开头#define声明选择执行其中的一个,并通过示波器观察各个引脚的输出波形。 2、GpioToggle.c文件 Example_2833xGpioToggle.c //

// TITLE: DSP2833x Device GPIO toggle test program.

#include \ // Device Headerfile and Examples Include File

// Select the example to compile in. Only one example should be set as 1 // the rest should be set as 0.

#define EXAMPLE1 1 // Use DATA registers to toggle I/O's #define EXAMPLE2 0 // Use SET/CLEAR registers to toggle I/O's #define EXAMPLE3 0 // Use TOGGLE registers to toggle I/O's

// Prototype statements for functions found within this file. void delay_loop(void);

void Gpio_select(void); //Gpio配置函数

void Gpio_example1(void); //用数据寄存器设置I/O引脚电平函数 void Gpio_example2(void); //用置位/清除寄存器设置I/O引脚电平函数 void Gpio_example3(void); //用切换寄存器设置I/O引脚电平函数

void main(void) {

// Step 1. Initialize System Control: // PLL, WatchDog, enable Peripheral Clocks

// This example function is found in the DSP2833x_SysCtrl.c file.

InitSysCtrl();

// Step 2. Initalize GPIO:

// This example function is found in the DSP2833x_Gpio.c file and // illustrates how to set the GPIO to it's default state. // InitGpio(); // Skipped for this example

// For this example use the following configuration: Gpio_select();

// Step 3. Clear all interrupts and initialize PIE vector table: // Disable CPU interrupts DINT;

// Initialize PIE control registers to their default state. // The default state is all PIE interrupts disabled and flags // are cleared.

// This function is found in the DSP2833x_PieCtrl.c file. InitPieCtrl();

// Disable CPU interrupts and clear all CPU interrupt flags: IER = 0x0000; IFR = 0x0000;

// Initialize the PIE vector table with pointers to the shell Interrupt // Service Routines (ISR).

// This will populate the entire table, even if the interrupt // is not used in this example. This is useful for debug purposes. // The shell ISR routines are found in DSP2833x_DefaultIsr.c. // This function is found in DSP2833x_PieVect.c. InitPieVectTable();

// Step 4. Initialize all the Device Peripherals:

// This function is found in DSP2833x_InitPeripherals.c // InitPeripherals(); // Not required for this example

// Step 5. User specific code:

#if EXAMPLE1

// This example uses DATA registers to toggle I/O's Gpio_example1();

#endif // - EXAMPLE1

#if EXAMPLE2

// This example uses SET/CLEAR registers to toggle I/O's Gpio_example2(); #endif

#if EXAMPLE3

// This example uses TOGGLE registers to toggle I/O's Gpio_example3(); #endif }

void delay_loop() {

short i;

for (i = 0; i < 1000; i++) {} }

void Gpio_example1(void) {

// Example 1:

// Toggle I/Os using DATA registers

for(;;) //无限循环 {

GpioDataRegs.GPADAT.all =0xAAAAAAAA; // 十六进制的A代表二进制的1010,所以A口的偶数引脚为高电平,

//奇数为低电平

GpioDataRegs.GPBDAT.all =0x0000000A; // B口的B3、B1为高电平,其余为低电平。

delay_loop();

GpioDataRegs.GPADAT.all =0x55555555; // 十六进制的5代表二进制的0101,所以A口的奇数引脚为高电平,

//偶数为低电平

GpioDataRegs.GPBDAT.all =0x00000005; //B口的B2、B0为高电平,其余为低电平。

delay_loop(); }

}

void Gpio_example2(void) {

// Example 2:

// Toggle I/Os using SET/CLEAR registers for(;;) {

GpioDataRegs.GPASET.all =0xAAAAAAAA; GpioDataRegs.GPACLEAR.all =0x55555555;

GpioDataRegs.GPBSET.all =0x0000000A; GpioDataRegs.GPBCLEAR.all =0x00000005; delay_loop();

GpioDataRegs.GPACLEAR.all =0xAAAAAAAA; GpioDataRegs.GPASET.all =0x55555555;

GpioDataRegs.GPBCLEAR.all =0x0000000A; GpioDataRegs.GPBSET.all =0x00000005;

delay_loop(); } }

void Gpio_example3(void) {

// Example 2:

// Toggle I/Os using TOGGLE registers

// Set pins to a known state

GpioDataRegs.GPASET.all =0xAAAAAAAA; GpioDataRegs.GPACLEAR.all =0x55555555;

GpioDataRegs.GPBSET.all =0x0000000A;

GpioDataRegs.GPBCLEAR.all =0x00000005;

// Use TOGGLE registers to flip the state of // the pins.

// Any bit set to a 1 will flip state (toggle)

// Any bit set to a 0 will not toggle. for(;;) {

GpioDataRegs.GPATOGGLE.all =0xFFFFFFFF; GpioDataRegs.GPBTOGGLE.all =0x0000000F; delay_loop(); } }

void Gpio_select(void) {

EALLOW;

GpioCtrlRegs.GPAMUX1.all = 0x00000000; // All GPIO 所有引脚设置为数字I/O GpioCtrlRegs.GPAMUX2.all = 0x00000000; // All GPIO GpioCtrlRegs.GPAMUX1.all = 0x00000000; // All GPIO

GpioCtrlRegs.GPADIR.all = 0xFFFFFFFF; // All outputs所有引脚设置为数字量输出 GpioCtrlRegs.GPBDIR.all = 0x0000000F; // All outputs EDIS; }

//=========================================================================== // No more.

//===========================================================================

4、 串行通信接口(SCI)

SCI串行通信接口是一个两线异步串口,可以看做是通用异步接收器和发送器(UART)。它允许F28X与其他外围设备之间的异步通信。所谓异步指通信双方微处理器使用各自的时钟,即使他们的时钟有相同完全的频率,但在时间上他们仍然是不相关的。

SCI模块的奇偶校验及数据格式是通过端口硬件事先设计好的,如此可以减少软件的开销。SCI模块可以下在半双工通信中进行独立的操作(半双工允许两个方向但不能同时进行数据传送,只能交替进行),或在全双工通信中同时进行操作(全双工允许两个方向同时进行数据传送)。由于不需要同步时钟,在只发不接受或只收不发一个方向传送数据(单工)条件下,SCI可单线发送或接受数据。 5、串行外围接口(SPI)

SPI是一个同步串行I/O端口,它在F28x与其他外围设备之间通过移位寄存器方式传送一个可变长度和速率的串行位流。SPI通常用于DSP控制器与板上外扩设备或者其他控制器之间的通信。

在数据传送过程中,一个SPI设备必须配置为主机,所有其他的设备配置为从机。主机通过总线为所有从机提供时钟信号。 SPI通信可以采用以下3种不同方式中的一种进行:

主机发数据,从机发送虚拟数据 主机发数据,一个从机发送数据 主机发虚拟数据,一个从机发送数据

SPI最简单的通信方式是一个可编程的移位寄存器。数据通过SPIDAT寄存器移入和移出。要传送的数据通过SPITXBUF写入SPIDAT寄存器,接收的数据锁存在SPIRXBUF寄存器以便CPU读取。

10.2、概述XINTF的配置

10.2.1、改变XINTF的配置和定时寄存器的步骤 10.2.3、XINTF的时钟

XINTF的时钟通过配置XINTCNF2寄存器的位,把XTIMCLK设置为和系统时钟相同或者等于系统时钟的一半。默认状态下XTIMCLK设置为SYSCLKOUT的一半。

开始进入所有的XINTF所有的区,都需要在XCLKOUT外部时钟的上升沿。外部逻辑可以关掉XCLKOUT。XCLKOUT的可以被配置为内一定的比例的XINTF的时钟XTIMCLK,外部时钟XCLKOUT可以和内部时钟XTIMCLK相等,或者为其一半。具体可以在XINTCNF2寄存器中配置。默认情况下, 外部时钟XCLKOUT是内部时钟XTIMCLK一半,系统时钟SYSCLKOUT的四分之一。 10.2.5、写缓冲区

默认状态下,进入写缓冲区是禁止的,为了提高XINTF的性能,可以使能写缓冲区。 10.2.6、XINTF每个区访问的建立,激活和跟踪的时序

XINTF区域是直接访问外部接口的存储器映射区域,任何对XINTF区域的读或写访问的时序可以分为3个阶段,即建立、激活和跟踪。在XTIMING寄存器相应的位可以设置每个XINTF区域访问各阶段时等待状态的XTIMCLK的周期数。读访问的时序可以和写访问时序区别配置。此外,为了与慢速外设接口,还可以使用X2TIMIING位使访问特定区域的建立、激活和跟踪等待状态延长1倍。

在建立阶段,访问区域的片选信号变为低电平,且地址放在地址总线(XA)上,建立的周期可以通过区域的XTIMCLK寄存器来配置,在默认情况下,对读和写访问来说,建立的周期最大为6个XTIMCLK周期。

在激活阶段对外设进行访问,如果是读访问,读选通信号(XRD’)被拉低,且将数据锁存到DSP;如果是写访问,写使能(XWE0’)选通信号被拉低,数据被送到数据总线(XD)上。

跟踪周期是保持片选信号为低电平一段时间,但是读写选通信号变为高电平。在区域的XINTIM寄存器中可以设置跟踪周期的XTIMCLK个数。

根据系统的设计要求,可以配置区域访问的建立、激活和跟踪等待周期数,以适用专用外设接口的访问。当选择时序参数时,需要考虑一下几个问题:

(1)最小的等待状态需求

(2)XINTF的时序特性,可参照相应的数据手册 (3)外部器件的时序特性

(4)F28335器件与外部器件的附加延时

10.3、配置的建立、激活和跟踪等待状态

本文来源:https://www.bwwdw.com/article/jnoa.html

Top