diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fc8aa04b..4d5fd5b5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,10 +12,11 @@ XCORE-VOICE change log * ADDED: Support for DFU over I2C for FFVA INT example. * ADDED: FFD example with I2S audio input to Cyberon speech recognition engine and model. - * CHANGED: Updated submodule fwk_rtos to version 3.1.0 from 3.0.5. - * ADDED: lib_sw_pll submodule v1.1.0. * REMOVED: flash settings in .xn files, as they are not required by XMOS Tools 15.2.x. + * ADDED: Support for reading registers over I2C slave in FFD examples. + * CHANGED: Updated submodule fwk_rtos to version 3.2.0 from 3.0.5. + * ADDED: lib_sw_pll submodule v1.1.0. 2.2.0 ----- diff --git a/doc/programming_guide/ffd/deploying/configuration.rst b/doc/programming_guide/ffd/deploying/configuration.rst index 0d130cf3..6b898d59 100644 --- a/doc/programming_guide/ffd/deploying/configuration.rst +++ b/doc/programming_guide/ffd/deploying/configuration.rst @@ -4,7 +4,7 @@ Configuring the Firmware ======================== -The default application performs as described in the :ref:`sln_voice_ffd_overview`. There are numerous compile time options that can be added to change the example design without requiring code changes. To change the options explained in the table below, add the desired configuration variables to the APP_COMPILE_DEFINITIONS cmake variable located `here `_. +The default application performs as described in the :ref:`sln_voice_ffd_overview`. There are numerous compile time options that can be added to change the example design without requiring code changes. To change the options explained in the table below, add the desired configuration variables to the APP_COMPILE_DEFINITIONS cmake variable in the ``.cmake`` file located in the ``examples/ffd/`` folder. If options are changed, the application firmware must be rebuilt. @@ -34,9 +34,24 @@ If options are changed, the application firmware must be rebuilt. * - appconfINTENT_UART_DEBUG_INFO_ENABLED - Enables/disables the UART intent debug information - 0 - * - appconfINTENT_I2C_OUTPUT_ENABLED - - Enables/disables the |I2C| intent message + * - appconfI2C_MASTER_DAC_ENABLED + - Enables/disables configuring the DAC over |I2C| master - 1 + * - appconfINTENT_I2C_MASTER_OUTPUT_ENABLED + - Enables/disables sending the intent message over |I2C| master + - 1 + * - appconfINTENT_I2C_MASTER_DEVICE_ADDR + - Sets the address of the |I2C| device receiving the intent via the |I2C| master interface + - 0x01 + * - appconfINTENT_I2C_SLAVE_POLLED_ENABLED + - Enables/disables allowing another device to poll the intent message via |I2C| slave + - 0 + * - appconfI2C_SLAVE_DEVICE_ADDR + - Sets the address of the |I2C| device receiving the intent via the |I2C| slave interface + - 0x42 + * - appconfINTENT_I2C_REG_ADDRESS + - Sets the address of the |I2C| register to store the intent message, this value can be read via the |I2C| slave interface + - 0x01 * - appconfUART_BAUD_RATE - Sets the baud rate for the UART tx intent interface - 9600 @@ -52,9 +67,6 @@ If options are changed, the application firmware must be rebuilt. * - appconfRECOVER_MCLK_I2S_APP_PLL - Enables/disables the recovery of the MCLK from the Software PLL application; this removes the need to use an external MCLK. - 0 - * - appconfINTENT_I2C_OUTPUT_DEVICE_ADDR - - Sets the |I2C| slave address to transmit the intent to - - 0x01 * - appconfINTENT_TRANSPORT_DELAY_MS - Sets the delay between host wake up requested and |I2C| and UART keyword code transmission - 50 @@ -78,3 +90,42 @@ If options are changed, the application firmware must be rebuilt. The ``example_ffd_i2s_input_cyberon`` has different default values from the ones in the table above. The list of updated values can be found in the ``APP_COMPILE_DEFINITIONS`` list in ``examples\ffd\ffd_i2s_input_cyberon.cmake``. + +Configuring the |I2C| interfaces +-------------------------------- + +The |I2C| interfaces are used to configure the DAC and to communicate with the host. The |I2C| interface can be configured as a master or a slave. +The DAC must be configured at bootup via the |I2C| master interface. +The |I2C| master is used when the FFD example asynchronously sends intent messages to the host. The |I2C| slave is used when the host wants to read intent messages from the FFD example through polling. + +.. note:: + The |I2C| interface cannot operate as both master and slave simultaneously. The FFD example design uses the |I2C| master interface to configure the DAC at device initialisation. + However, if the host reads intent messages from the FFD example using the |I2C| slave interface, the |I2C| master interface will be disabled after the DAC configuration is complete. + +To send the intent ID via the |I2C| master interface when a command is detected, set the following variables: + + - ``appconfINTENT_I2C_MASTER_OUTPUT_ENABLED`` to 1. + - ``appconfINTENT_I2C_MASTER_DEVICE_ADDR`` to the desired address used by the |I2C| slave device. + - ``appconfINTENT_I2C_SLAVE_POLLED_ENABLED`` to 0, this will disable the |I2C| slave interface. + +To configure the FFD example so that the host can poll for the intent via the |I2C| slave interface, set the following variables: + + - ``appconfINTENT_I2C_SLAVE_POLLED_ENABLED`` to 1. + - ``appconfI2C_SLAVE_DEVICE_ADDR`` to the desired address used by the |I2C| master device. + - ``appconfINTENT_I2C_REG_ADDRESS`` to the desired register read by the |I2C| master device. + - ``appconfINTENT_I2C_MASTER_OUTPUT_ENABLED`` to 0, this will disable the |I2C| master interface after initialization. + +The handling of the |I2C| slave registers is done in the ``examples\ffd\src\i2c_reg_handling.c`` file. The variable ``appconfINTENT_I2C_REG_ADDRESS`` is used in the callback function ``read_device_reg()``. + +Configuring the |I2S| interface +------------------------------- + +The |I2S| interface is used to play the audio command response to the DAC, and/or to receive the audio samples from the host. The |I2S| interface can be configured as either a master or a slave. +To configure the |I2S| interface, set the following variables: + + - ``appconfI2S_ENABLED`` to 1. + - ``appconfI2S_MODE`` to the desired mode, either ``appconfI2S_MODE_MASTER`` or ``appconfI2S_MODE_SLAVE``. + - ``appconfI2S_AUDIO_SAMPLE_RATE`` to the desired sample rate, either 16000 or 48000. + - ``appconfRECOVER_MCLK_I2S_APP_PLL`` to 1 if an external MCLK is not available, otherwise set it to 0. + - ``appconfAUDIO_PLAYBACK_ENABLED`` to 1, if the intent audio is to be played back. + - ``appconfUSE_I2S_INPUT`` to 1, if the |I2S| audio source is to be used instead of the microphone array audio source. diff --git a/doc/programming_guide/ffd/overview.rst b/doc/programming_guide/ffd/overview.rst index 868a6c0c..7e5cf1dc 100644 --- a/doc/programming_guide/ffd/overview.rst +++ b/doc/programming_guide/ffd/overview.rst @@ -13,6 +13,13 @@ The examples using the microphone array as the audio source include an audio pip #. Noise Suppressor (NS) #. Adaptive Gain Control (AGC) +The FFD examples provide several options to inform the host of a possible intent detected by the intent engine. The device can notify the host by: + + - sending the intent ID over a UART interface upon detecting the intent + - sending the intent ID over an |I2C| master interface upon detecting the intent + - allowing the host to poll the last detected intent ID over the |I2C| slave interface + - listening to an audio message over an |I2S| interface + When a wakeword phrase is detected followed by a command phrase, the application will output an audio response and a discrete message over |I2C| and UART. Sensory's THF and Cyberon's DSpotterâ„¢ libraries ship with an expiring development license. The Sensory one will suspend recognition after 11.4 hours or 107 recognition events, and the Cyberon one will suspend recognition after 100 recognition events. After the maximum number of recognitions is reached, a device reset is required to resume normal operation. To perform a reset, either power cycle the device or press the SW2 button. diff --git a/doc/programming_guide/low_power_ffd/deploying/configuration.rst b/doc/programming_guide/low_power_ffd/deploying/configuration.rst index 4faabefa..d9e93008 100644 --- a/doc/programming_guide/low_power_ffd/deploying/configuration.rst +++ b/doc/programming_guide/low_power_ffd/deploying/configuration.rst @@ -26,13 +26,13 @@ If options are changed, the application firmware must be rebuilt. * - appconfINTENT_UART_OUTPUT_ENABLED - Enables/disables the UART intent message - 1 - * - appconfINTENT_I2C_OUTPUT_ENABLED - - Enables/disables the |I2C| intent message + * - appconfINTENT_I2C_MASTER_OUTPUT_ENABLED + - Enables/disables sending the intent message over |I2C| master - 1 * - appconfUART_BAUD_RATE - Sets the baud rate for the UART tx intent interface - 9600 - * - appconfINTENT_I2C_OUTPUT_DEVICE_ADDR + * - appconfINTENT_I2C_MASTER_DEVICE_ADDR - Sets the |I2C| slave address to transmit the intent to - 0x01 * - appconfINTENT_TRANSPORT_DELAY_MS diff --git a/examples/ffd/bsp_config/XK_VOICE_L71/platform/driver_instances.c b/examples/ffd/bsp_config/XK_VOICE_L71/platform/driver_instances.c index 4ba009e3..49c86aaf 100644 --- a/examples/ffd/bsp_config/XK_VOICE_L71/platform/driver_instances.c +++ b/examples/ffd/bsp_config/XK_VOICE_L71/platform/driver_instances.c @@ -27,6 +27,9 @@ rtos_i2c_master_t *i2c_master_ctx = &i2c_master_ctx_s; static rtos_i2s_t i2s_ctx_s; rtos_i2s_t *i2s_ctx = &i2s_ctx_s; +static rtos_i2c_slave_t i2c_slave_ctx_s; +rtos_i2c_slave_t *i2c_slave_ctx = &i2c_slave_ctx_s; + static rtos_uart_tx_t uart_tx_ctx_s; rtos_uart_tx_t *uart_tx_ctx = &uart_tx_ctx_s; diff --git a/examples/ffd/bsp_config/XK_VOICE_L71/platform/driver_instances.h b/examples/ffd/bsp_config/XK_VOICE_L71/platform/driver_instances.h index cee3b29f..ebfb3180 100644 --- a/examples/ffd/bsp_config/XK_VOICE_L71/platform/driver_instances.h +++ b/examples/ffd/bsp_config/XK_VOICE_L71/platform/driver_instances.h @@ -12,6 +12,7 @@ extern "C" { #include "rtos_qspi_flash.h" #include "rtos_gpio.h" #include "rtos_i2c_master.h" +#include "rtos_i2c_slave.h" #include "rtos_i2s.h" #include "rtos_uart_tx.h" @@ -31,6 +32,7 @@ extern "C" { /* Tile specifiers */ #define FLASH_TILE_NO 0 #define I2C_TILE_NO 0 +#define I2C_CTRL_TILE_NO I2C_TILE_NO #define MICARRAY_TILE_NO 1 #define I2S_TILE_NO 1 #define UART_TILE_NO 0 @@ -59,6 +61,7 @@ extern rtos_gpio_t *gpio_ctx_t0; extern rtos_gpio_t *gpio_ctx_t1; extern rtos_mic_array_t *mic_array_ctx; extern rtos_i2c_master_t *i2c_master_ctx; +extern rtos_i2c_slave_t *i2c_slave_ctx; extern rtos_i2s_t *i2s_ctx; extern rtos_uart_tx_t *uart_tx_ctx; diff --git a/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_conf.h b/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_conf.h index 23d382de..40d68c24 100644 --- a/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_conf.h +++ b/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_conf.h @@ -54,6 +54,14 @@ #define appconfI2S_IO_CORE 2 /* Must be kept off core 0 with the RTOS tick ISR */ #endif /* appconfI2S_IO_CORE */ +#ifndef appconfI2C_IO_CORE +#define appconfI2C_IO_CORE 3 /* Must be kept off core 0 with the RTOS tick ISR */ +#endif /* appconfI2C_IO_CORE */ + +#ifndef appconfI2C_INTERRUPT_CORE +#define appconfI2C_INTERRUPT_CORE 0 /* Must be kept off I/O cores. */ +#endif /* appconfI2C_INTERRUPT_CORE */ + #ifndef appconfPDM_MIC_INTERRUPT_CORE #define appconfPDM_MIC_INTERRUPT_CORE 3 /* Must be kept off I/O cores. Best kept off core 0 with the tick ISR. */ #endif /* appconfPDM_MIC_INTERRUPT_CORE */ @@ -81,7 +89,11 @@ /* I/O Task Priorities */ /*****************************************/ #ifndef appconfQSPI_FLASH_TASK_PRIORITY -#define appconfQSPI_FLASH_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define appconfQSPI_FLASH_TASK_PRIORITY (configMAX_PRIORITIES-1) #endif /* appconfQSPI_FLASH_TASK_PRIORITY */ +#ifndef appconfI2C_TASK_PRIORITY +#define appconfI2C_TASK_PRIORITY (configMAX_PRIORITIES/2) +#endif /* appconfI2C_TASK_PRIORITY */ + #endif /* PLATFORM_CONF_H_ */ diff --git a/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_init.c b/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_init.c index e75a2d1e..9b09714d 100644 --- a/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_init.c +++ b/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_init.c @@ -12,7 +12,7 @@ static void mclk_init(chanend_t other_tile_c) { -#if ON_TILE(1) +#if ON_TILE(I2S_TILE_NO) app_pll_init(); #endif } @@ -54,7 +54,7 @@ static void gpio_init(void) intertile_ctx); #endif -#if ON_TILE(1) +#if ON_TILE(I2S_TILE_NO) rtos_gpio_init(gpio_ctx_t1); rtos_gpio_rpc_client_init( @@ -72,6 +72,15 @@ static void gpio_init(void) static void i2c_init(void) { +#if appconfINTENT_I2C_SLAVE_POLLED_ENABLED && ON_TILE(I2C_TILE_NO) + rtos_i2c_slave_init(i2c_slave_ctx, + (1 << appconfI2C_IO_CORE), + PORT_I2C_SCL, + PORT_I2C_SDA, + appconfI2C_SLAVE_DEVICE_ADDR); +#endif + +#if appconfI2C_MASTER_DAC_ENABLED || appconfINTENT_I2C_MASTER_OUTPUT_ENABLED static rtos_driver_rpc_t i2c_rpc_config; #if ON_TILE(I2C_TILE_NO) @@ -94,9 +103,10 @@ static void i2c_init(void) &i2c_rpc_config, intertile_ctx); #endif +#endif } -#if ON_TILE(1) && appconfRECOVER_MCLK_I2S_APP_PLL +#if ON_TILE(I2S_TILE_NO) && appconfRECOVER_MCLK_I2S_APP_PLL static int *p_lock_status = NULL; /// @brief Save the pointer to the pll lock_status variable static void set_pll_lock_status_ptr(int* p) @@ -107,7 +117,7 @@ static void set_pll_lock_status_ptr(int* p) static void platform_sw_pll_init(void) { -#if ON_TILE(1) && appconfRECOVER_MCLK_I2S_APP_PLL +#if ON_TILE(I2S_TILE_NO) && appconfRECOVER_MCLK_I2S_APP_PLL port_t p_bclk = PORT_I2S_BCLK; port_t p_mclk = PORT_MCLK; diff --git a/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_start.c b/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_start.c index f09943a7..d30445aa 100644 --- a/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_start.c +++ b/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_start.c @@ -14,6 +14,9 @@ #include "platform_conf.h" #include "platform/driver_instances.h" #include "dac3101.h" +#include "i2c_reg_handling.h" + +extern asr_result_t last_asr_result; extern void i2s_rate_conversion_enable(void); @@ -39,16 +42,34 @@ static void flash_start(void) static void i2c_master_start(void) { +#if appconfI2C_MASTER_DAC_ENABLED || appconfINTENT_I2C_MASTER_OUTPUT_ENABLED rtos_i2c_master_rpc_config(i2c_master_ctx, appconfI2C_MASTER_RPC_PORT, appconfI2C_MASTER_RPC_PRIORITY); #if ON_TILE(I2C_TILE_NO) rtos_i2c_master_start(i2c_master_ctx); #endif +#endif +} + +static void i2c_slave_start(void) +{ +#if appconfINTENT_I2C_SLAVE_POLLED_ENABLED && ON_TILE(I2C_TILE_NO) + rtos_i2c_slave_start(i2c_slave_ctx, + &last_asr_result, + (rtos_i2c_slave_start_cb_t) NULL, + (rtos_i2c_slave_rx_cb_t) write_device_reg, + (rtos_i2c_slave_tx_start_cb_t) read_device_reg, + (rtos_i2c_slave_tx_done_cb_t) NULL, + NULL, + NULL, + appconfI2C_INTERRUPT_CORE, + appconfI2C_TASK_PRIORITY); +#endif } static void audio_codec_start(void) { -#if appconfI2S_ENABLED +#if appconfI2S_ENABLED && appconfI2C_MASTER_DAC_ENABLED int ret = 0; #if ON_TILE(I2C_TILE_NO) if (dac3101_init(appconfI2S_AUDIO_SAMPLE_RATE) != 0) { @@ -114,4 +135,6 @@ void platform_start(void) mics_start(); i2s_start(); uart_start(); + // I2C slave can be started only after i2c_master_start() is completed + i2c_slave_start(); } diff --git a/examples/ffd/ffd_cyberon.cmake b/examples/ffd/ffd_cyberon.cmake index 70d69f3c..355e9657 100644 --- a/examples/ffd/ffd_cyberon.cmake +++ b/examples/ffd/ffd_cyberon.cmake @@ -91,6 +91,8 @@ set(APP_COMMON_LINK_LIBRARIES sln_voice::app::asr::intent_engine sln_voice::app::asr::intent_handler sln_voice::app::ffd::xk_voice_l71 + lib_src + lib_sw_pll ) #********************** diff --git a/examples/ffd/ffd_i2s_input_cyberon.cmake b/examples/ffd/ffd_i2s_input_cyberon.cmake index 9c990b2e..c5ebfa08 100644 --- a/examples/ffd/ffd_i2s_input_cyberon.cmake +++ b/examples/ffd/ffd_i2s_input_cyberon.cmake @@ -11,6 +11,7 @@ file(GLOB_RECURSE APP_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/*.c ) set(APP_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/src + ${CMAKE_CURRENT_LIST_DIR}/src/control ${CMAKE_CURRENT_LIST_DIR}/src/gpio_ctrl ${CMAKE_CURRENT_LIST_DIR}/src/intent_engine ${CMAKE_CURRENT_LIST_DIR}/src/power @@ -79,7 +80,9 @@ set(APP_COMPILE_DEFINITIONS appconfAUDIO_PLAYBACK_ENABLED=1 appconfI2S_MODE=appconfI2S_MODE_SLAVE appconfI2S_AUDIO_SAMPLE_RATE=48000 - appconfI2S_ENABLED=1 + appconfINTENT_I2C_SLAVE_POLLED_ENABLED=1 + appconfINTENT_I2C_MASTER_OUTPUT_ENABLED=0 + appconfI2C_MASTER_DAC_ENABLED=0 appconfRECOVER_MCLK_I2S_APP_PLL=1 appconfINTENT_UART_DEBUG_INFO_ENABLED=1 appconfAUDIO_PIPELINE_SKIP_IC_AND_VNR=1 diff --git a/examples/ffd/ffd_sensory.cmake b/examples/ffd/ffd_sensory.cmake index 1e7cb56b..d2ad4ac6 100644 --- a/examples/ffd/ffd_sensory.cmake +++ b/examples/ffd/ffd_sensory.cmake @@ -103,6 +103,8 @@ set(APP_COMMON_LINK_LIBRARIES sln_voice::app::asr::intent_engine sln_voice::app::asr::intent_handler sln_voice::app::ffd::xk_voice_l71 + lib_src + lib_sw_pll ) #********************** diff --git a/examples/ffd/src/app_conf.h b/examples/ffd/src/app_conf.h index 29eea01b..1a0e9e58 100644 --- a/examples/ffd/src/app_conf.h +++ b/examples/ffd/src/app_conf.h @@ -71,12 +71,17 @@ #define appconfINTENT_TRANSPORT_DELAY_MS 50 #endif -#ifndef appconfINTENT_I2C_OUTPUT_ENABLED -#define appconfINTENT_I2C_OUTPUT_ENABLED 1 +#ifndef appconfINTENT_I2C_MASTER_OUTPUT_ENABLED +#define appconfINTENT_I2C_MASTER_OUTPUT_ENABLED 1 #endif -#ifndef appconfINTENT_I2C_OUTPUT_DEVICE_ADDR -#define appconfINTENT_I2C_OUTPUT_DEVICE_ADDR 0x01 +#ifndef appconfINTENT_I2C_MASTER_DEVICE_ADDR +#define appconfINTENT_I2C_MASTER_DEVICE_ADDR 0x01 +#endif + +/* @brief Address for wakeword register to be read over I2C slave*/ +#ifndef appconfINTENT_I2C_REG_ADDRESS +#define appconfINTENT_I2C_REG_ADDRESS 0x01 #endif #ifndef appconfINTENT_UART_OUTPUT_ENABLED @@ -91,10 +96,6 @@ #define appconfUART_BAUD_RATE 9600 #endif -#ifndef appconfI2S_ENABLED -#define appconfI2S_ENABLED 1 -#endif - #ifndef appconfI2S_MODE_MASTER #define appconfI2S_MODE_MASTER 0 #endif @@ -103,10 +104,38 @@ #define appconfI2S_MODE_SLAVE 1 #endif +#ifndef appconfI2S_ENABLED +#define appconfI2S_ENABLED 1 +#endif + #ifndef appconfI2S_MODE #define appconfI2S_MODE appconfI2S_MODE_MASTER #endif +#ifndef appconfUSE_I2S_INPUT +#define appconfUSE_I2S_INPUT 0 +#endif + +#if appconfUSE_I2S_INPUT && !appconfI2S_ENABLED +#error "I2S must be enabled if receiving the audio over I2S" +#endif + +#ifndef appconfINTENT_I2C_MASTER_OUTPUT_ENABLED +#define appconfINTENT_I2C_MASTER_OUTPUT_ENABLED 1 +#endif + +#ifndef appconfI2C_MASTER_DAC_ENABLED +#define appconfI2C_MASTER_DAC_ENABLED 1 +#endif + +#ifndef appconfI2C_SLAVE_DEVICE_ADDR +#define appconfI2C_SLAVE_DEVICE_ADDR 0x42 +#endif + +#if appconfINTENT_I2C_MASTER_OUTPUT_ENABLED && appconfINTENT_I2C_SLAVE_POLLED_ENABLED +#error "The intent message cannot be sent over I2C master and polled via I2C slave simultaneously" +#endif + #ifndef appconfAUDIO_PIPELINE_SKIP_IC_AND_VNR #define appconfAUDIO_PIPELINE_SKIP_IC_AND_VNR 0 #endif diff --git a/examples/ffd/src/i2c_reg_handling.c b/examples/ffd/src/i2c_reg_handling.c new file mode 100644 index 00000000..9029d633 --- /dev/null +++ b/examples/ffd/src/i2c_reg_handling.c @@ -0,0 +1,41 @@ +// Copyright 2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#include "i2c_reg_handling.h" + +/** + * @brief Minimum length for a write request. + */ +#define WRITE_REQUEST_MIN_LEN 1 + +RTOS_I2C_SLAVE_CALLBACK_ATTR +size_t read_device_reg(rtos_i2c_slave_t *ctx, + asr_result_t *last_asr_result, + uint8_t **data) +{ +#if appconfINTENT_I2C_SLAVE_POLLED_ENABLED==1 + uint8_t * data_p = *data; + uint8_t reg_addr = data_p[0]; + uint8_t reg_value = 0xFF; + if (reg_addr == appconfINTENT_I2C_REG_ADDRESS) { + reg_value = last_asr_result->id; + } + data_p[0] = reg_value; + rtos_printf("Read from register 0x%02X value 0x%02X\n", reg_addr, reg_value); +#endif + return 1; +} + +RTOS_I2C_SLAVE_CALLBACK_ATTR +void write_device_reg(rtos_i2c_slave_t *ctx, + void *app_data, + uint8_t *data, + size_t len) +{ +#if appconfINTENT_I2C_SLAVE_POLLED_ENABLED==1 + // If the length is lower than WRITE_REQUEST_MIN_LEN, it is a read request + if (len > WRITE_REQUEST_MIN_LEN) { + rtos_printf("Write to register 0x%02X value 0x%02X (len %d)\n", data[0], data[1], len); + } +#endif +} diff --git a/examples/ffd/src/i2c_reg_handling.h b/examples/ffd/src/i2c_reg_handling.h new file mode 100644 index 00000000..449b13de --- /dev/null +++ b/examples/ffd/src/i2c_reg_handling.h @@ -0,0 +1,36 @@ +// Copyright 2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#include "rtos_i2c_slave.h" +#include "app_conf.h" +#include "asr.h" + +/** + * Callback for reading data from a device register over I2C slave. + * Only one byte of data is read from the register. + * + * @param ctx Pointer to the I2C slave context. + * @param last_asr_result Pointer to the last Automatic Speech Recognition (ASR) result. + * @param data Pointer to a pointer to the the data to be sent to the master device. + * + * @return The size of the data read. + */ +RTOS_I2C_SLAVE_CALLBACK_ATTR +size_t read_device_reg(rtos_i2c_slave_t *ctx, + asr_result_t *last_asr_result, + uint8_t **data); + +/** + * Callback for writing data to a device register over I2C slave. + * Only one byte of data is written to the register. + * + * @param ctx Pointer to the I2C slave context. + * @param app_data Pointer to application-specific data. Not used. + * @param data Pointer to the the data received from the master device. + * @param len The length of the data to be written. + */ +RTOS_I2C_SLAVE_CALLBACK_ATTR +void write_device_reg(rtos_i2c_slave_t *ctx, + void *app_data, + uint8_t *data, + size_t len); diff --git a/examples/ffd/src/main.c b/examples/ffd/src/main.c index 780782b4..43144628 100644 --- a/examples/ffd/src/main.c +++ b/examples/ffd/src/main.c @@ -15,9 +15,6 @@ /* Library headers */ #include "rtos_printf.h" -#if appconfI2S_ENABLED -#include "src.h" -#endif /* App headers */ #include "app_conf.h" @@ -31,6 +28,10 @@ #include "gpio_ctrl/leds.h" #include "intent_handler/intent_handler.h" +#if appconfI2S_ENABLED +#include "src.h" +#endif + #if appconfRECOVER_MCLK_I2S_APP_PLL /* Config headers for sw_pll */ #include "sw_pll.h" @@ -91,7 +92,7 @@ void audio_pipeline_input(void *input_app_data, size_t frame_count) { (void) input_app_data; - + #if !appconfUSE_I2S_INPUT static int flushed; while (!flushed) { @@ -125,8 +126,8 @@ void audio_pipeline_input(void *input_app_data, (int32_t *) tmp, frame_count, portMAX_DELAY); - - + + for (int i=0; i> 8) & 0xFF); diff --git a/examples/ffva/src/main.c b/examples/ffva/src/main.c index 1caceb76..faa80a72 100644 --- a/examples/ffva/src/main.c +++ b/examples/ffva/src/main.c @@ -68,7 +68,7 @@ void i2s_slave_intertile(void *args) { portMAX_DELAY); -#if ON_TILE(1) && appconfRECOVER_MCLK_I2S_APP_PLL +#if ON_TILE(I2S_TILE_NO) && appconfRECOVER_MCLK_I2S_APP_PLL sw_pll_ctx_t* i2s_callback_args = (sw_pll_ctx_t*) args; port_clear_buffer(i2s_callback_args->p_bclk_count); port_in(i2s_callback_args->p_bclk_count); // Block until BCLK transition to synchronise. Will consume up to 1/64 of a LRCLK cycle @@ -353,7 +353,7 @@ void startup_task(void *arg) rtos_printf("Startup task running from tile %d on core %d\n", THIS_XCORE_TILE, portGET_CORE_ID()); platform_start(); -#if ON_TILE(1) && appconfI2S_ENABLED && (appconfI2S_MODE == appconfI2S_MODE_SLAVE) +#if ON_TILE(I2S_TILE_NO) && appconfI2S_ENABLED && (appconfI2S_MODE == appconfI2S_MODE_SLAVE) // Use sw_pll_ctx only if the MCLK recovery is enabled #if appconfRECOVER_MCLK_I2S_APP_PLL diff --git a/examples/low_power_ffd/src/app_conf.h b/examples/low_power_ffd/src/app_conf.h index 64061cfd..3d28cfbe 100644 --- a/examples/low_power_ffd/src/app_conf.h +++ b/examples/low_power_ffd/src/app_conf.h @@ -67,12 +67,12 @@ #define appconfINTENT_TRANSPORT_DELAY_MS 50 #endif -#ifndef appconfINTENT_I2C_OUTPUT_ENABLED -#define appconfINTENT_I2C_OUTPUT_ENABLED 1 +#ifndef appconfINTENT_I2C_MASTER_OUTPUT_ENABLED +#define appconfINTENT_I2C_MASTER_OUTPUT_ENABLED 1 #endif -#ifndef appconfINTENT_I2C_OUTPUT_DEVICE_ADDR -#define appconfINTENT_I2C_OUTPUT_DEVICE_ADDR 0x01 +#ifndef appconfINTENT_I2C_MASTER_DEVICE_ADDR +#define appconfINTENT_I2C_MASTER_DEVICE_ADDR 0x01 #endif #ifndef appconfINTENT_UART_OUTPUT_ENABLED diff --git a/examples/low_power_ffd/src/intent_handler/intent_handler.c b/examples/low_power_ffd/src/intent_handler/intent_handler.c index 84fca4bf..3c9dbd1b 100644 --- a/examples/low_power_ffd/src/intent_handler/intent_handler.c +++ b/examples/low_power_ffd/src/intent_handler/intent_handler.c @@ -50,14 +50,14 @@ static void proc_keyword_res(void *args) { vTaskDelay(pdMS_TO_TICKS(appconfINTENT_TRANSPORT_DELAY_MS)); rtos_gpio_port_out(gpio_ctx_t0, p_out_wakeup, WAKEUP_LOW); } -#if appconfINTENT_I2C_OUTPUT_ENABLED +#if appconfINTENT_I2C_MASTER_OUTPUT_ENABLED i2c_res_t ret; uint32_t buf = id; size_t sent = 0; ret = rtos_i2c_master_write( i2c_master_ctx, - appconfINTENT_I2C_OUTPUT_DEVICE_ADDR, + appconfINTENT_I2C_MASTER_DEVICE_ADDR, (uint8_t*)&buf, sizeof(uint32_t), &sent, diff --git a/modules/asr/Cyberon/DSpotter_asr.c b/modules/asr/Cyberon/DSpotter_asr.c index 79da9ee7..89c0f52a 100644 --- a/modules/asr/Cyberon/DSpotter_asr.c +++ b/modules/asr/Cyberon/DSpotter_asr.c @@ -169,9 +169,8 @@ asr_error_t asr_get_result(asr_port_t *ctx, asr_result_t *result) { DBG_TRACE("\r\nGet %s, ID=%d, Score=%d, SG_Diff=%d, Energy=%d\r\n", szCommand, nCmdID, nCmdScore, nCmdSG, nCmdEnergy); result->id = nCmdID; - - result->score = nCmdScore; - result->gscore = nCmdSG; + result->sg_diff = nCmdSG; + result->energy = nCmdEnergy; // The following result fields are not implemented result->start_index = -1; result->end_index = -1; diff --git a/modules/asr/asr.h b/modules/asr/asr.h index 92ca22aa..4b6e496f 100644 --- a/modules/asr/asr.h +++ b/modules/asr/asr.h @@ -64,11 +64,16 @@ typedef struct asr_attributes_struct typedef struct asr_result_struct { uint16_t id; ///< Keyword or command ID + + // The following fields are optional and may not be supported by all ASR ports uint16_t score; ///< The confidence score of the detection uint16_t gscore; ///< The garbage score int32_t start_index; ///< The audio sample index that corresponds to the start of the utterance int32_t end_index; ///< The audio sample index that corresponds to the end of the utterance int32_t duration; ///< THe length of the utterance in samples + uint32_t sg_diff; ///< The voice similarity of the detection + uint32_t energy; ///< The energy of the detection + void* reserved; ///< Reserved for future use } asr_result_t; diff --git a/modules/asr/intent_engine/intent_engine.c b/modules/asr/intent_engine/intent_engine.c index 46a951ea..e8d231c6 100644 --- a/modules/asr/intent_engine/intent_engine.c +++ b/modules/asr/intent_engine/intent_engine.c @@ -112,6 +112,7 @@ static void timeout_event_handler(TimerHandle_t pxTimer) intent_state = STATE_EXPECTING_WAKEWORD; } } +asr_result_t last_asr_result = {0}; #pragma stackfunction 1000 void intent_engine_task(void *args) @@ -169,6 +170,8 @@ void intent_engine_task(void *args) if (asr_error != ASR_OK) continue; asr_error = asr_get_result(asr_ctx, &asr_result); + memcpy(&last_asr_result, &asr_result, sizeof(asr_result_t)); + if (asr_error != ASR_OK) continue; word_id = asr_result.id; diff --git a/modules/asr/intent_handler/intent_handler.c b/modules/asr/intent_handler/intent_handler.c index cfa4cee6..0d26de9d 100644 --- a/modules/asr/intent_handler/intent_handler.c +++ b/modules/asr/intent_handler/intent_handler.c @@ -56,14 +56,14 @@ static void proc_keyword_res(void *args) { vTaskDelay(pdMS_TO_TICKS(appconfINTENT_TRANSPORT_DELAY_MS)); rtos_gpio_port_out(gpio_ctx_t0, p_out_wakeup, WAKEUP_LOW); } -#if appconfINTENT_I2C_OUTPUT_ENABLED +#if appconfINTENT_I2C_MASTER_OUTPUT_ENABLED i2c_res_t ret; uint32_t buf = id; size_t sent = 0; ret = rtos_i2c_master_write( i2c_master_ctx, - appconfINTENT_I2C_OUTPUT_DEVICE_ADDR, + appconfINTENT_I2C_MASTER_DEVICE_ADDR, (uint8_t*)&buf, sizeof(uint32_t), &sent, @@ -98,7 +98,6 @@ int32_t intent_handler_create(uint32_t priority, void *args) args, priority, NULL); - return 0; } diff --git a/modules/rtos b/modules/rtos index 7be57246..44692113 160000 --- a/modules/rtos +++ b/modules/rtos @@ -1 +1 @@ -Subproject commit 7be57246f7541202b29f7cbab350a8b0e9a084f1 +Subproject commit 44692113625a04d85377ce4c4c909635a1c68932 diff --git a/test/asr/asr.cmake b/test/asr/asr.cmake index f3567622..e222b122 100644 --- a/test/asr/asr.cmake +++ b/test/asr/asr.cmake @@ -48,6 +48,8 @@ if(${TEST_ASR} STREQUAL "SENSORY") set(MODEL_FILE ${FFD_SRC_ROOT}/model/english_usa/command-pc62w-6.4.0-op10-prod-net.bin.nibble_swapped) set(TEST_ASR_LIBRARY_ID 0) set(TEST_ASR_NAME test_asr_sensory) + set(ASR_FLAG ASR_SENSORY=1) + elseif(${TEST_ASR} STREQUAL "CYBERON") message(STATUS "Building Cyberon ASR test") set(ASR_LIBRARY sln_voice::app::asr::Cyberon) @@ -58,6 +60,7 @@ elseif(${TEST_ASR} STREQUAL "CYBERON") set(MODEL_FILE ${FFD_SRC_ROOT}/model/english_usa/Hello_XMOS_pack_WithTxt.bin.Enc.NibbleSwap) set(TEST_ASR_LIBRARY_ID 1) set(TEST_ASR_NAME test_asr_cyberon) + set(ASR_FLAG ASR_CYBERON=1) else() message(FATAL_ERROR "Unable to build ${TEST_ASR} test") endif() @@ -82,18 +85,13 @@ set(APP_COMPILE_DEFINITIONS XUD_CORE_CLOCK=600 XSCOPE_HOST_IO_ENABLED=1 XSCOPE_HOST_IO_TILE=0 + ${ASR_FLAG} QSPI_FLASH_CALIBRATION_ADDRESS=${CALIBRATION_PATTERN_START_ADDRESS} QSPI_FLASH_MODEL_START_ADDRESS=${MODEL_START_ADDRESS} appconfASR_LIBRARY_ID=${TEST_ASR_LIBRARY_ID} appconfASR_BRICK_SIZE_SAMPLES=${ASR_BRICK_SIZE_SAMPLES} ) -if(${TEST_ASR} STREQUAL "SENSORY") - set(APP_COMPILE_DEFINITIONS - ${APP_COMPILE_DEFINITIONS} - ) -endif() - set(APP_LINK_OPTIONS -report ${CMAKE_CURRENT_LIST_DIR}/src/config.xscope diff --git a/test/ffd_gpio/src/app_conf.h b/test/ffd_gpio/src/app_conf.h index f5747b96..94a75cbb 100644 --- a/test/ffd_gpio/src/app_conf.h +++ b/test/ffd_gpio/src/app_conf.h @@ -15,10 +15,8 @@ #define I2C_SLAVE_CORE_MASK (1 << 3) #define I2C_SLAVE_ADDR 0x7A -#define appconfINTENT_I2C_OUTPUT_DEVICE_ADDR I2C_SLAVE_ADDR - #define appconfAUDIO_PLAYBACK_ENABLED 0 -#define appconfINTENT_I2C_OUTPUT_ENABLED 0 +#define appconfINTENT_I2C_MASTER_OUTPUT_ENABLED 0 #define appconfINTENT_UART_OUTPUT_ENABLED 0 #define ASR_TILE_NO 0