在用nRF52810的flash驱动nrf_fstorage_write写数据时,
发现驱动函数的3个参数:flash的物理地址,用户的数据缓存地址和
长度都必须4字节对齐,
比如你开一个uint8_t buff[16];用&buff[1]作为地址传入就会出错。
所以封装了一个可以非对齐的写入函数。
signed char fs_write(uint32_t wr_addr,uint8_t *p_wr,uint16_t len_to_wr);
static uint8_t fs_page_buf[4096] = {0};//写操作的页缓存
/*函数功能:
*在某一页内 任意起始位置 写flash
*只能被fs_write调用!
*/
static signed char fs_write_nocheck (uint32_t wr_start,uint8_t *p_wr,uint32_t wr_end)
{
ret_code_t rc; //库函数返回值
/*分 3 次写
头: 起始地址到首个4整除的地址
中间:首个4整除的地址到 最后一个4整除的地址
尾: 最后一个4整除的地址到最后*/
/*待写入flash示例:x:不改写的数据, 其他:要改写的字节
xxx1 ABCD ... DCBA 10xx
wr_start : xxx1 中 1 的地址; wr_end: 10xx 中 0 的地址.*/
uint32_t addr_temp = 0; //写入地址
uint16_t pos_temp = 0,len_temp = 0,num_to_wr = 0;
uint8_t remain_temp = 0,buff_temp[32] = {0};
if(wr_start > wr_end) //地址错误
{
return -1;
}
NRF_LOG_DEBUG("wr nocheck");
num_to_wr = 1 + wr_end - wr_start; //待写入的字节数
//NO.1 write head.............................................................................
remain_temp = wr_start%4; //xxx1 中不要改写的字节数 3
len_temp = 4 - remain_temp; //xxx1 中要改写的字节数 1
if(len_temp > num_to_wr)
len_temp = num_to_wr;
addr_temp = wr_start - remain_temp; //xxx1 第一个字节在flash中的物理地址
pos_temp = addr_temp % 4096; //xxx1 第一个字节在页缓存中的偏移
if((addr_temp % 4) != 0)
{
return -1;
}
//可能flash已被擦除,从页缓存里拷贝
memcpy(buff_temp,&fs_page_buf[pos_temp],4);
//修改要写入的新数据
memcpy(&buff_temp[remain_temp],p_wr,len_temp);
rc = nrf_fstorage_write(&fstorage, addr_temp, buff_temp, 4, NULL);
APP_ERROR_CHECK(rc);
wait_for_flash_ready(&fstorage);
//===================================
memcpy(buff_temp,(uint32_t *)addr_temp,len_temp);
NRF_LOG_DEBUG("wr head:%d,addr:0x%08x",len_temp,addr_temp);
NRF_LOG_HEXDUMP_DEBUG(buff_temp,4);
//===================================
//更新写入地址和写入数据缓存地址
p_wr += len_temp;
addr_temp += 4;
//是否写完
if(num_to_wr <= len_temp)
return 0;
else
num_to_wr -= len_temp;
//NO.2 write body...............................................................................
if(num_to_wr > 4)
{
uint16_t wr_body_ok_len = 0;
//除掉尾巴的长度
len_temp = num_to_wr - num_to_wr%4;
while(wr_body_ok_len < len_temp)
{
memcpy(buff_temp,p_wr+wr_body_ok_len,4);
//写入的源数据地址必须4字节对齐
rc = nrf_fstorage_write(&fstorage, addr_temp, buff_temp, 4, NULL);
APP_ERROR_CHECK(rc);
wait_for_flash_ready(&fstorage);
//===================================
NRF_LOG_DEBUG("body addr 0x%08x",addr_temp);
NRF_LOG_HEXDUMP_DEBUG(buff_temp,4);
//===================================
wr_body_ok_len += 4;
addr_temp += 4;
}
//是否写完
if(num_to_wr <= len_temp)
return 0;
else
p_wr += len_temp;
}
//NO.3 write tail...............................................................................................
remain_temp = wr_end%4;
len_temp = 1 + remain_temp;
addr_temp = wr_end - remain_temp;
memcpy(buff_temp,(uint32_t *)addr_temp,4);
memcpy(buff_temp,p_wr,len_temp);
rc = nrf_fstorage_write(&fstorage, addr_temp, buff_temp, 4, NULL);
APP_ERROR_CHECK(rc);
wait_for_flash_ready(&fstorage);
//===================================
memcpy(buff_temp,(uint32_t *)addr_temp,len_temp);
NRF_LOG_DEBUG("wr tail:%d addr_temp:0x%08x ",len_temp,addr_temp);
NRF_LOG_HEXDUMP_DEBUG(buff_temp,4);
//===================================
return 0;
}
/*函数功能:
*在 任意数据起始地址 任意flash起始位置 写入任意长度*/
signed char fs_write(uint32_t wr_addr,uint8_t *p_wr,uint16_t len_to_wr)
{
ret_code_t rc; //库函数返回值
uint16_t loop = 0;
uint16_t page_off = wr_addr % 4096; //页内偏移
uint32_t page_pos = wr_addr - page_off;//写入地址的页首物理地址
uint16_t page_remain = 4096 - page_off;//页内剩余待写入字节数
//地址不在范围内
if((wr_addr < MY_FLASH_DATA_START) || (wr_addr > MY_FLASH_DATA_END))
{
NRF_LOG_DEBUG("addr to write is not in range");
return -1;
}
while(len_to_wr)
{
//如果页剩余空间比待写入的长度大
if(page_remain > len_to_wr)
page_remain = len_to_wr;
//1、拷贝这页的内容
memcpy(fs_page_buf,(uint32_t *)page_pos,4096);
//NRF_LOG_DEBUG("PAGE_POS:0x%08x",page_pos);
//NRF_LOG_HEXDUMP_DEBUG(fs_page_buf,17);
//2、校验待写入的位置是否有非0xff的数据
for(loop = 0;loop < page_remain;loop++)
{
if(fs_page_buf[page_off + loop] != 0xff)//从偏移到页结束
{
break;//结束校验
}
}
//3、写入
if(loop < page_remain)
{
//需要擦除
nrf_fstorage_erase(&fstorage,page_pos,1,NULL);
wait_for_flash_ready(&fstorage);
//在拷贝的旧数据缓存中修改要写入的新数据
memcpy(&fs_page_buf[page_off],p_wr,page_remain);
//写入整页
rc = nrf_fstorage_write(&fstorage, page_pos, fs_page_buf, 4096, NULL);
APP_ERROR_CHECK(rc);
wait_for_flash_ready(&fstorage);
}
else
{
//不需要擦除
//首尾地址4字节对齐写入处理
if(fs_write_nocheck(wr_addr,p_wr,wr_addr + page_remain - 1) == -1)
return -1;
}
//4、更新地址长度
p_wr += page_remain;
wr_addr += page_remain;
len_to_wr -= page_remain;
page_off = 0;
page_pos += 4096;
page_remain = 4096;
}
return 0;
}
//写函数测试
void fs_write_test()
{
ret_code_t rc; //库函数返回值
uint8_t buff[64] = {0};
uint8_t loop = 0;
while(loop < 64)
{
buff[loop] = loop;
loop++;
}
fs_write(0x2f000,buff,64);
memset(buff,0x55,64);
fs_write(0x2f000+3,&buff[1],16);
//==============================
NRF_LOG_DEBUG("wr test result!");
memcpy(buff,(uint32_t *)(0x2f000+0),64);
NRF_LOG_HEXDUMP_DEBUG(buff,64);
//==============================
rc = nrf_fstorage_erase(&fstorage,0x2f000,1,NULL);
APP_ERROR_CHECK(rc);
wait_for_flash_ready(&fstorage);
}