1
0
Эх сурвалжийг харах

fal: add new example for norflash

ricky 1 сар өмнө
parent
commit
7475f5549d

+ 196 - 0
components/fal/samples/porting/fal_norflash_port.c

@@ -0,0 +1,196 @@
+#include <fal.h>
+#include "fal_def.h"
+
+#define FLASH_SECTOR_SIZE      ( 4 * 1024 )
+#define FLASH_START_ADDR       0U
+#define FLASH_END_ADDR         0x01000000U  // 16*1024*1024
+
+#define FLASH_PROGRAM_MIN_SIZE 256  // 256 bytes
+//每次对falsh写入时 底层可以写入的最大字节数为 FALSH_PAGE_SIZE
+#define FALSH_PAGE_SIZE        FLASH_PROGRAM_MIN_SIZE  // 256 bytes
+
+/**
+ * @brief 需要实现以下函数
+ */
+extern int norflash_init( void );
+extern void norflash_read( uint8_t* pbuf, uint32_t addr, uint16_t datalen );
+extern void norflash_write_page( uint8_t* pbuf, uint32_t addr, uint16_t datalen );
+extern void norflash_erase_sector( uint32_t saddr );
+
+static int init( void );
+static int read( long offset, uint8_t* buf, size_t size );
+static int write( long offset, const uint8_t* buf, size_t size );
+static int erase( long offset, size_t size );
+
+#define FAL_ALIGN_UP( size, align ) \
+    ( ( ( size ) + ( align ) - 1 ) - ( ( ( size ) + ( align ) - 1 ) % ( align ) ) )
+#define FAL_ALIGN_DOWN( size, align ) ( ( ( size ) / ( align ) ) * ( align ) )
+
+static int32_t get_sector( uint32_t address )
+{
+    uint32_t sector = 0;
+    if ( address < FLASH_END_ADDR && address >= FLASH_START_ADDR ) {
+        address -= FLASH_START_ADDR;
+        sector = address / FLASH_SECTOR_SIZE;
+        return sector;
+    }
+    return -1;
+}
+
+static int init( void )
+{
+    norflash_init();
+    return 0;
+}
+
+
+static int read( long offset, uint8_t* buf, size_t size )
+{
+    norflash_read( buf, offset + FLASH_START_ADDR, size );
+    return size;
+}
+
+static uint32_t judge_whether_erase( uint8_t* sector_buf, uint16_t len )
+{
+    uint8_t* p = sector_buf;
+    for ( size_t i = 0; i < len; i++ ) {
+        if ( p[ i ] != 0xFF ) {
+            return 1;
+        }
+    }
+    return 0;
+}
+/**
+ * @brief
+ *
+ * @param offset 绝对地址
+ * @param buf 读出来的扇区数据缓存
+ * @param size 从扇区开始要写的长度 小于扇区大小
+ * @return int
+ */
+static int write_sector( long offset, const uint8_t* buf, size_t size )
+{
+    uint32_t addr      = FLASH_START_ADDR + offset;
+    uint32_t addr_up   = FAL_ALIGN_UP( addr, FALSH_PAGE_SIZE );
+    uint32_t addr_down = FAL_ALIGN_DOWN( addr, FALSH_PAGE_SIZE );
+
+    uint32_t addr_end      = addr + size;
+    uint32_t addr_end_up   = FAL_ALIGN_UP( addr_end, FALSH_PAGE_SIZE );
+    uint32_t addr_end_down = FAL_ALIGN_DOWN( addr_end, FALSH_PAGE_SIZE );
+
+    uint32_t cur_addr      = addr_down;
+    uint32_t max_write_len = 0;
+    uint32_t write_len     = 0;
+    while ( cur_addr < addr_end_up ) {
+        if ( cur_addr < addr ) {
+            max_write_len = ( addr_up - addr );
+            write_len     = size >= max_write_len ? max_write_len : size;
+            norflash_write_page( buf, addr, write_len );
+            buf += write_len;
+        }
+        else if ( cur_addr == addr_end_down ) {
+            max_write_len = FALSH_PAGE_SIZE;
+            write_len     = addr_end - cur_addr;
+            write_len     = write_len >= max_write_len ? max_write_len : write_len;
+            norflash_write_page( buf, cur_addr, write_len );
+        }
+        else {
+            norflash_write_page( buf, cur_addr, FALSH_PAGE_SIZE );
+            buf += FALSH_PAGE_SIZE;
+        }
+
+        cur_addr += FALSH_PAGE_SIZE;
+    }
+    return size;
+}
+static int write( long offset, const uint8_t* buf, size_t size )
+{
+    uint32_t addr      = FLASH_START_ADDR + offset;
+    uint32_t addr_up   = FAL_ALIGN_UP( addr, FLASH_SECTOR_SIZE );
+    uint32_t addr_down = FAL_ALIGN_DOWN( addr, FLASH_SECTOR_SIZE );
+
+    uint32_t addr_end      = addr + size;
+    uint32_t addr_end_up   = FAL_ALIGN_UP( addr_end, FLASH_SECTOR_SIZE );
+    uint32_t addr_end_down = FAL_ALIGN_DOWN( addr_end, FLASH_SECTOR_SIZE );
+    uint32_t cur_addr      = addr_down;
+
+    uint32_t max_write_len = 0;
+    uint32_t write_len     = 0;
+
+    if ( addr_end_up > FLASH_END_ADDR || ( int )addr_end_down < FLASH_START_ADDR ) return -1;
+    //如果不使用内存分配可以定义一个static FLASH_SECTOR_SIZE 长度的buf 
+    uint8_t* read_sector_buf = FAL_MALLOC( FLASH_SECTOR_SIZE );
+    if ( read_sector_buf == RT_NULL ) {
+        return -2;
+    }
+    while ( cur_addr < addr_end_up ) {
+        // 首次扇区写
+        if ( cur_addr < addr ) {
+            read( cur_addr - FLASH_START_ADDR, read_sector_buf, FLASH_SECTOR_SIZE );
+            max_write_len = ( addr_up - addr );
+            write_len     = size >= max_write_len ? max_write_len : size;
+            if ( judge_whether_erase( read_sector_buf + addr - cur_addr, write_len ) ){
+                norflash_erase_sector( get_sector( cur_addr ) );
+                FAL_MEMCPY( read_sector_buf + ( addr - cur_addr ), buf, write_len );
+                write_sector( cur_addr, read_sector_buf, FLASH_SECTOR_SIZE );
+            }
+            else {
+                write_sector( addr, buf, write_len );
+            }
+            buf += write_len;
+        }
+        //最后一次扇区写
+        else if ( cur_addr == addr_end_down ) {
+            read( cur_addr - FLASH_START_ADDR, read_sector_buf, FLASH_SECTOR_SIZE );
+            max_write_len = FLASH_SECTOR_SIZE;
+            write_len     = addr_end - cur_addr;
+            write_len     = write_len >= max_write_len ? max_write_len : write_len;
+            if ( judge_whether_erase( read_sector_buf,  write_len ) ) {
+                FAL_MEMCPY( read_sector_buf, buf, write_len );
+                norflash_erase_sector( get_sector( cur_addr ) );
+                write_sector( cur_addr, read_sector_buf, FLASH_SECTOR_SIZE );
+            }
+            else {
+                write_sector( cur_addr, buf, write_len );
+            }
+        }
+        //中间扇区写 直接擦除
+        else {
+            norflash_erase_sector( get_sector( cur_addr ) );
+            write_sector( cur_addr, buf, FLASH_SECTOR_SIZE );
+            buf += FLASH_SECTOR_SIZE;
+        }
+        cur_addr += FLASH_SECTOR_SIZE;
+    }
+    FAL_FREE( read_sector_buf );
+    return size;
+}
+
+static int erase( long offset, size_t size )
+{
+    int32_t  cur_erase_sector;
+    uint32_t addr      = FLASH_START_ADDR + offset;
+    uint32_t addr_down = FAL_ALIGN_DOWN( addr, FLASH_SECTOR_SIZE );
+
+    uint32_t addr_end    = addr + size;
+    uint32_t addr_end_up = FAL_ALIGN_UP( addr_end, FLASH_SECTOR_SIZE );
+    uint32_t cur_addr    = addr_down;
+
+    while ( cur_addr < addr_end_up ) {
+        cur_erase_sector = get_sector( cur_addr );
+        if ( cur_erase_sector == -1 ) {
+            return cur_addr - addr;
+        }
+        norflash_erase_sector( cur_erase_sector );
+        cur_addr += FLASH_SECTOR_SIZE;
+    }
+    return size;
+}
+const struct fal_flash_dev norflash0 = {
+    .name       = "norflash0",
+    .addr       = FLASH_START_ADDR,
+    .len        = FLASH_END_ADDR - FLASH_START_ADDR,
+    .blk_size   = FLASH_SECTOR_SIZE,
+    .ops        = { init, read, write, erase },
+    .write_gran = 1,
+};