Skip to content

在components\fal\samples\porting\新增norflash移植示例 #10068

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 28, 2025
196 changes: 196 additions & 0 deletions components/fal/samples/porting/fal_norflash_port.c
Original file line number Diff line number Diff line change
@@ -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,
};