init
This commit is contained in:
Executable
+2
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "sd_card_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
menu "SD SPI Example Configuration"
|
||||
|
||||
config EXAMPLE_FORMAT_IF_MOUNT_FAILED
|
||||
bool "Format the card if mount failed"
|
||||
default n
|
||||
help
|
||||
If this config item is set, format_if_mount_failed will be set to true and the card will be formatted if
|
||||
the mount has failed.
|
||||
|
||||
config EXAMPLE_PIN_MOSI
|
||||
int "MOSI GPIO number"
|
||||
default 15 if IDF_TARGET_ESP32
|
||||
default 35 if IDF_TARGET_ESP32S2
|
||||
default 35 if IDF_TARGET_ESP32S3
|
||||
default 5 if IDF_TARGET_ESP32H2
|
||||
default 4 # C3 and others
|
||||
|
||||
config EXAMPLE_PIN_MISO
|
||||
int "MISO GPIO number"
|
||||
default 2 if IDF_TARGET_ESP32
|
||||
default 37 if IDF_TARGET_ESP32S2
|
||||
default 37 if IDF_TARGET_ESP32S3
|
||||
default 0 if IDF_TARGET_ESP32H2
|
||||
default 6 # C3 and others
|
||||
|
||||
config EXAMPLE_PIN_CLK
|
||||
int "CLK GPIO number"
|
||||
default 14 if IDF_TARGET_ESP32
|
||||
default 36 if IDF_TARGET_ESP32S2
|
||||
default 36 if IDF_TARGET_ESP32S3
|
||||
default 4 if IDF_TARGET_ESP32H2
|
||||
default 5 # C3 and others
|
||||
|
||||
config EXAMPLE_PIN_CS
|
||||
int "CS GPIO number"
|
||||
default 13 if IDF_TARGET_ESP32
|
||||
default 34 if IDF_TARGET_ESP32S2
|
||||
default 34 if IDF_TARGET_ESP32S3
|
||||
default 1 # C3 and others
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,17 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_io_expander_tca95xx_16bit: "^1.0.1"
|
||||
## Required IDF version
|
||||
idf:
|
||||
version: ">=4.1.0"
|
||||
# # Put list of dependencies here
|
||||
# # For components maintained by Espressif:
|
||||
# component: "~1.0.0"
|
||||
# # For 3rd party components:
|
||||
# username/component: ">=1.0.0,<2.0.0"
|
||||
# username2/component2:
|
||||
# version: "~1.0.0"
|
||||
# # For transient dependencies `public` flag can be set.
|
||||
# # `public` flag doesn't have an effect dependencies of the `main` component.
|
||||
# # All dependencies of `main` are public by default.
|
||||
# public: true
|
||||
Executable
+230
@@ -0,0 +1,230 @@
|
||||
/* SD card and FAT filesystem example.
|
||||
This example uses SPI peripheral to communicate with SD card.
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include "esp_vfs_fat.h"
|
||||
#include "sdmmc_cmd.h"
|
||||
#include "esp_io_expander_tca95xx_16bit.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "driver/i2s_pdm.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
|
||||
|
||||
#define EXAMPLE_PDM_TX_CLK_IO GPIO_NUM_13 // I2S PDM TX clock io number
|
||||
#define EXAMPLE_PDM_TX_DOUT_IO GPIO_NUM_12 // I2S PDM TX data out io number
|
||||
|
||||
#define EXAMPLE_PDM_TX_FREQ_HZ 44100 // I2S PDM TX frequency
|
||||
#define EXAMPLE_WAVE_AMPLITUDE (20000.0) // 1~32767
|
||||
#define CONST_PI (3.1416f)
|
||||
#define EXAMPLE_SINE_WAVE_LEN(tone) (uint32_t)((EXAMPLE_PDM_TX_FREQ_HZ / (float)tone) + 0.5) // The sample point number per sine wave to generate the tone
|
||||
#define EXAMPLE_TONE_LAST_TIME_MS 500
|
||||
#define EXAMPLE_BYTE_NUM_EVERY_TONE (EXAMPLE_TONE_LAST_TIME_MS * EXAMPLE_PDM_TX_FREQ_HZ / 1000)
|
||||
|
||||
|
||||
#define EXAMPLE_MAX_CHAR_SIZE 64
|
||||
|
||||
static const char *TAG = "example";
|
||||
|
||||
#define MOUNT_POINT "/sdcard"
|
||||
|
||||
// Pin assignments can be set in menuconfig, see "SD SPI Example Configuration" menu.
|
||||
// You can also change the pin assignments here by changing the following 4 lines.
|
||||
#define PIN_NUM_MISO CONFIG_EXAMPLE_PIN_MISO
|
||||
#define PIN_NUM_MOSI CONFIG_EXAMPLE_PIN_MOSI
|
||||
#define PIN_NUM_CLK CONFIG_EXAMPLE_PIN_CLK
|
||||
#define PIN_NUM_CS CONFIG_EXAMPLE_PIN_CS
|
||||
|
||||
#define AUDIO_BUFFER 2048
|
||||
|
||||
|
||||
|
||||
i2s_chan_handle_t tx_handle = NULL;
|
||||
|
||||
esp_io_expander_handle_t io_expander = NULL;
|
||||
|
||||
void init_io_expander() {
|
||||
i2c_port_t i2c_master_port = I2C_NUM_0;
|
||||
i2c_config_t conf = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = 4,
|
||||
.scl_io_num = 5,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE
|
||||
};
|
||||
conf.master.clk_speed = 100000;
|
||||
|
||||
i2c_param_config(i2c_master_port, &conf);
|
||||
i2c_driver_install(i2c_master_port, conf.mode, 0, 0, 0);
|
||||
|
||||
esp_io_expander_new_i2c_tca95xx_16bit(I2C_NUM_0, ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_000, &io_expander);
|
||||
esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_11 | IO_EXPANDER_PIN_NUM_12 | IO_EXPANDER_PIN_NUM_13, IO_EXPANDER_OUTPUT);
|
||||
esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1 | IO_EXPANDER_PIN_NUM_2 | IO_EXPANDER_PIN_NUM_3, IO_EXPANDER_OUTPUT);
|
||||
esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_11 | IO_EXPANDER_PIN_NUM_12 | IO_EXPANDER_PIN_NUM_13, 1);
|
||||
esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_0 | IO_EXPANDER_PIN_NUM_1 | IO_EXPANDER_PIN_NUM_2 | IO_EXPANDER_PIN_NUM_3, 1);
|
||||
esp_io_expander_set_level(io_expander, IO_EXPANDER_PIN_NUM_1, 0);
|
||||
}
|
||||
|
||||
|
||||
esp_err_t play_wav(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);
|
||||
|
||||
// create a writer buffer
|
||||
int16_t *buf = 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);
|
||||
|
||||
// i2s_channel_enable(tx_handle);
|
||||
|
||||
while (bytes_read > 0)
|
||||
{
|
||||
// write the buffer to the i2s
|
||||
i2s_channel_write(tx_handle, buf, bytes_read * sizeof(int16_t), &bytes_written, portMAX_DELAY);
|
||||
bytes_read = fread(buf, sizeof(int16_t), AUDIO_BUFFER, fh);
|
||||
ESP_LOGV(TAG, "Bytes read: %d", bytes_read);
|
||||
}
|
||||
|
||||
i2s_channel_disable(tx_handle);
|
||||
free(buf);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
static i2s_chan_handle_t i2s_example_init_pdm_tx(void)
|
||||
{
|
||||
i2s_chan_handle_t tx_chan; // I2S tx channel handler
|
||||
/* Setp 1: Determine the I2S channel configuration and allocate TX channel only
|
||||
* The default configuration can be generated by the helper macro,
|
||||
* it only requires the I2S controller id and I2S role,
|
||||
* but note that PDM channel can only be registered on I2S_NUM_0 */
|
||||
i2s_chan_config_t tx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
|
||||
tx_chan_cfg.auto_clear = true;
|
||||
ESP_ERROR_CHECK(i2s_new_channel(&tx_chan_cfg, &tx_chan, NULL));
|
||||
|
||||
/* Step 2: Setting the configurations of PDM TX mode and initialize the TX channel
|
||||
* The slot configuration and clock configuration can be generated by the macros
|
||||
* These two helper macros is defined in 'i2s_pdm.h' which can only be used in PDM TX mode.
|
||||
* They can help to specify the slot and clock configurations for initialization or re-configuring */
|
||||
i2s_pdm_tx_config_t pdm_tx_cfg = {
|
||||
.clk_cfg = I2S_PDM_TX_CLK_DEFAULT_CONFIG(EXAMPLE_PDM_TX_FREQ_HZ),
|
||||
/* The data bit-width of PDM mode is fixed to 16 */
|
||||
.slot_cfg = I2S_PDM_TX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
|
||||
.gpio_cfg = {
|
||||
.clk = EXAMPLE_PDM_TX_CLK_IO,
|
||||
.dout = EXAMPLE_PDM_TX_DOUT_IO,
|
||||
.invert_flags = {
|
||||
.clk_inv = false,
|
||||
},
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(i2s_channel_init_pdm_tx_mode(tx_chan, &pdm_tx_cfg));
|
||||
|
||||
/* Step 3: Enable the tx channel before writing data */
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(tx_chan));
|
||||
|
||||
return tx_chan;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
init_io_expander();
|
||||
esp_err_t ret;
|
||||
|
||||
// Options for mounting the filesystem.
|
||||
// If format_if_mount_failed is set to true, SD card will be partitioned and
|
||||
// formatted in case when mounting fails.
|
||||
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
|
||||
.format_if_mount_failed = true,
|
||||
.max_files = 5,
|
||||
.allocation_unit_size = 16 * 1024
|
||||
};
|
||||
sdmmc_card_t *card;
|
||||
const char mount_point[] = MOUNT_POINT;
|
||||
ESP_LOGI(TAG, "Initializing SD card");
|
||||
|
||||
// Use settings defined above to initialize SD card and mount FAT filesystem.
|
||||
// Note: esp_vfs_fat_sdmmc/sdspi_mount is all-in-one convenience functions.
|
||||
// Please check its source code and implement error recovery when developing
|
||||
// production applications.
|
||||
ESP_LOGI(TAG, "Using SPI peripheral");
|
||||
|
||||
// By default, SD card frequency is initialized to SDMMC_FREQ_DEFAULT (20MHz)/
|
||||
// For setting a specific frequency, use host.max_freq_khz (range 400kHz - 20MHz for SDSPI)
|
||||
// Example: for fixed frequency of 10MHz, use host.max_freq_khz = 10000;
|
||||
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
|
||||
|
||||
spi_bus_config_t bus_cfg = {
|
||||
.mosi_io_num = PIN_NUM_MOSI,
|
||||
.miso_io_num = PIN_NUM_MISO,
|
||||
.sclk_io_num = PIN_NUM_CLK,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = 4000,
|
||||
};
|
||||
ret = spi_bus_initialize(host.slot, &bus_cfg, SDSPI_DEFAULT_DMA);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to initialize bus.");
|
||||
return;
|
||||
}
|
||||
|
||||
// This initializes the slot without card detect (CD) and write protect (WP) signals.
|
||||
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
|
||||
sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
|
||||
slot_config.gpio_cs = PIN_NUM_CS;
|
||||
slot_config.host_id = host.slot;
|
||||
|
||||
ESP_LOGI(TAG, "Mounting filesystem");
|
||||
ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
if (ret == ESP_FAIL) {
|
||||
ESP_LOGE(TAG, "Failed to mount filesystem. "
|
||||
"If you want the card to be formatted, set the CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to initialize the card (%s). "
|
||||
"Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
|
||||
}
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "Filesystem mounted");
|
||||
|
||||
// Card has been initialized, print its properties
|
||||
sdmmc_card_print_info(stdout, card);
|
||||
|
||||
tx_handle = i2s_example_init_pdm_tx();
|
||||
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(play_wav("/sdcard/audio.wav"));
|
||||
|
||||
|
||||
// All done, unmount partition and disable SPI peripheral
|
||||
esp_vfs_fat_sdcard_unmount(mount_point, card);
|
||||
ESP_LOGI(TAG, "Card unmounted");
|
||||
|
||||
//deinitialize the bus after all devices are removed
|
||||
spi_bus_free(host.slot);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user