DSP学习预备知识——C语言和最小系统板介绍

1.C语言知识

1.1 define 和typedef

\qquad #define(宏定义)只是简单的字符串代换(原地扩展),它本身并不在编译过程中进行,而是在预处理过程就已经完成了。typedef是为了增加可读性而为标识符另起的新名称,它的新名字具有一定的封装性,以致于新命名的标识符具有更易定义变量的功能,它是语言编译过程的一部分,但它并不实际分配内存空间。define和typedef对指针操作不同,作用域等都不同。一般在控制器编程中将地址、常量define成一个变量标识符。而typedef一般用于定义类型的别名。

1.2. struct、union和enum

\qquad 结构体struct各成员各自拥有自己的内存,各自使用互不干涉,同时存在的,遵循内存对齐原则。一个struct变量的总长度等于所有成员的长度之和;

#include "stdio.h"
int main (void)
{
    struct A {
        int a;   //8 size
        double b;//8 size
        char c;  //4 size
        char d;	 //4 size
    };//one way to declare struct
    struct A AA;
    struct {
        struct A AA;  //24 size
        int a;		  //4 size
        char c;		  //4 size
        double b;	  //8 size
    }B;//another way to declare struct
    typedef struct{
        int a;		//4 size
        char c[10];	//4 size + 8 size
        double d;	//8 size
        char* e;	//8 size
    }STRUCT;//use typedef to declare struct
    STRUCT stu;
    struct BIT{
        char IO1:1;//1 bit
        char IO2:1;//1 bit
        char IO6:7;//over 8 bit then start another byte
    };
    struct BIT bitter;
    printf("%d\n",sizeof(AA)); //24
    printf("%d\n",sizeof(B));  //40
    printf("%d\n",sizeof(stu));//32
    printf("%d\n",sizeof(bitter));//2
    return 0;
}

\qquad 联合体union 各成员共用一块内存空间,并且同时只有一个成员可以得到这块内存的使用权(对该内存的读写),各变量共用一个内存首地址。因而,联合体比结构体更节约内存。一个union变量的总长度至少能容纳最大的成员变量,不允许对联合体变量名直接赋值或其他操作。union和struct声明类似。

#include "stdio.h"
int main (void)
{
    union u{
    int a[10];
    int b;
    double c;
    };//one way to declare union
    struct reg{
        int a:1;//count 0 bit 
        int b:6;//count 1 to 6 bit
    };
    typedef union{
        int  all;
        struct reg bit;//bit is declared as struct type
    }Typeu;//use typedef to declare union
    union u  var;
    var.b = 4;
    Typeu tu;
    tu.bit.a = 1;
    printf ("%d,\t%d\n",sizeof(var),var.a[0]);//40 4
    printf ("%d,\t%d",sizeof(tu),tu.bit.a);//4  -1
    return 0;
}

\qquad 枚举型enum是一个集合,集合中的元素(枚举成员)是一些命名的整型常量,元素之间用逗号,隔开。声明的没经验类型是一个标识符,可以看成这个集合的名字,是一个可选项,即是可有可无的项。第一个枚举成员的默认值为整型的0,后续枚举成员的值在前一个成员上加1。也可以人为设定枚举成员的值,从而自定义某个范围内的整数。

#include <stdio.h>
int main (void)
{
    enum SPEED{
        IO_10MHz = 1,//use ',' to separate each member
        IO_20MHz,
        IO_50MHz,
    };//one way to declare enum 
    enum SPEED speed;//enum type is same size as int 
    typedef enum {
        IO_AIN = 0x00,
        IO_IPD = 0x28,
        IO_PP = 0x10,
    }IOMODE;//use typedef to declare enum
    printf("%d\t %d\n",sizeof(speed),IO_20MHz);// 4 2
    printf("%d\t %d\n",sizeof(IOMODE),IO_PP);//4  16
    return 0;
}

\qquad 理解了上述例子,来看下面的例子,猜猜输出是什么

#include "stdio.h"
int main (void)
{
    enum GPIO{
        GPIO0 = 0x1111,
        GPIO1,GPIO2,GPIO3,
    };
    struct regbits{
        unsigned int a : 1;
        unsigned int b : 4;
        unsigned int c : 8;
    };
    typedef union{
        unsigned int  all;
        struct regbits bit;//bit is declared as struct type
    }Typeu;
    typedef struct {
        unsigned int a;
        Typeu REGS;
    }reg;
    reg Regs;
    Regs.REGS.all = GPIO3;
    printf ("%d,\t%d\n",sizeof(Regs),Regs.REGS.bit.b);//8 'b'1010->10
    printf ("%d\n,",Regs.REGS.bit.c);//'b'1000 1000->136
    return 0;
}

\qquad 查找一个外设的寄存器如下(学一个外设,可以按照下面的方式去逐级查找)

#include <stdio.h>
#define Uint16 unsigned int 
int main (void)
{
    struct PLLSTS_BITS   {    // bits  description
        Uint16 PLLLOCKS:1;     // 0     PLL lock status
        Uint16 rsvd1:1;        // 1     reserved
        Uint16 PLLOFF:1;       // 2     PLL off bit
        Uint16 MCLKSTS:1;      // 3     Missing clock status bit
        Uint16 MCLKCLR:1;      // 4     Missing clock clear bit
        Uint16 OSCOFF:1;       // 5     Oscillator clock off
        Uint16 MCLKOFF:1;      // 6     Missing clock detect
        Uint16 DIVSEL:2;       // 7     Divide Select
        Uint16 rsvd2:7;        // 15:7  reserved
    };
    union PLLSTS_REG {
        Uint16              all;
        struct PLLSTS_BITS  bit;
    };
    struct SYS_CTRL_REGS {
        Uint16              rsvd7;     // 0
        union   PLLSTS_REG  PLLSTS;    // 1
    };
    struct SYS_CTRL_REGS SysCtrlRegs;
    SysCtrlRegs.PLLSTS.bit.PLLLOCKS= 1;
    printf("%d,\t%d",sizeof(SysCtrlRegs),SysCtrlRegs.PLLSTS.bit.PLLLOCKS);
    return 0;
}

\qquad 下图显示了寄存器的表达方式。
在这里插入图片描述

1.3 extern、volatile

\qquad 在嵌入式系统编程过程中,extern表明变量或者函数是定义在其他其他文件中的。用法有几点需要注意:(a)一个c文件需要调用另一个c文件里的变量或者函数,而不能从.h文件中调用变量;(b)一般用extern声明变量时不要给其赋值,最好在定义这个变量的时候声明,若定义该变量时无法确定其初始值,可以令其等于0,或避免使用extern关键字,采用地址传参。(c)引用函数和引用变量是一样的,如果需要调用其他.c文件中的函数,在文件中的函数声明前加extern即可,不加extern而直接声明函数也可以,因为声明全局函数默认前面带有extern;(d)如果不想让其他.c文件引用本文件中的变量,加上static即可;
\qquad volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。下面举例说明。在DSP开发中,经常需要等待某个事件的触发,比如声明一个结构体变量时(volatile struct EPWM_REGS EPwm1Regs;)常常需要添加关键字volatile;

2.最小系统板设计

2.1 电源部分

\qquad DSP芯片内部的电压较多,一般可以分为IO口电压、内核电压、ADC相关电压等,具体细分如下:(a)IO口电压VDDIO(3.3V);(b)芯片内核电压VDD(1.9V);(c)ADC模拟电源引脚VDDA2,VDDAIO(3.3V);(d)ADC模拟IO电源引脚;(e)ADC模拟电源电源引脚VDD1A18,VDD2A18(1.9V)。接地引脚(a)芯片接地VSS;(b)ADC模拟IO电源接地引脚VSSAIO;(c)ADC模拟接地引脚VSS1AGND,VSS2AGND等;其中,各个3.3V,1.9V,GND引脚都可以各自连接到一起,但为了走线时分辨好回路,电源一般用磁珠隔离,地线用0Ω隔离。
在这里插入图片描述
\qquad 电源部分采用TD6821芯片,芯片特点:双通道输出SOIC-8封装、1.5MHz同步降压、输出电流达1.5A、输入电压范围3V-5.5V、内部开关管的Rds(on)较小,内部软起动和限制浪涌电流等。注意到上面说的输入电压范围3V-5.5V,显然这时候需要再输入端接一个保护电路来保护TD6821和后面的主控芯片。电源部分电路如图:
在这里插入图片描述
\qquad 当输入小于齐纳二极管MM1Z5B1的钳位电压5.1V时,Q2管不导通,PMOS的g级被下拉到地,输入VIN经过PMOS到电源芯片输入;当输入过压时,Q2管导通,PMOS的g级和s级等电位(忽略PNP的导通压降),此时PMOS不通,VIN无法进入电源芯片输入脚,保护了电源芯片和后续电路。通上面的分析,可以知道,PMOS需要选一个导通压降低,Rds(on)低的PMOS较好。后续的输出电压按照芯片手册上的公式 V o 1 , o 2   =    ( 1 + R f 2 R f 1 ) × V F B V_{o1,o2} \ = \ \ (1+\frac{Rf2}{Rf1})\times V_{FB} Vo1,o2 =  (1+Rf1Rf2)×VFB

2.2 时钟部分

在这里插入图片描述
\qquad 如果不使用片上振荡器,时钟由X1X2或XCLKIN引脚上的外部时钟源输入产生。如果从XCLKIN引脚接入时钟,那么X1保持地电平,X2浮空,外部接入一个3.3V的时钟源。如果从X1和X2接入时钟源,那么XCLKIN保持低电平,X1接外部时钟信号,X2仍然浮空。
\qquad 总的来说,这里OSC电路可以通过在X1和X2之间接入一个晶振来产生(并最好保持XCLKIN接地)。如果没有在X1和X2之间接入晶振,那么就需要保持X1接地,X2浮空,并且在XCLINK之间接入振荡器。注意晶振(Crystal)、共振器(Resonator)、振荡器(Oscillator)的区别。可以简单的认为晶振和共振器是无源晶振(需要接外部电路才可以起振),而振荡器是有源晶振。那么最简单的方式就是在X1和X2之间接入晶振或者共振器,然后利用28335内部电路使得晶振起振。
\qquad 时钟源进来后,首先必须将OSCOFF位置1,这样才能使得时钟源进入直接选择器和经PLL模块到选择器。在PLL模块这里有一个PLLOFF位是用来关断PLL的,选择不关断(默认),接下来就是倍频环节PLLCR寄存器,低四位用来设置倍频。经过倍频到选择器输出后,设置寄存器PLLSTS的第8位和第7位DIVSEL来设置分频系数,在倍频设值之前必须将分频系数置零。通常我们的150MHz是OSCCLK(30MHz) × \times × PLLCR(10)/DIVSEL(2)=150MHz;

2.3 IO口引出

\qquad 引出88个GPIO引脚和16个ADC输入引脚和系统时钟输出引脚CLKOUT基本上就可以了。加上滤波、Jtag、Reset、以及芯片手册上推荐的一些电阻电容就可以了。

在这里插入图片描述
 PCB

2.4 tms320f28335与stm32f103zet6对比
tms320f28335stm32f103zet6
公司tist
最高工作频率(MHz)15072
位数(bit)3232
定时数目311
PWM个数1618
SRAM34k$\times$1664k
通信接口SCI、SPI、CAN、IIC等IIS、CAN、UART等
IO电压(V)3.32.0~3.6
ADC channel3221
DMA channel612
DAC channel02
IO 个数88112
复用关系重映射复用器
仿真器XDSstlink/jtag等
中断
  • 8
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值