参考apollo3 FLASH样例改写实际应用的接口函数(带磨损均衡处理)

// 状态码
typedef enum 
{
    FLASH_OK = 0,
    FLASH_ERR_INVALID_PARAM,
    FLASH_ERR_ADDR_OUT_OF_RANGE,
    FLASH_ERR_WRITE_FAILURE,
    FLASH_ERR_MEM_ALLOC
} flash_status_t;

#define FLASH_PAGE_SIZE         AM_HAL_FLASH_PAGE_SIZE        //每页大小为8K字节,
#define FLASH_INSTANCE_SIZE     AM_HAL_FLASH_INSTANCE_SIZE    //每个实例512K,2个实例一共1M用作用户存储
#define FLASH_TOTAL_SIZE        (2 * FLASH_INSTANCE_SIZE - 1)    //2个实例一共1M用作用户存储

#define START_PAGE_ADDRESS         (0x80000)            //(AM_HAL_FLASH_INSTANCE_SIZE)
#define WEAR_LEVELING_PAGE_NUM    20                 // 磨损均衡页数(20页)
#define WEAR_LEVELING_END_ADDR    (START_PAGE_ADDRESS + WEAR_LEVELING_PAGE_NUM * FLASH_PAGE_SIZE - 1) // 结束地址

#define RECORD_BUF_SIZE        510

typedef struct
{    
    uint8_t frame_num;                    //
    uint8_t temp[4];
    uint8_t buffer[RECORD_BUF_SIZE];    //
    uint8_t crc;                        //异哉较验
}__attribute__((aligned(4)))flash_record_t;

#include <stdlib.h>
#include <stdbool.h>
#include "am_mcu_apollo.h"
#include "am_bsp.h"
#include "am_util.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "dev_flash.h"


QueueHandle_t xFlashQueue = NULL;
flash_record_t flash_record;

static uint32_t ui32Source[512];

/******************************************************************************
 * @brief 带自动对齐的Flash写入函数
 * @param pDest 目标Flash地址(需在已擦除区域)
 * @param pSrc 源数据指针
 * @param ui32DataLen 数据实际长度(字节)
 * @return flash_status_t 操作状态码
 *****************************************************************************///
flash_status_t flash_flex_write(uint32_t ui32DestAddr, uint8_t *pData, uint32_t ui32DataLen)
{
    uint16_t i, WordCount = 0;
    
    // 参数基础校验
    if ((ui32DataLen == 0) || (ui32DestAddr >= (FLASH_TOTAL_SIZE - 1))) 
    {
        am_util_debug_printf("write option error...\n");
        return FLASH_ERR_INVALID_PARAM;
    }

    // 计算需要填充的字节数(对齐到4字节)
    uint32_t ui32Padding = (4 - (ui32DataLen % 4)) % 4;        //和__attribute__((aligned(4)))定义功能一样,二者用其一即可
    uint32_t ui32TotalLen = ui32DataLen + ui32Padding;

    am_util_stdio_printf("TotalLen: %d Padding = %d\n", ui32TotalLen, ui32Padding);
    // 检查地址范围
    if ((ui32DestAddr + ui32TotalLen) > (FLASH_TOTAL_SIZE - 1))
    {
        am_util_debug_printf("write addr exceed...\n");
        return FLASH_ERR_ADDR_OUT_OF_RANGE;
    }

    WordCount = ui32TotalLen / 4;
    // 将每 4 个字节复制到 uint32_t 缓冲区
    for (i = 0; i < WordCount; i++) 
    {
        memcpy(&ui32Source[i], (pData + i * 4), 4);        
    }

    // 执行Flash编程
    int32_t i32Ret = am_hal_flash_program_main(
        AM_HAL_FLASH_PROGRAM_KEY,
        ui32Source,
        (uint32_t*)ui32DestAddr,
        WordCount);
    am_util_stdio_printf("ui32WordCount: %d OK:%d \n", WordCount, i32Ret);
    
    return (i32Ret == 0) ? FLASH_OK : FLASH_ERR_WRITE_FAILURE;
}

/*******************************************************************************
 * @brief 灵活读取Flash数据
 * @param pDest 目标缓冲区指针
 * @param ui32SrcAddr Flash源地址
 * @param ui32DataLen 需要读取的实际数据长度
 * @return flash_status_t 操作状态码
 *******************************************************************************/
flash_status_t flash_flex_read(uint8_t *pData, uint32_t ui32SrcAddr, uint32_t ui32DataLen)
{
    uint32_t ix;
    
    // 参数基础校验
    if ((ui32DataLen == 0) || (ui32SrcAddr >= (FLASH_TOTAL_SIZE - 1)))
    {
        am_util_debug_printf("read option error...\n");
        return FLASH_ERR_INVALID_PARAM;
    }

    // 计算实际需要读取的字节数(包含填充)
    uint32_t ui32TotalLen = ui32DataLen + ((4 - (ui32DataLen % 4)) % 4);        //和__attribute__((aligned(4)))定义功能一样,二者用其一即可

    // 检查地址范围
    if ((ui32SrcAddr + ui32TotalLen) > (FLASH_TOTAL_SIZE - 1))
    {
        am_util_debug_printf("read addr exceed...\n");
        return FLASH_ERR_ADDR_OUT_OF_RANGE;
    }
    am_util_stdio_printf("TotalLen: %d len = %d\n", ui32TotalLen, ui32DataLen);
    for ( ix = 0; ix < ui32DataLen; ix++ )
    {
        *pData = *(uint32_t*)(ui32SrcAddr + ix);
        pData++;
    }

    return FLASH_OK;
}

/*******************************************************************************
//Flash 擦除操作以页(Page)为单位,每个页的大小为固定值(如 8KB = 0x2000 字节)。
页起始地址必须是页大小的整数倍,例如:
第 0 页起始地址:0x0000
第 1 页起始地址:0x2000
第 2 页起始地址:0x4000
*******************************************************************************/
void write_system_config(void)
{
    uint16_t i,k,vlength;
    uint8_t *vPointer;
    uint8_t    vValue;
    
    vValue = 0;
      k = 0;
    vlength = sizeof(flash_record_t);
    vPointer = (uint8_t*)(&flash_record);
      for(i = 0;i < (vlength-1);i++)
      {
           vValue = (vValue^(*vPointer)) + k;
         k++;
        vPointer++;
      }
      flash_record.crc = vValue;

    am_util_stdio_printf("write: %d crc= %d\n", vlength, flash_record.crc);
    // 先擦除目标页
    uint32_t ui32PageAddr = START_PAGE_ADDRESS & ~(FLASH_PAGE_SIZE - 1);    //计算给定地址所在的 Flash 页起始地址
    am_hal_flash_page_erase(AM_HAL_FLASH_PROGRAM_KEY,
                           AM_HAL_FLASH_ADDR2INST(ui32PageAddr),
                           AM_HAL_FLASH_ADDR2PAGE(ui32PageAddr));

    // 写入数据(自动处理对齐)
    vValue = flash_flex_write(START_PAGE_ADDRESS, (uint8_t*)&flash_record, sizeof(flash_record_t));
    am_util_stdio_printf("status: %d\n", vValue);
}

void read_system_config(void)
{
    uint16_t i,k,vlength;
    uint8_t *vPointer;
    uint8_t    vValue;

    
    // 读取数据
    flash_flex_read((uint8_t*)&flash_record, START_PAGE_ADDRESS, sizeof(flash_record_t));

    // 验证数据
        vValue = 0;
           k = 0;
        vlength = sizeof(flash_record_t);
        vPointer = (uint8_t*)(&flash_record);
        for(i = 0; i < (vlength -1); i++)
          {
               vValue = (vValue^(*vPointer)) + k;
             k++;
            vPointer++;
          }
        am_util_stdio_printf("vlength:%d check: %d crc= %d\n", vlength,vValue, flash_record.crc);
        am_util_debug_printf("read:%s\n", (uint8_t*)(&flash_record));
        if(vValue == flash_record.crc)
        {
            am_util_debug_printf("read flash option ok\r\n");            
        }
         else 
        {
            memset(&flash_record, 0x0, vlength);
            am_util_debug_printf("read flash init\r\n");
            flash_record.frame_num = '1';
            flash_record.temp[0] = '2';
            flash_record.temp[1] = '3';
            flash_record.temp[2] = '4';
            flash_record.temp[3] = '5';
            for(i = 0; i < RECORD_BUF_SIZE; i++)
                {
                    flash_record.buffer[i] = '0' + i;
                }
            write_system_config();
         }
}

void init_flash(void)
{
    int32_t i32ReturnCode;
    uint32_t ui32PrgmAddr;
    uint32_t *pui32Src;
    uint32_t *pui32Dst;
    int32_t ix;
    
    ui32PrgmAddr = START_PAGE_ADDRESS;

    //
    // Erase the whole block of FLASH instance 1.
    //
    //am_util_stdio_printf("    ... erasing all of flash instance %d.\n", AM_HAL_FLASH_ADDR2INST(ui32PrgmAddr) );
    //i32ReturnCode = am_hal_flash_mass_erase(AM_HAL_FLASH_PROGRAM_KEY, 1);

    //
    // Check for an error from the HAL.
    //
    if (i32ReturnCode)
    {
        am_util_stdio_printf("FLASH_MASS_ERASE i32ReturnCode =    0x%x.\n",
                         i32ReturnCode);
    }

    am_util_stdio_printf("  ... programming flash instance %d, page %d.\n",
                          AM_HAL_FLASH_ADDR2INST(ui32PrgmAddr),
                          AM_HAL_FLASH_ADDR2PAGE(ui32PrgmAddr) );
    pui32Src = ui32Source;
    for (ix = 0x100; ix < (0x100 + (512 * 4)); ix += 4)
    {
        *pui32Src++ = ix;
    }

    memset(ui32Source, 0x0, sizeof(ui32Source));
    
    pui32Dst = (uint32_t *) ui32PrgmAddr;
    i32ReturnCode = am_hal_flash_program_main(AM_HAL_FLASH_PROGRAM_KEY,
                                              ui32Source,
                                              pui32Dst,
                                              512);

    //
    // Check for an error from the HAL.
    //
    if (i32ReturnCode)
    {
        am_util_stdio_printf("FLASH program page at 0x%08x "
                             "i32ReturnCode = 0x%x.\n",
                             ui32PrgmAddr,
                             i32ReturnCode);
    }
    //
    // Check the page just programmed.
    //
    am_util_stdio_printf("  ... verifying the page just programmed.\n");
    for ( ix = 0; ix < 512; ix++ )
    {
        if ( *(uint32_t*)(ui32PrgmAddr + (ix*4)) != ui32Source[ix] )
        {
            am_util_stdio_printf("ERROR: flash address 0x%08x did not program properly:\n"
                                 "  Expected value = 0x%08x, programmed value = 0x%08x.\n",
                                 ui32PrgmAddr + (ix * 4),
                                 ui32Source[ix],
                                 *(uint32_t*)(ui32PrgmAddr + (ix * 4)) );
        }
    }
}
/*******************************************************************************
// 磨损均衡处理
//均衡写入分布:通过动态跳转写入地址,避免集中写入某一页。
//跨页处理:通过 ui32PageRemain 判断是否触发擦除下一页的操作。
//页起始地址对齐:s_ui32CurrentWriteAddr 必须是页大小的整数倍(如 0x4000, 0x8000)
//取模运算:得到当前地址相对于页起始地址的偏移量。
//例如:若 s_ui32CurrentWriteAddr = 0x8400,则偏移量 = 0x8400 % 0x2000 = 0x400。
*******************************************************************************/

static uint32_t s_ui32CurrentWriteAddr = START_PAGE_ADDRESS;
void flash_wear_leveling_write(uint8_t *pSrc, uint32_t ui32DataLen)
{
    // 1. 检查当前页剩余空间
    uint32_t ui32CurrentPageOffset = s_ui32CurrentWriteAddr - START_PAGE_ADDRESS;
    uint32_t ui32PageRemain = FLASH_PAGE_SIZE - (ui32CurrentPageOffset % FLASH_PAGE_SIZE);

    // 2. 若剩余空间不足,跳转到下一页
    if (ui32DataLen > ui32PageRemain)
    {
        // 计算目标页地址
        uint32_t ui32NextPageAddr = s_ui32CurrentWriteAddr + ui32PageRemain;
        
        // 地址超出循环窗口时,回到基地址
        if (ui32NextPageAddr > WEAR_LEVELING_END_ADDR)
        {
            ui32NextPageAddr = START_PAGE_ADDRESS;
        }

        // 3. 擦除目标页(需确保地址对齐到页起始)
        uint32_t ui32PageToErase = AM_HAL_FLASH_ADDR2PAGE(ui32NextPageAddr);
        
        am_util_stdio_printf("erase: 0x%08x Remain= 0x%08x  %d\n", ui32PageToErase,ui32PageRemain, ui32NextPageAddr);
        
        am_hal_flash_page_erase(AM_HAL_FLASH_PROGRAM_KEY,
                                AM_HAL_FLASH_ADDR2INST(ui32NextPageAddr),
                                ui32PageToErase);

        // 更新写入地址到目标页起始
        s_ui32CurrentWriteAddr = ui32NextPageAddr;
    }

    flash_flex_write(s_ui32CurrentWriteAddr, pSrc, ui32DataLen);
    am_util_stdio_printf("Current: 0x%08x len= %d\n", s_ui32CurrentWriteAddr, ui32DataLen);
    // 5. 更新写入地址
    s_ui32CurrentWriteAddr += ui32DataLen;
    if (s_ui32CurrentWriteAddr > WEAR_LEVELING_END_ADDR)
    {
        s_ui32CurrentWriteAddr = START_PAGE_ADDRESS + (s_ui32CurrentWriteAddr - WEAR_LEVELING_END_ADDR - 1);
    }
}

void flash_test(void)
{
        uint16_t i,vlength;
        
        vlength = sizeof(flash_record_t);
            memset(&flash_record, 0x0, vlength);
            flash_record.frame_num = '1';
            flash_record.temp[0] = '2';
            flash_record.temp[1] = '3';
            flash_record.temp[2] = '4';
            flash_record.temp[3] = '5';
            for(i = 0; i < 100; i++)
                {
                    flash_wear_leveling_write((uint8_t*)&flash_record, vlength);
                    vTaskDelay(100 / portTICK_PERIOD_MS);
                }
}


//更新FLASH数据
void flash_send_to_updata(uint8_t Type)
{
    uint8_t data = Type;
    
    xQueueSend(xFlashQueue,&data,0);
}

//*****************************************************************************
//
//initial setup for the flash task.
//
//*****************************************************************************
void flash_task_function (void * pvParameter)
{
    char file_type = 0;    
    //
    // Print a debug message.
    am_util_debug_printf("Running flash tasks...\r\n");
    //read_system_config();
    //flash_test();
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    xFlashQueue = xQueueCreate(5,1);
    
    while (1)
        {
            if(xQueueReceive(xFlashQueue, &file_type, portMAX_DELAY)== pdPASS)
            {
                //write_system_config();
            }
            vTaskDelay(100 / portTICK_PERIOD_MS);
        }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/42203.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Web纯前端实现在线打开编辑保存PPT幻灯片

很多项目中有时会需要在线打开PPT并编辑保存到服务器。猿大师办公助手可以完美调用本地office在线打开ppt文件&#xff0c;跟本地打开效果一样。还可以在线打开word、excel、pdf等文件&#xff0c;支持本机OFFICE完整嵌入模式&#xff0c;本机OFFICE所有功能基本都可以在网页上…

java版嘎嘎快充玉阳软件互联互通中电联云快充协议充电桩铁塔协议汽车单车一体充电系统源码uniapp

演示&#xff1a; 微信小程序&#xff1a;嘎嘎快充 http://server.s34.cn:1888/ 系统特色&#xff1a; 多商户、汽车单车一体、互联互通、移动管理端&#xff08;开发中&#xff09; 另外有PHP版源码&#xff1a;小程序搜索 河南玉阳软件 成熟线上运营中。可定制代理分销分账…

【Linux加餐-验证UDP:TCP】-windows作为client访问Linux

一、验证UDP-windows作为client访问Linux UDP client样例代码 #include <iostream> #include <cstdio> #include <thread> #include <string> #include <cstdlib> #include <WinSock2.h> #include <Windows.h>#pragma warning(dis…

linux input子系统深度剖析

input 就是输入的意思&#xff0c;因此 input 子系统就是管理输入的子系统&#xff0c;和 pinctrl 、 gpio 子系统 一样&#xff0c;都是 Linux 内核针对某一类设备而创建的框架。比如按键输入、键盘、鼠标、触摸屏等 等这些都属于输入设备&#xff0c;不同的输入设备…

leetcode40-组合总和II

leetcode 40 思路 在做本题之前可以参考之前的文章&#xff1a;组合总和和组合总和III 本题的关键点是&#xff1a;每个元素只能使用一次&#xff0c;另外本题给的数组是无序的&#xff0c;并且元素之间可能存在重复项&#xff0c;举个例子&#xff0c;candidates [1,2,1,1…

CentOS 7 源码安装libjsoncpp-1.9.5库

安装依赖工具 sudo yum install cmake make gcc cmake 需要升级至 3.8.0 以上可参考&#xff1a;CentOS安装CMakegcc 需要升级至9.0 以上可参考&#xff1a;CentOS 7升级gcc版本 下载源码 wget https://github.com/open-source-parsers/jsoncpp/archive/refs/tags/1.9.5.…

本地部署Stable Diffusion生成爆火的AI图片

直接上代码 Mapping("/send") Post public Object send(Body String promptBody) { JSONObject postSend new JSONObject(); System.out.println(promptBody); JSONObject body JSONObject.parseObject(promptBody); List<S…

知识就是力量——物联网应用技术

基础知识篇 一、常用电子元器件1——USB Type C 接口引脚详解特点接口定义作用主从设备关于6P引脚的简介 2——常用通信芯片CH343P概述特点引脚定义 CH340概述特点封装 3——蜂鸣器概述类型驱动电路原文链接 二、常用封装介绍贴片电阻电容封装介绍封装尺寸与功率关系&#xff1…

.Net SSO 单点登录方式

SSO单点登录目的 之前一般来讲系统简单&#xff0c;登录后 本地 cookie 加服务器 session 存储用户身份信息&#xff0c;以此为依据来判断用户再次登录时免验证 但随着互联网发展&#xff0c;很多应用 部署在不同的服务器上&#xff0c;而用户体系是一套&#xff0c;那么按照原…

MyBatis-Flex、MyBatis-Plus 与 Fluent-Mybatis 的比较分析

MyBatis-Flex、MyBatis-Plus 与 Fluent-Mybatis 的比较分析 在日常开发中&#xff0c;很多项目会选择 MyBatis 作为 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;而为了减少样板代码和提升开发效率&#xff0c;各种扩展库层出不穷。其中&#xff0c;MyBatis-Flex…

LVS NAT模式实现三台RS的轮询访问

节点规划: 配置RS&#xff1a; RS1-RS3的网关配置均为 192.168.163.8 配置RS1&#xff1a; [rootlocalhost ~]# hostnamectl hostname rs1 [rootlocalhost ~]# nmcli c modify ens160 ipv4.method manual ipv4.addresses 192.168.163.7/24 ipv4.gateway 192.168.163.8 conne…

软考中级-软件设计师 23种设计模式(内含详细解析)

23种设计模式 &#x1f3af; 创建型设计模式&#x1f4cc; 抽象工厂&#xff08;Abstract Factory&#xff09; 设计模式&#x1f4cc; 工厂方法&#xff08;Factory Method&#xff09;设计模式&#x1f4cc; 单例&#xff08;Singleton&#xff09;设计模式&#x1f4cc; 生成…

子数组 之 logTrick算法,求解或,与,LCM,GCD

文章目录 gcd的问题最大公约数 求解子数组的&,|,lcm,gcd的最值or计数问题&#xff0c;如果采用暴力的做法&#xff0c;那么时间复杂度会来到o(n^2),其实在求解的过程中&#xff0c;会出现很多的结果不变的情况&#xff0c;所以我们就可以提前结束 存在一定的单调性&#x…

密码学——知识问答

目录 1、阐述公开密钥算法的定义&#xff0c;结合RSA算法说明公钥密码的基本要求。 说明公钥与私钥两种密码学并举例与其应用 1. 公钥密码学&#xff08;非对称加密&#xff09;&#xff1a; 2. 私钥密码学&#xff08;对称加密&#xff09;&#xff1a; 对比公钥与私钥密码…

MySQL 表连接(内连接与外连接)

&#x1f3dd;️专栏&#xff1a;Mysql_猫咪-9527的博客-CSDN博客 &#x1f305;主页&#xff1a;猫咪-9527-CSDN博客 “欲穷千里目&#xff0c;更上一层楼。会当凌绝顶&#xff0c;一览众山小。” 目录 1、表连接的核心概念 1.1 为什么需要表连接&#xff1f; 2、内连接&a…

CI/CD(六) helm部署ingress-nginx(阿里云)

零、修改iptable为ipvs&#xff08;可选&#xff09; 修改 kube-proxy 配置&#xff1a; kubectl edit cm kube-proxy -n kube-system # 将 mode 字段改为 "ipvs" 重启 kube-proxy&#xff1a; kubectl delete pod -l k8s-appkube-proxy -n kube-system 验证 IPVS …

Git 之配置ssh

1、打开 Git Bash 终端 2、设置用户名 git config --global user.name tom3、生成公钥 ssh-keygen -t rsa4、查看公钥 cat ~/.ssh/id_rsa.pub5、将查看到的公钥添加到不同Git平台 6、验证ssh远程连接git仓库 ssh -T gitgitee.com ssh -T gitcodeup.aliyun.com

为Windows10的WSL Ubuntu启动sshd服务并使用Trae远程连接

Windows10的WSL Ubuntu&#xff0c;使用起来非常方便&#xff0c;但是美中不足的是&#xff0c;无法从Windows主机ssh到Ubuntu 。 解决的方法是在Ubuntu安装sshd服务 Ubuntu安装sshd服务 执行命令 sudo apt install openssh-server 安装好后&#xff0c;先本地测试&#x…

unity一个图片的物体,会有透明的效果

如图 想要去掉这个透明效果 选择一个高层级的layer即可。

Windows安装Jenkins配置Allure踩坑,必须单独配置当前windows系统为新的node节点,才可在工具位置中指定节点服务器allure的位置

背景 我为了图省事&#xff0c;在Windows上安装运行Jenkins&#xff0c;通过配置gitee插件拉取代码部署接口自动化项目&#xff0c;配置构建后运行Allure报告&#xff0c;结果报错&#xff1a;找不到Allure和生成的数据。 Allure报错信息 ERROR: Step ‘Allure Report’ abort…