前面的文章介绍了 DAC 方式播放和用更高精度的 PWM 方式直接播放音频文件,但是很明显我们遇到了的2个问题: 1. 1.存储空间有限,APP中最大只能存放2.7MB的音频; 2. 2.每次都需要手工将数据转化为 .h ,比较麻烦。
这次就介绍如何在 FireBeetle上使用更大的空间。从介绍中可以看到FireBeetleFlash 为16MB,但是 APP 最大只能用到3MB,余下的空间要么分配给 SPIFFS,要么分给 FATFS。
SPIFFS 和 FATFS 都是一种文件系统。其中SPIFFS是一个用于SPI NOR flash 设备的嵌入式文件系统,支持磨损均衡、文件系统一致性检查等功能【参考1】。同样的 FATFS也是一种文件系统【参考2】。很明显ESP32 上我们可以使用更大的空间,因此这里尝试使用FATSFS来存储音频文件。 对于 ESP32 来说,每次上传的 APP 和 FATFS 是分开的。比如,编译之后生成了一个3MB 的APP, 那么上传时只会烧写更新3MB APP 那一段的SPINOR 中的内容,余下的部分不会改变(加上压缩以及快速的串口通讯,我们并不会感觉上传太慢)。因此,我们还需要一个额外的工具来完成上传 FATFS 的部分。这个工具就是Arduinoesp32fs 插件,这个插件能将文件传输到ESP32 的SPIFFS,LittleFS 或者FatFS 分区上,项目地址如下: 下载到编译好的文件是一个 JAR文件。
安装方法是在你 Arduino.exe 的目录中,Tools下创建ESP32FS/Tool 目录,然后将上面这个文件放置进去:
重启 Arduino 之后在 Tools 菜单中会出现 “ESP32Sketch Data Upload”的选项。
为了给 FATFS 分区上传,我们还需要2个额外的工具 mklittlefs.exe 和 mkfatfs.exe。这两个工具需要放在C:\Users\用户名\AppData\Local\Arduino15\packages\firebeetle32\hardware\esp32\0.1.1\tools目录下。 上面准备妥当之后,先编写一个测试程序。这个程序会列出当前 FATFS 上面的文件名称。
- #include "FS.h"
- #include "FFat.h"
-
- void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
- Serial.printf("Listing directory: %s\r\n", dirname);
-
- File root = fs.open(dirname);
- if(!root){
- Serial.println("- failed to open directory");
- return;
- }
- if(!root.isDirectory()){
- Serial.println(" - not a directory");
- return;
- }
-
- File file = root.openNextFile();
- while(file){
- if(file.isDirectory()){
- Serial.print(" DIR : ");
- Serial.println(file.name());
- if(levels){
- listDir(fs, file.name(), levels -1);
- }
- } else {
- Serial.print(" FILE: ");
- Serial.print(file.name());
- Serial.print("\tSIZE: ");
- Serial.println(file.size());
- }
- file = root.openNextFile();
- }
-
-
- }
-
- void setup() {
- Serial.begin(115200);
- if(!FFat.begin()){
- Serial.println("FFat Mount Failed");
- return;
- }
- Serial.printf("Total space: %10u\n", FFat.totalBytes());
- Serial.printf("Free space: %10u\n", FFat.freeBytes());
-
- }
-
- void loop() {
- listDir(FFat, "/", 0);
- delay(5000);
- }
复制代码
此外,我们还要在程序目录下创建一个 data 目录,然后将3支歌曲的文件放在里面。
直接使用菜单上传FATFS分区。
选择 FATFS:
看到下面的字样就表示已经成功:
接下来,像普通 Arduino 代码一样上传我们的程序,打开串口就能看到结果:
有了上面的代码,我们可以很容易编写出来播放代码: - #include "FS.h"
- #include "FFat.h"
-
- #include "data\1990.h"
- #include "soc/sens_reg.h" // For dacWrite() patch, TEB Sep-16-2019
-
- void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
- Serial.printf("Listing directory: %s\r\n", dirname);
-
- File root = fs.open(dirname);
- if(!root){
- Serial.println("- failed to open directory");
- return;
- }
- if(!root.isDirectory()){
- Serial.println(" - not a directory");
- return;
- }
-
- File file = root.openNextFile();
- while(file){
- if(file.isDirectory()){
- Serial.print(" DIR : ");
- Serial.println(file.name());
- if(levels){
- listDir(fs, file.name(), levels -1);
- }
- } else {
- Serial.print(" FILE: ");
- Serial.print(file.name());
- Serial.print("\tSIZE: ");
- Serial.println(file.size());
- }
- file = root.openNextFile();
- }
-
-
- }
-
- void playFile(fs::FS &fs, const char * path){
- Serial.printf("Playing file: %s\r\n", path);
-
- File file = fs.open(path);
- if(!file){
- Serial.println("- failed to open file for reading");
- return;
- }
-
- uint8_t buffer[1024*4];
- size_t bytessend;
- while(file.available()){
- bytessend=file.read(buffer, 1024*4);
- for (int i=0;i<1024*4;i++) {
- CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN1_M);
- SET_PERI_REG_BITS(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_DAC, buffer[i], RTC_IO_PDAC1_DAC_S);
- SET_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_XPD_DAC | RTC_IO_PDAC1_DAC_XPD_FORCE);
- ets_delay_us(125);
- }
- }
- file.close();
- }
- void setup() {
- Serial.begin(115200);
- if(!FFat.begin()){
- Serial.println("FFat Mount Failed");
- return;
- }
- Serial.printf("Total space: %10u\n", FFat.totalBytes());
- Serial.printf("Free space: %10u\n", FFat.freeBytes());
-
- listDir(FFat, "/", 0);
- }
-
- void loop() {
- playFile(FFat, "/1st.wav");
- playFile(FFat, "/10years.wav");
- playFile(FFat, "/1990.wav");
- }
复制代码
参考:
|