working I2S DAC

This commit is contained in:
2021-09-14 22:03:30 +02:00
parent 9769c5f7c9
commit 42581b0ec5
12 changed files with 50346 additions and 35 deletions

11
FW/m5stack_audio/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,11 @@
{
"files.associations": {
"array": "cpp",
"deque": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"initializer_list": "cpp"
}
}

Binary file not shown.

View File

@@ -0,0 +1 @@
test_test_test

View File

@@ -0,0 +1,2 @@
Import("env")
env.Replace( MKSPIFFSTOOL=env.get("PROJECT_DIR") + '/mklittlefs' )

BIN
FW/m5stack_audio/mklittlefs Executable file

Binary file not shown.

View File

@@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
ota_0, app, ota_0, 0x10000, 0x1A0000,
ota_1, app, ota_1, , 0x1A0000,
otadata, data, ota, 0x350000, 0x2000,
nvs, data, nvs, , 0x6000,
data, data, spiffs, , 0xA8000,
1 # Name Type SubType Offset Size Flags
2 ota_0 app ota_0 0x10000 0x1A0000
3 ota_1 app ota_1 0x1A0000
4 otadata data ota 0x350000 0x2000
5 nvs data nvs 0x6000
6 data data spiffs 0xA8000

View File

@@ -10,9 +10,13 @@
[env:m5stack-core2] [env:m5stack-core2]
platform = espressif32 platform = espressif32
board = m5stack-core2 board = esp-wrover-kit
framework = arduino framework = arduino
lib_deps = lib_deps =
earlephilhower/ESP8266Audio@^1.9.2 earlephilhower/ESP8266Audio@^1.9.2
m5stack/M5Core2@^0.0.6 ;m5stack/M5Core2@^0.0.6
https://github.com/lorol/LITTLEFS.git
monitor_speed = 115200 monitor_speed = 115200
lib_ldf_mode = deep+
extra_scripts = ./littlefsbuilder.py

View File

@@ -1,55 +1,96 @@
#pragma mark - Depend ESP8266Audio and ESP8266_Spiram libraries #include <Arduino.h>
/*
cd ~/Arduino/libraries
git clone https://github.com/earlephilhower/ESP8266Audio
git clone https://github.com/Gianbacchio/ESP8266_Spiram
*/
#include "AudioFileSourcePROGMEM.h"
#include <M5Core2.h> #include <AudioFileSourceLittleFS.h>
#include <driver/i2s.h> //#include "AudioGeneratorWAV.h"
#include <WiFi.h>
#include "AudioFileSourceSD.h"
#include "AudioFileSourceID3.h"
#include "AudioGeneratorMP3.h" #include "AudioGeneratorMP3.h"
#include "AudioFileSourceID3.h"
#include "AudioOutputI2S.h" #include "AudioOutputI2S.h"
#include "storage.h"
// VIOLA sample taken from https://ccrma.stanford.edu/~jos/pasp/Sound_Examples.html
#include "viola.h"
//AudioGeneratorWAV *wav;
AudioGeneratorMP3 *mp3; AudioGeneratorMP3 *mp3;
AudioFileSourceSD *file;
AudioOutputI2S *out;
AudioFileSourceID3 *id3; AudioFileSourceID3 *id3;
#define OUTPUT_GAIN 30 AudioFileSourceLittleFS *file;
AudioOutputI2S *out;
const char *waveFile = "/003_short.mp3";
// Called when a metadata event occurs (i.e. an ID3 tag, an ICY block, etc.
void MDCallback(void *cbData, const char *type, bool isUnicode, const char *string)
{
(void)cbData;
Serial.printf("ID3 callback for: %s = '", type);
if (isUnicode)
{
string += 2;
}
while (*string)
{
char a = *(string++);
if (isUnicode)
{
string++;
}
Serial.printf("%c", a);
}
Serial.printf("'\n");
Serial.flush();
}
// Called when there's a warning or error (like a buffer underflow or decode hiccup)
void StatusCallback(void *cbData, int code, const char *string)
{
const char *ptr = reinterpret_cast<const char *>(cbData);
// Note that the string may be in PROGMEM, so copy it to RAM for printf
char s1[64];
strncpy_P(s1, string, sizeof(s1));
s1[sizeof(s1)-1]=0;
Serial.printf("STATUS(%s) '%d' = '%s'\n", ptr, code, s1);
Serial.flush();
}
void setup() void setup()
{ {
M5.begin(); Serial.begin(115200);
M5.Axp.SetSpkEnable(true); delay(1000);
WiFi.mode(WIFI_OFF); initStorage();
delay(500);
M5.Lcd.setTextFont(2);
M5.Lcd.printf("Sample MP3 playback begins...\n");
Serial.printf("Sample MP3 playback begins...\n");
file = new AudioFileSourceSD("/003.mp3"); audioLogger = &Serial;
file = new AudioFileSourceLittleFS(waveFile);
id3 = new AudioFileSourceID3(file); id3 = new AudioFileSourceID3(file);
out = new AudioOutputI2S(0, 0); // Output to builtInDAC id3->RegisterMetadataCB(MDCallback, (void *)"ID3TAG");
out->SetPinout(12, 0, 2);
out->SetOutputModeMono(true);
out->SetGain((float)OUTPUT_GAIN/100.0);
mp3 = new AudioGeneratorMP3(); mp3 = new AudioGeneratorMP3();
mp3->RegisterStatusCB(StatusCallback, (void*)"mp3");
out = new AudioOutputI2S();
out->SetPinout(21, 13, 14); //bclk, wclk, data
mp3->begin(id3, out); mp3->begin(id3, out);
out->SetGain(0.25);
} }
void loop() void loop()
{ {
if (mp3->isRunning()) { if (mp3->isRunning())
if (!mp3->loop()) mp3->stop(); {
} else { if (!mp3->loop())
Serial.printf("MP3 done\n"); {
mp3->stop();
}
}
else
{
Serial.printf("sound done\n");
delay(1000); delay(1000);
} }
} }

View File

@@ -0,0 +1,343 @@
#include "storage.h"
#include <Arduino.h>
#include "FS.h"
#include <LITTLEFS.h>
#ifndef CONFIG_LITTLEFS_FOR_IDF_3_2
#include <time.h>
#endif
/* You only need to format LITTLEFS the first time you run a
test or else use the LITTLEFS plugin to create a partition
https://github.com/lorol/arduino-esp32littlefs-plugin */
#define FORMAT_LITTLEFS_IF_FAILED false
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 : ");
#ifdef CONFIG_LITTLEFS_FOR_IDF_3_2
Serial.println(file.name());
#else
Serial.print(file.name());
time_t t = file.getLastWrite();
struct tm *tmstruct = localtime(&t);
Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec);
#endif
if (levels)
{
listDir(fs, file.name(), levels - 1);
}
}
else
{
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
#ifdef CONFIG_LITTLEFS_FOR_IDF_3_2
Serial.println(file.size());
#else
Serial.print(file.size());
time_t t = file.getLastWrite();
struct tm *tmstruct = localtime(&t);
Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec);
#endif
}
file = root.openNextFile();
}
}
void createDir(fs::FS &fs, const char *path)
{
Serial.printf("Creating Dir: %s\n", path);
if (fs.mkdir(path))
{
Serial.println("Dir created");
}
else
{
Serial.println("mkdir failed");
}
}
void removeDir(fs::FS &fs, const char *path)
{
Serial.printf("Removing Dir: %s\n", path);
if (fs.rmdir(path))
{
Serial.println("Dir removed");
}
else
{
Serial.println("rmdir failed");
}
}
void readFile(fs::FS &fs, const char *path)
{
Serial.printf("Reading file: %s\r\n", path);
File file = fs.open(path);
if (!file || file.isDirectory())
{
Serial.println("- failed to open file for reading");
return;
}
Serial.println("- read from file:");
while (file.available())
{
Serial.write(file.read());
}
file.close();
}
void writeFile(fs::FS &fs, const char *path, const char *message)
{
Serial.printf("Writing file: %s\r\n", path);
File file = fs.open(path, FILE_WRITE);
if (!file)
{
Serial.println("- failed to open file for writing");
return;
}
if (file.print(message))
{
Serial.println("- file written");
}
else
{
Serial.println("- write failed");
}
file.close();
}
void appendFile(fs::FS &fs, const char *path, const char *message)
{
Serial.printf("Appending to file: %s\r\n", path);
File file = fs.open(path, FILE_APPEND);
if (!file)
{
Serial.println("- failed to open file for appending");
return;
}
if (file.print(message))
{
Serial.println("- message appended");
}
else
{
Serial.println("- append failed");
}
file.close();
}
void renameFile(fs::FS &fs, const char *path1, const char *path2)
{
Serial.printf("Renaming file %s to %s\r\n", path1, path2);
if (fs.rename(path1, path2))
{
Serial.println("- file renamed");
}
else
{
Serial.println("- rename failed");
}
}
void deleteFile(fs::FS &fs, const char *path)
{
Serial.printf("Deleting file: %s\r\n", path);
if (fs.remove(path))
{
Serial.println("- file deleted");
}
else
{
Serial.println("- delete failed");
}
}
// SPIFFS-like write and delete file, better use #define CONFIG_LITTLEFS_SPIFFS_COMPAT 1
void writeFile2(fs::FS &fs, const char *path, const char *message)
{
if (!fs.exists(path))
{
if (strchr(path, '/'))
{
Serial.printf("Create missing folders of: %s\r\n", path);
char *pathStr = strdup(path);
if (pathStr)
{
char *ptr = strchr(pathStr, '/');
while (ptr)
{
*ptr = 0;
fs.mkdir(pathStr);
*ptr = '/';
ptr = strchr(ptr + 1, '/');
}
}
free(pathStr);
}
}
Serial.printf("Writing file to: %s\r\n", path);
File file = fs.open(path, FILE_WRITE);
if (!file)
{
Serial.println("- failed to open file for writing");
return;
}
if (file.print(message))
{
Serial.println("- file written");
}
else
{
Serial.println("- write failed");
}
file.close();
}
void deleteFile2(fs::FS &fs, const char *path)
{
Serial.printf("Deleting file and empty folders on path: %s\r\n", path);
if (fs.remove(path))
{
Serial.println("- file deleted");
}
else
{
Serial.println("- delete failed");
}
char *pathStr = strdup(path);
if (pathStr)
{
char *ptr = strrchr(pathStr, '/');
if (ptr)
{
Serial.printf("Removing all empty folders on path: %s\r\n", path);
}
while (ptr)
{
*ptr = 0;
fs.rmdir(pathStr);
ptr = strrchr(pathStr, '/');
}
free(pathStr);
}
}
void testFileIO(fs::FS &fs, const char *path)
{
Serial.printf("Testing file I/O with %s\r\n", path);
static uint8_t buf[512];
size_t len = 0;
File file = fs.open(path, FILE_WRITE);
if (!file)
{
Serial.println("- failed to open file for writing");
return;
}
size_t i;
Serial.print("- writing");
uint32_t start = millis();
for (i = 0; i < 2048; i++)
{
if ((i & 0x001F) == 0x001F)
{
Serial.print(".");
}
file.write(buf, 512);
}
Serial.println("");
uint32_t end = millis() - start;
Serial.printf(" - %u bytes written in %u ms\r\n", 2048 * 512, end);
file.close();
file = fs.open(path);
start = millis();
end = start;
i = 0;
if (file && !file.isDirectory())
{
len = file.size();
size_t flen = len;
start = millis();
Serial.print("- reading");
while (len)
{
size_t toRead = len;
if (toRead > 512)
{
toRead = 512;
}
file.read(buf, toRead);
if ((i++ & 0x001F) == 0x001F)
{
Serial.print(".");
}
len -= toRead;
}
Serial.println("");
end = millis() - start;
Serial.printf("- %u bytes read in %u ms\r\n", flen, end);
file.close();
}
else
{
Serial.println("- failed to open file for reading");
}
}
void initStorage()
{
if (!LITTLEFS.begin(FORMAT_LITTLEFS_IF_FAILED))
{
Serial.println("LITTLEFS Mount Failed");
return;
}
listDir(LITTLEFS, "/", 0);
//testFileIO(LITTLEFS, "/test.txt");
//listDir(LITTLEFS, "/", 0);
//deleteFile(LITTLEFS, "/test.txt");
Serial.println("Test complete");
}
void handleStorage()
{
}

View File

@@ -0,0 +1,5 @@
#pragma once
void initStorage();

49898
FW/m5stack_audio/src/viola.h Normal file

File diff suppressed because it is too large Load Diff

BIN
Tunes/003_short.mp3 Normal file

Binary file not shown.