<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[YTM32B1ME15 MCAL 0.8.0：EEPROM ECC 错误处理]]></title><description><![CDATA[<p dir="auto"><strong>环境</strong>：<br />
YTM32B1ME15；<br />
Yuntu MCAL <strong>0.8.0</strong>；</p>
<h3>1、问题</h3>
<p dir="auto">EEPROM 单比特 ECC 错误可由硬件纠正；双比特错误不可纠正，实测读取时会触发精确 BusFault，且先于 EEPROM 中断处理。仅在 <code>EEPROM_IRQHandler</code> 中处理，会因故障指令反复执行而升级为 HardFault。</p>
<p dir="auto">MCAL 0.8.0 的 Eep 驱动提供 ECC 中断使能接口，但未实现完整的错误处理和日志记录。</p>
<h3>2、处理方案</h3>
<p dir="auto">示例在应用层实现：</p>
<ul>
<li><strong>单比特</strong>：在 EEPROM 中断中记录错误地址、计数等信息并清除标志，数据由硬件纠正。</li>
<li><strong>双比特</strong>：通过 RAM 向量表接管 BusFault，识别 EEPROM 不可纠正错误，按 Thumb-2 指令长度跳过故障读取指令，记录错误，并将错误地址按 4 字节对齐后擦除对应字。</li>
<li><strong>前提</strong>：启动代码已将向量表复制到 RAM；示例在初始化时安装 BusFault 处理函数。</li>
</ul>
<h3>3、验证结果</h3>
<p dir="auto">实板测试中，正常读写、单比特纠错、双比特检测及后续重写恢复四步均通过：<code>Eep_EccStepResult=0x01010101</code>，<code>Eep_EccTestFailCnt=0</code>。双比特错误地址为 <code>0x02000040</code>，程序未再出现 BusFault 升级为 HardFault。<br />
<img src="https://yt-static-main.oss-cn-shanghai.aliyuncs.com/nodebb/599/2c9c115b-02a1-4de9-81ba-c32c057276ed.png" alt="99d327fa-a27f-4ed0-9f2c-f750d5bfa25b-image.png" class=" img-fluid img-markdown" /><br />
<img src="https://yt-static-main.oss-cn-shanghai.aliyuncs.com/nodebb/599/8f5a5e55-8667-4ee3-9334-22e7b2522ec7.png" alt="c455d210-b380-4896-a820-67683f11b28c-image.png" class=" img-fluid img-markdown" /></p>
<h3>5、注意事项</h3>
<ul>
<li>跳过故障加载指令<strong>不会产生有效读取值</strong>。实测 Eep 作业仍可能返回 <code>MEMIF_JOB_OK</code>，不能仅凭作业结果判断数据有效。</li>
<li>擦除会破坏整个 4 字节字的数据，需由应用恢复；示例未向上层报告擦除超时或命令失败，且异常上下文操作 EEPROM 可能与 Eep 作业竞争。量产前须结合芯片手册验证失败处理及数据恢复。</li>
<li>错误注入仅用于测试，测试会写入并擦除 EEPROM 测试区域。</li>
</ul>
<h3>6、代码实现</h3>
<h4>6.1 初始化</h4>
<p dir="auto">main.c 初始化 MCU 时钟，随后 Board_Init 调用 Platform_Init、Fls_Init、Eep_Init 和 Eep_EccDemoInit。启动代码须先将向量表复制到 RAM 并设置 VTOR。</p>
<pre><code>IVT_RAM_start[5U] = (uint32)Eep_BusFault_Handler;
__DSB(); __ISB();
SCB-&gt;SHCSR |= SCB_SHCSR_BUSFAULTENA_Msk;
SCB-&gt;CCR |= SCB_CCR_BFHFNMIGN_Msk;
EEPROM-&gt;STS = EEPROM_STS_UNRECOVERR_MASK | EEPROM_STS_RECOVERR_MASK |
              EEPROM_STS_CMD_FAIL_MASK | EEPROM_STS_ACCERR_MASK;
EEPROM-&gt;CTRL |= EEPROM_CTRL_RECOVERRIE_MASK | EEPROM_CTRL_UNRECOVERRIE_MASK;
(void)Platform_SetIrq(EEPROM_IRQn, TRUE);
</code></pre>
<h4>6.2 注入与读取</h4>
<p dir="auto">源码使用偏移 0x40、长度 8 字节，先写入测试数据。单比特模式为 1，双比特模式为 2，模式 0 关闭注入；Eep_EccReadJob 通过 Eep_MainFunction 等待作业完成。</p>
<pre><code>EEPROM-&gt;ERR_INJECT_CTRL = EEPROM_ERR_INJECT_CTRL_ECCERR_INJ_EN(Mode) |
                          EEPROM_ERR_INJECT_CTRL_ECCERR_INJ_ADDR(Offset);
Eep_EccInject(EEP_ECC_INJ_MULTI_BIT, EEP_ECC_TEST_ADDR);
Eep_EccJobResultAfterMulti = (uint32)Eep_EccReadJob(
    EEP_ECC_TEST_ADDR, ReadBuffer, EEP_ECC_TEST_LEN);
Eep_EccInject(EEP_ECC_INJ_DISABLE, 0U);
Eep_EccPollMultiBit();
</code></pre>
<p dir="auto">上述寄存器赋值为非零模式分支摘录。注入仅供测试，示例会写入并擦除 EEPROM 测试区域。</p>
<h4>6.3 BusFault 处理</h4>
<p dir="auto">应用的 naked 异常入口根据 EXC_RETURN 位 2 选择 MSP 或 PSP，将堆栈指针传给 Eep_BusFaultHandlerC。当前实现使用 pStack[6] 作为保存的 PC，下面为对应 C 代码摘录。</p>
<pre><code>FaultPc = pStack[6];
if (0U != (EEPROM-&gt;STS &amp; EEPROM_STS_UNRECOVERR_MASK))
{
    if (0x1DU &lt;= (*(volatile uint16 *)(FaultPc) &gt;&gt; 11U))
        InsnLen = 4U;
    else
        InsnLen = 2U;
    pStack[6] = FaultPc + InsnLen;
    Eep_EccHandleBusFault();
}
else if (TRUE == Fls_Lld_GetTwoBitEccErrFlag())
{
    pStack[6] = FaultPc + 2U;
}
SCB-&gt;CFSR = SCB_CFSR_BUSFAULTSR_Msk | SCB_CFSR_PRECISERR_Msk;
</code></pre>
<p dir="auto">重要限制：跳过加载指令不会生成有效读取值，也不保证 Eep 作业失败。</p>
<h4>6,4 错误记录与对齐擦除</h4>
<p dir="auto">Eep_EccHandleBusFault 读取错误地址与计数，更新日志，关闭注入并清状态后调用 Eep_EccEraseWord。以下摘录省略地址范围校验及状态清理。</p>
<pre><code>ErrAddr = EEPROM-&gt;ECCERR_ADDR;
Eep_EccLog.MultiBitErrCnt++;
Eep_EccLog.LastErrAddr = ErrAddr;
Eep_EccLog.LastErrCnt = EEPROM-&gt;ECCERR_CNT &amp; EEPROM_ECCERR_CNT_ECCERR_CNT_MASK;
Eep_EccLog.LastErrType = EEP_ECC_ERR_TYPE_MULTI;
Eep_EccLog.NotifyCnt++;
EEPROM-&gt;ERR_INJECT_CTRL = 0U;
EEPROM-&gt;STS = EEPROM_STS_UNRECOVERR_MASK;
Eep_EccEraseWord(ErrAddr);
WordAddr = HwAddr &amp; (uint32)(~0x3U);
WordPtr = (volatile uint32 *)WordAddr;
EEPROM-&gt;CTRL |= EEPROM_CTRL_WE_MASK;
/* 源码在写入前后执行 ISB 和 DSB */
*WordPtr = 0x00000000U;
EEPROM-&gt;CTRL &amp;= (uint32)(~EEPROM_CTRL_WE_MASK);
EEPROM-&gt;CMD_UNLOCK = EEP_ECC_CMD_UNLOCK_KEY;
EEPROM-&gt;CMD = EEP_ECC_ERASE_SECTOR_CMD;
/* 轮询 DONE 或等待超时，然后清状态 */
</code></pre>
<p dir="auto">擦除会破坏整个对齐字的数据。当前代码未向上层报告擦除超时或命令失败，且在异常上下文直接操作 EEPROM，可能与正在进行的 Eep 作业竞争；产品化前须核对芯片手册并验证失败处理和数据恢复，不能仅凭日志认定擦除成功。</p>
<h4>6.5 EEPROM ECC 中断</h4>
<p dir="auto">EEPROM_IRQHandler 根据 STS 处理：单比特分支记录 RECOVERR 并清标志；双比特分支临时关闭 UNRECOVERRIE，记录并调用 Eep_EccEraseWord，最后清状态并重开。双比特读取可能先进入 BusFault。<br />
<a href="https://yt-static-main.oss-cn-shanghai.aliyuncs.com/nodebb/599/ad17d2e3-fa93-4554-be41-f88e449a2ec5.zip" rel="nofollow ugc">6b63415c-6681-4394-8366-8aae3e5fef6d-ME15_ECC_EccErrorHandling_Demo.zip</a></p>
]]></description><link>https://forum.ytmicro.com/topic/2340/ytm32b1me15-mcal-0-8-0-eeprom-ecc-错误处理</link><generator>RSS for Node</generator><lastBuildDate>Thu, 05 Nov 2026 13:49:52 GMT</lastBuildDate><atom:link href="https://forum.ytmicro.com/topic/2340.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 05 Nov 2026 06:28:51 GMT</pubDate><ttl>60</ttl></channel></rss>