逆夏的流年 发表于 2021-3-5 08:54

复旦微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">&nbsp;</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、命令判断&nbsp; 指令码: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 />
&nbsp;</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 &amp; (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 &gt;&gt; <span class="hljs-number">2</span>;
    FL_DMA_Init(DMA, &amp;initStruct, FL_DMA_CHANNEL_7);
   
    FL_DMA_WriteFlashAddress(DMA, address &gt;&gt; <span class="hljs-number">2</span>);
    FL_DMA_WriteMemoryAddress(DMA, (uint32_t)data &gt;&gt; <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 &gt; 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 &amp; (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 &lt; 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 &gt; 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&lt;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&lt;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))
                &amp;&amp;(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))
                &amp;&amp;(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&lt;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">&nbsp;</div>

<div style="white-space: pre-wrap; text-indent: 28px; text-align: left; line-height: 1.75; font-size: 14px;" yne-bulb-block="paragraph">&nbsp;</div>

<div style="white-space: pre-wrap; text-align: left; line-height: 1.75; font-size: 14px;" yne-bulb-block="paragraph">&nbsp;</div>

w494143467 发表于 2021-3-5 11:32

<p>感谢分享!</p>

qwqwqw2088 发表于 2021-3-5 11:53

<p>可以总结一下FM33LC046N存储Flash<span style="color:#333333">情况是什么样,有没有</span>读取Flash内容时卡死</p>

freebsder 发表于 2021-3-6 21:40

<p>自己写这么多代码,这个评测做的很认真了!</p>

Jacktang 发表于 2021-3-8 20:27

<p>flash擦除之前需要key验证</p>

soso 发表于 2021-3-9 16:02

<p>能得到FREE肯定不容易,楼主继续加油</p>

逆夏的流年 发表于 2021-3-9 16:39

qwqwqw2088 发表于 2021-3-5 11:53
可以总结一下FM33LC046N存储Flash情况是什么样,有没有读取Flash内容时卡死

<p>FM33LC046N的flash资源的详细介绍在官方文档中可查询到,我只是验证了简单的flash读写操作;至于读取时会不会卡死这个问题,我暂时并没有发现过</p>

逆夏的流年 发表于 2021-3-9 16:43

Jacktang 发表于 2021-3-8 20:27
flash擦除之前需要key验证

<p>文档介绍是需要先进行校验才能操作flash</p>

逆夏的流年 发表于 2021-3-9 16:44

soso 发表于 2021-3-9 16:02
能得到FREE肯定不容易,楼主继续加油

<p>谢谢</p>

逆夏的流年 发表于 2021-3-9 16:47

freebsder 发表于 2021-3-6 21:40
自己写这么多代码,这个评测做的很认真了!

<p>新的东西总能提起人的兴趣,开发板也一样</p>

Jacktang 发表于 2021-3-9 20:31

<p>串口通信最后的图片,读数据返回和读数据一致?</p>

逆夏的流年 发表于 2021-3-11 14:34

Jacktang 发表于 2021-3-9 20:31
串口通信最后的图片,读数据返回和读数据一致?

<p>是不同的,绿色是发送,蓝色是接收</p>
页: [1]
查看完整版本: 复旦微FM33LC046N评测+FLASH存储