|
| 1 | +#include <fal.h> |
| 2 | +#include "fal_def.h" |
| 3 | + |
| 4 | +#define FLASH_SECTOR_SIZE ( 4 * 1024 ) |
| 5 | +#define FLASH_START_ADDR 0U |
| 6 | +#define FLASH_END_ADDR 0x01000000U // 16*1024*1024 |
| 7 | + |
| 8 | +#define FLASH_PROGRAM_MIN_SIZE 256 // 256 bytes |
| 9 | +//每次对falsh写入时 底层可以写入的最大字节数为 FALSH_PAGE_SIZE |
| 10 | +#define FALSH_PAGE_SIZE FLASH_PROGRAM_MIN_SIZE // 256 bytes |
| 11 | + |
| 12 | +/** |
| 13 | + * @brief 需要实现以下函数 |
| 14 | + */ |
| 15 | +extern int norflash_init( void ); |
| 16 | +extern void norflash_read( uint8_t* pbuf, uint32_t addr, uint16_t datalen ); |
| 17 | +extern void norflash_write_page( uint8_t* pbuf, uint32_t addr, uint16_t datalen ); |
| 18 | +extern void norflash_erase_sector( uint32_t saddr ); |
| 19 | + |
| 20 | +static int init( void ); |
| 21 | +static int read( long offset, uint8_t* buf, size_t size ); |
| 22 | +static int write( long offset, const uint8_t* buf, size_t size ); |
| 23 | +static int erase( long offset, size_t size ); |
| 24 | + |
| 25 | +#define FAL_ALIGN_UP( size, align ) \ |
| 26 | + ( ( ( size ) + ( align ) - 1 ) - ( ( ( size ) + ( align ) - 1 ) % ( align ) ) ) |
| 27 | +#define FAL_ALIGN_DOWN( size, align ) ( ( ( size ) / ( align ) ) * ( align ) ) |
| 28 | + |
| 29 | +static int32_t get_sector( uint32_t address ) |
| 30 | +{ |
| 31 | + uint32_t sector = 0; |
| 32 | + if ( address < FLASH_END_ADDR && address >= FLASH_START_ADDR ) { |
| 33 | + address -= FLASH_START_ADDR; |
| 34 | + sector = address / FLASH_SECTOR_SIZE; |
| 35 | + return sector; |
| 36 | + } |
| 37 | + return -1; |
| 38 | +} |
| 39 | + |
| 40 | +static int init( void ) |
| 41 | +{ |
| 42 | + norflash_init(); |
| 43 | + return 0; |
| 44 | +} |
| 45 | + |
| 46 | + |
| 47 | +static int read( long offset, uint8_t* buf, size_t size ) |
| 48 | +{ |
| 49 | + norflash_read( buf, offset + FLASH_START_ADDR, size ); |
| 50 | + return size; |
| 51 | +} |
| 52 | + |
| 53 | +static uint32_t judge_whether_erase( uint8_t* sector_buf, uint16_t len ) |
| 54 | +{ |
| 55 | + uint8_t* p = sector_buf; |
| 56 | + for ( size_t i = 0; i < len; i++ ) { |
| 57 | + if ( p[ i ] != 0xFF ) { |
| 58 | + return 1; |
| 59 | + } |
| 60 | + } |
| 61 | + return 0; |
| 62 | +} |
| 63 | +/** |
| 64 | + * @brief |
| 65 | + * |
| 66 | + * @param offset 绝对地址 |
| 67 | + * @param buf 读出来的扇区数据缓存 |
| 68 | + * @param size 从扇区开始要写的长度 小于扇区大小 |
| 69 | + * @return int |
| 70 | + */ |
| 71 | +static int write_sector( long offset, const uint8_t* buf, size_t size ) |
| 72 | +{ |
| 73 | + uint32_t addr = FLASH_START_ADDR + offset; |
| 74 | + uint32_t addr_up = FAL_ALIGN_UP( addr, FALSH_PAGE_SIZE ); |
| 75 | + uint32_t addr_down = FAL_ALIGN_DOWN( addr, FALSH_PAGE_SIZE ); |
| 76 | + |
| 77 | + uint32_t addr_end = addr + size; |
| 78 | + uint32_t addr_end_up = FAL_ALIGN_UP( addr_end, FALSH_PAGE_SIZE ); |
| 79 | + uint32_t addr_end_down = FAL_ALIGN_DOWN( addr_end, FALSH_PAGE_SIZE ); |
| 80 | + |
| 81 | + uint32_t cur_addr = addr_down; |
| 82 | + uint32_t max_write_len = 0; |
| 83 | + uint32_t write_len = 0; |
| 84 | + while ( cur_addr < addr_end_up ) { |
| 85 | + if ( cur_addr < addr ) { |
| 86 | + max_write_len = ( addr_up - addr ); |
| 87 | + write_len = size >= max_write_len ? max_write_len : size; |
| 88 | + norflash_write_page( buf, addr, write_len ); |
| 89 | + buf += write_len; |
| 90 | + } |
| 91 | + else if ( cur_addr == addr_end_down ) { |
| 92 | + max_write_len = FALSH_PAGE_SIZE; |
| 93 | + write_len = addr_end - cur_addr; |
| 94 | + write_len = write_len >= max_write_len ? max_write_len : write_len; |
| 95 | + norflash_write_page( buf, cur_addr, write_len ); |
| 96 | + } |
| 97 | + else { |
| 98 | + norflash_write_page( buf, cur_addr, FALSH_PAGE_SIZE ); |
| 99 | + buf += FALSH_PAGE_SIZE; |
| 100 | + } |
| 101 | + |
| 102 | + cur_addr += FALSH_PAGE_SIZE; |
| 103 | + } |
| 104 | + return size; |
| 105 | +} |
| 106 | +static int write( long offset, const uint8_t* buf, size_t size ) |
| 107 | +{ |
| 108 | + uint32_t addr = FLASH_START_ADDR + offset; |
| 109 | + uint32_t addr_up = FAL_ALIGN_UP( addr, FLASH_SECTOR_SIZE ); |
| 110 | + uint32_t addr_down = FAL_ALIGN_DOWN( addr, FLASH_SECTOR_SIZE ); |
| 111 | + |
| 112 | + uint32_t addr_end = addr + size; |
| 113 | + uint32_t addr_end_up = FAL_ALIGN_UP( addr_end, FLASH_SECTOR_SIZE ); |
| 114 | + uint32_t addr_end_down = FAL_ALIGN_DOWN( addr_end, FLASH_SECTOR_SIZE ); |
| 115 | + uint32_t cur_addr = addr_down; |
| 116 | + |
| 117 | + uint32_t max_write_len = 0; |
| 118 | + uint32_t write_len = 0; |
| 119 | + |
| 120 | + if ( addr_end_up > FLASH_END_ADDR || ( int )addr_end_down < FLASH_START_ADDR ) return -1; |
| 121 | + //如果不使用内存分配可以定义一个static FLASH_SECTOR_SIZE 长度的buf |
| 122 | + uint8_t* read_sector_buf = FAL_MALLOC( FLASH_SECTOR_SIZE ); |
| 123 | + if ( read_sector_buf == RT_NULL ) { |
| 124 | + return -2; |
| 125 | + } |
| 126 | + while ( cur_addr < addr_end_up ) { |
| 127 | + // 首次扇区写 |
| 128 | + if ( cur_addr < addr ) { |
| 129 | + read( cur_addr - FLASH_START_ADDR, read_sector_buf, FLASH_SECTOR_SIZE ); |
| 130 | + max_write_len = ( addr_up - addr ); |
| 131 | + write_len = size >= max_write_len ? max_write_len : size; |
| 132 | + if ( judge_whether_erase( read_sector_buf + addr - cur_addr, write_len ) ){ |
| 133 | + norflash_erase_sector( get_sector( cur_addr ) ); |
| 134 | + FAL_MEMCPY( read_sector_buf + ( addr - cur_addr ), buf, write_len ); |
| 135 | + write_sector( cur_addr, read_sector_buf, FLASH_SECTOR_SIZE ); |
| 136 | + } |
| 137 | + else { |
| 138 | + write_sector( addr, buf, write_len ); |
| 139 | + } |
| 140 | + buf += write_len; |
| 141 | + } |
| 142 | + //最后一次扇区写 |
| 143 | + else if ( cur_addr == addr_end_down ) { |
| 144 | + read( cur_addr - FLASH_START_ADDR, read_sector_buf, FLASH_SECTOR_SIZE ); |
| 145 | + max_write_len = FLASH_SECTOR_SIZE; |
| 146 | + write_len = addr_end - cur_addr; |
| 147 | + write_len = write_len >= max_write_len ? max_write_len : write_len; |
| 148 | + if ( judge_whether_erase( read_sector_buf, write_len ) ) { |
| 149 | + FAL_MEMCPY( read_sector_buf, buf, write_len ); |
| 150 | + norflash_erase_sector( get_sector( cur_addr ) ); |
| 151 | + write_sector( cur_addr, read_sector_buf, FLASH_SECTOR_SIZE ); |
| 152 | + } |
| 153 | + else { |
| 154 | + write_sector( cur_addr, buf, write_len ); |
| 155 | + } |
| 156 | + } |
| 157 | + //中间扇区写 直接擦除 |
| 158 | + else { |
| 159 | + norflash_erase_sector( get_sector( cur_addr ) ); |
| 160 | + write_sector( cur_addr, buf, FLASH_SECTOR_SIZE ); |
| 161 | + buf += FLASH_SECTOR_SIZE; |
| 162 | + } |
| 163 | + cur_addr += FLASH_SECTOR_SIZE; |
| 164 | + } |
| 165 | + FAL_FREE( read_sector_buf ); |
| 166 | + return size; |
| 167 | +} |
| 168 | + |
| 169 | +static int erase( long offset, size_t size ) |
| 170 | +{ |
| 171 | + int32_t cur_erase_sector; |
| 172 | + uint32_t addr = FLASH_START_ADDR + offset; |
| 173 | + uint32_t addr_down = FAL_ALIGN_DOWN( addr, FLASH_SECTOR_SIZE ); |
| 174 | + |
| 175 | + uint32_t addr_end = addr + size; |
| 176 | + uint32_t addr_end_up = FAL_ALIGN_UP( addr_end, FLASH_SECTOR_SIZE ); |
| 177 | + uint32_t cur_addr = addr_down; |
| 178 | + |
| 179 | + while ( cur_addr < addr_end_up ) { |
| 180 | + cur_erase_sector = get_sector( cur_addr ); |
| 181 | + if ( cur_erase_sector == -1 ) { |
| 182 | + return cur_addr - addr; |
| 183 | + } |
| 184 | + norflash_erase_sector( cur_erase_sector ); |
| 185 | + cur_addr += FLASH_SECTOR_SIZE; |
| 186 | + } |
| 187 | + return size; |
| 188 | +} |
| 189 | +const struct fal_flash_dev norflash0 = { |
| 190 | + .name = "norflash0", |
| 191 | + .addr = FLASH_START_ADDR, |
| 192 | + .len = FLASH_END_ADDR - FLASH_START_ADDR, |
| 193 | + .blk_size = FLASH_SECTOR_SIZE, |
| 194 | + .ops = { init, read, write, erase }, |
| 195 | + .write_gran = 1, |
| 196 | +}; |
0 commit comments