From 02b05ac0ba5d3f8127d9079bb88c0103cabb952a Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Mon, 22 Jan 2024 11:57:19 +0100 Subject: [PATCH 1/4] Initial: I2S support --- cores/arduino/IRQManager.cpp | 33 ++++++++++++++++++++++++++++ cores/arduino/IRQManager.h | 12 +++++++++- variants/PORTENTA_C33/pins_arduino.h | 1 + 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/cores/arduino/IRQManager.cpp b/cores/arduino/IRQManager.cpp index 4d9e6e1e8..ef765bc49 100644 --- a/cores/arduino/IRQManager.cpp +++ b/cores/arduino/IRQManager.cpp @@ -23,6 +23,7 @@ #define ADC_PRIORITY 12 #define CAN_PRIORITY 12 #define CANFD_PRIORITY 12 +#define I2S_PRIORITY 12 #define FIRST_INT_SLOT_FREE 0 IRQManager::IRQManager() : last_interrupt_index{0} { @@ -930,6 +931,38 @@ bool IRQManager::addPeripheral(Peripheral_t p, void *cfg) { } } #endif + +#if I2S_HOWMANY > 0 + /* ********************************************************************** + I2S + ********************************************************************** */ + else if(p == IRQ_I2S && cfg != NULL) { + i2s_cfg_t *i2s_cfg = (i2s_cfg_t *)cfg; + + if(i2s_cfg->txi_irq == FSP_INVALID_VECTOR) { + i2s_cfg->txi_irq = (IRQn_Type)last_interrupt_index; + i2s_cfg->txi_ipl = I2S_PRIORITY; + *(irq_ptr + last_interrupt_index) = (uint32_t)ssi_txi_isr; + R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_SSI0_TXI); + last_interrupt_index++; + } + if(i2s_cfg->rxi_irq == FSP_INVALID_VECTOR) { + i2s_cfg->rxi_irq = (IRQn_Type)last_interrupt_index; + i2s_cfg->rxi_ipl = I2S_PRIORITY; + *(irq_ptr + last_interrupt_index) = (uint32_t)ssi_rxi_isr; + R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_SSI0_RXI); + last_interrupt_index++; + } + if(i2s_cfg->int_irq == FSP_INVALID_VECTOR) { + i2s_cfg->int_irq = (IRQn_Type)last_interrupt_index; + i2s_cfg->idle_err_ipl = I2S_PRIORITY; + *(irq_ptr + last_interrupt_index) = (uint32_t)ssi_int_isr; + R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_SSI0_INT); + last_interrupt_index++; + } + } +#endif + else { rv = false; } diff --git a/cores/arduino/IRQManager.h b/cores/arduino/IRQManager.h index 2f9e093cc..efa4284d1 100644 --- a/cores/arduino/IRQManager.h +++ b/cores/arduino/IRQManager.h @@ -18,6 +18,15 @@ #include "r_external_irq_api.h" #endif +#if I2S_HOWMANY > 0 +#include "r_ssi.h" +extern "C" { +void ssi_txi_isr(void); +void ssi_rxi_isr(void); +void ssi_int_isr(void); +} +#endif + #include "r_timer_api.h" #ifdef ELC_EVENT_DMAC0_INT @@ -43,7 +52,8 @@ typedef enum { IRQ_CAN, IRQ_ETHERNET, IRQ_CANFD, - IRQ_SDCARD + IRQ_SDCARD, + IRQ_I2S } Peripheral_t; #if SDCARD_HOWMANY > 0 diff --git a/variants/PORTENTA_C33/pins_arduino.h b/variants/PORTENTA_C33/pins_arduino.h index 898a1940d..338186d39 100644 --- a/variants/PORTENTA_C33/pins_arduino.h +++ b/variants/PORTENTA_C33/pins_arduino.h @@ -161,6 +161,7 @@ static const uint8_t SS = PIN_SPI_CS; /****** SDCARD CORE DEFINES *******/ #define SDCARD_HOWMANY 1 +#define I2S_HOWMANY 1 #define EXT_INTERRUPTS_HOWMANY 8 From 0ebafc293ce4bd1a5502fb8702c582d10d00a194 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Mon, 29 Jan 2024 19:15:00 +0100 Subject: [PATCH 2/4] i2s: setup context for irq --- cores/arduino/IRQManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cores/arduino/IRQManager.cpp b/cores/arduino/IRQManager.cpp index ef765bc49..185d1bd23 100644 --- a/cores/arduino/IRQManager.cpp +++ b/cores/arduino/IRQManager.cpp @@ -944,6 +944,7 @@ bool IRQManager::addPeripheral(Peripheral_t p, void *cfg) { i2s_cfg->txi_ipl = I2S_PRIORITY; *(irq_ptr + last_interrupt_index) = (uint32_t)ssi_txi_isr; R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_SSI0_TXI); + R_FSP_IsrContextSet(i2s_cfg->txi_irq, (void*)i2s_cfg->p_context); last_interrupt_index++; } if(i2s_cfg->rxi_irq == FSP_INVALID_VECTOR) { @@ -951,6 +952,7 @@ bool IRQManager::addPeripheral(Peripheral_t p, void *cfg) { i2s_cfg->rxi_ipl = I2S_PRIORITY; *(irq_ptr + last_interrupt_index) = (uint32_t)ssi_rxi_isr; R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_SSI0_RXI); + R_FSP_IsrContextSet(i2s_cfg->rxi_irq, (void*)i2s_cfg->p_context); last_interrupt_index++; } if(i2s_cfg->int_irq == FSP_INVALID_VECTOR) { @@ -958,6 +960,7 @@ bool IRQManager::addPeripheral(Peripheral_t p, void *cfg) { i2s_cfg->idle_err_ipl = I2S_PRIORITY; *(irq_ptr + last_interrupt_index) = (uint32_t)ssi_int_isr; R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_SSI0_INT); + R_FSP_IsrContextSet(i2s_cfg->int_irq, (void*)i2s_cfg->p_context); last_interrupt_index++; } } From 8d714297888c5bc9ca4aed36dcebb2597fde0b2f Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 30 Jan 2024 10:00:04 +0100 Subject: [PATCH 3/4] I2S: package initial library for read() --- libraries/I2S/I2S.cpp | 77 +++++++++++++++++++ libraries/I2S/I2S.h | 16 ++++ libraries/I2S/config.c | 71 +++++++++++++++++ .../RecordAndStream/RecordAndStream.ino | 14 ++++ 4 files changed, 178 insertions(+) create mode 100644 libraries/I2S/I2S.cpp create mode 100644 libraries/I2S/I2S.h create mode 100644 libraries/I2S/config.c create mode 100644 libraries/I2S/examples/RecordAndStream/RecordAndStream.ino diff --git a/libraries/I2S/I2S.cpp b/libraries/I2S/I2S.cpp new file mode 100644 index 000000000..73717731d --- /dev/null +++ b/libraries/I2S/I2S.cpp @@ -0,0 +1,77 @@ +#include "I2S.h" + +#define BUFF_SIZE 1024 +static volatile i2s_event_t g_i2s_event = I2S_EVENT_TX_EMPTY; //an actual event updates in callback + +extern "C" ssi_instance_ctrl_t g_i2s0_ctrl; +extern "C" i2s_cfg_t g_i2s0_cfg; + +static volatile int32_t g_dest_buff[BUFF_SIZE] __attribute__((aligned(4))); +static volatile int16_t g_final[BUFF_SIZE / 2] __attribute__((aligned(4))); + +bool I2SClass::begin() { + + IRQManager::getInstance().addPeripheral(IRQ_I2S, &g_i2s0_cfg); + auto err = R_SSI_Open(&g_i2s0_ctrl, &g_i2s0_cfg); + + if (err != FSP_SUCCESS) { + return false; + } + + // Need to find the timer connected to GPT_TIMER 2A for internal clock + auto pwm = new PwmOut(64); + pwm->begin(100, 50, true); + + pinPeripheral(BSP_IO_PORT_01_PIN_12, (uint32_t) (IOPORT_CFG_PERIPHERAL_PIN | IOPORT_PERIPHERAL_SSI)); + pinPeripheral(BSP_IO_PORT_01_PIN_13, (uint32_t) (IOPORT_CFG_PERIPHERAL_PIN | IOPORT_PERIPHERAL_SSI)); + pinPeripheral(BSP_IO_PORT_01_PIN_14, (uint32_t) (IOPORT_CFG_PERIPHERAL_PIN | IOPORT_PERIPHERAL_SSI)); + pinPeripheral(BSP_IO_PORT_01_PIN_15, (uint32_t) (IOPORT_CFG_PERIPHERAL_PIN | IOPORT_PERIPHERAL_SSI)); + + err = R_SSI_Read(&g_i2s0_ctrl, (void*)g_dest_buff, BUFF_SIZE * sizeof(g_dest_buff[0])); + + if (err != FSP_SUCCESS) { + return false; + } + return true; +} + +static volatile bool hasData = false; +extern "C" void i2s_callback(i2s_callback_args_t *p_args) +{ + if ( NULL != p_args) + { + /* capture callback event for validating the i2s transfer event*/ + g_i2s_event = p_args->event; + if (g_i2s_event == I2S_EVENT_RX_FULL) { + hasData = true; + } + if (g_i2s_event == I2S_EVENT_IDLE) { + R_SSI_Read(&g_i2s0_ctrl, (void*)g_dest_buff, BUFF_SIZE * sizeof(g_dest_buff[0])); + } + } +} + +bool I2SClass::available() { + return hasData; +} + +size_t I2SClass::read(int16_t* buf) { + + while (hasData == false) { + delayMicroseconds(1); + } + + for (int i = 0; i < BUFF_SIZE; i += 2) { + if (g_dest_buff[i] != 0) { + g_final[i / 2] = (int16_t)((((int32_t)((g_dest_buff[i] << 14))) / (1 << 14)) + 0x1C00); + } else { + g_final[i / 2] = 0; + } + } + + memcpy(buf, (void*)g_final, BUFF_SIZE); + hasData = false; + return BUFF_SIZE; +} + + I2SClass I2S; \ No newline at end of file diff --git a/libraries/I2S/I2S.h b/libraries/I2S/I2S.h new file mode 100644 index 000000000..63daf42f5 --- /dev/null +++ b/libraries/I2S/I2S.h @@ -0,0 +1,16 @@ +#include "r_i2s_api.h" +#include "r_ssi.h" +#include "pwm.h" + +class I2SClass { +public: + I2SClass() {} + bool begin(); + bool start() {} + bool stop() {} + bool available(); + size_t read(int16_t* buf); + size_t write(int32_t* buf, size_t len) {} +}; + +extern I2SClass I2S; \ No newline at end of file diff --git a/libraries/I2S/config.c b/libraries/I2S/config.c new file mode 100644 index 000000000..71970f5ca --- /dev/null +++ b/libraries/I2S/config.c @@ -0,0 +1,71 @@ +#include "r_i2s_api.h" +#include "r_ssi.h" +#include "r_dtc.h" + +void i2s_callback(i2s_callback_args_t *p_args); + +dtc_instance_ctrl_t g_transfer0_ctrl; + +transfer_info_t g_transfer0_info = +{ .transfer_settings_word_b.dest_addr_mode = TRANSFER_ADDR_MODE_FIXED, + .transfer_settings_word_b.repeat_area = TRANSFER_REPEAT_AREA_SOURCE, + .transfer_settings_word_b.irq = TRANSFER_IRQ_END, + .transfer_settings_word_b.chain_mode = TRANSFER_CHAIN_MODE_DISABLED, + .transfer_settings_word_b.src_addr_mode = TRANSFER_ADDR_MODE_INCREMENTED, + .transfer_settings_word_b.size = TRANSFER_SIZE_4_BYTE, + .transfer_settings_word_b.mode = TRANSFER_MODE_BLOCK, + .p_dest = (void*) NULL, + .p_src = (void const*) NULL, + .num_blocks = 0, + .length = 0, }; + +const dtc_extended_cfg_t g_transfer0_cfg_extend = +{ .activation_source = VECTOR_NUMBER_SSI0_TXI, }; + +const transfer_cfg_t g_transfer0_cfg = +{ + .p_info = &g_transfer0_info, + .p_extend = &g_transfer0_cfg_extend +}; + +/* Instance structure to use this module. */ +const transfer_instance_t g_transfer0 = +{ + .p_ctrl = &g_transfer0_ctrl, + .p_cfg = &g_transfer0_cfg, + .p_api = &g_transfer_on_dtc +}; +ssi_instance_ctrl_t g_i2s0_ctrl; + +/** SSI instance configuration */ +const ssi_extended_cfg_t g_i2s0_cfg_extend = +{ + .audio_clock = SSI_AUDIO_CLOCK_INTERNAL, + .bit_clock_div = SSI_CLOCK_DIV_1 +}; + +/** I2S interface configuration */ +const i2s_cfg_t g_i2s0_cfg = +{ + .channel = 0, + .pcm_width = I2S_PCM_WIDTH_18_BITS, + //.pcm_width = I2S_PCM_WIDTH_32_BITS, + .operating_mode = I2S_MODE_MASTER, + .word_length = I2S_WORD_LENGTH_32_BITS, + .ws_continue = I2S_WS_CONTINUE_ON, + .p_callback = i2s_callback, + .p_context = &g_i2s0_ctrl, + .p_extend = &g_i2s0_cfg_extend, + .txi_irq = FSP_INVALID_VECTOR, + .rxi_irq = FSP_INVALID_VECTOR, + .int_irq = FSP_INVALID_VECTOR, + .txi_ipl = (2), + .rxi_ipl = (2), + .idle_err_ipl = (2), + .p_transfer_tx = NULL, // MAY be null + .p_transfer_rx = NULL, +}; + +/* Instance structure to use this module. */ +const i2s_instance_t g_i2s0 = +{ .p_ctrl = &g_i2s0_ctrl, .p_cfg = &g_i2s0_cfg, .p_api = &g_i2s_on_ssi }; \ No newline at end of file diff --git a/libraries/I2S/examples/RecordAndStream/RecordAndStream.ino b/libraries/I2S/examples/RecordAndStream/RecordAndStream.ino new file mode 100644 index 000000000..04d0f64c8 --- /dev/null +++ b/libraries/I2S/examples/RecordAndStream/RecordAndStream.ino @@ -0,0 +1,14 @@ +#include "I2S.h" + +int16_t buffer[1024]; + +void setup() { + Serial.begin(2000000); + I2S.begin(); +} + +void loop() { + while (!I2S.available()) {} + auto howMany = I2S.read(buffer); + Serial.write((uint8_t*)buffer, howMany); +} From 3c1396655587f7249141d08194fe38144d132abe Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Mon, 29 Jan 2024 19:14:39 +0100 Subject: [PATCH 4/4] backtrace: remove spurious file --- cores/arduino/cm_backtrace/fault_handler/gcc/cmb_fault.S | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cores/arduino/cm_backtrace/fault_handler/gcc/cmb_fault.S b/cores/arduino/cm_backtrace/fault_handler/gcc/cmb_fault.S index 9491663f2..ca305c6d3 100644 --- a/cores/arduino/cm_backtrace/fault_handler/gcc/cmb_fault.S +++ b/cores/arduino/cm_backtrace/fault_handler/gcc/cmb_fault.S @@ -26,6 +26,8 @@ * Created on: 2016-12-16 */ +#ifdef BACKTRACE_SUPPORT + .syntax unified .thumb .text @@ -41,3 +43,5 @@ HardFault_Handler: Fault_Loop: BL Fault_Loop /* while(1) */ + +#endif \ No newline at end of file