本文深入源码讲述了Contiki文件系统Coffee的格式化,即擦除整个FLASH,并初始化结构体protected_mem

1. 格式化

1.1 硬盘格式化

(1)低级格式化

低级格式化就是将空白的磁盘划分出柱面和磁道,再将磁道划分为若干个扇区,每个扇区又划分出标识部分ID、间隔区GAP和数据区DATA等。可见,低级格式化是高级格式化之前的一件工作,低级格式化只能针对一块硬盘而不能支持单独的某一个分区。每块硬盘在出厂时,已由硬盘生产商进行低级格式化,因此通常使用者无需再进行低级格式化操作。其实,我们对一张软盘进行的全面格式化就是一种低级格式化。对于硬盘上出现逻辑坏道或者软性物理坏道,用户可以试试使用低级格式化来达到屏蔽坏道的作用,这样能在一定程度上保证用户数据的可靠性,但坏道却会随着硬盘分区、格式化次数的增长而扩散蔓延[3]。

(2)高级格式化

高级格式化又称逻辑格式化,它是指根据用户选定的文件系统(如FAT12、FAT16、FAT32、NTFS、EXT2、EXT3等),在磁盘的特定区域写入特定数据,以达到初始化磁盘或磁盘分区、清除原磁盘或磁盘分区中所有文件的一个操作。高级格式化包括对主引导记录中分区表相应区域的重写、根据用户选定的文件系统,在分区中划出一片用于存放文件分配表、目录表等用于文件管理的磁盘空间,以便用户使用该分区管理文件[4]。

1.2 Coffee格式化

跟硬盘格式化类似,FLASH低级格式化(可以如此理解,也许根本就没有,由产家弄好了)已经把FLASH按块-页分好了,Coffee格式化类似于硬盘的高级格式化,但不尽相同。第一使用Coffee文件系统,必须进行格式化,将整个FLASH擦除(FLASH物理特性,先擦除后写)。

2. cfs_coffee_format

cfs_coffee_format主要工作将Coffee管理的FLASH区域全部写入“0”(而不是擦除,极易被COFFEE_ERASE这个名字误导),以及初始化结构体protected_mem,源码如下:

int cfs_coffee_format(void)
{
  unsigned i;
  PRINTF("Coffee: Formatting %u sectors", COFFEE_SECTOR_COUNT);

  *next_free = 0;
  for (i = 0; i < COFFEE_SECTOR_COUNT; i++)
  {
    COFFEE_ERASE(i);
    PRINTF(".");
  }

  memset(&protected_mem, 0, sizeof(protected_mem)); /* Formatting invalidates the file information.*/

  PRINTF(" done!\n");
  return 0;
}

2.1 next_free

next_freeprotected_mem_t结构体的一个成员变量,指向下一个空闲的页,初始化为0,源码如下:

static struct protected_mem_t
{
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];
  coffee_page_t next_free;
  char gc_wait;
} protected_mem;

static struct file *const coffee_files = protected_mem.coffee_files;
static struct file_desc *const coffee_fd_set = protected_mem.coffee_fd_set;
static coffee_page_t *const next_free = &protected_mem.next_free;
static char *const gc_wait = &protected_mem.gc_wait;

2.2 COFFEE_ERASE

Coffee格式化是按区擦除,可以把COFFEE_SECTOR_SIZE设成几倍的块大小(片外FLASH,即NAND FLASH)或者几倍的页大小(片上FLASH,即NOR FLASH,按页擦除或整个FLASH擦除),这将有利于容量大的存储设备。[2]是这么说的,COFFEE_SECTOR_SIZE用于应付大的存储设备(比如SD卡),在这种情况下,将其设置大一点可加快顺序扫描速度。

COFFEE_ERASE宏被定义到硬件相关的擦除函数(这也是Coffee文件移植需做的事,在cfs-coffee-arch.h文件中),如下:

#define COFFEE_ERASE(sector) stm32_flash_erase(sector)

stm32_flash_erase函数源代码(在cfs-coffee-arch.c中)如下:

void stm32_flash_erase(u8_t sector)
{
  u32_t addr = COFFEE_START + (sector) *COFFEE_SECTOR_SIZE;
  u32_t end = addr + COFFEE_SECTOR_SIZE;

  /* This prevents from accidental write to CIB. */
  if (!(addr >= FLASH_START && end <= (FLASH_START+FLASH_PAGES*COFFEE_SECTOR_SIZE)))
  {
    return ;
  }
  FLASH_Unlock();
  FLASH_ErasePage(addr);
}

咋一看,上述的代码有只有当COFFEE_SECTOR_SIZE(逻辑区大小)与FLASH_PAGE_SIZE(FLASH物理页大小)相等的时候,才不会有问题。若COFFEE_SECTOR_SIZE大于FLASH_PAGE_SIZE,但FLASH_ErasePage只擦除一页,那余下的就没擦除了;倘若COFFEE_SECTOR_SIZE小于FLASH_PAGE_SIZE,那还多擦除了部分。在我们的例子,将COFFEE_SECTOR_SIZE被设成FLASH物理页大小FLASH_PAGE_SIZE,所以没出现问题。

细心的你会发现,即便如此也还有问题,因为FLASH是页读写,按块擦除,而块通常由若干页组成,而代码却是按页擦除。但你忽略了另一个问题,平台相关性,我们例子的FLASH是片上FLASH,即NOR FLASH,与内存统一编址,可以随机读取,按页擦除或者整块擦除,所以一直没出问题。

注意:这是我之前的理解,后来发现有误。事实上,COFFEE_ERASE并不是将FLASH擦除,而是将FLASH写入“0”,修改后的源代码如下:

void stm32_flash_erase(u8_t sector)
{
  u32_t data = 0;
  u32_t addr = COFFEE_START + (sector) * COFFEE_SECTOR_SIZE;
  u32_t end = addr + COFFEE_SECTOR_SIZE;

  if(!(addr>=COFFEE_START && end<=COFFEE_START+COFFEE_SIZE)) //确保地址在Coffee管理的区间
  {
    return;
  }

  FLASH_Unlock();
  FLASH_ErasePage(addr); //先擦除 NOTE:assume COFFEE_SECTOR_SIZE=FLASH_PAGE_SIZE
  for(; addr < end; addr += 4)
  {
    if(FLASH_ProgramWord(addr, data) != FLASH_COMPLETE)
    {
      PRINTF("FLASH_ProgramHalfWord Error.\n");
    }
  }
  FLASH_Lock();
}

2.3 memset

memset函数功能是将一段内存块填充某个给定的值,通常用于对较大结构体或数组清零操作。memset(void *s, int c, size_t n),即将从地址s开始往后的n个字节都设成c[5]。在这里,将protected_mem结构体(见2.1)的成员变量都设成0(数组的每个元素也为0)。奇怪了,实现这个函数怎么会在Install_Software\IAR Systems\Embedded Workbench 5.4\arm\INC呢?源码如下,完全看不懂:-(

#define _DLIB_STRING_SKIP_INLINE_MEMSET
#pragma inline
void *memset(void *_D, int _C, size_t _N)
{
  __aeabi_memset(_D, _N, _C);
  return _D;
}

至此Coffee文件系统格式化完毕:-)

参考资料:

[1] Enabling Large-Scale Storage in Sensor Networks with the Coffee File System.pdf

[2]

[3] 文章《》

[4] 维基百科词条:

[5] 博文《memset用法详解

本文系Spark & Shine原创,转载需注明出处本文最近一次修改时间 2022-03-22 00:25

results matching ""

    No results matching ""