在做CC2530 Flash读写时,对该芯片的Flash存储器典型操作进行了一些学习,总结在这里。理解不当甚至错误之处,请高手赐教,谢谢。
CC2530的Flash按页组织,每页2048字节。与其它Flash存储器一样,被擦除为1,被写为 0。另外,在后面与逻辑空间映射时,还有个BANK的概念,是32KB。
对Flash存储器有3种操作,简介如下:
擦除:最小单元是页,即2048字节;
写入:最小单元是32位字,即4字节,这也是后面的代码中写入地址必须为4的倍数的原因;
读取:数据手册中说,当被CPU访问读取代码或数据时,是字节可寻址。当被Flash控制器访问时,是字可寻址,其中一个字由32位组成。我们要做的从Flash读取数据是前一种情况,可字节寻址,也就是可以逐字节读取。后一种情况我还没用过。(⊙o⊙)…
三种操作的代码如下。
一、 擦除
擦除没啥好说的,这是写入之前必须进行的操作。在数据手册中描述的比较详细,也有代码,直接用即可。
/**************************************************************************************************
* @fn FLASH_PageErase
*
* @brief This function erases flash page of the 'pageNum'th page.
*
* input parameters
*
* @param pageNum - Valid flash page num.
*
* output parameters
*
* None.
*
* @return None.
**************************************************************************************************
*/
void FLASH_PageErase(uint8_t pageNum)
{
EA=0;
while(FCTL & 0x80);//等待闪存控制器整备好
FADDRH = pageNum << 1;//选择擦除页面的序号,共128页
FCTL |= 0x01;//启动页面擦除
while(FCTL & 0x80);//等待擦除完成
EA=1;
}
二、 写入
数据手册对写入描述的也比较详细。其中有一点比较重要,手册中说Flash写操作正在进行的时候,CPU不能访问闪存,即读取程序代码。也就是说如果直接写Flash,程序就没法执行了。所以,提供了两种写入方式:使用DMA传输(首选方法),或者使用CPU运行来自SRAM的代码。我选择推荐的DMA方法。所以,在真正写入之前要初始化DMA控制器,详见代码。
/**************************************************************************************************
* @fn FLASH_Write
*
* @brief This function writes 'num_bytes' bytes to the uint16_ternal flash.
*
* input parameters
*
* @param addr - Valid flash write address: actual addr / 4 and quad-aligned.
* @param data - Valid buffer space at least as big as 'cnt' X 4.
* @param num_bytes - Number of bytes to write, MUST be Divisible by 4.
*
* output parameters
*
* None.
*
* @return None.
**************************************************************************************************
*/
void FLASH_Write(uint16_t addr,uint8_t *data, uint16_t num_bytes)
{
//配置DMA通道每次传送一个字节
DMADesc_t dmaConfig0;//定义DMA通道
dmaConfig0.SRCADDRH = ((uint16_t)data >> 8) & 0x00FF; //XData - To Be Written to Flash - Gets Incremented;存储data的高8位;
dmaConfig0.SRCADDRL = (uint16_t)data & 0x00FF;//存储data地址的低8位;
dmaConfig0.DESTADDRH = (((uint16_t)&FWDATA) >> 8) & 0x00FF; //Flash Controller Data Address - Flash Controller Writes Data//存储写寄存器的地址的高8位
dmaConfig0.DESTADDRL = ((uint16_t)&FWDATA) & 0x00FF;//存储写寄存器的低8位;
dmaConfig0.VLEN = 0; //Variable num_bytes Transfer - 0=Fixed LEN Transfer//采用LEN作为传送长度
dmaConfig0.LENH = (num_bytes>>8) & 0x00FF; //Number of WORDSZIE in Transfer - Must be Divisible by 4 - NET_ADDR_SIZE=4//存储传送长度高5位
dmaConfig0.LENL = num_bytes & 0x00FF;//存储长度低8位;
dmaConfig0.WORDSIZE = 0; //Size of Each Transfer - 0=8 Bit;每个DMA传送采用8位传送
dmaConfig0.TMODE = 0; //Transfer Mode - 1=Block, 0=Single,传送模式为单一模式
dmaConfig0.TRIG = 18; //DMA Trigger - 0=Manual Via DMAREQ, 18=Flash;flash触发
dmaConfig0.SRCINC = 1; //Source Address Increment - 1=1 Byte//源地址增量模式为1字节/字
dmaConfig0.DESTINC = 0; //Destination Address Increment - 0=0 Bytes (Always Write to FWDATA, No Need to Increment)目标地址增量模式0字节/字
dmaConfig0.IRQMASK = 0; //uint16_terrupt Mask - 0=Disable uint16_terrupts//禁止通道完成中断产生
dmaConfig0.M8 = 0; //8th Bit Mode - 0=Use All 8 Bits使用全部8位作为传送长度
dmaConfig0.PRIORITY = 2; //Priority - 10(2)=High Priority优先级为DMA优先
//DMA模式写
while (FCTL & 0x80); //Wait Until DMA Controller is Available - Busy Bit 7//等待写或擦除状态被激活
/********* 存储写入flash页地址 ***********************************************/
FADDRH =(addr >> 10) & 0x00FF; // page size: 2048; select the flash page via FADDRH[7:1] bits//由于写入flash时是字(4字节)寻址的,所以存储高位需要右移2位;
FADDRL =(addr >> 2) & 0x00FF; //4字节寻址,存储要写入flash地址的低字节需要右移2位
//通道0配置地址
DMA0CFGH = (((uint16_t)&dmaConfig0) >> 8) & 0x00FF; //Pass DmaConfig0
DMA0CFGL = ((uint16_t)&dmaConfig0) & 0x00FF;
DMAARM |= 0x01; //Arm the DMA Channel//通道0进去工作状态
FCTL |= 0x02; //Start Write
//while (!(DMAIRQ & 0x01)); //Wait Until Write Complete
//DMAIRQ &= 0xFE; //Clear Any DMA IRQ on Channel 0 - Bit 0
while (FCTL & (0x80)); //Wait Until Flash Controller is Not Busy - Busy Bit 7//等待或者擦除状态激活
return;
}
三、 读取
这个比较关键,数据手册里写的不是很详细,我在这里也费了些功夫。需要结合第2章和第6章一起理解。
首先,在CC2530中有CODE、DATA、XDATA、SFR等逻辑存储空间,参考这个博客,不同存储空间的特性总结如下:
1. CODE :程序存储器, 用处存放程序代码和一些常量
有16根地址总线,所以CODE的寻址范围是 0000H~FFFFH 共64KB
2. DATA 数据存储器,用于存放程序运行过程中的数据
有8根地址总线,所以DATA的寻址空间为 00H~FFH 共256 byte.低128位可以直接寻址,高128位只能间接寻址。
3. XDATA 外部数据存储器(只能间接寻址,访问速度比较慢) DMA是在XDATA上寻址的,这一点很重要
有16根地址总线,所以 XDATA 的寻址空间为 0000H ~ FFFFH 共64K
4. SFR 特殊功能寄存器 就是那些T1CTL, EA, P0 等配置寄存器存储的地方 共128K。因为CC2530的配置寄存器比较多,所以一些多余的寄存器就放到了XREG 里面。XREG的大小为1K XREG的访问速度比 SFR慢。
这些存储空间实际是存储在3个物理存储器(Flash程序存储器、SRAM和存储映射存储器)中的。这里很明显有个问题,CODE寻址范围只有64KB,但CC2530的Flash最大却有256KB。那怎么保证Flash的空间都能被寻址呢?
所以,芯片搞了个映射机制,CODE空间的映射如下:
也就是说,CODE空间中前32KB是固定的,而后32KB是可设置的(从Flash的BANK0~BANK7),具体配置为哪个Flash,可通过寄存器FMAP设置。
类似地,XDATA的存储空间如下:
由于XDATA是可以读/写的数据存储空间,而它的XBANK区域(0x8000~0xFFFF范围)可由寄存器MEMCTR设置为Flash的任一BANK。因此,可以通过设置MEMCTR选择需要读取的BANK,然后从XDATA数据存储器中读取出来。读取部分代码如下。若想查看读取时存储器中的值,可以在MEMCTR = old_map;语句处打断点,按照XDATA的存储空间映射,计算得出存储器在XDATA空间中的实际地址(即offset的值),查看即可。
/**************************************************************************************************
* @fn FLASH_Read
*
* @brief This function reads 'num_bytes' bytes from flash address addr to array data.
*
* input parameters
*
* @param addr - Valid flash read address: .
* @param data - Valid buffer space to store the data.
* @param num_bytes - Number of bytes to read.
*
* output parameters
*
* None.
*
* @return None.
**************************************************************************************************
*/
void FLASH_Read(uint16_t addr,uint8_t* data,uint8_t num_bytes)
{
uint8_t old_map;
uint8_t bank_num;
uint16_t offset;
uint8_t old_ea;
old_ea = EA;
EA = 0; // close global interrupt
bank_num = (addr>>FLASH_BANK_SHIFT)&FLASH_BANK_MAP_MASK;
offset = (addr & (FLASH_BANK_SIZE-1))+FLASH_BASE_ADDR;
old_map = MEMCTR;
MEMCTR = (old_map&~0X7)|bank_num; //map the correct flash bank to XBANK
memcpy(data,(uint8_t*)offset,num_bytes);
MEMCTR = old_map;
EA = old_ea;
return;
}
完整的IAR工程可以在如下链接下载:https://download.csdn.net/download/hnxyxiaomeng/10643545