文章目录
前言
背景介绍
Memory映射
RAM
ROM
外设Register
Memory分配
应用实例
总结
参考资料
前言
见《【研发日记】嵌入式处理器技能解锁(一)——多任务异步执行调度的三种方法》
见《【研发日记】嵌入式处理器技能解锁(二)——TI C2000 DSP的SCI(串口)通信》
见《【研发日记】嵌入式处理器技能解锁(三)——TI C2000 DSP的C28x内核》
背景介绍
本文要讲的Memory是TI C2000 DSP的片上存储器。其在芯片的整体架构中,所处的位置如下:
Tips:除了上图中的ROM和RAM,另外的外设寄存器从广义的角度讲也是Memory的一部分。
Memory映射
存储器映射表,描述了存储器中各个组成部分的地址,用于读写寻址,如下图所示:
RAM
TI C2000 DSP的RAM由三个部分组成:Mx RAM、LSx RAM和GSx RAM。
M0 RAM和M1 RAM,总计4KB,是两个具有专用功能的RAM模块,与CPU紧密耦合,只有CPU可以访问,软件开发人员一般不用关注。
LS0-7 RAM,总计32KB,是本地共享RAM(Local shared RAM),CPU、CLA和BGCRC可访问,可以用作软件的堆栈等通用功能,需要软件开发人员关注。
GS0-3 RAM,总计32KB,是全局共享RAM(Global shared RAM),除了CPU、CLA和BGCRC可访问,另外HIC和DMA也都具有对这些存储器的完全读写访问权限,比LSx RAM具有更广泛的用途,可供软件开发人员更灵活地使用。
Tips:另外的几种消息RAM是特定模块的专用RAM,在对应功能启用时用于共享数据。
ROM
TI C2000 DSP的ROM也是由三个部分组成:Boot Rom、Secure Rom和Flash Bankx。
Boot Rom,总计64KB,里边中存放着芯片厂家制定的一些代码,芯片每次复位后都要先执行这里的代码,然后才开始执行软件开发人员编译的代码。Boot ROM中代码的功能是芯片层面的初始化(不是main函数中的初始化),去执行一些类似于clear RAM这样的任务,软件开发人员只需要知道这部分的存在即可,一般不需要特别关注。
Secure Rom,总计48KB,是一些具有更高权限的存储区域,CPU和外设通过常规的方式无法对其读写,需要使用特殊的API和Password才能访问。Secure ROM中是芯片厂家为用户提供的特定功能(function),如果没有启用这些功能,一般也不需要关注。
Flash Bank 0-2,总计3*128KB。其中每个组(Bank)又由16个扇区(Selector)组成,总计16*8KB。每个扇区(Selector)又由64个页(Page)组成,总计64*128Byte。是通用型存储空间,可以存放软件开发人员的Code和Bytes。在程序运行时,CPU可以直接在上面寻址并抓取指令和Bytes。
Tips:另外还有一种OTP(one-time programmable) ROM,它只能写入一次,不能擦除。一般用于存放芯片ID或者ECU ID,以及一些Configure和其他出厂信息。
外设Register
外设(Peripheral)寄存器是DSP各个外设子系统(例如ADC)的存储单元,其特点时固定地址存储固定数据。DSP的外设子系统非常多,功能各不相同。每个外设也都有很多寄存器,主要用于Configure外设的模式和反馈外设的Status/Result。外设ADC(Analog to Digital Converter)的部分寄存器,示例如下:
Tips:外设寄存器的用法与各个外设的功能高度相关,后面用到哪个外设时再针对性研究。
Memory分配
软件开发人员在使用TI C2000 DSP芯片时,Memory主要被分配成如下几个部分:
Stack(栈):包含临时创建的局部变量、函数调用入口的参数、函数返回值、const修饰的局部常量。
Heap(堆):用于存放程序运行中被软件开发人员动态分布的内存段,可增可减,一般用malloc等函数实现动态分布内存。用malloc函数分布的内存,必须用free进行内存释放,否则会造成Memory溢出。
Global/Static:这两种变量都具有穿越代码运行周期的能力(只是作用范围不同),所以需要在Memory中分配固定的地址。
Zi-data:表示未初始化赋值(Zero initialized)的全局变量和Static修饰的变量,它是直接在RAM中分配一个固定地址。
Code(Instruction):字面指软件开发人员写的代码,但是在Memory中已经是编译后的东西,它被划分为指令和数据两部分,上图中的Code准确讲应该叫指令(Instruction)。
Ro-data:字面指只能读取的数据,即程序中定义的常量,例如#define 宏定义、用const修饰过变量等。这些常量是一直在ROM中的,芯片运行起来后CPU直接从ROM中读取。
Rw-data:字面指可读可写的数据,它实际上包括了堆、栈和全局变量等。这些数据又分为已被初始化赋值的和未被初始化赋值的。但是在Memory分配图中为了便于描述,把Rw-data理解为已被初始化的即可。ROM中的Rw-data从烧录文件中而来,在Memory中是固定地址和固定Value的。芯片启动时会被移到RAM中使用,芯片运行起来之后Rw-data就是动态变化的了,堆栈的地址和Value都会实时变化,Global/Static只有Value会变化。
应用实例
这里展示一个示例Demo代码,直接用代码中的注释进行说明。
Demo.c File
#include <xxxx.h>
uint16 Val1 = 1; //Val1是Global变量,并且已经初始化了,在RAM的Rw-data区域有一个固定地址。但是为了芯片下电时不丢失,所以在ROM的Rw-data区域中也有一个地址来存放。Val1在ROM中的Value一直都是1,但是在RAM中的Value会随着代码的运行而变化。
static uint16 Val2 = 2; // Val2也是已初始化的Static变量,跟Val1的Memory分配是一样的Rw-data区域。这里的static修饰代表它的作用范围有限。
uint16 Val3; //Val3也是Global变量,但是未初始化,所以分配在RAM中Zi-data区域的一个固定地址。
const uint16 Val4 = 4; //Val4被const修饰了,是一个常量,分配在ROM的Ro-data区域。
uint16 DemoFcn(uint16 Num) //Num是函数入口的参数,分配在Stack区域
{
uint16 Var5 = 5; //Var5是局部变量,只在DemoFcn()函数调用时临时使用,所以分配在RAM Stack区域的一个随机地址,DemoFcn()函数退出时就会把这个Memory释放掉。因为Var5有一个初始值,所以在ROM栈区也会分配一个空间。
static uint16 Var6 = 6; // Var6被static修饰,代表它的Value要穿越芯片运行周期,即下一次读取Var6时,它前一次写入的值仍能被读到,所以它被非标配在RAM中Rw-data区域的固定地址上。
const uint16 Var7 = 7; // Var7被const修饰,所以是常量,但是它只在DemoFcn()函数中短暂使用,所以是局部常量,被分配在RAM中Rw-data的Stack区域。
void *p;
p = malloc(8); //动态分配一个size 8的Memory,p是这片Memory区域的起始地址,它是分配在RAM Heap区域的一个随机地址。
*p = 1; //使用这片区域
*(p+1) = 2; //使用这片区域
free(p); //释放这片区域
return (Num+*p); //函数的返回值存放在RAM Stack区域
}
void main()
{
uint16 Var8 = 0; //Var8是局部变量,分配在RAM Stack区域的一个随机地址。
Var8 = DemoFcn (9); //存放在RAM Stack区域的函数返回值,赋给Var8。
}
Tips:除了上述的Data,还有内部的赋值、加法等运算,会被编译常指令(Instruction),然后分配在ROM的Code区域。
总结
以上就是本人在研发中使用嵌入式处理器的Memory时,一些个人理解和分析的总结,主要介绍了TI C2000 DSP Memory的工作原理,展示了具体的使用方法,并对比分析了它的特点和适用场景。
后续还会分享另外几个最近解锁的嵌入式处理器新技能,欢迎评论区留言、点赞、收藏和关注,这些鼓励和支持都将成文本人持续分享的动力。
另外,上述例程使用的Demo工程,可以到笔者的主页查找和下载。
参考资料
TMS320F28003x Real-Time Microcontrollers datasheet.pdf
版权声明,原创文章,转载和引用请注明出处和链接,侵权必究!