DSP28335笔记——内部Flash中进行数据读写(Flash_API的使用)
Program时的报错返回值较为常见,对返回值30、31进行详解:返回值为30:每次操作写入16位的字节,直到Buffer中的数据全部写入,若写入的数据位超过16位时则返回值30。返回值为31:表示尝试将已有数据位上的0写成1。一般情况下,在Program操作之前,会将指定部分中的数据进行擦除;但擦除函数执行时间较久,且只能以扇区为单位进行擦除,因此也可以在已有数据的基础上再进行Program,但
背景:
在使用DSP28335进行开发时,一些项目中需要将数据信息存储到Flash中,在掉电后能够对数据进行保存,以便再次上电时能够取出使用。为了完成上述操作,TI官方提供了Flash_API(application program interface),本文基于TI官网给出的技术文件"Flash2833x_API_Readme",对官网提供的Flash_API的使用方式进行简要的说明。
一、相关的库文件与工程文件
在TI官网上搜索SPR539,下载TMS320F2833x Flash APIs (v2.00),解压后安装setup_Flash2833x_API_V210,根据现有的硬件选择文件,我这里使用Flash28335_API_V210。
将lib文件夹中的库文件添加入已有工程的lib中,将include文件夹中的两个头文件:"Flash2833x_API_Config.h"与"Flash2833x_API_Library.h"添加入已有工程的include中。并在CCS中添加lib与头文件的路径。
将库文件与头文件都包含入工程中后,开始对程序进行修改。
二、程序配置
1、修改Flash2833x_API_Config.h头文件
在Flash2833x_API_Config.h中选择系统CPU的主频,我这里的主频为150MHz。给定头文件中列出了几种常见的主频,也可以根据自己硬件设备修改程序,比如125MHz时CPU_RATE为8.00L。
Flash2833x_API_Config.h头文件中还给出了Flash分频系数,该部分不需要修改。
注意!要求原工程中PLL配置正确,避免设备进入limp 模式。
2、将Flash_API中的程序复制至内部SARAM中运行
由于28335只有一个Flash array,无法在擦除、读写flash的同时执行flash中的程序,因此需要先将Flash_API中的程序复制至SARAM中,从SARAM中执行程序。此外,Flash_API函数中有严格的时序要求,复制至SARAM中运行的程序是无延时的,能够使得运行更准确。
将程序复制至SARAM中的具体操作如下:
首先,修改cmd文件,在cmd文件中加入一个名为flash28_API的SECTIONS,也可以直接加入在原工程的SECTIONS中。
SECTIONS
{
Flash28_API:
{
-lFlash28335_API_V210.lib(.econst)
-lFlash28335_API_V210.lib(.text)
}
LOAD = FLASHA,
RUN = RAML0,
LOAD_START(_Flash28_API_LoadStart),
LOAD_END(_Flash28_API_LoadEnd),
RUN_START(_Flash28_API_RunStart),
PAGE = 0
}
这部分SECTIONS包含了Flash_API的程序(.text)和常数参数(.econst),并且定义了Flash_API程序的加载开始地址、结束地址与运行开始地址,并且已经将这些定义写入了Flash2833x_API_Library.h中供用户使用。
其次,在已有工程的主函数中包含Flash2833x_API_Library.h,并使用MemCopy函数进行复制。
MemCopy(&Flash28_API_LoadStart, &Flash28_API_LoadEnd, &Flash28_API_RunStart);
MemCopy函数在DSP2833x.MemCopy.c中,该函数也可以用于其他需要从Flash复制至SARAM中运行的情况。
void MemCopy(Uint16 *SourceAddr, Uint16* SourceEndAddr, Uint16* DestAddr)
{
while(SourceAddr < SourceEndAddr)
{
*DestAddr++ = *SourceAddr++;
}
return;
完成上述两步后,Flash_API中的函数就被复制至SARAM中了。
3、初始化Flash_API时钟分频系数
Flash_API函数中有许多特定的延时,因此正确地配置Flash_API的时钟非常重要,将下列语句加入至已有工程的主函数中能够实现Flash_API的分频,该语句左右两边的变量在Flash2833x_API_Library.h 和 Flash2833x_API_Config.h中已经被定义。
EALLOW;
Flash_CPUScaleFactor = SCALE_FACTOR;
EDIS;
4、初始化回调函数指针
回调函数指针能够在Flash_API执行擦除、读写操作的同时安全地执行某个函数。要执行回调函数,必须首先初始化函数指针Flash_CallbackPtr。如果不打算使用回调函数指针,则将指针设置为NULL,在这里我不使用回调函数指针。(写为NULL时需要include <stdio.h>)
#include <stdio.h>
Flash_CallbackPtr = NULL;
5、禁止全局中断、禁止看门狗
在使用Flash_API之前,有以下注意事项:
(1) 由于Flash_API中的函数有严格的时序要求,在使用Flash_API中的函数时,必须关闭全局中断与看门狗,以免打乱时序。在进行擦除、读写操作之前,使用DINT语句关闭全局中断,在操作完成后再使用EINT语句开启中断,DINT与EINT在DSP2833x_Device.h中已被定义。
(2) 同一时刻只能调用一个Flash_API函数,例如:首先调用擦除Flash函数,在擦除完成之前,不能直接调用写入Flash的函数。
(3) 代码安全模块(CSM)保护F2833x的Flash、ROM、SARAM。若Flash_API在非安全存储区调用,则调用前应先给CSM进行解锁。
三、常用Flash_API函数及使用方式
1、Flash_ToggleTest
该函数用于测试Flash_API时钟配置是否正确,若系统时钟与Flash_API的分频系数都正确配置,则该函数能够在指定引脚生成一个10kHz的脉冲方波。
extern void Flash_ToggleTest(volatile Uint32 *ToggleReg, Uint32 Mask);
其中*ToggleReg表示指定GPIO的指针,Mask为指定GPIO的掩码值,在进行ToogleTest前,需要先将目标GPIO进行初始化,并配置为GPIO输出模式。
下面以GPIO32为例进行ToogleTest。
GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 0; //设置GPIO32为通用I/O口
GpioCtrlRegs.GPBDIR.bit.GPIO32 = 1; //设置GPIO32为输出引脚
Flash_ToggleTest((volatile Uint32*)0x00006FCE,(Uint32)0x00000001);//GPIO32的ToggleTest
若生成脉冲方波频率不为10kHz,则时钟配置有误,需仔细检查。
2、Flash_Erase
该函数用于指定区域Flash的擦除,擦除操作执行后返回一个状态值。
extern Uint16 Flash_Erase(Uint16 SectorMask, FLASH_ST *FEraseStat);
其中SectorMask为指定擦除的扇区。28335片内Flash分为A~H共8个扇区,其中B扇区被分配至数据空间,用来存放数据,其余扇区被分配至程序空间,用来存放程序,我们进行数据擦写时一般在B扇区中进行,其地址范围为0x330000~0x337FFF,共32K*16位。*FEraseStat为结构体指针,如果擦除过程失败,API会把错误信息存储在这个指针所指的结构体变量。
下为FLASH_ST结构体定义,该定义在Flash2833x_API_Library.h中。
typedef struct {
Uint32 FirstFailAddr;
Uint16 ExpectedData;
Uint16 ActualData;
}FLASH_ST;
另外,Flash2833x_API_Library.h还对扇区进行了定义,在使用时只需要将指定扇区写入即可。
#define SECTORA (Uint16)0x0001
#define SECTORB (Uint16)0x0002
#define SECTORC (Uint16)0x0004
#define SECTORD (Uint16)0x0008
#define SECTORE (Uint16)0x0010
#define SECTORF (Uint16)0x0020
#define SECTORG (Uint16)0x0040
#define SECTORH (Uint16)0x0080
下面以擦除B扇区为例进行Flash_Erase的应用
FLASH_ST EraseStatus;
Erase_Status = Flash_Erase(SECTORB,&EraseStatus);//擦除Flash的SectorB
若Erase_Status返回值为0,则擦除成功。
3、Flash_Program
该函数用于Flash的写入,操作执行后返回一个状态值。
extern Uint16 Flash_Program(Uint16 *FlashAddr, Uint16 *BufAddr, Uint32 Length, FLASH_ST *FProgStatus);
其中*FlashAddr为要写入Flash的地址位置,例如扇区B则为0x330000~0x337FFF,*BufAddr为要写入的数组的指针,Length为写入数组的长度,*FProgStatus为结构体指针,如果写入过程失败,API会把错误信息存储在这个指针所指的结构体变量。
下面进行写操作的应用,在扇区B的头部写入一个数组。
FLASH_ST ProgStatus;
Uint16 Buffer[4] = {1,2,3,4};
Program_Status = Flash_Program((Uint16*)0x330000,Buffer,sizeof(Buffer),&ProgStatus);
若Program_Status返回值为0,则写入成功。
4、Flash_Verify
该函数用于Flash的校验,将一定地址中Flash的数据与指定数组进行比较,若两者相同则返回状态值0,若两者不同则返回状态值40。
extern Uint16 Flash_Verify(Uint16 *StartAddr, Uint16 *BufAddr, Uint32 Length, FLASH_ST *FVerifyStat);
其中*StartAddr为要比对的Flash地址的开始,其余与Flash_Program相同,不再赘述。
下面进行校验操作的应用,将给定数组与B扇区头部的数据进行比较。
Uint16 Buffer1[4] = {1,2,3,4};
Verify_Status = Flash_Verify((Uint16*)0x330000,Buffer1,sizeof(Buffer1),&VerifyStat);
若Verify_Status返回值为0则Flash中的数据为{1,2,3,4 },若返回值为40则不是。
5、函数返回值
返回值表示各函数执行的状态,其具体的取值定义在Flash2833x_API_Library.h中,如下:
/*---------------------------------------------------------------------------
API Status Messages
The following status values are returned from the API to the calling
program. These can be used to determine if the API function passed
or failed.
---------------------------------------------------------------------------*/
// Operation passed, no errors were flagged
#define STATUS_SUCCESS 0
// The CSM is preventing the function from performing its operation
#define STATUS_FAIL_CSM_LOCKED 10
// Device REVID does not match that required by the API
#define STATUS_FAIL_REVID_INVALID 11
// Invalid address passed to the API
#define STATUS_FAIL_ADDR_INVALID 12
// Incorrect PARTID
// For example the F2806 API was used on a F2808 device.
#define STATUS_FAIL_INCORRECT_PARTID 13
// API/Silicon missmatch. An old version of the
// API is being used on silicon it is not valid for
// Please update to the latest API.
#define STATUS_FAIL_API_SILICON_MISMATCH 14
// ---- Erase Specific errors ----
#define STATUS_FAIL_NO_SECTOR_SPECIFIED 20
#define STATUS_FAIL_PRECONDITION 21
#define STATUS_FAIL_ERASE 22
#define STATUS_FAIL_COMPACT 23
#define STATUS_FAIL_PRECOMPACT 24
// ---- Program Specific errors ----
#define STATUS_FAIL_PROGRAM 30
#define STATUS_FAIL_ZERO_BIT_ERROR 31
// ---- Verify Specific errors ----
#define STATUS_FAIL_VERIFY 40
// Busy is set by each API function before it determines
// a pass or fail condition for that operation.
// The calling function will will not receive this
// status condition back from the API
#define STATUS_BUSY 999
其中擦除、写入和校验的状态值定义如下
Program时的报错返回值较为常见,对返回值30、31进行详解:
返回值为30:每次操作写入16位的字节,直到Buffer中的数据全部写入,若写入的数据位超过16位时则返回值30。
返回值为31:表示尝试将已有数据位上的0写成1。一般情况下,在Program操作之前,会将指定部分中的数据进行擦除;但擦除函数执行时间较久,且只能以扇区为单位进行擦除,因此也可以在已有数据的基础上再进行Program,但无法将已有数据的位中的0值写成1。
例如:Program写入0x0001,然后尝试对相同的位置Program写入0x0002,则返回值31。因为单个比特不可以从0写成1;Program写入0xFFFF,然后对相同位置Program写入0xFFFC,则成功。
另外,28335的Flash_API中似乎没有直接将Flash中的数据读取出来的函数,因此在需要读取时,只能采用Verify函数将Flash中的数据与已有数组进行比较,比较返回值为0则Flash中的数据为该数组中的数据。
参考:TI官网Flash2833x_API_Readme
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)