复旦微FM33LC046N评测+FLASH存储
<p>一、概述</p><div style="white-space: pre-wrap; text-indent: 28px; text-align: left; line-height: 1.75; font-size: 14px;" yne-bulb-block="paragraph">1、FLASH容量64K * 32=256K</div>
<div style="white-space: pre-wrap; text-indent: 56px; text-align: left; line-height: 1.75; font-size: 14px;" yne-bulb-block="paragraph">页---page(512B)</div>
<div style="white-space: pre-wrap; text-indent: 56px; text-align: left; line-height: 1.75; font-size: 14px;" yne-bulb-block="paragraph">扇区--sector(2K)</div>
<div style="white-space: pre-wrap; text-indent: 28px; text-align: left; line-height: 1.75; font-size: 14px;" yne-bulb-block="paragraph">2、支持页擦除,扇区擦除,全擦(仅支持SWD程序下载模式)</div>
<div style="white-space: pre-wrap; text-indent: 28px; text-align: left; line-height: 1.75; font-size: 14px;" yne-bulb-block="paragraph">3、flash内存</div>
<div style="white-space: pre-wrap; text-indent: 28px; text-align: left; line-height: 1.75; font-size: 14px;" yne-bulb-block="paragraph">大小:256k</div>
<div style="white-space: pre-wrap; text-indent: 28px; text-align: left; line-height: 1.75; font-size: 14px;" yne-bulb-block="paragraph"><span style="color: rgb(223, 64, 42);">范围:0x00000000 -- 0x00040000</span></div>
<div style="white-space: pre-wrap; text-indent: 28px; text-align: left; line-height: 1.75; font-size: 14px;" yne-bulb-block="paragraph">Flash 扇区(Sector)大小为 512 字节,每 16 个扇区组成一个 8K 字节的块(Block)。</div>
<div style="white-space: pre-wrap; text-indent: 28px; text-align: left; line-height: 1.75; font-size: 14px;" yne-bulb-block="paragraph">Flash 包含 4 个 information 扇区, 2 个 LDT 扇区, 1 个冗余扇区, 1 个DCT 扇区。其中 DCT 和 LDT为芯片原厂保留扇区,不对用户开放。Information 为用户配置扇区,用于保存用户配置信息。所有</div>
<div style="white-space: pre-wrap; text-indent: 28px; text-align: left; line-height: 1.75; font-size: 14px;" yne-bulb-block="paragraph">option 扇区在地址上与 Flash 主区域互相隔离。</div>
<div style="white-space: pre-wrap; text-indent: 28px; text-align: left; line-height: 1.75; font-size: 14px;" yne-bulb-block="paragraph"> </div>
<divyne-bulb-block="paragraph">二、flash擦除方法
<div style="white-space: pre-wrap; text-align: left; line-height: 1.75; font-size: 14px;" yne-bulb-block="paragraph">三、软件实现步骤</div>
<div style="white-space: pre-wrap; text-align: left; line-height: 1.75; font-size: 14px;" yne-bulb-block="paragraph">1、在串口通信的基础上,通过串口发送数据到MCU,操作读/写flash</div>
<div >2、命令判断 指令码:flash操作固定0x01;</div>
<divyne-bulb-block="paragraph">操作码:0x01--读, 0x04--写</div>
<div yne-bulb-block="paragraph">
<p>以上命令均以HEX数据格式发送<br />
<br />
范例:</p>
<p>(1)写数据<br />
68 01 04 02 12 34 16 //向flash中写两个字节的数据,数据为0x12, 0x34<br />
无返回,可通过读取数据来进行检验<br />
(2)读数据<br />
68 01 01 01 05 16 (6 bytes) //从flash中读取5个字节的数据<br />
68 01 81 05 <span style="color: rgb(223, 64, 42);">11 22 33 44 55</span> 16 (10 bytes)//读到的数据为:<span style="color: rgb(223, 64, 42);">11 22 33 44 55</span><br />
</p>
<p>3、flash读函数</p>
</div>
</div>
<divyne-bulb-block="paragraph">
<div aria-label="代码段 小部件" contenteditable="false" role="region" tabindex="-1">
<div aria-label="代码段 小部件" contenteditable="false" role="region" tabindex="-1">
<pre data-widget="codesnippet">
<code class="hljs language-cpp">ErrorStatus FL_FLASH_Read_Dma(FLASH_Type* FLASHx, uint32_t address, uint32_t *data, uint16_t length)
<span class="hljs-comment">//FLASHx:外设地址</span>
<span class="hljs-comment">//address:操作的地址(页首地址)</span>
<span class="hljs-comment">//data:读回的数据存放地址</span>
<span class="hljs-comment">//length:读取的长度</span>
ErrorStatus FL_FLASH_Read_Dma(FLASH_Type* FLASHx, uint32_t address, uint32_t *data, uint16_t length)
{
ErrorStatus ret;
uint32_t Timeout;
FL_DMA_InitTypeDef initStruct={<span class="hljs-number">0</span>};
<span class="hljs-comment">/* 入口参数检查 */</span>
assert_param(IS_FLASH_ALL_INSTANCE(FLASHx));
assert_param(IS_FL_FLASH_MAX_ADDR(address));
<span class="hljs-comment">/* 半页对齐*/</span>
<span class="hljs-keyword">if</span>(address & (FL_FLASH_SECTOR_SIZE_BYTE / <span class="hljs-number">2</span> - <span class="hljs-number">1</span>))
{
<span class="hljs-comment">/*地址未对齐*/</span>
<span class="hljs-keyword">return</span> FAIL;
}
initStruct.circMode = DISABLE;
initStruct.direction = FL_DMA_DIR_FLASH_TO_RAM;
initStruct.memoryAddressIncMode = FL_DMA_CH7_MEMORY_INC_MODE_INCREASE;
initStruct.flashAddressIncMode = FL_DMA_CH7_FLASH_INC_MODE_INCREASE;
initStruct.priority = FL_DMA_PRIORITY_HIGH;
initStruct.periphAddress = address >> <span class="hljs-number">2</span>;
FL_DMA_Init(DMA, &initStruct, FL_DMA_CHANNEL_7);
FL_DMA_WriteFlashAddress(DMA, address >> <span class="hljs-number">2</span>);
FL_DMA_WriteMemoryAddress(DMA, (uint32_t)data >> <span class="hljs-number">2</span>, FL_DMA_CHANNEL_7);
FL_DMA_WriteTransmissionSize(DMA, length - <span class="hljs-number">1</span>, FL_DMA_CHANNEL_7);
FL_DMA_ClearFlag_TransferComplete(DMA, FL_DMA_CHANNEL_7);
FL_DMA_EnableChannel(DMA, FL_DMA_CHANNEL_7);
FL_DMA_Enable(DMA);
Timeout = <span class="hljs-number">0</span>;
<span class="hljs-keyword">while</span> (<span class="hljs-number">1</span>)
{
Timeout++;
<span class="hljs-keyword">if</span>(Timeout > FL_FLASH_ERASE_TIMEOUT)
{
ret = FAIL;
<span class="hljs-keyword">break</span>;
}
<span class="hljs-keyword">if</span> (FL_DMA_IsActiveFlag_TransferComplete(DMA, FL_DMA_CHANNEL_7) == SET)
{
ret = PASS;
<span class="hljs-keyword">break</span>;
}
}
<span class="hljs-keyword">return</span> ret;
}</code></pre>
</div>
</div>
<p>4、flash写函数</p>
<div aria-label="代码段 小部件" contenteditable="false" role="region" tabindex="-1">
<div aria-label="代码段 小部件" contenteditable="false" role="region" tabindex="-1">
<pre data-widget="codesnippet">
<code class="hljs language-cpp">ErrorStatus FL_FLASH_PageErase(FLASH_Type* FLASHx, uint32_t address)
<span class="hljs-comment">//页擦写函数</span>
<span class="hljs-comment">//FLASHx:外设地址</span>
<span class="hljs-comment">//address:操作的地址(页首地址)</span>
ErrorStatus FL_FLASH_Program_Page(FLASH_Type* FLASHx, uint32_t pageNum, uint32_t *data)
<span class="hljs-comment">//FLASHx:外设地址</span>
<span class="hljs-comment">//pageNum:扇区号</span>
<span class="hljs-comment">//data:读回的数据存放地址</span>
ErrorStatus FL_FLASH_Program_Page(FLASH_Type* FLASHx, uint32_t pageNum, uint32_t *data)
{
uint32_t count;
uint32_t primask;
uint32_t address;
uint32_t timeout;
ErrorStatus ret;
<span class="hljs-comment">/* 入口参数检查 */</span>
assert_param(IS_FLASH_ALL_INSTANCE(FLASHx));
assert_param(IS_FL_FLASH_MAX_PAGE((uint32_t)pageNum));
address = pageNum*FL_FLASH_PAGE_SIZE_BYTE;
<span class="hljs-comment">/* 页对齐*/</span>
<span class="hljs-keyword">if</span>(address & (FL_FLASH_PAGE_SIZE_BYTE-<span class="hljs-number">1</span>))
{
<span class="hljs-comment">/*地址未对齐*/</span>
<span class="hljs-keyword">return</span> FAIL;
}
FL_RCC_EnableGroup2BusClock(FL_RCC_GROUP2_BUSCLK_FLASH);
FL_RCC_EnableGroup2OperationClock(FL_RCC_GROUP2_OPCLK_FLASH);
FL_FLASH_EnableProgram(FLASHx);
<span class="hljs-keyword">if</span>(FL_FLASH_GetFlashLockStatus(FLASHx) != FL_FLASH_KEY_STATUS_PROGRAM)
{
<span class="hljs-comment">/* Key 序列*/</span>
primask = __get_PRIMASK();
__disable_irq();
FL_FLASH_UnlockFlash(FLASHx,FL_FLASH_PROGRAM_KEY1);
FL_FLASH_UnlockFlash(FLASHx,FL_FLASH_PROGRAM_KEY2);
__set_PRIMASK(primask);
}
<span class="hljs-keyword">for</span> (count = <span class="hljs-number">0</span>; count < FL_FLASH_PAGE_SIZE_BYTE; count += <span class="hljs-number">4</span>)
{
timeout = <span class="hljs-number">0</span>;
FL_FLASH_EnableProgram(FLASHx);
*((uint32_t*)address) =*(data++);
address += <span class="hljs-number">4</span>;
<span class="hljs-keyword">while</span>(<span class="hljs-number">1</span>)
{
timeout++;
<span class="hljs-keyword">if</span>((timeout > FL_FLASH_ERASE_TIMEOUT)\
||(FL_FLASH_IsActiveFlag_ClockError(FLASHx))\
||(FL_FLASH_IsActiveFlag_KeyError(FLASHx))\
||(FL_FLASH_IsActiveFlag_AuthenticationError(FLASHx)))
{
<span class="hljs-comment">/* 超时或出现错误 */</span>
ret = FAIL;
<span class="hljs-keyword">break</span>;
}
<span class="hljs-keyword">if</span>(FL_FLASH_IsActiveFlag_ProgramComplete(FLASHx))
{
<span class="hljs-comment">/*编程成功*/</span>
FL_FLASH_ClearFlag_ProgramComplete(FLASHx);
ret = PASS;
<span class="hljs-keyword">break</span>;
}
}
}
FL_FLASH_LockFlash(FLASHx);
FL_RCC_DisableGroup2OperationClock(FL_RCC_GROUP2_OPCLK_FLASH);
<span class="hljs-keyword">return</span> ret;
}</code></pre>
</div>
</div>
<p>5、串口通信测试</p>
<div aria-label="代码段 小部件" contenteditable="false" role="region" tabindex="-1">
<div aria-label="代码段 小部件" contenteditable="false" role="region" tabindex="-1">
<pre data-widget="codesnippet">
<code class="hljs language-cpp"><span class="hljs-keyword">if</span>(uc_uart0_revok==<span class="hljs-number">1</span>)<span class="hljs-comment">//串口数据接收完成</span>
{
uc_uart0_revok=<span class="hljs-number">0</span>;
<span class="hljs-keyword">if</span>(uc_uart0_rev[<span class="hljs-number">1</span>]==<span class="hljs-number">0x01</span>)<span class="hljs-comment">//flash操作</span>
{
<span class="hljs-keyword">if</span>(uc_uart0_rev[<span class="hljs-number">2</span>]==<span class="hljs-number">0x01</span>)<span class="hljs-comment">//读flash</span>
{
FL_FLASH_Read_Dma(FLASH,<span class="hljs-number">0x00004000</span>,(uint32_t * )DataTowrite,<span class="hljs-number">512</span>);
uc_uart0_sendbuf[<span class="hljs-number">0</span>]=<span class="hljs-number">0x68</span>;
uc_uart0_sendbuf[<span class="hljs-number">1</span>]=<span class="hljs-number">0x01</span>;
uc_uart0_sendbuf[<span class="hljs-number">2</span>]=<span class="hljs-number">0x81</span>;
uc_uart0_sendbuf[<span class="hljs-number">3</span>]=uc_uart0_rev[<span class="hljs-number">4</span>];
<span class="hljs-keyword">for</span>(i1=<span class="hljs-number">0</span>;i1<uc_uart0_rev[<span class="hljs-number">4</span>];i1++)
{
uc_uart0_sendbuf[<span class="hljs-number">4</span>+i1]=DataTowrite;
}
uc_uart0_sendbuf[<span class="hljs-number">4</span>+uc_uart0_rev[<span class="hljs-number">4</span>]]=<span class="hljs-number">0x16</span>;
uc_uart0_sendlight=<span class="hljs-number">5</span>+uc_uart0_rev[<span class="hljs-number">4</span>];
uart0_send();
}
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(uc_uart0_rev[<span class="hljs-number">2</span>]==<span class="hljs-number">0x04</span>)<span class="hljs-comment">//写flash</span>
{
<span class="hljs-built_in">memset</span>(DataTowrite,<span class="hljs-number">0</span>,<span class="hljs-number">512</span>);<span class="hljs-comment">//清缓冲区数据</span>
<span class="hljs-keyword">for</span>(i1=<span class="hljs-number">0</span>;i1<uc_uart0_rev[<span class="hljs-number">3</span>];i1++)
{
DataTowrite=uc_uart0_rev[<span class="hljs-number">4</span>+i1];
}
FL_FLASH_PageErase(FLASH, <span class="hljs-number">0x00004000</span>);<span class="hljs-comment">//页擦写</span>
FL_FLASH_Program_Page(FLASH,<span class="hljs-number">32</span>,DataTowrite);
}
}
}</code></pre>
</div>
</div>
<p>6、串口中断服务函数</p>
<div aria-label="代码段 小部件" contenteditable="false" role="region" tabindex="-1">
<pre data-widget="codesnippet">
<code class="language-cpp hljs"><span class="hljs-keyword">void</span> UART0_IRQHandler(<span class="hljs-keyword">void</span>)
{
uint8_t tmp08;
<span class="hljs-comment">//接收中断处理</span>
<span class="hljs-keyword">if</span>((ENABLE == FL_UART_IsEnabledIT_RXBuffFull(UART0))
&&(SET == FL_UART_IsActiveFlag_RXBuffFull(UART0)))
{
<span class="hljs-comment">//中断转发接收到的数据</span>
uc_uart0_rev=FL_UART_ReadRXBuff(UART0);<span class="hljs-comment">//接收中断标志可通过读取rxreg寄存器清除</span>
uc_uart0_num++;
uc_uart0_revouttime=<span class="hljs-number">20</span>;<span class="hljs-comment">//200ms超时</span>
}
<span class="hljs-comment">//发送中断处理</span>
<span class="hljs-keyword">if</span>((ENABLE == FL_UART_IsEnabledIT_TXShiftBuffEmpty(UART0))
&&(SET == FL_UART_IsActiveFlag_TXShiftBuffEmpty(UART0)))
{
<span class="hljs-comment">//发送中断标志可通过写txreg寄存器清除或txif写1清除</span>
<span class="hljs-comment">//发送指定长度的数据</span>
<span class="hljs-keyword">if</span>(uc_uart0_sendnum<uc_uart0_sendlight)
{
FL_UART_WriteTXBuff(UART0, uc_uart0_sendbuf); <span class="hljs-comment">//发送一个数据</span>
uc_uart0_sendnum++;
}
<span class="hljs-keyword">else</span>
{
uc_uart0_sendnum=<span class="hljs-number">0</span>;
uc_uart0_sendlight=<span class="hljs-number">0</span>;
}
FL_UART_ClearFlag_TXShiftBuffEmpty(UART0); <span class="hljs-comment">//清除发送中断标志</span>
}
}</code></pre>
</div>
<p>7、串口发送函数</p>
<div aria-label="代码段 小部件" contenteditable="false" role="region" tabindex="-1">
<pre data-widget="codesnippet">
<code class="language-cpp hljs"><span class="hljs-comment">//uart0 串口发送函数</span>
<span class="hljs-keyword">void</span> uart0_send(<span class="hljs-keyword">void</span>)
{
uc_uart0_sendnum=<span class="hljs-number">1</span>;
FL_UART_ClearFlag_TXShiftBuffEmpty(UART0);<span class="hljs-comment">//清除UART发送移位寄存器标志</span>
FL_UART_EnableIT_TXShiftBuffEmpty(UART0);<span class="hljs-comment">//启用UART发送移位寄存器中断</span>
FL_UART_WriteTXBuff(UART0, uc_uart0_sendbuf[<span class="hljs-number">0</span>]);
DelayMs(<span class="hljs-number">50</span>);<span class="hljs-comment">//软件延时</span>
FL_UART_DisableIT_TXShiftBuffEmpty(UART0); <span class="hljs-comment">//禁用UART发送移位寄存器中断</span>
FL_UART_EnableIT_RXBuffFull(UART0);<span class="hljs-comment">//启用UART接收缓冲区中断</span>
}</code></pre>
</div>
<p>8、串口助手通信报文截图</p>
<p></p>
</div>
<div style="white-space: pre-wrap; text-indent: 28px; text-align: left; line-height: 1.75; font-size: 14px;" yne-bulb-block="paragraph"> </div>
<div style="white-space: pre-wrap; text-indent: 28px; text-align: left; line-height: 1.75; font-size: 14px;" yne-bulb-block="paragraph"> </div>
<div style="white-space: pre-wrap; text-align: left; line-height: 1.75; font-size: 14px;" yne-bulb-block="paragraph"> </div> <p>感谢分享!</p>
<p>可以总结一下FM33LC046N存储Flash<span style="color:#333333">情况是什么样,有没有</span>读取Flash内容时卡死</p>
<p>自己写这么多代码,这个评测做的很认真了!</p>
<p>flash擦除之前需要key验证</p>
<p>能得到FREE肯定不容易,楼主继续加油</p> qwqwqw2088 发表于 2021-3-5 11:53
可以总结一下FM33LC046N存储Flash情况是什么样,有没有读取Flash内容时卡死
<p>FM33LC046N的flash资源的详细介绍在官方文档中可查询到,我只是验证了简单的flash读写操作;至于读取时会不会卡死这个问题,我暂时并没有发现过</p>
Jacktang 发表于 2021-3-8 20:27
flash擦除之前需要key验证
<p>文档介绍是需要先进行校验才能操作flash</p>
soso 发表于 2021-3-9 16:02
能得到FREE肯定不容易,楼主继续加油
<p>谢谢</p>
freebsder 发表于 2021-3-6 21:40
自己写这么多代码,这个评测做的很认真了!
<p>新的东西总能提起人的兴趣,开发板也一样</p>
<p>串口通信最后的图片,读数据返回和读数据一致?</p>
Jacktang 发表于 2021-3-9 20:31
串口通信最后的图片,读数据返回和读数据一致?
<p>是不同的,绿色是发送,蓝色是接收</p>
页:
[1]