当前位置: 首页 > news >正文

SYD8801操作内部flash空间(【3K(ProfileData)空间操作方法】 【24K(FlashData)空间操作方法】)

提前说明

SYD8811/SYD8810/SYD8801以及其他SYDTEK下的芯片,都支持内部空间的操作,因为在SYD8801的时候ProfileData空间(芯片默认给用户预留的空间,不用配置就存在),所以这里用3K来代表ProfileData,也不是所有芯片的ProfileData都是3k空间,比如SYD8821就是4K,各个芯片的API名字可能不完全一样,但是原理是一致的。和ProfileData一样,这里使用24K来代表FlashData,FlashData的空间大小是开发者可以配置的,在Studio的Setting中有如下功能,这里选择合适的大小后点击"Write"按钮即可配置自己需要的大小:

SYD8801的falsh空间安排(请看之前博客:http://blog.csdn.net/chengdong1314/article/details/54956664)如下:

SYD8801的flash中有两个区域给用户存储数据使用,一个空间是3K,一个空间是24K.

3K空间操作方法

在库的头文件(lib.h)中定义了如下函数:

/* read&write flash */
extern uint8_t ReadProfileData(uint16_t addr , uint16_t len, uint8_t *p_buf); 返回1代表成功 0代表失败
extern uint8_t WriteProfileData(uint16_t addr , uint16_t len, uint8_t *p_buf); 返回1代表成功 0代表失败

这两个函数可以操作用户3k空间,也就是上面那个图中最后的Profile Paratemers,操作这个空间不需要调用擦除函数,只需要读写就行。

注意:WriteProfileData函数每次最大只能够写入128个字节,ReadProfileData函数没有长度限制

注意:WriteProfileData函数交由底层代码负责写操作,调用WriteProfileData函数的时候底层代码会先把数据放在缓冲区,只用调用了ble_sched_execute函数的时候真正的写flash操作才会起效,因为写flash的时间比较长,所以ble_schedK_execute函数一般在主函数的主循环调用,ble_sched_execute函数相关内容具体请看:http://blog.csdn.net/chengdong1314/article/details/76169279

这里使用如下的测试代码:

while(1)
{
if(get_key()==1){
err=ReadProfileData( currer_address,10,read_buff );
dbg_printf("Read currer_address:%04x \r\n",currer_address);
dbg_printf("[syd8801] err:%04x \r\n",err);
dbg_hexdump("buff:\r\n",read_buff,10);
GPO_CTRL->GPO_4=~GPO_CTRL->GPO_4;
delay_ms(300);
}else if(get_key()==2){
err=WriteProfileData( currer_address,10,buff );
dbg_printf("Write currer_address:%04x \r\n",currer_address);
dbg_printf("[syd8801] err:%04x \r\n",err);
dbg_hexdump("buff:\r\n",buff,10);
GPO_CTRL->GPO_5=~GPO_CTRL->GPO_5;
for(i=0;i<10;i++){
buff[i]++;
}
delay_ms(300);
}else if(get_key()==3){
currer_address +=5;
dbg_printf("currer_address:%04x \r\n",currer_address);
GPO_CTRL->GPO_6=~GPO_CTRL->GPO_6;
delay_ms(300);
}else if(get_key()==4){
currer_address -=5;
dbg_printf("currer_address:%04x \r\n",currer_address);
GPO_CTRL->GPO_7=~GPO_CTRL->GPO_7;
delay_ms(300);
}
led_turn(LED0);
}

当按下开发板的SW1的时候对currer_address地址进行读操作,然后调用dbg_hexdump("buff:\r\n",read_buff,10);把读到的信息答应出来,按下SW2进行写操作,然后调用dbg_hexdump("buff:\r\n",read_buff,10);把学信息答应出来,按下SW3读写地址自加5,按下SW4读写地址自减5.
上面这套程序已经测试OK

注意:这里的写函数都会进行整个扇区的擦除操作,不管写入的数据是多少字节!

这里上传上本博客工程代码:http://download.csdn.net/detail/chengdong1314/9775236

下面是带上蓝牙功能的工程:http://download.csdn.net/detail/chengdong1314/9885501

24K空间操作方法

注意:对于SYD8811/8810,24K空间就是指FLASHDATA,这个空间是用户自己分配的,调用API传入的首地址是0(API接口内部已经自动做了偏移),关于flash分配的问题请看文章:https://blog.csdn.net/chengdong1314/article/details/118210536 ,请使用Studio工具在setting选择卡中的FLASH DATA进行空间分配!

正常情况下从0x19000开始的24K空间用户都是可以使用的,在库的头文件(lib.h)中定义了如下函数:

extern uint8_t ble_flash_erase(uint32_t address, uint8_t num);
extern uint8_t ble_flash_read(uint32_t address, uint8_t len, uint8_t *p_buf);
extern uint8_t ble_flash_write(uint32_t address, uint8_t len, uint8_t *p_buf);

注意:这里的擦除函数ble_flash_erase很关键,使用的时候需谨慎,其中的num变量代表的是要删除多少个扇区,而不是要擦除那个扇区(相对address的偏移),因为擦除函数会参数flash上的内容,所以使用的时候要注意不要擦除不应该擦除的地址!

这些算是flash标准擦除读写函数,这里可以使用下面的测试代码
if(get_key()==1){
/*
uint8_t ble_flash_erase(uint32_t address, uint8_t );
参数 address:要擦除扇区的首地址
num:要擦除的扇区数
注:一个扇区的大小是4096B
用户能够使用的是从0x00019000开始的24KB的空间,最后一个扇区留给协议栈使用

uint8_t ble_flash_read(uint32_t address, uint8_t len, uint8_t *p_buf);
参数 address:要读取flash的首地址
len:要读取flash的长度,单位为byte
p_buf:读取数据保存的位置

uint8_t ble_flash_write(uint32_t address, uint8_t len, uint8_t *p_buf);
参数 address:要写入的flash的首地址
len:要写入flash的长度,单位为byte
p_buf:写入数据保存的位置
*/

//erase
if(sector>=6) sector=0;
dbg_printf("erase user flash addr:%x sector_num:%x start\r\n",USER_FLASH_BASE_ADDR+USER_FLASH_SECTOR_SIZE*sector,1);
err=ble_flash_erase (USER_FLASH_BASE_ADDR, sector);
if(err) dbg_printf("erase user flash OK\r\n");
else {dbg_printf("erase user flash error\r\n"); break;}

//write
dbg_printf("write user flash addr:%x size:%x start\r\n",USER_FLASH_BASE_ADDR+USER_FLASH_SECTOR_SIZE*sector+1024,sizeof(write_buff));
err=ble_flash_write (USER_FLASH_BASE_ADDR+USER_FLASH_SECTOR_SIZE*sector+1024, sizeof(write_buff),write_buff);
if(err) dbg_printf("write user flash OK \r\n");
else {dbg_printf("write user flash error \r\n"); break;}

//read
dbg_printf("read user flash addr:%x size:%x start\r\n",USER_FLASH_BASE_ADDR+USER_FLASH_SECTOR_SIZE*sector+1024,sizeof(read_buff));
err=ble_flash_read (USER_FLASH_BASE_ADDR+USER_FLASH_SECTOR_SIZE*sector+1024, sizeof(read_buff),read_buff);
if(err) dbg_printf("read user flash OK\r\n");
else {dbg_printf("read user flash error \r\n"); break;}

//compare
dbg_printf("compare read and write data size:%x start\r\n",sizeof(read_buff));
for(i=0;i<200;i++){
if(write_buff[i] != read_buff[i]) break;
}
if(i<200) dbg_printf("flash operation error \r\n");
else dbg_printf("flash operation ok \r\n");

//disaply
dbg_hexdump("read_buff[0:50]:\r\n",read_buff,50);

sector++;
if(sector>=6) sector=0;
delay_ms(300);
}else if(get_key()==2){
if(sector>=6) continue;
//read
dbg_printf("read user flash addr:%x size:%x start\r\n",USER_FLASH_BASE_ADDR+USER_FLASH_SECTOR_SIZE*sector+1024,sizeof(read_buff));
err=ble_flash_read (USER_FLASH_BASE_ADDR+USER_FLASH_SECTOR_SIZE*sector+1024, sizeof(read_buff),read_buff);
if(err) dbg_printf("read user flash OK");
else {dbg_printf("read user flash error \r\n"); break;}

//disaply
dbg_hexdump("read_buff[0:50]:\r\n",read_buff,50);

sector++;
if(sector>=6) sector=0;
delay_ms(300);
}
}
这里按下按键1则会进行擦除、写入、读取、比较工作,同时扇区数将会自加,也就是说按下6次按键就能够擦除所有的用户flash空间,按下按键按键2只会进行读取操作,同时扇区数将会自加。

以上代码已经测试成功!

注意:这里的写函数都会进行整个扇区的擦除操作,不管写入的数据是多少字节!

这里上传上本博客使用的工程代码:

http://download.csdn.net/detail/chengdong1314/9775295

Flashdata传入的数组不能够来自代码区

今天遇到一个问题,只要调用WriteFlashData函数就会死机:

phaseNum = wave_data_len[index] / 8; dbg_printf("w1 addr:%x len:%x buff:%x\r\n",FLASH_INTERNAL_WAVEDATA_ADDR + 1024 * index,sizeof(phaseNum),(uint32_t)&phaseNum); dbg_printf("w2 addr:%x len:%x buff:%x\r\n",FLASH_INTERNAL_WAVEDATA_ADDR + 1024 * index + sizeof(phaseNum),wave_data_len[index],(uint32_t)wave_data_arr[index]); WriteFlashData(FLASH_INTERNAL_WAVEDATA_ADDR + 1024 * index, sizeof(phaseNum), (uint8_t *)&phaseNum); WriteFlashData(FLASH_INTERNAL_WAVEDATA_ADDR + 1024 * index + sizeof(phaseNum), wave_data_len[index], (uint8_t *)wave_data_arr[index]);

log如下:

Syd8811_UART w1 addr:1000 len:4 buff:200042D4 w2 addr:1004 len:60 buff:10006412 w1 addr:1400 len:4 buff:200042D4 w2 addr:1404 len:60 buff:10006472 w1 addr:1800 len:4 buff:200042D4 w2 addr:1804 len:60 buff:100064D2 w1 addr:1C00 len:4 buff:200042D4 w2 addr:1C04 len:60 buff:10006532

可以看到buff的地址是0X1xxxxxxx,这个是代码区的地址,看代码是数组前面加了const 变量来修饰并且直接传入这个变量:"const uint8_t wave_data_mode1[] "

这个是不允许的,flashdata写入的指针不能够来自代码区,所以这里可以加一个缓冲问题就能够解决:

for (index = 0; index < MAX_MODE; index++) { phaseNum = wave_data_len[index] / 8; dbg_printf("w1 addr:%x len:%x buff:%x\r\n",FLASH_INTERNAL_WAVEDATA_ADDR + 1024 * index,sizeof(phaseNum),(uint32_t)&phaseNum); dbg_printf("w2 addr:%x len:%x buff:%x\r\n",FLASH_INTERNAL_WAVEDATA_ADDR + 1024 * index + sizeof(phaseNum),wave_data_len[index],(uint32_t)wave_data_arr[index]); WriteFlashData(FLASH_INTERNAL_WAVEDATA_ADDR + 1024 * index, sizeof(phaseNum), (uint8_t *)&phaseNum); WriteFlashData(FLASH_INTERNAL_WAVEDATA_ADDR + 1024 * index + sizeof(phaseNum), wave_data_len[index], (uint8_t *)wave_data_arr[index]); }

log如下并且不会死机了:

Syd8811_UART w1 addr:1000 len:4 buff:200042D4 w2 addr:1004 len:60 buff:1000643E w1 addr:1400 len:4 buff:200042D4 w2 addr:1404 len:60 buff:1000649E w1 addr:1800 len:4 buff:200042D4 w2 addr:1804 len:60 buff:100064FE w1 addr:1C00 len:4 buff:200042D4 w2 addr:1C04 len:60 buff:1000655E
http://www.cnnetsun.cn/news/3327205.html

相关文章:

  • 揭秘金融级AI客服Agent上线全过程:从0到日均处理50万次对话的7个关键决策点
  • 从 LLM 到 Agentic SDLC:ChatGPT Pro、Plus 与 CODEX 如何重构软件开发生命周期
  • VS Code C# Dev Kit 1.0 配置指南:5个必装插件与 .NET 8 项目创建实战
  • Java 大厂面试高频题:别再只会 new 了!Java 创建对象竟然有这么多种方式
  • 团队协作中的技术栈选择:平衡效率与可维护性
  • 62-LangGraph有状态AI工作流-状态图-条件边-审批Agent实现
  • Windows系统文件blb_ps.dll丢失找不到问题解决
  • HarmonyKit | 鸿蒙开发:@kit.UIDesignKit 组件体系完整解读
  • Palworld存档编辑完全掌握:从零开始实现游戏数据可视化修改
  • RapidOCR:突破性多引擎架构实现微秒级实时文字识别
  • 如何在3小时内构建零样本图像分类系统?CLIP ViT-Base-Patch16实战指南
  • 什么是 AGENTS.md?如何为 Claude Code、Codex、Cursor 及其他 AI 编程代理创建它
  • Vendure插件开发实战:5个高级场景深度解析
  • 企业获客软件获客效率技术对比:获客工具与CRM的操作链路与数据能力差异分析
  • 2026餐饮店怎么选GEO服务商:6类核心能力对比分析,全程0代码
  • Open Design 中文保姆级下载安装教程及入门教程(2026最新版)
  • Linux游戏性能翻倍秘籍:lsfg-vk无损帧生成技术深度解析
  • A/B 测试 3 大统计陷阱:辛普森悖论如何扭曲实验结论
  • LiveAutoRecord:跨平台直播自动录制的终极解决方案
  • 从0到1部署WebWalker:LLM网页遍历智能体的本地化与规模化实践指南
  • Glorytun安全配置详解:保护你的UDP隧道通信的完整策略
  • QEMU 8.2.2 Windows 部署 UOS ARM 虚拟机:3步脚本配置与 SSH 端口 2222 映射
  • 3个秘籍让旧版Python在Windows上重获新生
  • 告别 Demo 陷阱:用 LangGraph 构建可观测的生产级 Agent 工作流
  • Inventory Kamera未来路线图:计划中的新功能和改进方向 [特殊字符]
  • 2026年AI论文生成工具哪家强?5款热门工具实测对比
  • 终极指南:1500+ AI代理技能库如何彻底改变你的开发工作流
  • 如何快速上手Laguna-XS-2.1-bf16:5分钟完成MLX模型安装与推理
  • 探索CountryPicker核心功能:国旗显示、本地化名称与ISO标准支持
  • AI 写达梦/金仓代码疯狂翻车?我手撸了一套“信创专属 AI 生成引擎”,把大模型的方言幻觉按在地上摩擦!