52810非4字节对齐地址、非4字节对齐长度、非4字节对齐源数据地址的flash写函数

在用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);
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_28851611/article/details/99655914
今日推荐