CC2530学习笔记2——Flash读写程序设计

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hnxyxiaomeng/article/details/82354011

在做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

猜你喜欢

转载自blog.csdn.net/hnxyxiaomeng/article/details/82354011