技术详解)
操作系统嵌入式物联网嵌入式OSRTOS【免费下载链接】rt-threadRT-Thread is an open source IoT Real-Time Operating System (RTOS). https://rt-thread.github.io/rt-thread/项目地址https://gitcode.com/gh_mirrors/rt/rt-thread点击查看免费下载本篇技术指南以 RT-Thread 仓库中bsp/microchip/samc21板级支持包内嵌的 Microchip Atmel Start HAL 的 Flash 驱动文档 为核心骨架结合 SAMC21 NVMCTRL 底层驱动源码与官方示例系统讲解 Flash 驱动的读写、擦除、锁定/解锁等全部能力、参数约束与底层实现原理。读完本文你将能够在 SAM C21 平台上正确使用 Flash 驱动实现 Boot Loader、掉电数据保存等非易失存储方案并理解为何写入前必须擦除、为何地址必须页对齐这类关键设计。Flash 驱动是什么Flash 是一种可重复编程re-programmable的非易失存储器即使掉电也能保持程序与数据。用户可以从 Flash 中任意有效地址读取若干字节也可以向其中写入若干字节但与 RAM 不同Flash 的擦除、锁定与解锁操作对地址有严格的对齐要求且写入前往往需要先擦除。在本仓库的 SAM C21 板级支持包中Flash 驱动由两层组成HAL 层硬件抽象层对外提供统一、易用的 API位于bsp/microchip/samc21/bsp/hal/核心文件为 hal_flash.c 与 hal_flash.hHPL 层硬件平台层直接操作 NVMCTRL 外设寄存器位于bsp/microchip/samc21/bsp/hpl/nvmctrl/hpl_nvmctrl.cHAL 层通过 hpl_flash.h 声明的_flash_*接口完成底层动作。这套驱动由 Microchip 的 Atmel Start 代码生成器产出被集成到 RT-Thread 的 SAMC21 BSP 中可直接配合 RT-Thread 的 Flash 设备框架components/drivers中的rt_device模型或 FAL 分区抽象使用。驱动特性一览依据官方文档该 Flash 驱动具备以下能力初始化/反初始化flash_init/flash_deinit完成 HAL 实例与 NVMCTRL 硬件的配置字节级读写flash_read/flash_write可对任意有效地址读写若干字节页的锁定/解锁/擦除flash_lock/flash_unlock/flash_erase命令就绪或错误通知通过回调机制flash_register_callback上报可接收新命令与出错两类事件。典型应用场景迷你磁盘Mini disk利用 Flash 的可重复编程特性保存程序与数据Boot Loader在引导程序中读写、擦除 Flash实现固件升级非易失存储Non volatile storage保存配置参数、校准数据、运行日志等掉电不丢失的数据。依赖关系驱动正常运行所依赖的硬件是控制可重复编程存储器的外设在 SAM C21 上即 NVMCTRLNon-Volatile Memory Controller。从源码看hpl_nvmctrl.c 中_flash_init会直接配置 NVMCTRL 的 CTRLB 寄存器保持读等待状态 RWS 与手动写 MANW 位并使能 NVMCTRL 中断NVIC_EnableIRQ(NVMCTRL_IRQn)。因此依赖关系可概括为HAL Flash → HPL FlashNVMCTRL 外设驱动→ SAMC21 硬件。核心 API 与参数说明HAL 层 API 均以struct flash_descriptor *flash作为第一参数该结构定义于 hal_flash.h内嵌底层设备描述符与回调函数指针。BSP 中通常已通过 Atmel Start 生成全局实例FLASH_0见bsp/microchip/samc21/bsp/driver_init.c。初始化与反初始化API原型说明flash_initint32_t flash_init(struct flash_descriptor *flash, void *const hw)初始化 HAL 实例与硬件绑定就绪/错误回调hw传 NVMCTRL 硬件基地址flash_deinitint32_t flash_deinit(struct flash_descriptor *flash)反初始化禁用 NVMCTRL 中断并清空硬件句柄flash_init在底层返回非零时会直接透传错误见 hal_flash.c成功返回ERR_NONE。读写操作API原型说明flash_readint32_t flash_read(struct flash_descriptor *flash, uint32_t src_addr, uint8_t *buffer, uint32_t length)从src_addr读取length字节到bufferflash_writeint32_t flash_write(struct flash_descriptor *flash, uint32_t dst_addr, uint8_t *buffer, uint32_t length)向dst_addr写入length字节flash_appendint32_t flash_append(struct flash_descriptor *flash, uint32_t dst_addr, uint8_t *buffer, uint32_t length)追加写入写前不擦除依赖 Flash 位从 1→0 的特性读写操作对地址没有对齐要求——文档明确指出用户可以从任意有效地址读写若干字节。但 HAL 层仍会做两项校验见 hal_flash.c地址合法性src_addr / dst_addr length不得超过page_size * total_pages整个 Flash 空间否则返回ERR_BAD_ADDRESS写/追加操作会先检查目标区域是否被锁定若_flash_is_locked()返回真则返回ERR_DENIED拒绝访问。擦除、锁定与解锁API原型说明flash_eraseint32_t flash_erase(struct flash_descriptor *flash, const uint32_t dst_addr, const uint32_t page_nums)从dst_addr开始擦除page_nums个页flash_lockint32_t flash_lock(struct flash_descriptor *flash, const uint32_t dst_addr, const uint32_t page_nums)锁定指定页返回实际锁定页数flash_unlockint32_t flash_unlock(struct flash_descriptor *flash, const uint32_t dst_addr, const uint32_t page_nums)解锁指定页返回实际解锁页数这三类命令有两个硬性约束地址必须页对齐dst_addr必须是页起始地址。HAL 内部通过 flash_is_address_aligned 检查dst_addr (page_size - 1)非对齐时返回ERR_BAD_ADDRESS命令不会执行页数不得越界若page_nums超过总页数或dst_addr / page_size page_nums超出总页数返回ERR_INVALID_ARG。另外文档特别说明一次可锁定/解锁的页数取决于 Flash 的 region 大小且不同器件返回值不同。用户在应用层应以函数返回值为准。以 SAM C21 为例NVMCTRL 把整个 Flash 划分为 16 个 regionregion 大小即NVMCTRL_FLASH_SIZE / 16页_flash_lock/_flash_unlock要求page_nums恰好等于 region 页数否则返回ERR_INVALID_ARG见 hpl_nvmctrl.c。回调与工具函数API原型说明flash_register_callbackint32_t flash_register_callback(struct flash_descriptor *flash, const enum flash_cb_type type, flash_cb_t func)注册FLASH_CB_READY可接收新命令或FLASH_CB_ERROR出错回调注册时会联动使能/关闭底层对应中断flash_get_page_sizeuint32_t flash_get_page_size(struct flash_descriptor *flash)返回页大小SAM C21 为NVMCTRL_PAGE_SIZE即 512 字节flash_get_total_pagesuint32_t flash_get_total_pages(struct flash_descriptor *flash)返回 Flash 总页数FLASH_NB_OF_PAGESflash_get_versionuint32_t flash_get_version(void)返回驱动版本号当前源码中为0x00000001u底层实现原理NVMCTRL 视角要真正用好 Flash 驱动有必要理解 HPL 层的实现细节这些直接解释了文档中写操作会先擦除行内容的限制。读取强制 16 位字访问SAM C21 的 NVM必须以 16 位字half-word为单位访问。_flash_readhpl_nvmctrl.c会先等待 NVMCTRL READY 中断位随后按 16 位字读取并对奇地址做首字节偏移处理最后手动拆分为高低字节存入缓冲区。写入行缓存 先擦后写Flash 写入的本质是按页编程page program而页编程的前提是该页处于已擦除全 0xFF状态。因此_flash_writehpl_nvmctrl.c的流程是计算目标地址所在的行row起始与结束地址SAM C21 一行 NVMCTRL_ROW_PAGES页把整行原有内容读入临时缓冲区tmp_bufferNVMCTRL_ROW_PAGES * NVMCTRL_PAGE_SIZE大小在栈上分配用待写入数据覆盖缓冲区对应位置擦除整行NVMCTRL_CTRLA_CMD_ER将缓冲区按页写回 FlashNVMCTRL_CTRLA_CMD_WP。这就是文档Limitations中关于栈空间警告的根源驱动在栈上管理一个用于缓存未改动数据的临时缓冲区应用线程必须设置足够大的栈大小否则写/擦除时会栈溢出。追加写入不擦除的页编程_flash_appendhpl_nvmctrl.c则不同它直接对目标地址执行页编程命令从不先擦除。因此它只适合向已擦除全 1的区域追加数据例如日志追加、按序写入的存储桶。如果目标位已为 0写 1 将不生效。擦除按行擦除的页数换算_flash_erasehpl_nvmctrl.c在地址未与行起始对齐时会先对起始页执行写 0xFF模拟擦除当剩余页数达到整行时直接发行擦除命令余数页则再次用写 0xFF 的方式处理。也就是说擦除的最小物理单位是行驱动以擦行 伪擦除的组合实现对任意页数的擦除。锁定/解锁与区域判定_flash_lock/_flash_unlock等待 READY → 写 ADDR 寄存器dst_addr / 2即字地址→ 写 CTRLA 命令CMD_LR或CMD_URCMDEX_KEY返回 region 页数_flash_is_lockedhpl_nvmctrl.c根据地址计算 region 编号dst_addr / (NVMCTRL_FLASH_SIZE / 16)再查询 LOCK 寄存器对应位返回是否被锁定。中断与回调通知NVMCTRL 中断服务函数 NVMCTRL_Handler 检查 READY 位与 ERROR 位分别调用就绪/错误回调这正是文档关于错误或可接收新命令的通知能力的实现基础。HAL 层的flash_register_callback会通过_flash_set_irq_state控制INTEN_READY/INTEN_ERROR中断的开关。可复用的官方示例代码BSP 内置了可直接运行的主 Flash 读写示例位于 driver_examples.cstatic uint8_t src_data[128]; static uint8_t chk_data[128]; void FLASH_0_example(void) { uint32_t page_size; uint16_t i; /* 获取页大小并填充源数据 */ page_size flash_get_page_size(FLASH_0); for (i 0; i page_size; i) { src_data[i] i; } /* 向地址 0x3200 写入一页数据 */ flash_write(FLASH_0, 0x3200, src_data, page_size); /* 从同一地址读回并比对 */ flash_read(FLASH_0, 0x3200, chk_data, page_size); }需要说明该示例地址0x3200是 Atmel Start 示例默认选定的可擦写区域实际工程中请根据自身 Flash 布局尤其避免覆盖应用程序代码区与 Boot Loader 区选择安全地址并先调用flash_erase擦除目标页。针对支持 RWWEERead-While-Write EEPROM阵列的器件如 SAM C20/C21/D21/L21/L22 等底层还提供了_rww_flash_get_page_size、_rww_flash_write、_rww_flash_read等接口示例 RWW_FLASH_0_example 展示了向NVMCTRL_RWW_EEPROM_ADDR写入一页数据并读回校验的完整流程写/读失败或校验失败均会陷入死循环便于调试定位。NVMCTRL 配置项说明NVMCTRL 的行为可通过bsp/microchip/samc21/bsp/config/hpl_nvmctrl_config.h配置该文件由 Atmel Start 生成可通过重新配置项目更新宏定义取值含义CONF_NVM_READ_MODE0x00No Miss Penalty /0x01Low Power /0x02Deterministic读取模式选择影响读取命中率与功耗CONF_NVM_SLEEPPRM0x00Wake On Access /0x01Wake Up Instant /0x03Disabled睡眠期间功耗降低模式CONF_NVM_CACHE0使能/1禁用是否禁用 Flash 缓存这些配置在 hpl_nvmctrl.c 中被组合进_nvm配置结构并在_flash_init时写入 NVMCTRL_CTRLB 寄存器。若配置读取模式或缓存策略影响系统执行速度可从这里入手调整。使用注意事项与限制结合官方文档的 Limitations 一节与源码在实际应用中需重点注意栈空间必须充足_flash_write与_flash_erase会在栈上分配整行大小的临时缓冲区SAM C21 为NVMCTRL_ROW_PAGES × NVMCTRL_PAGE_SIZE字节。若在 RT-Thread 线程中调用请为该线程分配足够大的栈必要时改为在任务外或借助 RT-Thread 的动态内存管理规避栈压力。写入前自动擦行由于 SAMD21/D20/L21/L22/C20/C21/D09/D10/D11/R21 等器件含 SAM C21的 Flash 架构限制写操作在每次写入前都会擦除所在行内容。这意味着写入一个字节也会触发整行擦除重写频繁小粒度写入会显著消耗 Flash 擦写寿命若目标行包含其他有效数据驱动会先缓存整行再写回因此逻辑上数据不会丢失但需要更大栈与更长执行时间。擦除/锁定/解锁必须页对齐地址非页起始地址时命令直接失败返回ERR_BAD_ADDRESS务必通过flash_get_page_size动态计算页边界而非硬编码假设。锁定数量以返回值为准不同器件 Flash 的 region 大小不同一次可锁定/解锁的页数应以flash_lock/flash_unlock的返回值实际页数为准。并发性官方文档标注该驱动并发性为 N/A不适用即驱动本身不提供多任务并发保护。在 RT-Thread 多线程环境下若多个线程同时访问 Flash建议使用 RT-Thread 的互斥量mutex或信号量对 Flash 访问进行串行化。已知问题官方文档注明暂无已知问题与规避方案N/A但如上所述栈空间、擦写寿命与地址对齐仍是实践中最常见的三类坑。总结SAM C21 BSP 的 Flash 驱动是一套典型的HAL 面向应用、HPL 面向寄存器的分层实现HAL 层负责参数校验地址越界、页对齐、锁定检查与回调管理HPL 层负责 NVMCTRL 的 16 位字访问、行缓存写、按行擦除与 region 锁定等底层动作。开发者只需遵循读写任意地址、擦除锁定解锁页对齐、锁定页数以返回值为准、栈空间留足这几条核心规则即可安全地在 RT-Thread 上构建 Boot Loader、参数存储等非易失存储应用。进一步可结合 flash.rst 原文、hal_flash.h 头文件注释与 driver_examples.c 示例深入研读。赞分享操作系统嵌入式物联网嵌入式OSRTOS【免费下载链接】rt-threadRT-Thread is an open source IoT Real-Time Operating System (RTOS). https://rt-thread.github.io/rt-thread/项目地址https://gitcode.com/gh_mirrors/rt/rt-thread点击查看免费下载相关推荐RT-Thread 微芯 SAME70 平台 I2C 主机同步驱动HAL i2c_m_sync技术指南RT Thread 微芯 SAME70 平台 I2C 主机同步驱动HAL i2c_m_sync技术指南 本篇技术指南以 RT Thread 仓库中 bsp/操作系统嵌入式物联网嵌入式OSRTOScontainerd 开发报告深度解读2017 年 5 月的镜像推送、Go 客户端与测试体系建设containerd 开发报告深度解读2017 年 5 月的镜像推送、Go 客户端与测试体系建设 本文基于 docs/historical/reports/2操作系统嵌入式物联网嵌入式OSRTOSRT-Thread 微芯 SAMC21 平台 ADC 同步驱动hal_adc_sync原理与实战指南RT Thread 微芯 SAMC21 平台 ADC 同步驱动hal_adc_sync原理与实战指南 本指南围绕 RT Thread 仓库中 bsp/mic操作系统嵌入式物联网嵌入式OSRTOS上一篇CICC/bert-base-chinese推理代码逐行解读文本预处理到分类结果输出全流程下一篇OBS Studio直播画质增强终极指南从模糊到专业的3个关键步骤 创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考