[置顶] Z-STACK之cc2530 flash驱动详解下

     今天来分析一下flash的write函数:

void HalFlashWrite(uint16 addr, uint8 *buf, uint16 cnt)
{
  halDMADesc_t *ch = HAL_NV_DMA_GET_DESC();

  HAL_DMA_SET_SOURCE(ch, buf);
  HAL_DMA_SET_DEST(ch, &FWDATA);
  HAL_DMA_SET_VLEN(ch, HAL_DMA_VLEN_USE_LEN);
  HAL_DMA_SET_LEN(ch, (cnt * HAL_FLASH_WORD_SIZE));
  HAL_DMA_SET_WORD_SIZE(ch, HAL_DMA_WORDSIZE_BYTE);
  HAL_DMA_SET_TRIG_MODE(ch, HAL_DMA_TMODE_SINGLE);
  HAL_DMA_SET_TRIG_SRC(ch, HAL_DMA_TRIG_FLASH);
  HAL_DMA_SET_SRC_INC(ch, HAL_DMA_SRCINC_1);
  HAL_DMA_SET_DST_INC(ch, HAL_DMA_DSTINC_0);
  // The DMA is to be polled and shall not issue an IRQ upon completion.
  HAL_DMA_SET_IRQ(ch, HAL_DMA_IRQMASK_DISABLE);
  HAL_DMA_SET_M8( ch, HAL_DMA_M8_USE_8_BITS);
  HAL_DMA_SET_PRIORITY(ch, HAL_DMA_PRI_HIGH);
  HAL_DMA_CLEAR_IRQ(HAL_NV_DMA_CH);
  HAL_DMA_ARM_CH(HAL_NV_DMA_CH);

  FADDRL = (uint8)addr;
  FADDRH = (uint8)(addr >> 8);
  HalFlashWriteTrigger();
}

这个函数的功能就是向flash内部的addr地址处写cnt个字节的buf内容。

我们知道flash-write operation 有两种方法:

Using DMA transfer (preferred method)

Using CPU, running code from SRAM

肯定DMA是首选!DMA驱动在

http://blog.csdn.net/crystal736/article/details/8544586中已讲的非常清楚了!

注意一点 DMA控制器传输的数据都是在XDATA地址空间范围内的,当然它可以存储在ram中也可以存储在flash中!只不过他们都必须映射到XDATA空间中!

The DMA controller controls data transfers over the entire address range in XDATA memory space

看到datasheet有这样几句:

The CPU cannot access the flash, e.g., to read program code, while a flash write operation is in progress.
Therefore, the program code executing the flash write must be executed from RAM.

CPU不能直接访问flash来读取程序代码,但是可以进行写flash操作!执行flash write的程序代码必须在RAM中执行!当然这是针对flash-write operation的第二种方法!如果我们用第一种方法,即DMA传输,我们先看一下流程图:

                                                                                             [置顶] Z-STACK之cc2530 flash驱动详解下_第1张图片

DMA描述符的配置过程具体就不说了!看代码

 FADDRL = (uint8)addr;
  FADDRH = (uint8)(addr >> 8);
  HalFlashWriteTrigger();

将地址赋值给FADDRL:FADDRH,这个addr是16位的,但是如果我们想往地址0x3FFEE地址写数据,那岂不是写不了?这里为什么是16位的地址呢?

其实,我们在写flash之前都已经将要写的地址映射到了XDATA空间的XBANK区了!

 

我们先来看一下这个HalFlashWrite函数用在哪些地方!

找到OSAL_Nv.c文件中有一两个函数调用了HalFlashWrite,分别是

static void writeWord( uint8 pg, uint16 offset, uint8 *buf )

static void writeWordM( uint8 pg, uint16 offset, uint8 *buf, uint16 cnt )

这两个函数其实对HalFlashWrite的封装。我们可以对照一下HalFlashRead函数的声明:

void HalFlashRead(uint8 pg, uint16 offset, uint8 *buf, uint16 cnt)

他们的返回值和参数都是一样的!

 

我们看下函数writeWord的代码

  offset = (offset >> 2) + ((uint16)pg << 9);

  if ( OSAL_NV_CHECK_BUS_VOLTAGE )
  {
    HalFlashWrite(offset, buf, 1);
  }
  else
  {
    failF = TRUE;
  }

 

这里为我们计算offset即为映射之后的地址值!这是咋计算出来的呢?假如我们要在121page的 offset为0的地址处写值,注意有这么一句:

When accessed by the flash controller, the flash memory is word-addressable, where a word consists of 32 bits. 所以我们write flash时必须指定offset为4的整数倍,要不然会写不进去的!所以有了 offset>>2,即除以4,我们通过flash controller访问flash时,看到的地址都是0x0000 0x0004 0x0008..............即末位都是4的倍数的值,

((uint16)pg << 9)即将pg乘以2KB再除以4,这个表达式相当于

 offset = (offset + pg×2KB)/4,分子为pg,offset的真正地址,然后将其除以4,然后调用

HalFlashWrite(offset, buf, 1);对应参数为,addr = offset,buf = buf, cnt = 1;

所以执行HalFlashWrite,向offset地址处写4个字节

我们看到有这么一句注释:

@param       addr - Valid HAL flash write address: actual addr / 4 and quad-aligned.

@param       cnt - Number of 4-byte blocks to write.

实际地址是addr/4,所以要将offset除以4!但是我们知道这个addr的值是XDATA地址空间的地址,我们是往flash中写数据,也就是说在write flash之前,必须将pg所在的bank映射到XBANK中,然后再将buf中数据写到XBANK的flash中!但是找了半天,没有发现执行映射的语句!这一点还没想通!

在程序初始化的时候:

__low_level_init函数中执行了 MEMCTR = (MEMCTR & 0xF8) | 0x01;

它将bank1 映射到XDATA中,即将这部分flash当做data使用!,但是好像我们不都是在bank1中写数据,

That is a problem!

 

实际上,在程序执行的时候,是不允许write flash的,因为这样会破坏flash中的code,所以cc2530就想了个办法,当需要write flash时,将执行write flash的函数代码复制到sram中,然后从sram中执行这个函数,这样write flash 就得以进行!在这个http://e2e.ti.com/support/low_power_rf/f/155/t/231885.aspx里面解释了原因!

 

所以在上篇文章中提到的HalFlashWriteTrigger函数就是那个执行write flash的函数,在flash初始化的时候,复制到sram中,然后将sram映射到code空间中,CPU从sram中执行HalFlashWriteTrigger, 进行write flash,当write complete时,此函数返回,同样sram switch back to XDATA,CPU继续执行code空间中的代码。

 

以上的两个问题还没完全弄明白!可能哪儿理解还不到位!

最后是flash erase ,

void HalFlashErase(uint8 pg)
{
  FADDRH = pg * (HAL_FLASH_PAGE_SIZE / HAL_FLASH_WORD_SIZE / 256);
  FCTL |= 0x01;
}

这个函数较为简单,根据datasheet[置顶] Z-STACK之cc2530 flash驱动详解下_第2张图片

 

                      while(FCTL & 0X80) 一句可以不要!  事实上在write flash时,要求先将该page erase,然后再写入值!这个原因可以在datasheet中找到!

 

          Z-STACK中的flash驱动主要是提供给OSAL_Nv, zigbee需要将IEEE地址或某些信息永久存储在flash中,所以就 非易失性 存储!

 

 

 

你可能感兴趣的:(zigbee,CC2530,Flash驱动,Z-Stack)