Preliminary speaker driver changes

This commit is contained in:
Mitchell Marino 2025-03-25 23:49:46 -05:00
parent 42aa5fa315
commit babe2f828e
13 changed files with 99 additions and 89 deletions

View File

@ -1,53 +1,9 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | Linux |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | ----- |
# BLK_BOX_TC
# Hello World Example
ESP-IDF version `v5.3.2`
Starts a FreeRTOS task to print "Hello World".
Firmware for the BLK_BOX Top control board for the puzzle `PDE001`.
(See the README.md file in the upper level 'examples' directory for more information about examples.)
Convert audio files to 44100Hz mono signed 16 uncompressed .wav files with the following command:
```ffmpeg -i input.mp3 -ac 1 -ar 44100 -sample_fmt s16 output.wav```
## How to use example
Follow detailed instructions provided specifically for this example.
Select the instructions depending on Espressif chip installed on your development board:
- [ESP32 Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/index.html)
- [ESP32-S2 Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/get-started/index.html)
## Example folder contents
The project **hello_world** contains one source file in C language [hello_world_main.c](main/hello_world_main.c). The file is located in folder [main](main).
ESP-IDF projects are built using CMake. The project build configuration is contained in `CMakeLists.txt` files that provide set of directives and instructions describing the project's source files and targets (executable, library, or both).
Below is short explanation of remaining files in the project folder.
```
├── CMakeLists.txt
├── pytest_hello_world.py Python script used for automated testing
├── main
│ ├── CMakeLists.txt
│ └── hello_world_main.c
└── README.md This is the file you are currently reading
```
For more information on structure and contents of ESP-IDF projects, please refer to Section [Build System](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html) of the ESP-IDF Programming Guide.
## Troubleshooting
* Program upload failure
* Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs.
* The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again.
## Technical support and feedback
Please use the following feedback channels:
* For technical queries, go to the [esp32.com](https://esp32.com/) forum
* For a feature request or bug report, create a [GitHub issue](https://github.com/espressif/esp-idf/issues)
We will get back to you as soon as possible.

View File

@ -11,7 +11,9 @@ void init_drivers() {
init_bottom_half();
init_sd();
init_speaker();
init_sseg();
init_game_timers();
}
/// @brief Initializes I2C_NUM_0.

View File

@ -6,16 +6,16 @@
// #include "drivers/tft.h"
// #include "drivers/wires.h"
// #include "drivers/sd.h"
// #include "drivers/game_timer.h"
// #include "drivers/speaker.h"
// #include "drivers/char_lcd.h"
// #include "drivers/leds.h"
// #include "drivers/power.h"
#include "char_lcd.h"
#include "drivers/bottom_half.h"
#include "bottom_half.h"
#include "sd.h"
#include "speaker.h"
#include "game_timer.h"
void init_drivers();

View File

@ -1,4 +1,5 @@
#include "bottom_half.h"
#include <esp_log.h>
static const char *TAG = "bottom_half";

View File

@ -3,7 +3,6 @@
#include "driver/i2c.h"
#include "driver/gpio.h"
#include "esp_log.h"
#define BOTTOM_I2C_NUM I2C_NUM_0
#define BOTTOM_I2C_ADDR 126

View File

@ -1,4 +1,7 @@
#include "game_timer.h"
#include <esp_log.h>
static const char* TAG = "game_timer";
static bool is_module_playing;
static bool is_game_playing;
@ -12,6 +15,14 @@ static uint32_t module_time_left;
static void game_timer_task(void *arg);
static uint32_t sat_sub(uint32_t x, uint32_t y);
void init_game_timers() {
ESP_LOGI(TAG, "Initializing game timers...");
xTaskCreate(game_timer_task, "game_timers", 4096, NULL, 10, NULL);
ESP_LOGI(TAG, "Game timers initialized!");
}
static void write_game_time(uint32_t millis) {
if (millis > 60'000) {
int disp_time = (millis / 60'000) * 100;
@ -31,23 +42,19 @@ static void write_module_time(uint32_t millis) {
}
}
void init_game_module_timer(void) {
xTaskCreate(game_timer_task, "game_module_timer", 4096, NULL, 10, NULL);
}
void start_game_timer(void) {
void start_game_timer() {
is_game_playing = true;
}
void stop_game_timer(void) {
void stop_game_timer() {
is_game_playing = false;
}
void start_module_timer(void) {
void start_module_timer() {
is_module_playing = true;
}
void stop_module_timer(void) {
void stop_module_timer() {
is_module_playing = false;
}
@ -91,8 +98,7 @@ void time_penalty(uint32_t penalty) {
}
}
static void game_timer_task(void *arg)
{
static void game_timer_task(void *arg) {
TickType_t lastWakeTime = xTaskGetTickCount();
const uint32_t frequency = 100;
@ -118,8 +124,7 @@ static void game_timer_task(void *arg)
vTaskDelete(NULL);
}
static uint32_t sat_sub(uint32_t x, uint32_t y)
{
static uint32_t sat_sub(uint32_t x, uint32_t y) {
uint32_t res = x - y;
res &= -(res <= x);
return res;

View File

@ -5,17 +5,17 @@
#include "sseg.h"
/// Initializes the game and module timers.
void init_game_module_timer(void);
void init_game_timers();
/// Starts the game timer
void start_game_timer(void);
void start_game_timer();
/// Stops the game timer
void stop_game_timer(void);
void stop_game_timer();
/// Starts the module timer
void start_module_timer(void);
void start_module_timer();
/// Stops the module timer
void stop_module_timer(void);
void stop_module_timer();
/// Sets the game time in ms
void set_game_time(int32_t new_time);

View File

@ -22,8 +22,10 @@ extern sdmmc_card_t *card;
/// @brief Initializes the SD card
///
/// This requires the char_lcd to have been initialized.
/// @return
/// @return true if the sd card was successfully initialized
bool init_sd();
/// @brief Unmounts the sd card
void deinit_sd();
#endif /* SD_H */

View File

@ -57,9 +57,48 @@ esp_err_t play_raw_stop_queue(const char *fp, QueueHandle_t stop_handle) {
return ESP_OK;
}
esp_err_t play_wav(const char *fp) {
FILE *fh = fopen(fp, "rb");
if (fh == NULL) {
ESP_LOGE(TAG, "Failed to open file");
return ESP_ERR_INVALID_ARG;
}
// skip the header...
fseek(fh, 44, SEEK_SET);
int16_t *buf = (int16_t*) calloc(AUDIO_BUFFER, sizeof(int16_t));
size_t bytes_read = 0;
size_t bytes_written = 0;
bytes_read = fread(buf, sizeof(int16_t), AUDIO_BUFFER, fh);
for (int i = 0; i < bytes_read; i++) {
buf[i] = buf[i] >> 2;
}
i2s_channel_preload_data(tx_chan, buf, bytes_read * sizeof(int16_t), &bytes_written);
i2s_channel_enable(tx_chan);
while (bytes_read > 0)
{
bytes_read = fread(buf, sizeof(int16_t), AUDIO_BUFFER, fh);
for (int i = 0; i < bytes_read; i++) {
buf[i] = buf[i] >> 2;
}
// write the buffer to the i2s
i2s_channel_write(tx_chan, buf, bytes_read * sizeof(int16_t), &bytes_written, portMAX_DELAY);
// ESP_LOGI(TAG, "Bytes read: %d", bytes_read);
}
i2s_channel_disable(tx_chan);
free(buf);
return ESP_OK;
}
esp_err_t play_raw(const char *fp) {
FILE *fh = fopen(fp, "rb");
if (fh == NULL)
if (fh == NULL) {
ESP_LOGE(TAG, "Failed to open file");
return ESP_ERR_INVALID_ARG;
}
@ -70,18 +109,17 @@ esp_err_t play_raw(const char *fp) {
size_t bytes_read = 0;
size_t bytes_written = 0;
esp_err_t channel_enable_result = i2s_channel_enable(tx_chan);
ESP_ERROR_CHECK_WITHOUT_ABORT(channel_enable_result);
if (channel_enable_result != ESP_OK) {
return channel_enable_result;
}
bytes_read = fread(read_buf, sizeof(uint8_t), AUDIO_BUFFER, fh);
for (int i = 0; i < bytes_read; i++) {
write_buf[i] = read_buf[i] << 4;
}
// i2s_channel_enable(tx_handle);
i2s_channel_preload_data(tx_chan, write_buf, bytes_read * sizeof(int16_t), &bytes_written);
esp_err_t channel_enable_result = i2s_channel_enable(tx_chan);
ESP_ERROR_CHECK_WITHOUT_ABORT(channel_enable_result);
if (channel_enable_result != ESP_OK) {
return channel_enable_result;
}
while (bytes_read > 0) {
// write the buffer to the i2s
@ -90,12 +128,12 @@ esp_err_t play_raw(const char *fp) {
// int16_t val = buf[i];
// printf("%s0x%04X ", (val < 0 ? "-" : "+"), (val < 0 ? -val : val));
// }>
i2s_channel_write(tx_chan, write_buf, bytes_read * sizeof(int16_t), &bytes_written, portMAX_DELAY);
bytes_read = fread(read_buf, sizeof(uint8_t), AUDIO_BUFFER, fh);
for (int i = 0; i < bytes_read; i++) {
write_buf[i] = read_buf[i] << 4;
}
vTaskDelay(pdMS_TO_TICKS(10));
i2s_channel_write(tx_chan, write_buf, bytes_read * sizeof(int16_t), &bytes_written, portMAX_DELAY);
}
i2s_channel_disable(tx_chan);
@ -130,6 +168,9 @@ void init_speaker(void) {
};
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_chan, &tx_std_cfg));
ESP_ERROR_CHECK_WITHOUT_ABORT(play_wav("/sdcard/startup.wav"));
ESP_ERROR_CHECK_WITHOUT_ABORT(play_raw("/sdcard/boot.pcm"));
ESP_LOGI(TAG, "Speaker initialized!");
}

View File

@ -26,7 +26,8 @@ extern i2s_chan_handle_t tx_chan;
esp_err_t play_raw_stop_queue(const char *fp, QueueHandle_t stop_handle);
esp_err_t play_raw(const char *fp);
void init_speaker(void);
/// @brief Initalizes the speaker
void init_speaker();
void play_example();
#endif /* SPEAKER_H */

View File

@ -1,11 +1,16 @@
#include "sseg.h"
#include "esp_log.h"
TM1640* sseg = nullptr;
static const char *TAG = "sseg_driver";
static const char *TAG = "sseg";
void init_sseg() {
ESP_LOGI(TAG, "Initializing sseg...");
sseg = new TM1640(SSEG_PIN_DATA, SSEG_PIN_CLK, 8);
ESP_LOGI(TAG, "Sseg initialized!");
}
void set_game_sseg_raw(const uint8_t* digits) {
@ -22,7 +27,7 @@ void set_module_sseg_raw(const uint8_t* digits) {
sseg->setSegments(digits[3], 7);
}
void set_game_sseg_num(unsigned int value, int dot_pos) {
void set_game_sseg_num(uint32_t value, uint8_t dot_pos) {
for (int i = 0; i < 4; i++) {
auto idx = value % 10;
sseg->sendChar(3-i, TM16XX_NUMBER_FONT[idx], i == dot_pos);
@ -30,7 +35,7 @@ void set_game_sseg_num(unsigned int value, int dot_pos) {
}
}
void set_module_sseg_num(unsigned int value, int dot_pos) {
void set_module_sseg_num(uint32_t value, uint8_t dot_pos) {
for (int i = 0; i < 4; i++) {
auto idx = value % 10;
sseg->sendChar(7-i, TM16XX_NUMBER_FONT[idx], i == dot_pos);

View File

@ -27,9 +27,9 @@ void set_game_sseg_raw(const uint8_t* digits);
void set_module_sseg_raw(const uint8_t* digits);
/// sets the game timer to the given number, with the dot at position `dot_pos` from the right (0 => right-most digit).
void set_game_sseg_num(unsigned int value, int dot_pos);
void set_game_sseg_num(uint32_t value, uint8_t dot_pos);
/// sets the module timer to the given number, with the dot at position `dot_pos` from the right (0 => right-most digit).
void set_module_sseg_num(unsigned int value, int dot_pos);
void set_module_sseg_num(uint32_t value, uint8_t dot_pos);
#endif /* SSEG_H */

View File

@ -25,8 +25,6 @@ extern "C" void app_main(void) {
init_drivers();
init_tft();
init_sseg();
init_game_module_timer();
init_leds();
init_wires();
init_power_board();