AiPi-Eyes-S1是安信可开源团队专门为Ai-M61-32S设计的一款开发板,支持WiFi6、BLE5.3。所搭载的Ai-M61-32S 模组具有丰富的外设接口,具体包括 DVP、MJPEG、Dispaly、AudioCodec、USB2.0、SDU、以太网 (EMAC)、SD/MMC(SDH)、SPI、UART、I2C、I2S、PWM、GPDAC、GPADC、ACOMP 和 GPIO 等。
AiPi-Eyes-S1集成了SPI屏幕接口,DVP摄像头接口,外置ES8388音频编解码芯片以及预留TF卡座,并且引出USB接口,可接入USB摄像头。
从零开始学习小安派:
Flash 简称闪存,它的特点是擦除和编程速度快,单片机的程序一般都是存储在一定空间内中进行运行。在 C 语言中,程序分为代码段、常量区、静态数据区(BSS 段,数据段)、栈、堆五个部分组成。内部空间就分为 ROM 和 RAM,都是可以用来存储内容,区别在于:
ROM 的存储特性比较稳定,很久以前它不可擦除,所以只可读不可写,FLASH 就是一种特殊的 ROM,可擦除可读可写,在掉电后不丢失。RAM 的存储特性较不稳定,但读写速度快,掉电后丢失。
它们的差异如下:
数据存储区域 | 类型 | 所在存储空间 |
代码段 | 宏定义、枚举、字面常量(整数、浮点类型) | ROM(也可在 RAM) |
常量区 | 只读变量、const 修饰的全局变量、常量字符串(char *p=“hi”) | ROM |
静态数据区 BSS 段
| 全局变量和 static 修饰后的静态变量(未初始化,如 int a) | RAM |
静态数据区数据段 | 全局变量和 static 修饰后的静态变量(已初始化,如 int a=0) | ROM,运行时拷贝到 RAM 中 |
栈 | 局部变量,如函数内临时定义的 int b,在函数运行完自动释放 | RAM |
堆 | malloc 申请的空间,需要用户手动申请/释放 | RAM |
总结:FLASH 也就是 ROM,掉电后不丢失,读写速度较慢,空间大,可以理解未电脑上的硬盘。RAM 速度快,掉电后丢失,可以理解未电脑上的内存。
618FLASH 物理上的地址起始地址是 0XA0000000。M61-32S 的 FLASH 大小是 8M。在数据手册中可以看到所有的模块地址映射,包括外设的地址。
在这之前需要了解分区表的概念,分区表就是划分 FLASH 的清单,将 FLASH 划分为多个不同功能区域用于其它功能。在操作 FLASH 时得看一下分区表,查看哪些地址可以使用。在 SDK 中有 4M 的分区表,里面规划了一些分区的命名,起始地址和大小,这个目录下找到。
AiPi-Open-Kits/aithinker_Ai-M6X_SDK/bsp/board/bl616dk/config/partition_cfg_4M.toml,在参与编译时会在工程文件夹下的 build/build_out 中生成 partition.bin。我们在 flash_prog_cfg.ini 中可以看到,常见的有 BOOT2 固件,filedir:固件路径,address:地址,boot2 必须使用 0 地址。而 partition 表示分区表固件,address 是根据 partition_cfg_4M.toml 指定。而 FW 则表示需要烧录的应用固件,FW 可以在 partition_cfg_4M.toml 中看到。
![微信截图_20231106163957.png](http://mmbiz.qpic.cn/sz_mmbiz_jpg/wDN2fZTUMRUbjJKibZicn4j9Q4KY4E7LRGO0ISuEqT6oiczAmyyDyxNdbCuUqG6XwHLLpw4frp6eba7m7KBIGXaiag/640?wx_fmt=jpeg&from=appmsg)
我们可以添加一样的“分区”,创建属于自己的名字,也可以在分区表中查看已有的分区使用。当然,建议还是使用原厂分配的分区表。
1.bflb_flash_init
说明: flash 初始化,自动识别支持的 flash 并重新配置 flash 的参数。如果返回错误,必须停止运行代码。
int bflb_flash_init(void);
parameter | description |
return | 返回 0 表示成功,其他表示错误,必须停止运行代码 |
2.bflb_flash_get_jedec_id
说明: 获取 flash jedec id。
uint32_t bflb_flash_get_jedec_id(void);
parameter | description |
return | 返回 flash jedec id |
3.bflb_flash_get_cfg
说明: 获取 flash 配置。
void bflb_flash_get_cfg(uint8_t **cfg_addr, uint32_t *len);
parameter | description |
cfg_addr | 保存 flash 配置的地址 |
len | flash 配置的长度 |
4.bflb_flash_set_iomode
说明: 设置 flash IO 工作模式。
void bflb_flash_set_iomode(uint8_t iomode);
parameter | description |
iomode | flash IO 工作模式 |
可填入以下几种模式:
#define FLASH_IOMODE_NIO 0
#define FLASH_IOMODE_DO 1
#define FLASH_IOMODE_QO 2
#define FLASH_IOMODE_DIO 3
#define FLASH_IOMODE_QIO 4
5.bflb_flash_get_image_offset
说明: 获取代码 xip 虚拟地址实际所在的 flash 物理地址。
uint32_tbflb_flash_get_image_offset(void);
parameter | description |
return | 返回 flash xip 物理地址 |
6.bflb_flash_erase
说明: flash 扇区擦除。len 为擦除的长度,需要为 4096 倍数,假设 addr 为 0 , len 为 4096,则擦除范围为 0 ~ 4095。
intbflb_flash_erase(uint32_t addr,uint32_t len);
parameter | description |
addr | 擦除的物理地址 |
len | 擦除长度,需要是 4096 的倍数 |
return | 返回 0 表示成功,其他表示错误 |
7.bflb_flash_write
说明:获取代码 xip 虚拟地址实际所在的 flash 物理地址。
intbflb_flash_write(uint32_t addr, uint8_t *data,uint32_t len);
parameter | description |
addr | 写入的物理地址 |
data | 写入的数据缓冲区 |
len | 写入长度 |
return | 返回 0 表示成功,其他表示错误 |
8.bflb_flash_read
说明: 获取代码 xip 虚拟地址实际所在的 flash 物理地址。
intbflb_flash_read(uint32_t addr,uint8_t *data,uint32_t len);
parameter
| description |
addr | 读取的物理地址 |
data | 读取的数据缓冲区 |
len | 读取长度 |
return | 返回 0 表示成功,其他表示错误 |
9.bflb_flash_aes_init
说明: 配置某一段 flash 区域进行硬件 aes 解密,能够通过 xip 直接读取解密后的内容。
voidbflb_flash_aes_init(struct bflb_flash_aes_config_s *config);
parameter | description |
config | flash aes 配置 |
10.bflb_flash_aes_enable
说明: 使能 flash aes 解密。
voidbflb_flash_aes_enable(void);
11.bflb_flash_aes_disable
说明: 关闭 flash aes 解密。
voidbflb_flash_aes_disable(void);
1.首次写入
#include "bflb_flash.h"
#include "board.h"
#include "string.h"
#define FLASH_RW_START_ADDR 0x3F3000
static uint8_t write_buf[16];
static uint8_t read_buf[16];
int main(void)
{
uint32_t i;
board_init();
memset(write_buf, 0, sizeof(write_buf));
memset(read_buf, 0, sizeof(read_buf));
strcpy(write_buf,"HelloWorld!");
bflb_flash_erase(FLASH_RW_START_ADDR,sizeof(write_buf));
bflb_flash_read(FLASH_RW_START_ADDR, read_buf, sizeof(read_buf));
for (i = 0; i < sizeof(read_buf); i++) {
if (read_buf[i] != write_buf[i]) {
printf("\r\nflash read fail at %d, expect:%d but get %d", i, write_buf[i], read_buf[i]);
}
}
bflb_flash_write(FLASH_RW_START_ADDR, write_buf, sizeof(write_buf));
memset(read_buf, 0, sizeof(read_buf));
bflb_flash_read(FLASH_RW_START_ADDR, read_buf, sizeof(read_buf));
printf("\r\n%s",read_buf);
while (1) {
}
}
第一次运行程序效果:在擦除了后读出来的 ASCII 码为 255
![FirstWrite.png](http://mmbiz.qpic.cn/sz_mmbiz_jpg/wDN2fZTUMRUbjJKibZicn4j9Q4KY4E7LRGYYNoDajohEQOn7Nuia0vTDwjVPjSBic3mW5E3ickriahEdFMHDKToibgnpg/640?wx_fmt=jpeg&from=appmsg)
2.二次读取,查看上电打印信息
#include "bflb_flash.h"
#include "board.h"
#include "string.h"
#define FLASH_RW_START_ADDR 0x3F3000
static uint8_t write_buf[16];
static uint8_t read_buf[16];
int main(void)
{
uint32_t i;
board_init();
memset(write_buf, 0, sizeof(write_buf));
memset(read_buf, 0, sizeof(read_buf));
strcpy(write_buf,"HelloWorld!");
bflb_flash_read(FLASH_RW_START_ADDR, read_buf, sizeof(read_buf));
for (i = 0; i < sizeof(read_buf); i++) {
if (read_buf[i] != write_buf[i]) {
printf("\r\nflash read fail at %d, expect:%d but get %d", i, write_buf[i], read_buf[i]);
}
}
printf("\r\n%s",read_buf);
while (1) {
}
}
二次读取后的运行效果:校验成功,只读取出 hellowold
![SecondRead.png](http://mmbiz.qpic.cn/sz_mmbiz_jpg/wDN2fZTUMRUbjJKibZicn4j9Q4KY4E7LRGQbY18SApicFXFnaOyFlUJDx0AFgLyAdvQxs0AuUr0JH9c5wZCtHUeLQ/640?wx_fmt=jpeg&from=appmsg)