打印
[STM32F1]

关于STM32对FLASH的设计思路

[复制链接]
1898|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lando|  楼主 | 2020-3-19 12:15 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我这种存储方式不知道有没有改进的空间,请大家帮忙指正。

W25Q128将16M的容量分为256个块(Block),每个块大小为64K字节,每个块又分为
16个扇区(Sector),每个扇区4K个字节。W25Q128的最小擦除单位为一个扇区,也就是每次
必须擦除4K个字节。

所以我是按照扇区为单位存储数据的。

第一个扇区为配置信息数据,第二个扇区为升级程序(SPI远程升级用的)长度。第三、四个扇区为升级程序。第五个扇区存储离线数据占的扇区个数(后简称扇区标识位),第六个扇区以后存储离线数据。

其实前面4个扇区不用说了,关键是离线数据那块想了好久,才出了这个解决方案。

应用场景:
如果出现通信不畅的问题,需要将GPS信息缓存到flash里,等通信正常以后再传出去。

我想的是以扇区为单位进行存储,因为如果缓存数据量很庞大,我可以一个扇区一个扇区进行读,发送,擦除操作,避免通信通道被大量离线数据拥堵。

解决方法:
1. 第五个扇区存储离线数据占的扇区个数,也就是最后一个未满扇区的标志位。这样数据存进来直接根据这个扇区获取到可以存放的扇区基地址。

2. 找到这个扇区基地址以后,要先查前四位,这前四位为此扇区的数据长度。如果存入数据的长度加此扇区的数据长度大于扇区长度,那么就要新开辟一块扇区,并且扇区标识位要加1。如果没超过,将整个扇区取出,修改数据长度,末尾追加新数据。

3. 取数据的时候,也是先去查询扇区标识位然后得到最后数据的扇区地址,取出此扇区数据,格式化此扇区,修改扇区标识位。属于先进后出的方式(因为GPS信息有时间,所以不在乎顺序问题)

4. 数据存满了怎么办,当再次开辟新扇区时,发现扇区标识位+1 大于FLASH扇区个数或者设计离线数据占用扇区个数。那么开辟新扇区会直接返回数据的最后一块扇区,擦除以后再将新数据存入。相当于如果数据太大,就只会保存头数据和尾数据,而把中间的数据丢弃掉。

大家发现有设计不合理的,帮忙指正!谢谢!

使用特权

评论回复
沙发
21ic小喇叭| | 2020-3-20 09:48 | 只看该作者
楼主把自己的问题、思路、尝试过的办法,写的都比较详细,希望大家看到后能尽快帮楼主解决问题~~~

使用特权

评论回复
板凳
21ic小喇叭| | 2020-3-20 09:49 | 只看该作者
奖励您10家园币,家园币是我们新上线的产品,您可以兑换礼品~

使用特权

评论回复
地板
lando|  楼主 | 2020-3-20 20:39 | 只看该作者
既然被推荐了,那我就把昨天调了一晚上的核心代码部分传上来。已经测试通过了,非常好用。
                SPI_FLASH_SectorErase(FLASH_OFFLINE_LENGTH);
                SPI_FLASH_SectorErase(FLASH_OFFLINE_DATA);
                offlineLengthInit();
                char data[] = "0102030405040304938473625364738473645263748594837463547182736475847364";
                int index = 60;
                while(index > 0 )
                {       
                        writeOfflineData(data, strlen(data));
                        index--;
                }
               
                readOfflineData();
                readOfflineData();
                readOfflineData();

        //初始化离线数据扇区
void offlineDataInit(int data_index)
{       
        SPI_FLASH_SectorErase(W25Q128FV_SUBSECTOR_SIZE * data_index);
        uint8_t data_length[5] = {0};
        sprintf((char*)data_length, "%04x", 0);
        SPI_FLASH_BufferWrite(data_length, W25Q128FV_SUBSECTOR_SIZE * data_index, 4);
}

// 初始化离线数据标识扇区
void offlineLengthInit(void)
{
        uint8_t data_index_length[5] = {0};
        SPI_FLASH_SectorErase(FLASH_OFFLINE_LENGTH);
        sprintf((char*)data_index_length, "%04x", 6);
        SPI_FLASH_BufferWrite(data_index_length, FLASH_OFFLINE_LENGTH, 4);
       
        offlineDataInit(6);
}

// 修改离线数据标识
u32 newOfflineLength(int d_index)
{       
        if(d_index < 6 ){
                d_index = 6;
        }
        if(d_index > 256 ){
                d_index = 256;
        }
       
        printf("\r\n newOfflineLength: %d \r\n", d_index);
        uint8_t data_index[5] = {0};
        SPI_FLASH_SectorErase(FLASH_OFFLINE_LENGTH);
        sprintf((char*)data_index, "%04x", d_index);
        SPI_FLASH_BufferWrite(data_index, FLASH_OFFLINE_LENGTH, 4);
       
        return W25Q128FV_SUBSECTOR_SIZE * d_index;
}

void readOfflineData(void)
        {
        // 查询离线数据标识确定最后数据地址
        uint8_t data_index[5] = {0};
        SPI_FLASH_BufferRead(data_index, FLASH_OFFLINE_LENGTH, 4);
        int d_index = charhex_to_dec((char*)data_index);
        printf("\r\n readOfflineData: %d \r\n", d_index);
        u32 data_address = W25Q128FV_SUBSECTOR_SIZE * d_index;
       
        // 查询离线数据标识扇区内数据长度标识
        uint8_t data_length[5] = {0};
        SPI_FLASH_BufferRead(data_length, data_address, 4);
        int d_length = charhex_to_dec((char*)data_length);
       
        SPI_FLASH_BufferRead(read_data, data_address + 4, d_length);
        SPI_FLASH_SectorErase(data_address);
        if(d_index > 6){
                newOfflineLength(d_index - 1);
        }

        printf("\r\n 读出长度为:%d \r\n", d_length);
        printf("\r\n 读出的数据为:%s \r\n", read_data);
        printf("\r\n 读出长度为:%d \r\n", strlen((char*)read_data));
        memset(read_data, 0, 4069);
}

void writeOfflineData(char* data, int dataLength)
        {

        // 查询离线数据标识确定最后数据地址
        uint8_t data_index[5] = {0};
        SPI_FLASH_BufferRead(data_index, FLASH_OFFLINE_LENGTH, 4);
        int d_index = charhex_to_dec((char*)data_index);
        u32 data_address = W25Q128FV_SUBSECTOR_SIZE * d_index;
       
        // 查询离线数据标识扇区内数据长度标识
        uint8_t data_length[5] = {0};
        SPI_FLASH_BufferRead(data_length, data_address, 4);
        int d_length = charhex_to_dec((char*)data_length);
       
       
        // 如果新数据+扇区数据长度>扇区长度
        if((dataLength + d_length) > W25Q128FV_SUBSECTOR_SIZE){
                // 开辟新扇区
                data_address = newOfflineLength(d_index + 1);
                SPI_FLASH_SectorErase(data_address);
               
               
                sprintf((char*)write_data, "%04x%s", dataLength, data);
                SPI_FLASH_BufferWrite(write_data, data_address,  strlen((char*)write_data));
                printf("\r\n 写入的数据为:%s \r\t", write_data);
                printf("\r\n 长度:%d \r\t", strlen((char*)write_data));
               
        } else if(d_length == 0)
        {
                SPI_FLASH_SectorErase(data_address);
                       
                sprintf((char*)write_data, "%04x%s", dataLength, data);
                SPI_FLASH_BufferWrite(write_data, data_address, strlen((char*)write_data));
        } else
        {
                // 将旧数据读出,修改扇区数据长度,末尾追加新数据
                SPI_FLASH_BufferRead(read_data, data_address + 4, d_length);
                SPI_FLASH_SectorErase(data_address);
               
                sprintf((char*)write_data, "%04x%s%s%s", dataLength + d_length + 1, read_data, ",", data);

                SPI_FLASH_BufferWrite(write_data, data_address, strlen((char*)write_data));
        }
        memset(write_data, 0, 4069);
}


只只是个DEMO,还没往产品里移植呢,如果需要完整代码的,可以找我要。

使用特权

评论回复
5
花自向阳开| | 2020-3-21 08:42 | 只看该作者
你是BIOS RD嗎

使用特权

评论回复
6
花自向阳开| | 2020-3-21 08:52 | 只看该作者
STM32L452CCU6-C01 ST UFQFPN48这款呼吸灯控制芯片的FW有写过吗?

使用特权

评论回复
7
lando|  楼主 | 2020-3-23 11:28 | 只看该作者
花自向阳开 发表于 2020-3-21 08:52
STM32L452CCU6-C01 ST UFQFPN48这款呼吸灯控制芯片的FW有写过吗?

现在在研究L系列

使用特权

评论回复
8
晓伍| | 2020-4-6 18:12 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
9
八层楼| | 2020-4-6 18:23 | 只看该作者

非常感谢楼主分享

使用特权

评论回复
10
观海| | 2020-4-6 18:23 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
11
guanjiaer| | 2020-4-6 18:23 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
12
heimaojingzhang| | 2020-4-6 18:24 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

15

帖子

1

粉丝