本文写的十分草率,许多我自创的函数未做解释。等整个项目完成,我会慢慢整理资料。。。
一、大概实现
大致思路:在flash8M内存的高位划分出4k大小的若干块,每个应用程序占有最多4K的数据,在应用启动时读取数据,在应用结束时擦除这4K的flash并重新写入数据。
例如:
注:Fls_Get函数是从flash中读取数据
函数原型:Fls_Get(uint32_t addr, void* buff, uint32_t cnt)
Fls_Set是写入数据
#ifndef DATA_DINO_H
#define DATA_DINO_H
#include "TableAddress.h"
#include "Table.h"
//用户数据
uint8_t historyScore[100];
void dino_loadconf(void)
{
//读取数据
Fls_Get(DATA_DINO+0, historyScore, 100)
}
void dino_saveconf(void)
{
//保存数据
W25Q64_SectorErase(DATA_DINO)
Fls_Set(DATA_DINO+0, historyScore, 100)
}
#endif
TableAddress是所有资源文件在flash中的地址索引(当然也包括这4K的用户数据),只有一个变量时当然好办,直接从首地址开读即可,但是有多个变量时还得考虑变量的存储顺序、字节偏移等问题。 于是这个代码可能变成了这样
#ifndef DATA_SYSTEM_H
#define DATA_SYSTEM_H
#include "TableAddress.h"
#include "Table.h"
//用户数据
uint8_t animaionFadeTime = 10;
uint8_t alertMarginTop = 10;
uint8_t alertMarginBottom = 10;
uint8_t alertMarginLeft = 10;
uint8_t alertMarginRight = 10;
uint16_t a = 10;
void system_loadconf(void)
{
//读取数据
Fls_Get(DATA_SYSTEM+0, &animaionFadeTime, 1)
Fls_Get(DATA_SYSTEM+1, &alertMarginTop, 1)
Fls_Get(DATA_SYSTEM+2, &alertMarginBottom, 1)
Fls_Get(DATA_SYSTEM+3, &alertMarginLeft, 1)
Fls_Get(DATA_SYSTEM+4, &alertMarginRight, 1)
Fls_Get(DATA_SYSTEM+5, &a, 2)
}
void system_saveconf(void)
{
//保存数据
W25Q64_SectorErase(DATA_SYSTEM)
Fls_Set(DATA_SYSTEM+0, &animaionFadeTime, 1)
Fls_Set(DATA_SYSTEM+1, &alertMarginTop, 1)
Fls_Set(DATA_SYSTEM+2, &alertMarginBottom, 1)
Fls_Set(DATA_SYSTEM+3, &alertMarginLeft, 1)
Fls_Set(DATA_SYSTEM+4, &alertMarginRight, 1)
Fls_Set(DATA_SYSTEM+5, &a, 2)
}
#endif
于是我们需要手搓编译工具
二、python工具
输入数据:我们需要定义的变量。直接给个json,例如:
type:变量类型
value:变量初始值
num:变量长度(如果变量不是数组,不管他)
{
"animaionFadeTime":{
"type":"uint8_t",
"value":10
},
"alertMarginTop":{
"type":"uint8_t",
"value":10
},
"alertMarginBottom":{
"type":"uint8_t",
"value":10
},
"alertMarginLeft":{
"type":"uint8_t",
"value":10
},
"alertMarginRight":{
"type":"uint8_t",
"value":10
},
"a":{
"type":"uint16_t",
"value":10
}
}
python把这个json里面的变量按顺序排布就得到了要往flash中写入的数据的内存布局。注意:数据的存储要分大端小端大端与小端_大小端-CSDN博客
首先要把数据打包成二进制流,放在最终写入flash的数据流中。装二进制数据用python的bytearray再合适不过了。打包的话用struct.pack
三、把编译后的数据烧录到w25q64中
# !/usr/bin/env python
# -*- coding: utf-8 -*-
"""
# ============================================================
# @Date : 2022/05/16 21:50:12
# @Author : miles
# @Email : lishan@st.xatu.edu.cn
# @File : serial_demo.py
# @IDE : PyCharm
# @Func : Describes the function of the file
# @Note : pip install pyserial
# ============================================================
"""
import time
import serial.tools.list_ports
from conf import DB
BSIZE = 256
if __name__ == '__main__':
# 读取串口列表
ports_list = list(serial.tools.list_ports.comports())
if len(ports_list) <= 0:
print("无串口设备")
else:
print("可用的串口设备如下: ")
print("%-10s %-30s %-10s" % ("num", "name", "number"))
for i in range(len(ports_list)):
comport = list(ports_list[i])
comport_number, comport_name = comport[0], comport[1]
print("%-10s %-30s %-10s" % (i, comport_name, comport_number))
i = input("Serial Number\n")
# 打开串口
port_num = ports_list[int(i)][0]
print("默认选择串口: %s" % port_num)
# 串口号: port_num, 波特率: 115200, 数据位: 8, 停止位: 1, 超时时间: 55.5秒
ser = serial.Serial(port=port_num, baudrate=115200, bytesize=serial.EIGHTBITS, stopbits=serial.STOPBITS_ONE,
timeout=55.5)
if not ser.isOpen():
print("打开串口失败")
else:
print("打开串口成功, 串口号: %s" % ser.name)
print("等待擦除")
while True:
ser_input = ser.read_all()
if b"!" in ser_input:
print(ser_input, end="")
break
with open(DB, 'rb') as fp:
total = 0
length = BSIZE
while length > 0:
data = fp.read(BSIZE)
length = len(data)
if length < BSIZE and length != 0:
data += b"\0"*(BSIZE-length)
length = len(data)
# 串口发送字符串数据
ser.write(data)
while True:
ser_input = ser.read_all()
if b"Recieve" in ser_input:
total += length
print(f"收到回复:{ser_input}, 累计写入字节数:{total}")
break
# 关闭串口
ser.close()
if ser.isOpen():
print("串口未关闭")
else:
print("串口已关闭")
#include "usart.h"
#include "W25Q64.h"
#include "../GUI/GUI.h"
#define DOWNLOAD_B_SIZE 256
#define DOWNLOAD_CAPACITY 0x800000
uint8_t Download_Buff[DOWNLOAD_B_SIZE];
uint32_t Dowmload_Counter = 0;
uint8_t Download_Cbid;
uint32_t Download_Address = 0;
void Download_Printf(uint32_t addr)
{
W25Q64_ReadData(addr, Download_Buff, DOWNLOAD_B_SIZE);
UsartPrintf(USART1, Download_Buff);
}
void Download_Write(void)
{
W25Q64_PageProgram(Download_Address, Download_Buff, DOWNLOAD_B_SIZE);
UsartPrintf(USART1, "Recieved!\n");
Download_Address += DOWNLOAD_B_SIZE;
}
void Download_Recieve(char a)
{
Download_Buff[Dowmload_Counter] = a;
Dowmload_Counter++;
if (Dowmload_Counter == DOWNLOAD_B_SIZE)
{
Download_Write();
Dowmload_Counter = 0;
}
}
void Download_Init(void)
{
uint16_t did;
uint8_t mid;
uint32_t addr = 0;
Usart1_Init(115200);
W25Q64_Init();
Download_Cbid = Usart1_AddCallback(Download_Recieve);
Usart1_SetCallback(Download_Cbid);
W25Q64_ReadID(&mid, &did);
UsartPrintf(USART1, "Download Inited, MID: %d DID: %d\n", mid, did);
UsartPrintf(USART1, "Erase full flash\n");
while (addr < DOWNLOAD_CAPACITY)
{
W25Q64_SectorErase(addr);
addr += 1024*4;
}
UsartPrintf(USART1, "Erase full flash end!\n");
}
注意:w25Q64一次擦除4K,一次最多写入256byte,我看错这个256byte的限制,试了三天没结果!!!
改过来以后发现一个灵异事件:每次写入一段时间后会卡住!!!,一开始以为是flash卡在了waitbuzy,开始各种的换芯片,直到做了一个测试后发现是卡在了usart发送!
写入字节256
收到回复:b'Start Program!\n'
收到回复:b'wait busy\nRecieved!\n'
收到回复:b'wait busy\nRecieved!\n', 累计写入字节数:18432
写入字节256
收到回复:b'Start Program!\n'
收到回复:b'wait busy\nRecieved!\n'
收到回复:b'wait busy\nRecieved!\n', 累计写入字节数:18688
写入字节256
收到回复:b'Start Program!\n'
收到回复:b'wait busy\nRecieved!\n'
收到回复:b'wait busy\nRecieved!\n', 累计写入字节数:18944
写入字节256
收到回复:b'Start Program!\n'
收到回复:b'wait busy\nRecieved!\n'
收到回复:b'wait busy\nRecieved!\n', 累计写入字节数:19200
写入字节256
收到回复:b'Start Program!\n'
收到回复:b'wait busy\nRecieved!\n'
收到回复:b'wait busy\nRecieved!\n', 累计写入字节数:19456
写入字节256
收到回复:b'Start Program!\n'
收到回复:b'wait busy\nRec'
我们发现接收到waitbusy之后还收到了Rec,对应到程序上是:
UsartPrintf(USART1, "Start Program!\n");
W25Q64_PageProgram(Download_Address, Download_Buff, DOWNLOAD_B_SIZE);
Download_Address += DOWNLOAD_B_SIZE;
UsartPrintf(USART1, "Recieved!\n");
改大缓冲区
ser.set_buffer_size(81920, 81920)
还是会卡
也有可能是进中断卡死了,上个锁验证一下
bool is_Write = false;
void Download_Write(void)
{
if (is_Write)
{
UsartPrintf(USART1, "recursively call\n");
return;
}
is_Write = true;
if (Download_Etimer >= DOWNLOAD_E_T)
{
UsartPrintf(USART1, "Start Erase!\n");
W25Q64_SectorErase(Download_Address);
Download_Etimer = 0;
UsartPrintf(USART1, "end Erase!\n");
}
Download_Etimer++;
UsartPrintf(USART1, "Start Program!\n");
W25Q64_PageProgram(Download_Address, Download_Buff, DOWNLOAD_B_SIZE);
Download_Address += DOWNLOAD_B_SIZE;
UsartPrintf(USART1, "Recieved!\n");
is_Write = false;
}
这就说明可能是芯片卡死了,换芯片尝试
写入字节256
收到回复:b'Start Erase!\n'
收到回复:b'end Erase!\nStart Program!\n'
收到回复:b'end Erase!\nStart Program!\n'
收到回复:b'wait busy\nRecieved!\n'
收到回复:b'wait busy\nRecieved!\n', 累计写入字节数:20736
写入字节256
收到回复:b'Start Program!\n'
收到回复:b'wait busy\nRecieved!\n'
收到回复:b'wait busy\nRecieved!\n', 累计写入字节数:20992
写入字节256
收到回复:b'Start Program!\n'
收到回复:b'wait busy\nRecieved!\n'
收到回复:b'wait busy\nRecieved!\n', 累计写入字节数:21248
写入字节256
收到回复:b'Start Program!\n'
收到回复:b'wait busy\nRecieved!\n'
收到回复:b'wait busy\nRecieved!\n', 累计写入字节数:21504
写入字节256
收到回复:b'Start Program!\n'
收到回复:b'wait busy\nRecieved!\n'
收到回复:b'wait busy\nRecieved!\n', 累计写入字节数:21760
写入字节256
收到回复:b'Start Program!\n'
收到回复:b'wait busy\nRecieved!\n'
收到回复:b'wait busy\nRecieved!\n', 累计写入字节数:22016
写入字节256
收到回复:b'Start Program!\n'
收到回复:b'wait busy\nRe'
依旧卡死
void USART1_IRQHandler(void)
{
if (USART_GetFlagStatus(USART1, USART_FLAG_PE) != RESET)
{
USART_ReceiveData(USART1);
USART_ClearFlag(USART1, USART_FLAG_PE);
}
if (USART_GetFlagStatus(USART1, USART_FLAG_ORE) != RESET)
{
USART_ReceiveData(USART1);
USART_ClearFlag(USART1, USART_FLAG_ORE);
}
if (USART_GetFlagStatus(USART1, USART_FLAG_FE) != RESET)
{
USART_ReceiveData(USART1);
USART_ClearFlag(USART1, USART_FLAG_FE);
}
if (USART_GetFlagStatus(USART1, USART_FLAG_NE) != RESET)
{
USART_ReceiveData(USART1);
USART_ClearFlag(USART1, USART_FLAG_NE);
}
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
{
if (Usart1_RecieveCallback[Usart1_CurrentCallback] != NULL)
{
Usart1_RecieveCallback[Usart1_CurrentCallback](USART_ReceiveData(USART1));
}
USART_ClearITPendingBit(USART1, USART_FLAG_RXNE);
}
}
依旧卡死,降低为128byte,依旧卡死,将为164byte的缓冲区依旧卡死,最后发现是pyserial的问题
我把read_all换成read_until('\n')成功解决!!!
为什么呢?原来是timeout设置大了
最终找到这位大佬的文章:
四、测试
图片&文字
#include "stm32f10x.h"
#include "usart.h"
#include "AD.h"
#include "Delay.h"
#include "Draw.h"
#include "Time.h"
#include "Key.h"
#include "../GUI/GUI.h"
#include "../GUI/Widgets.h"
#include "Download.h"
#include "dino.h"
#include "yuan.h"
#include "../UI/video.h"
#include "Home.h"
void Init_Apps(void)
{
Home_Register();
Video_Register();
Dino_Register();
Yuan_Register();
}
int main(void)
{
Usart1_Init(115200);
Key_Init();
GUI_Init();
Time_Init();
W25Q64_Init();
GUI_Image img;
Fls_GetImage(&img, PICTURES_APPICOS_ABOUT);
GUI_DrawPicture(img.picture, 0, 0, img.size.w, img.size.h, BLIT_NORMAL);
Fls_FreeImage(&img);
GUI_DrawText("Hello World!", 0, 0, FONTS_FONT_BAHNSCHRIFT_12, BLIT_NORMAL);
GUI_DrawText("Hello world", 0, 20, FONTS_FONT_SQUARE_24, BLIT_NORMAL);
GUI_Update();
Init_Apps();
while (1)
{
Widget_Update();
}
}
预读取器
#include "stm32f10x.h"
#include "usart.h"
#include "AD.h"
#include "Delay.h"
#include "Draw.h"
#include "Time.h"
#include "Key.h"
#include "../GUI/GUI.h"
#include "../GUI/Widgets.h"
#include "Download.h"
#include "dino.h"
#include "yuan.h"
#include "../UI/video.h"
#include "../Storage/pictures_appicos.h"
#include "../Storage/pictures_maze.h"
int main(void)
{
Usart1_Init(115200);
Key_Init();
GUI_Init();
Time_Init();
W25Q64_Init();
GUI_Rect rect = {
.size.h = 0,
.size.w = 0,
.topleft.x = 0,
.topleft.y = 0
};
pictures_appicos_load();
pictures_maze_load();
rect.size = pictures_appicos_osc.size;
GUI_DrawImage(&pictures_appicos_osc, rect);
pictures_appicos_clear();
pictures_maze_clear();
GUI_Update();
while (1)
{
Widget_Update();
}
}