Arduino-esp32: Using i2s example fails build

Created on 13 Sep 2017  路  11Comments  路  Source: espressif/arduino-esp32

I can't build the i2s example code. If I change in i2s.h:

typedef struct {
    i2s_mode_t              mode;                   /*!< I2S work mode*/
    int                     sample_rate;            /*!< I2S sample rate*/
    i2s_bits_per_sample_t   bits_per_sample;        /*!< I2S bits per sample*/
    i2s_channel_fmt_t       channel_format;         /*!< I2S channel format */
    i2s_comm_format_t       communication_format;   /*!< I2S communication format */
    int                     intr_alloc_flags;       /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */
    int                     dma_buf_count;          /*!< I2S DMA Buffer Count */
    int                     dma_buf_len;            /*!< I2S DMA Buffer Length */
} i2s_config_t;

i2s_mode_t and i2s_comm_format_t to int. Then it builds and works.

Hardware:

Board: ESP32 Dev Module
Core Installation/update date: 12/Sep/2017
IDE name: Arduino IDE 1.8.3

Description:

Describe your problem here

Sketch:

#include "driver/i2s.h"

static const i2s_config_t i2s_config = {
     .mode = I2S_MODE_MASTER | I2S_MODE_TX,
     .sample_rate = 48000,
     .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
     .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //I2S_CHANNEL_FMT_RIGHT_LEFT,
     .communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
     .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority
     .dma_buf_count = 6,
     .dma_buf_len = 512
};

void setup() {
}

void loop() {
}

Debug Messages:

"C:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/xtensa-esp32-elf/bin/xtensa-esp32-elf-g++" -DESP_PLATFORM -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h" -DHAVE_CONFIG_H "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/config" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/bluedroid" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/app_trace" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/app_update" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/bootloader_support" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/bt" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/driver" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/esp32" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/ethernet" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/fatfs" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/freertos" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/heap" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/jsmn" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/log" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/mdns" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/mbedtls" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/mbedtls_port" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/newlib" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/nvs_flash" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/openssl" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/soc" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/spi_flash" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/sdmmc" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/tcpip_adapter" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/ulp" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/vfs" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/wear_levelling" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/xtensa-debug-module" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/newlib" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/coap" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/wpa_supplicant" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/expat" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/json" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/nghttp" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32/tools/sdk/include/lwip" -std=gnu++11 -fno-exceptions -fno-rtti -Os -g3 -Wpointer-arith -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -mlongcalls -nostdlib -Wall -Werror=all -Wno-error=unused-function -Wno-error=unused-but-set-variable -Wno-error=unused-variable -Wno-error=deprecated-declarations -Wno-unused-parameter -Wno-sign-compare -fno-rtti -MMD -c -DF_CPU=240000000L -DARDUINO=10803 -DARDUINO_ESP32_DEV -DARDUINO_ARCH_ESP32  -DESP32 -DCORE_DEBUG_LEVEL=0 "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32\cores\esp32" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32\variants\esp32" "-IC:\Users\jpmendoza\Documents\Arduino\libraries\SGTL5000" "-IC:\Users\jpmendoza\Documents\Arduino\hardware\espressif\esp32\libraries\Wire\src" "C:\Users\JPMEND~1\AppData\Local\Temp\arduino_build_937948\sketch\SDMMC_Test.ino.cpp" -o "C:\Users\JPMEND~1\AppData\Local\Temp\arduino_build_937948\sketch\SDMMC_Test.ino.cpp.o"
SDMMC_Test:37: error: invalid conversion from 'int' to 'i2s_mode_t' [-fpermissive]

 };

 ^

SDMMC_Test:37: error: invalid conversion from 'int' to 'i2s_comm_format_t' [-fpermissive]

exit status 1
invalid conversion from 'int' to 'i2s_mode_t' [-fpermissive]

stale

Most helpful comment

.mode = static_cast(I2S_MODE_MASTER | I2S_MODE_TX),

That equates to 5 which is not a valid (unscoped) enumeration (can be 1,2,4,8.16 or 64)

.communication_format = static_cast(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),

That equates to 3 which is also not a valid (unscoped) enumeration (can be 1,2,4,8,16 or 32)

Casting rules
Unscoped enum constants can be implicitly converted to int, but an int is never implicitly convertible to an enum value.

source

As you have shown, it must be explicitly cast to circumvent the typing system. This should not be required and is a code smell.

All 11 comments

I had the "i2s_mode_t" and "i2s_port_t" with this error too (using VS Code). The reason is the same for both - strict typing.

The "i2s_port_t" is caused by the definition in the Espressif reference example:
static const i2s_port_t i2s_num = 0; // i2s port number

Which is fixed by using the enumerated type (i2s_port_t) for port 0:
static const i2s_port_t i2s_num = I2S_NUM_0; // i2s port number

Mode is defined as an enum within the "i2s_config_t" structure and it will only compile, as is, with the permissive flag. Unless this flag is set one cannot combine the mode flags into a bit-field (hence the "int" which is the result of ORing multiple enums).
Either the mode field of "i2s_config_t should be an uint type to take a bit-field or one should only use one enumerated option. [I consider using fpermissive as an anti-pattern.]

@riataman did you try the extern C thing?

I did and it failed with the same error. A standard c cast (.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX)), didn't work either.

What worked at the end was this:

static const i2s_config_t i2s_config = {
  .mode = static_cast<i2s_mode_t>(I2S_MODE_MASTER | I2S_MODE_TX),
  .sample_rate = 44100,
  .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
  .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
  .communication_format = static_cast<i2s_comm_format_t>(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
  .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority
  .dma_buf_count = 3,
  .dma_buf_len = 512
};

.mode = static_cast(I2S_MODE_MASTER | I2S_MODE_TX),

That equates to 5 which is not a valid (unscoped) enumeration (can be 1,2,4,8.16 or 64)

.communication_format = static_cast(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),

That equates to 3 which is also not a valid (unscoped) enumeration (can be 1,2,4,8,16 or 32)

Casting rules
Unscoped enum constants can be implicitly converted to int, but an int is never implicitly convertible to an enum value.

source

As you have shown, it must be explicitly cast to circumvent the typing system. This should not be required and is a code smell.

Until the issue is fixed, i use following template:

template<typename Enum>  
Enum operator |(Enum lhs, Enum rhs)  
{
    return static_cast<Enum> (lhs | rhs);
} 

This way i can use the code from esp32 example as it is:

static const i2s_config_t i2s_config = {
     .mode = I2S_MODE_MASTER | I2S_MODE_TX,
     .sample_rate = 44100,
     .bits_per_sample = 16,
     .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
     .communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
     .intr_alloc_flags = 0, // default interrupt priority
     .dma_buf_count = 8,
     .dma_buf_len = 64,
     .use_apll = false
};

This example code from espidf cannot be plain copied to C++ code.
I solved this by copying the example code in a separate .c file (accompanied with a .h file) and declared a function in the .c file which does the talking to i2s.

This is an ancient, abandoned issue. There is now an example that demonstrates how to cast the field.

Tnx @lbernstone !!
However, how would one know that the well maintained repository https://github.com/espressif/esp-idf (which is recommended framework?!) contains examples that are 'not suitable for the job' ? Or am I confused about what the recommended framework is for ESP32 programming? Thought that Arduino framework was kinda 'nahh' ?

The examples in that repository work fine. They will not work with arduino; many are straight up incompatible with C++ without significant modifications.
The esp-idf framework is an official framework supported by espressif staff, for use with gcc. arduino-esp32 is community supported (with a lot of help from a single espressif employee).

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. Thank you for your contributions.

[STALE_DEL] This stale issue has been automatically closed. Thank you for your contributions.

Was this page helpful?
0 / 5 - 0 ratings