From cfc284c68e4f84627e7410beb28d3baf27209fe5 Mon Sep 17 00:00:00 2001 From: NikhitaR-IFX Date: Mon, 7 Oct 2024 13:03:17 +0530 Subject: [PATCH 1/6] ports/psoc6: Read API enablement. Signed-off-by: NikhitaR-IFX --- ports/psoc6/machine_pdm_pcm.c | 355 +++++++++++++++++++++++++--------- ports/psoc6/machine_pdm_pcm.h | 102 ++++++++++ ports/psoc6/mpconfigport.h | 1 + 3 files changed, 362 insertions(+), 96 deletions(-) create mode 100644 ports/psoc6/machine_pdm_pcm.h diff --git a/ports/psoc6/machine_pdm_pcm.c b/ports/psoc6/machine_pdm_pcm.c index 614d68dd62c86..a7ca09a27424c 100644 --- a/ports/psoc6/machine_pdm_pcm.c +++ b/ports/psoc6/machine_pdm_pcm.c @@ -27,79 +27,101 @@ #include #include "py/runtime.h" +#include "py/stream.h" #include "py/mphal.h" #include "machine_pin_phy.h" #include "modmachine.h" #include "mplogger.h" #if MICROPY_PY_MACHINE_PDM_PCM +#include "machine_pdm_pcm.h" -#define pdm_pcm_assert_raise_val(msg, ret) if (ret != CY_RSLT_SUCCESS) { \ - mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT(msg), ret); \ +cyhal_clock_t pdm_pcm_audio_clock; + +#if MICROPY_PY_MACHINE_PDM_PCM_RING_BUF +static void ringbuf_init(ring_buf_t *rbuf, uint8_t *buffer, size_t size) { + rbuf->buffer = buffer; + rbuf->size = size; + rbuf->head = 0; + rbuf->tail = 0; } -#define DEFAULT_LEFT_GAIN 0 -#define DEFAULT_RIGHT_GAIN 0 -#define MICROPY_HW_MAX_PDM_PCM 1 +static bool ringbuf_push(ring_buf_t *rbuf, uint8_t data) { + size_t next_tail = (rbuf->tail + 1) % rbuf->size; -#define AUDIO_SYS_CLOCK_24_576_000_HZ 24576000u /* (Ideally 24.576 MHz) For sample rates: 8 KHz / 16 KHz / 48 KHz */ -#define AUDIO_SYS_CLOCK_22_579_000_HZ 22579000u /* (Ideally 22.579 MHz) For sample rates: 22.05 KHz / 44.1 KHz */ + if (next_tail != rbuf->head) { + rbuf->buffer[rbuf->tail] = data; + rbuf->tail = next_tail; + return true; + } + // full + return false; +} -cyhal_clock_t pdm_pcm_audio_clock; +static bool ringbuf_pop(ring_buf_t *rbuf, uint8_t *data) { + if (rbuf->head == rbuf->tail) { + // empty + return false; + } + *data = rbuf->buffer[rbuf->head]; + rbuf->head = (rbuf->head + 1) % rbuf->size; + return true; +} -// Constructor args -enum { - ARG_clk, - ARG_data, - ARG_sample_rate, - ARG_decimation_rate, - ARG_bits, - ARG_format, - ARG_left_gain, - ARG_right_gain, -}; +static size_t ringbuf_available_data(ring_buf_t *rbuf) { + return (rbuf->tail - rbuf->head + rbuf->size) % rbuf->size; +} + +static size_t ringbuf_available_space(ring_buf_t *rbuf) { + return rbuf->size - ringbuf_available_data(rbuf) - 1; +} + +static uint32_t fill_appbuf_from_ringbuf(machine_pdm_pcm_obj_t *self, mp_buffer_info_t *appbuf) { + uint32_t num_bytes_copied_to_appbuf = 0; + uint8_t *app_p = (uint8_t *)appbuf->buf; + uint8_t appbuf_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); // !J: Why only 16 or 32? + uint32_t num_bytes_needed_from_ringbuf = appbuf->len * (PDM_PCM_RX_FRAME_SIZE_IN_BYTES / appbuf_sample_size_in_bytes); + uint8_t discard_byte; + while (num_bytes_needed_from_ringbuf) { + + uint8_t f_index = get_frame_mapping_index(self->bits, self->format); + + for (uint8_t i = 0; i < PDM_PCM_RX_FRAME_SIZE_IN_BYTES; i++) { + int8_t r_to_a_mapping = pdm_pcm_frame_map[f_index][i]; + if (r_to_a_mapping != -1) { + if (self->io_mode == BLOCKING) { + // poll the ringbuf until a sample becomes available, copy into appbuf using the mapping transform + while (ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping) == false) { + ; + } + num_bytes_copied_to_appbuf++; + } else { + return 0; // should never get here (non-blocking mode does not use this function) + } + } else { // r_a_mapping == -1 + // discard unused byte from ring buffer + if (self->io_mode == BLOCKING) { + // poll the ringbuf until a sample becomes available + while (ringbuf_pop(&self->ring_buffer, &discard_byte) == false) { + ; + } + } else { + return 0; // should never get here (non-blocking mode does not use this function) + } + } + num_bytes_needed_from_ringbuf--; + } + app_p += appbuf_sample_size_in_bytes; + } +exit: + return num_bytes_copied_to_appbuf; +} + +#endif // MICROPY_PY_MACHINE_PDM_PCM_RING_BUF + +/*========================================================================================================================*/ +// PDM_PCM higher level MPY functions (extmod/machine_pdm_pcm.c) -typedef enum { - BITS_16 = 16, - BITS_18 = 18, - BITS_20 = 20, - BITS_24 = 24 -} pdm_pcm_word_length_t; - -// To be compatible with extmod -typedef enum { - MONO_LEFT = CYHAL_PDM_PCM_MODE_LEFT, - MONO_RIGHT = CYHAL_PDM_PCM_MODE_RIGHT, - STEREO = CYHAL_PDM_PCM_MODE_STEREO -} format_t; - -typedef enum { - BLOCKING, - NON_BLOCKING, -} io_mode_t; - - -typedef struct _machine_pdm_pcm_obj_t { - mp_obj_base_t base; - uint8_t pdm_pcm_id; // Private variable in this port. ID not associated to any port pin pdm-pcm group. - cyhal_pdm_pcm_t pdm_pcm_obj; - uint32_t clk; - uint32_t data; - io_mode_t io_mode; - format_t format; - uint8_t bits; - uint32_t sample_rate; - uint8_t decimation_rate; - int16_t left_gain; - int16_t right_gain; -} machine_pdm_pcm_obj_t; - -static void mp_machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, mp_arg_val_t *args); -static machine_pdm_pcm_obj_t *mp_machine_pdm_pcm_make_new_instance(mp_int_t pdm_pcm_id); -static void mp_machine_pdm_pcm_deinit(machine_pdm_pcm_obj_t *self); - - -// To be preesent in extmod/pdm_pcm MP_NOINLINE static void machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, @@ -114,7 +136,6 @@ MP_NOINLINE static void machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_pos_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - mp_machine_pdm_pcm_init_helper(self, args); } @@ -140,14 +161,27 @@ static void machine_pdm_pcm_print(const mp_print_t *print, mp_obj_t self_in, mp_ ); } +// PDM_PCM(...) Constructor +static mp_obj_t machine_pdm_pcm_make_new(const mp_obj_type_t *type, size_t n_pos_args, size_t n_kw_args, const mp_obj_t *args) { + mp_arg_check_num(n_pos_args, n_kw_args, 1, MP_OBJ_FUN_ARGS_MAX, true); + mp_int_t pdm_pcm_id = mp_obj_get_int(args[0]); + + machine_pdm_pcm_obj_t *self = mp_machine_pdm_pcm_make_new_instance(pdm_pcm_id); + + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw_args, args + n_pos_args); + machine_pdm_pcm_init_helper(self, n_pos_args - 1, args + 1, &kw_args); + + return MP_OBJ_FROM_PTR(self); +} + // PDM_PCM.init(...) -static mp_obj_t machine_pdm_pcm_init(size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - machine_pdm_pcm_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - mp_machine_pdm_pcm_deinit(self); - machine_pdm_pcm_init_helper(self, n_pos_args - 1, pos_args + 1, kw_args); +static mp_obj_t machine_pdm_pcm_init(mp_obj_t self_in) { + machine_pdm_pcm_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_machine_pdm_pcm_init(self); return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_KW(machine_pdm_pcm_init_obj, 1, machine_pdm_pcm_init); +static MP_DEFINE_CONST_FUN_OBJ_1(machine_pdm_pcm_init_obj, machine_pdm_pcm_init); // PDM_PCM.deinit() static mp_obj_t machine_pdm_pcm_deinit(mp_obj_t self_in) { @@ -157,23 +191,69 @@ static mp_obj_t machine_pdm_pcm_deinit(mp_obj_t self_in) { } static MP_DEFINE_CONST_FUN_OBJ_1(machine_pdm_pcm_deinit_obj, machine_pdm_pcm_deinit); -// PDM_PCM() Constructor -static mp_obj_t machine_pdm_pcm_make_new(const mp_obj_type_t *type, size_t n_pos_args, size_t n_kw_args, const mp_obj_t *args) { - mp_arg_check_num(n_pos_args, n_kw_args, 1, MP_OBJ_FUN_ARGS_MAX, true); - mp_int_t pdm_pcm_id = mp_obj_get_int(args[0]); +// ======================================================================================= +// Port Private functions for DMA support (ports/psoc6) - machine_pdm_pcm_obj_t *self = mp_machine_pdm_pcm_make_new_instance(pdm_pcm_id); +static inline void _dma_buff_init(machine_pdm_pcm_obj_t *self) { + for (uint32_t i = 0; i < SIZEOF_DMA_BUFFER; i++) { + self->dma_active_buffer[i] = 0; + self->dma_processing_buffer[i] = 0; + } - mp_map_t kw_args; - mp_map_init_fixed_table(&kw_args, n_kw_args, args + n_pos_args); - machine_pdm_pcm_init_helper(self, n_pos_args - 1, args + 1, &kw_args); + self->dma_active_buf_p = self->dma_active_buffer; + self->dma_processing_buf_p = self->dma_processing_buffer; +} - return MP_OBJ_FROM_PTR(self); +static inline void _dma_swap_active_dmabuf(machine_pdm_pcm_obj_t *self) { + uint32_t *temp = self->dma_active_buf_p; + self->dma_active_buf_p = self->dma_processing_buf_p; + self->dma_processing_buf_p = temp; +} + +static void _dma_copy_from_dmabuf_to_ringbuf(machine_pdm_pcm_obj_t *self) { + uint8_t dma_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); + uint8_t *dma_buff_p = (uint8_t *)self->dma_processing_buf_p; + uint32_t num_bytes_needed_from_ringbuf = SIZEOF_DMA_BUFFER_IN_BYTES * (PDM_PCM_RX_FRAME_SIZE_IN_BYTES / dma_sample_size_in_bytes); + + // when space exists, copy samples into ring buffer + if (ringbuf_available_space(&self->ring_buffer) >= num_bytes_needed_from_ringbuf) { + uint8_t f_index = get_frame_mapping_index(self->bits, self->format); + uint32_t i = 0; + while (i < SIZEOF_DMA_BUFFER_IN_BYTES) { + for (uint8_t j = 0; j < PDM_PCM_RX_FRAME_SIZE_IN_BYTES; j++) { + int8_t r_to_a_mapping = pdm_pcm_frame_map[f_index][j]; + if (r_to_a_mapping != -1) { + ringbuf_push(&self->ring_buffer, dma_buff_p[i]); + i++; + } else { // r_a_mapping == -1 + ringbuf_push(&self->ring_buffer, -1); + } + } + } + } } // ======================================================================================= -// Private functions +// PDM_PCM low-level abstracted functions (ports/psoc6) +// Init hardware block +static void pdm_pcm_init(machine_pdm_pcm_obj_t *self, cyhal_clock_t *clock) { + cyhal_pdm_pcm_cfg_t config = + { + .sample_rate = self->sample_rate, + .decimation_rate = self->decimation_rate, + .mode = self->format, + .word_length = self->bits, /* bits */ + .left_gain = self->left_gain, /* dB */ + .right_gain = self->right_gain, /* dB */ + }; + + cy_rslt_t result = cyhal_pdm_pcm_init(&self->pdm_pcm_obj, self->data, self->clk, &pdm_pcm_audio_clock, &config); + assert_pin_phy_used(result); + pdm_pcm_assert_raise_val("PDM_PCM initialisation failed with return code %lx !", result); +} + +// Initialize audio clock void pdm_pcm_audio_clock_init(uint32_t audio_clock_freq_hz) { cyhal_clock_t pll_clock; cy_rslt_t result; @@ -213,30 +293,56 @@ void pdm_pcm_audio_clock_init(uint32_t audio_clock_freq_hz) { } cyhal_clock_free(&pll_clock); - cyhal_system_delay_ms(1); } -// PDM_PCM hardware block init -static void pdm_pcm_init(machine_pdm_pcm_obj_t *self, cyhal_clock_t *clock) { - cyhal_pdm_pcm_cfg_t config = - { - .sample_rate = self->sample_rate, - .decimation_rate = self->decimation_rate, - .mode = self->format, - .word_length = self->bits, /* bits */ - .left_gain = self->left_gain, /* dB */ - .right_gain = self->right_gain, /* dB */ - }; +// Set PDM_PCM async mode to DMA +static void pdm_pcm_set_async_mode_dma(machine_pdm_pcm_obj_t *self) { + cy_rslt_t result = cyhal_pdm_pcm_set_async_mode(&self->pdm_pcm_obj, CYHAL_ASYNC_DMA, CYHAL_DMA_PRIORITY_DEFAULT); + pdm_pcm_assert_raise_val("PDM_PCM set DMA mode failed with return code %lx !", result); +} - cy_rslt_t result = cyhal_pdm_pcm_init(&self->pdm_pcm_obj, self->data, self->clk, &pdm_pcm_audio_clock, &config); - assert_pin_phy_used(result); - pdm_pcm_assert_raise_val("PDM_PCM initialisation failed with return code %lx !", result); +// Read from PDM_PCM reg to provisioned DMA buffer +static void pdm_pcm_read_rxbuf(machine_pdm_pcm_obj_t *self) { + // ToDo: Check the value of dma_half_buff_word_size and adapt for PDM-PCM + uint16_t dma_half_buff_word_size = SIZEOF_DMA_BUFFER_IN_BYTES / 2; + cy_rslt_t result = cyhal_pdm_pcm_read_async(&self->pdm_pcm_obj, self->dma_active_buf_p, dma_half_buff_word_size); + pdm_pcm_assert_raise_val("PDM_PCM DMA read failed with return code %lx !", result); +} + +// IRQ Handler +static void pdm_pcm_irq_handler(void *arg, cyhal_pdm_pcm_event_t event) { + machine_pdm_pcm_obj_t *self = (machine_pdm_pcm_obj_t *)arg; + + if (0u != (event & CYHAL_PDM_PCM_ASYNC_COMPLETE)) { + _dma_swap_active_dmabuf(self); + pdm_pcm_read_rxbuf(self); + _dma_copy_from_dmabuf_to_ringbuf(self); + + // ToDo: Implementation placeholder for non-blocking mode + /*if ((self->io_mode == NON_BLOCKING) && (self->non_blocking_descriptor.copy_in_progress)) { + fill_appbuf_from_ringbuf_non_blocking(self); + }*/ + } +} + +// Configure PDM_PCM IRQ +static void pdm_pcm_irq_configure(machine_pdm_pcm_obj_t *self) { + cyhal_pdm_pcm_register_callback(&self->pdm_pcm_obj, &pdm_pcm_irq_handler, self); + cyhal_pdm_pcm_enable_event(&self->pdm_pcm_obj, CYHAL_PDM_PCM_ASYNC_COMPLETE, CYHAL_ISR_PRIORITY_DEFAULT, true); +} + +// Start PDM_PCM receive operation +static void pdm_pcm_start_rx(machine_pdm_pcm_obj_t *self) { + pdm_pcm_read_rxbuf(self); + cy_rslt_t result = cyhal_pdm_pcm_start(&self->pdm_pcm_obj); + pdm_pcm_assert_raise_val("PDM_PCM start failed with return code %lx !", result); } // ======================================================================================= -// MPY bindings in ports/psoc6 +// MPY bindings for PDM_PCM (ports/psoc6) +// constructor() static machine_pdm_pcm_obj_t *mp_machine_pdm_pcm_make_new_instance(mp_int_t pdm_pcm_id) { (void)pdm_pcm_id; machine_pdm_pcm_obj_t *self = NULL; @@ -248,14 +354,13 @@ static machine_pdm_pcm_obj_t *mp_machine_pdm_pcm_make_new_instance(mp_int_t pdm_ break; } } - if (self == NULL) { mp_raise_ValueError(MP_ERROR_TEXT("all available pdm pcm instances are allocated")); } - return self; } +// init.helper() static void mp_machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, mp_arg_val_t *args) { // Assign pins @@ -300,15 +405,74 @@ static void mp_machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, mp_arg_v mp_raise_ValueError(MP_ERROR_TEXT("rate not supported")); } + // !ToDo: Check the value of ibuf and if needs to be set by user + int32_t ring_buffer_len = 20000; // !J: How can user calculate this? Easier if we set internally? + if (ring_buffer_len < 0) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid ibuf")); + } + self->ibuf = ring_buffer_len; + self->callback_for_non_blocking = MP_OBJ_NULL; + self->io_mode = BLOCKING; + self->ring_buffer_storage = m_new(uint8_t, ring_buffer_len); + + ringbuf_init(&self->ring_buffer, self->ring_buffer_storage, ring_buffer_len); pdm_pcm_audio_clock_init(audio_clock_freq_hz); pdm_pcm_init(self, &pdm_pcm_audio_clock); + pdm_pcm_irq_configure(self); + pdm_pcm_set_async_mode_dma(self); + _dma_buff_init(self); + pdm_pcm_start_rx(self); } +// init() +static void mp_machine_pdm_pcm_init(machine_pdm_pcm_obj_t *self) { + cyhal_pdm_pcm_start(&self->pdm_pcm_obj); +} + +// deinit() static void mp_machine_pdm_pcm_deinit(machine_pdm_pcm_obj_t *self) { + cyhal_pdm_pcm_stop(&self->pdm_pcm_obj); cyhal_pdm_pcm_free(&self->pdm_pcm_obj); MP_STATE_PORT(machine_pdm_pcm_obj[self->pdm_pcm_id]) = NULL; } +// ======================================================================================= +// Implementation for stream protocol (ports/psoc6) + +static mp_uint_t machine_pdm_pcm_stream_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { + machine_pdm_pcm_obj_t *self = MP_OBJ_TO_PTR(self_in); + + uint8_t appbuf_sample_size_in_bytes = (self->bits / 8) * (self->format == STEREO ? 2: 1); + // uint8_t appbuf_sample_size_in_bytes = (self->bits + 7) /8; // round up to higher limit. Consider 20 bits and 18 bits case. + if (size % appbuf_sample_size_in_bytes != 0) { // size should be multiple of sample size + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } + + if (size == 0) { + return 0; + } + + if (self->io_mode == BLOCKING) { // blocking mode + mp_buffer_info_t appbuf; + appbuf.buf = (void *)buf_in; // To store read bits + appbuf.len = size; + #if MICROPY_PY_MACHINE_PDM_PCM_RING_BUF + uint32_t num_bytes_read = fill_appbuf_from_ringbuf(self, &appbuf); + #else + uint32_t num_bytes_read = fill_appbuf_from_dma(self, &appbuf); + #endif + return num_bytes_read; + } else { // // ToDo: Placeholder for non-blocking mode + return 0; + } +} + +static const mp_stream_p_t pdm_pcm_stream_p = { + .read = machine_pdm_pcm_stream_read, + .is_text = false, +}; + static const mp_rom_map_elem_t machine_pdm_pcm_locals_dict_table[] = { // Methods { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pdm_pcm_init_obj) }, @@ -331,16 +495,15 @@ static const mp_rom_map_elem_t machine_pdm_pcm_locals_dict_table[] = { }; MP_DEFINE_CONST_DICT(machine_pdm_pcm_locals_dict, machine_pdm_pcm_locals_dict_table); - MP_REGISTER_ROOT_POINTER(struct _machine_pdm_pcm_obj_t *machine_pdm_pcm_obj[MICROPY_HW_MAX_PDM_PCM]); - MP_DEFINE_CONST_OBJ_TYPE( machine_pdm_pcm_type, MP_QSTR_PDM_PCM, MP_TYPE_FLAG_NONE, make_new, machine_pdm_pcm_make_new, print, machine_pdm_pcm_print, + protocol, &pdm_pcm_stream_p, locals_dict, &machine_pdm_pcm_locals_dict ); diff --git a/ports/psoc6/machine_pdm_pcm.h b/ports/psoc6/machine_pdm_pcm.h new file mode 100644 index 0000000000000..96843d9ec45a9 --- /dev/null +++ b/ports/psoc6/machine_pdm_pcm.h @@ -0,0 +1,102 @@ +#if MICROPY_PY_MACHINE_PDM_PCM + +#define MICROPY_HW_MAX_PDM_PCM 1 +#define DEFAULT_LEFT_GAIN 0 +#define DEFAULT_RIGHT_GAIN 0 + +#define AUDIO_SYS_CLOCK_24_576_000_HZ 24576000u /* (Ideally 24.576 MHz) For sample rates: 8 KHz / 16 KHz / 48 KHz */ +#define AUDIO_SYS_CLOCK_22_579_000_HZ 22579000u /* (Ideally 22.579 MHz) For sample rates: 22.05 KHz / 44.1 KHz */ + +#define SIZEOF_DMA_BUFFER (1024) +#define SIZEOF_DMA_BUFFER_IN_BYTES (1024 * sizeof(uint32_t)) +#define PDM_PCM_RX_FRAME_SIZE_IN_BYTES (8) + +#define pdm_pcm_assert_raise_val(msg, ret) if (ret != CY_RSLT_SUCCESS) { \ + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT(msg), ret); \ +} + +// Constructor args +enum { + ARG_clk, + ARG_data, + ARG_sample_rate, + ARG_decimation_rate, + ARG_bits, + ARG_format, + ARG_left_gain, + ARG_right_gain, +}; + +typedef enum { + BITS_16 = 16, + BITS_18 = 18, + BITS_20 = 20, + BITS_24 = 24 +} pdm_pcm_word_length_t; + +typedef enum { + MONO_LEFT = CYHAL_PDM_PCM_MODE_LEFT, + MONO_RIGHT = CYHAL_PDM_PCM_MODE_RIGHT, + STEREO = CYHAL_PDM_PCM_MODE_STEREO +} format_t; + +typedef enum { + BLOCKING, + NON_BLOCKING, +} io_mode_t; + +#if MICROPY_PY_MACHINE_PDM_PCM_RING_BUF + +typedef struct _ring_buf_t { + uint8_t *buffer; + size_t head; + size_t tail; + size_t size; +} ring_buf_t; + +static void ringbuf_init(ring_buf_t *rbuf, uint8_t *buffer, size_t size); +static bool ringbuf_push(ring_buf_t *rbuf, uint8_t data); +static bool ringbuf_pop(ring_buf_t *rbuf, uint8_t *data); +static size_t ringbuf_available_data(ring_buf_t *rbuf); +static size_t ringbuf_available_space(ring_buf_t *rbuf); +// static void fill_appbuf_from_ringbuf_non_blocking(machine_pdm_pcm_obj_t *self); + +#endif // MICROPY_PY_MACHINE_PDM_PCM_RING_BUF + + +typedef struct _non_blocking_descriptor_t { + mp_buffer_info_t appbuf; + uint32_t index; + bool copy_in_progress; +} non_blocking_descriptor_t; + +typedef struct _machine_pdm_pcm_obj_t { + mp_obj_base_t base; + uint8_t pdm_pcm_id; // Private variable in this port. ID not associated to any port pin pdm-pcm group. + cyhal_pdm_pcm_t pdm_pcm_obj; + uint32_t clk; + uint32_t data; + io_mode_t io_mode; + format_t format; + uint8_t bits; + uint32_t sample_rate; + uint8_t decimation_rate; + int16_t left_gain; + int16_t right_gain; + int32_t ibuf; + mp_obj_t callback_for_non_blocking; + uint32_t dma_active_buffer[SIZEOF_DMA_BUFFER]; + uint32_t dma_processing_buffer[SIZEOF_DMA_BUFFER]; + uint32_t *dma_active_buf_p; + uint32_t *dma_processing_buf_p; + ring_buf_t ring_buffer; + uint8_t *ring_buffer_storage; + non_blocking_descriptor_t non_blocking_descriptor; // For non-blocking mode +} machine_pdm_pcm_obj_t; + +static void mp_machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, mp_arg_val_t *args); +static machine_pdm_pcm_obj_t *mp_machine_pdm_pcm_make_new_instance(mp_int_t pdm_pcm_id); +static void mp_machine_pdm_pcm_init(machine_pdm_pcm_obj_t *self); +static void mp_machine_pdm_pcm_deinit(machine_pdm_pcm_obj_t *self); + +#endif // MICROPY_PY_MACHINE_PDM_PCM diff --git a/ports/psoc6/mpconfigport.h b/ports/psoc6/mpconfigport.h index 9a17d5cc1a8ac..4f23022a35877 100644 --- a/ports/psoc6/mpconfigport.h +++ b/ports/psoc6/mpconfigport.h @@ -151,6 +151,7 @@ #define MICROPY_PY_MACHINE_I2S_INCLUDEFILE "ports/psoc6/machine_i2s.c" #define MICROPY_PY_MACHINE_PDM_PCM (1) +#define MICROPY_PY_MACHINE_PDM_PCM_RING_BUF (1) // VFS #define MICROPY_VFS (1) #define MICROPY_READER_VFS (1) From 23e42cb0d66465acb36ac00a22b3e212d66fc1f0 Mon Sep 17 00:00:00 2001 From: NikhitaR-IFX Date: Mon, 7 Oct 2024 13:46:26 +0530 Subject: [PATCH 2/6] ports/psoc6: Read API enablement. Signed-off-by: NikhitaR-IFX --- ports/psoc6/machine_pdm_pcm.c | 17 ++++++++++++++++- ports/psoc6/machine_pdm_pcm.h | 9 +++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/ports/psoc6/machine_pdm_pcm.c b/ports/psoc6/machine_pdm_pcm.c index a7ca09a27424c..b2a76ef28cb13 100644 --- a/ports/psoc6/machine_pdm_pcm.c +++ b/ports/psoc6/machine_pdm_pcm.c @@ -39,6 +39,7 @@ cyhal_clock_t pdm_pcm_audio_clock; #if MICROPY_PY_MACHINE_PDM_PCM_RING_BUF + static void ringbuf_init(ring_buf_t *rbuf, uint8_t *buffer, size_t size) { rbuf->buffer = buffer; rbuf->size = size; @@ -113,7 +114,6 @@ static uint32_t fill_appbuf_from_ringbuf(machine_pdm_pcm_obj_t *self, mp_buffer_ } app_p += appbuf_sample_size_in_bytes; } -exit: return num_bytes_copied_to_appbuf; } @@ -339,6 +339,21 @@ static void pdm_pcm_start_rx(machine_pdm_pcm_obj_t *self) { pdm_pcm_assert_raise_val("PDM_PCM start failed with return code %lx !", result); } +int8_t get_frame_mapping_index(int8_t bits, format_t format) { + if ((format == MONO_LEFT) | (format == MONO_RIGHT)) { + if (bits == 16) { + return 0; + } else { // 32 bits + return 1; + } + } else { // STEREO + if (bits == 16) { + return 2; + } else { // 32 bits + return 3; + } + } +} // ======================================================================================= // MPY bindings for PDM_PCM (ports/psoc6) diff --git a/ports/psoc6/machine_pdm_pcm.h b/ports/psoc6/machine_pdm_pcm.h index 96843d9ec45a9..928208959c0d3 100644 --- a/ports/psoc6/machine_pdm_pcm.h +++ b/ports/psoc6/machine_pdm_pcm.h @@ -99,4 +99,13 @@ static machine_pdm_pcm_obj_t *mp_machine_pdm_pcm_make_new_instance(mp_int_t pdm_ static void mp_machine_pdm_pcm_init(machine_pdm_pcm_obj_t *self); static void mp_machine_pdm_pcm_deinit(machine_pdm_pcm_obj_t *self); + +static const int8_t pdm_pcm_frame_map[4][PDM_PCM_RX_FRAME_SIZE_IN_BYTES] = { + { 0, 1, -1, -1, -1, -1, -1, -1 }, // Mono, 16-bits + { 0, 1, 2, 3, -1, -1, -1, -1 }, // Mono, 32-bits + { 0, 1, -1, -1, 2, 3, -1, -1 }, // Stereo, 16-bits + { 0, 1, 2, 3, 4, 5, 6, 7 }, // Stereo, 32-bits +}; +int8_t get_frame_mapping_index(int8_t bits, format_t format); + #endif // MICROPY_PY_MACHINE_PDM_PCM From 14f2faa8bf00023965f573b62b4deb322aa37957 Mon Sep 17 00:00:00 2001 From: NikhitaR-IFX Date: Tue, 8 Oct 2024 15:27:18 +0530 Subject: [PATCH 3/6] ports/psoc6: Implemented gain functions. Signed-off-by: NikhitaR-IFX --- ports/psoc6/machine_pdm_pcm.c | 79 ++++++++++++++++++++++++++++++++--- ports/psoc6/machine_pdm_pcm.h | 2 +- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/ports/psoc6/machine_pdm_pcm.c b/ports/psoc6/machine_pdm_pcm.c index b2a76ef28cb13..08b5530928784 100644 --- a/ports/psoc6/machine_pdm_pcm.c +++ b/ports/psoc6/machine_pdm_pcm.c @@ -78,34 +78,42 @@ static size_t ringbuf_available_space(ring_buf_t *rbuf) { } static uint32_t fill_appbuf_from_ringbuf(machine_pdm_pcm_obj_t *self, mp_buffer_info_t *appbuf) { + mplogger_print("fill_appbuf_from_ringbuf \r\n"); uint32_t num_bytes_copied_to_appbuf = 0; uint8_t *app_p = (uint8_t *)appbuf->buf; uint8_t appbuf_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); // !J: Why only 16 or 32? uint32_t num_bytes_needed_from_ringbuf = appbuf->len * (PDM_PCM_RX_FRAME_SIZE_IN_BYTES / appbuf_sample_size_in_bytes); uint8_t discard_byte; + mp_printf(&mp_plat_print, "num_bytes_needed_from_ringbuf: %d \r\n", num_bytes_needed_from_ringbuf); while (num_bytes_needed_from_ringbuf) { uint8_t f_index = get_frame_mapping_index(self->bits, self->format); + mp_printf(&mp_plat_print, "f_index: %d \r\n", f_index); for (uint8_t i = 0; i < PDM_PCM_RX_FRAME_SIZE_IN_BYTES; i++) { int8_t r_to_a_mapping = pdm_pcm_frame_map[f_index][i]; if (r_to_a_mapping != -1) { + mp_printf(&mp_plat_print, "r_to_a_mapping: %d \r\n", r_to_a_mapping); if (self->io_mode == BLOCKING) { // poll the ringbuf until a sample becomes available, copy into appbuf using the mapping transform while (ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping) == false) { ; } + printf("Sample available \r\n"); + mp_printf(&mp_plat_print, "app_p + r_to_a_mapping: %d \r\n", app_p + r_to_a_mapping); num_bytes_copied_to_appbuf++; } else { return 0; // should never get here (non-blocking mode does not use this function) } } else { // r_a_mapping == -1 + mp_printf(&mp_plat_print, "r_to_a_mapping: %d \r\n", r_to_a_mapping); // discard unused byte from ring buffer if (self->io_mode == BLOCKING) { // poll the ringbuf until a sample becomes available while (ringbuf_pop(&self->ring_buffer, &discard_byte) == false) { - ; + printf("ringbuf_pop in unused byte \r\n"); } + mp_printf(&mp_plat_print, "discard_byte: %d \r\n", discard_byte); } else { return 0; // should never get here (non-blocking mode does not use this function) } @@ -123,6 +131,7 @@ static uint32_t fill_appbuf_from_ringbuf(machine_pdm_pcm_obj_t *self, mp_buffer_ // PDM_PCM higher level MPY functions (extmod/machine_pdm_pcm.c) MP_NOINLINE static void machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mplogger_print("machine_pdm_pcm_init_helper \r\n"); static const mp_arg_t allowed_args[] = { { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_data, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, @@ -163,6 +172,7 @@ static void machine_pdm_pcm_print(const mp_print_t *print, mp_obj_t self_in, mp_ // PDM_PCM(...) Constructor static mp_obj_t machine_pdm_pcm_make_new(const mp_obj_type_t *type, size_t n_pos_args, size_t n_kw_args, const mp_obj_t *args) { + mplogger_print("machine_pdm_pcm_make_new \r\n"); mp_arg_check_num(n_pos_args, n_kw_args, 1, MP_OBJ_FUN_ARGS_MAX, true); mp_int_t pdm_pcm_id = mp_obj_get_int(args[0]); @@ -177,6 +187,7 @@ static mp_obj_t machine_pdm_pcm_make_new(const mp_obj_type_t *type, size_t n_pos // PDM_PCM.init(...) static mp_obj_t machine_pdm_pcm_init(mp_obj_t self_in) { + mplogger_print("machine_pdm_pcm_init \r\n"); machine_pdm_pcm_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_machine_pdm_pcm_init(self); return mp_const_none; @@ -185,16 +196,46 @@ static MP_DEFINE_CONST_FUN_OBJ_1(machine_pdm_pcm_init_obj, machine_pdm_pcm_init) // PDM_PCM.deinit() static mp_obj_t machine_pdm_pcm_deinit(mp_obj_t self_in) { + mplogger_print("machine_pdm_pcm_deinit \r\n"); machine_pdm_pcm_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_machine_pdm_pcm_deinit(self); return mp_const_none; } static MP_DEFINE_CONST_FUN_OBJ_1(machine_pdm_pcm_deinit_obj, machine_pdm_pcm_deinit); +// PDM_PCM.set_gain() +static mp_obj_t machine_pdm_pcm_set_gain(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mplogger_print("machine_pdm_pcm_set_gain \r\n"); + + enum { ARG_left_gain, ARG_right_gain}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_left_gain, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_LEFT_GAIN} }, + { MP_QSTR_right_gain, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_RIGHT_GAIN} } + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + machine_pdm_pcm_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + int16_t left_gain = args[ARG_left_gain].u_int; + int16_t right_gain = args[ARG_right_gain].u_int; + + int16_t prev_left_gain = self->left_gain; + int16_t prev_right_gain = self->right_gain; + + self->left_gain = (left_gain == prev_left_gain) ? prev_left_gain : left_gain; + self->right_gain = (right_gain == prev_right_gain) ? prev_right_gain : right_gain; + + mp_machine_pdm_pcm_set_gain(self, left_gain, right_gain); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_KW(machine_pdm_pcm_set_gain_obj, 1, machine_pdm_pcm_set_gain); + // ======================================================================================= // Port Private functions for DMA support (ports/psoc6) static inline void _dma_buff_init(machine_pdm_pcm_obj_t *self) { + mplogger_print("_dma_buff_init \r\n"); for (uint32_t i = 0; i < SIZEOF_DMA_BUFFER; i++) { self->dma_active_buffer[i] = 0; self->dma_processing_buffer[i] = 0; @@ -205,12 +246,14 @@ static inline void _dma_buff_init(machine_pdm_pcm_obj_t *self) { } static inline void _dma_swap_active_dmabuf(machine_pdm_pcm_obj_t *self) { + mplogger_print("_dma_swap_active_dmabuf \r\n"); uint32_t *temp = self->dma_active_buf_p; self->dma_active_buf_p = self->dma_processing_buf_p; self->dma_processing_buf_p = temp; } static void _dma_copy_from_dmabuf_to_ringbuf(machine_pdm_pcm_obj_t *self) { + mplogger_print("_dma_copy_from_dmabuf_to_ringbuf \r\n"); uint8_t dma_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); uint8_t *dma_buff_p = (uint8_t *)self->dma_processing_buf_p; uint32_t num_bytes_needed_from_ringbuf = SIZEOF_DMA_BUFFER_IN_BYTES * (PDM_PCM_RX_FRAME_SIZE_IN_BYTES / dma_sample_size_in_bytes); @@ -238,6 +281,7 @@ static void _dma_copy_from_dmabuf_to_ringbuf(machine_pdm_pcm_obj_t *self) { // Init hardware block static void pdm_pcm_init(machine_pdm_pcm_obj_t *self, cyhal_clock_t *clock) { + mplogger_print("pdm_pcm_init \r\n"); cyhal_pdm_pcm_cfg_t config = { .sample_rate = self->sample_rate, @@ -255,6 +299,7 @@ static void pdm_pcm_init(machine_pdm_pcm_obj_t *self, cyhal_clock_t *clock) { // Initialize audio clock void pdm_pcm_audio_clock_init(uint32_t audio_clock_freq_hz) { + mplogger_print("pdm_pcm_audio_clock_init \r\n"); cyhal_clock_t pll_clock; cy_rslt_t result; @@ -298,12 +343,14 @@ void pdm_pcm_audio_clock_init(uint32_t audio_clock_freq_hz) { // Set PDM_PCM async mode to DMA static void pdm_pcm_set_async_mode_dma(machine_pdm_pcm_obj_t *self) { + mplogger_print("pdm_pcm_set_async_mode_dma \r\n"); cy_rslt_t result = cyhal_pdm_pcm_set_async_mode(&self->pdm_pcm_obj, CYHAL_ASYNC_DMA, CYHAL_DMA_PRIORITY_DEFAULT); pdm_pcm_assert_raise_val("PDM_PCM set DMA mode failed with return code %lx !", result); } // Read from PDM_PCM reg to provisioned DMA buffer static void pdm_pcm_read_rxbuf(machine_pdm_pcm_obj_t *self) { + mplogger_print("pdm_pcm_read_rxbuf \r\n"); // ToDo: Check the value of dma_half_buff_word_size and adapt for PDM-PCM uint16_t dma_half_buff_word_size = SIZEOF_DMA_BUFFER_IN_BYTES / 2; cy_rslt_t result = cyhal_pdm_pcm_read_async(&self->pdm_pcm_obj, self->dma_active_buf_p, dma_half_buff_word_size); @@ -328,13 +375,14 @@ static void pdm_pcm_irq_handler(void *arg, cyhal_pdm_pcm_event_t event) { // Configure PDM_PCM IRQ static void pdm_pcm_irq_configure(machine_pdm_pcm_obj_t *self) { + mplogger_print("pdm_pcm_irq_configure \r\n"); cyhal_pdm_pcm_register_callback(&self->pdm_pcm_obj, &pdm_pcm_irq_handler, self); cyhal_pdm_pcm_enable_event(&self->pdm_pcm_obj, CYHAL_PDM_PCM_ASYNC_COMPLETE, CYHAL_ISR_PRIORITY_DEFAULT, true); } // Start PDM_PCM receive operation static void pdm_pcm_start_rx(machine_pdm_pcm_obj_t *self) { - pdm_pcm_read_rxbuf(self); + mplogger_print("pdm_pcm_start_rx \r\n"); cy_rslt_t result = cyhal_pdm_pcm_start(&self->pdm_pcm_obj); pdm_pcm_assert_raise_val("PDM_PCM start failed with return code %lx !", result); } @@ -359,6 +407,7 @@ int8_t get_frame_mapping_index(int8_t bits, format_t format) { // constructor() static machine_pdm_pcm_obj_t *mp_machine_pdm_pcm_make_new_instance(mp_int_t pdm_pcm_id) { + mplogger_print("mp_machine_pdm_pcm_make_new_instance \r\n"); (void)pdm_pcm_id; machine_pdm_pcm_obj_t *self = NULL; for (uint8_t i = 0; i < MICROPY_HW_MAX_PDM_PCM; i++) { @@ -377,7 +426,7 @@ static machine_pdm_pcm_obj_t *mp_machine_pdm_pcm_make_new_instance(mp_int_t pdm_ // init.helper() static void mp_machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, mp_arg_val_t *args) { - + mplogger_print("mp_machine_pdm_pcm_init_helper \r\n"); // Assign pins self->clk = pin_addr_by_name(args[ARG_clk].u_obj); self->data = pin_addr_by_name(args[ARG_data].u_obj); @@ -435,31 +484,47 @@ static void mp_machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, mp_arg_v pdm_pcm_init(self, &pdm_pcm_audio_clock); pdm_pcm_irq_configure(self); pdm_pcm_set_async_mode_dma(self); - _dma_buff_init(self); pdm_pcm_start_rx(self); + _dma_buff_init(self); + // pdm_pcm_read_rxbuf(self); } // init() static void mp_machine_pdm_pcm_init(machine_pdm_pcm_obj_t *self) { + mplogger_print("mp_machine_pdm_pcm_init \r\n"); cyhal_pdm_pcm_start(&self->pdm_pcm_obj); } // deinit() static void mp_machine_pdm_pcm_deinit(machine_pdm_pcm_obj_t *self) { + mplogger_print("mp_machine_pdm_pcm_deinit \r\n"); cyhal_pdm_pcm_stop(&self->pdm_pcm_obj); cyhal_pdm_pcm_free(&self->pdm_pcm_obj); MP_STATE_PORT(machine_pdm_pcm_obj[self->pdm_pcm_id]) = NULL; } +// set_gain() +static void mp_machine_pdm_pcm_set_gain(machine_pdm_pcm_obj_t *self, int16_t left_gain, int16_t right_gain) { + mplogger_print("mp_machine_pdm_pcm_set_gain \r\n"); + mp_printf(&mp_plat_print, "machine.PDM_PCM: Setting left mic gain to %d and right mic gain to %d\n", self->left_gain, self->right_gain); + cy_rslt_t result = cyhal_pdm_pcm_set_gain(&self->pdm_pcm_obj, self->left_gain, self->right_gain); + pdm_pcm_assert_raise_val("PDM_PCM set gain failed with return code %lx !", result); +} + // ======================================================================================= // Implementation for stream protocol (ports/psoc6) static mp_uint_t machine_pdm_pcm_stream_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { + mplogger_print("machine_pdm_pcm_stream_read \r\n"); machine_pdm_pcm_obj_t *self = MP_OBJ_TO_PTR(self_in); uint8_t appbuf_sample_size_in_bytes = (self->bits / 8) * (self->format == STEREO ? 2: 1); + printf("appbuf_sample_size_in_bytes: %d \r\n", appbuf_sample_size_in_bytes); + printf("size: %d \r\n", size); + printf("size by appbuf_sample_size_in_bytes: %d \r\n", size % appbuf_sample_size_in_bytes); // uint8_t appbuf_sample_size_in_bytes = (self->bits + 7) /8; // round up to higher limit. Consider 20 bits and 18 bits case. if (size % appbuf_sample_size_in_bytes != 0) { // size should be multiple of sample size + printf("Error here! \r\n"); *errcode = MP_EINVAL; return MP_STREAM_ERROR; } @@ -474,6 +539,7 @@ static mp_uint_t machine_pdm_pcm_stream_read(mp_obj_t self_in, void *buf_in, mp_ appbuf.len = size; #if MICROPY_PY_MACHINE_PDM_PCM_RING_BUF uint32_t num_bytes_read = fill_appbuf_from_ringbuf(self, &appbuf); + #else uint32_t num_bytes_read = fill_appbuf_from_dma(self, &appbuf); #endif @@ -492,6 +558,9 @@ static const mp_rom_map_elem_t machine_pdm_pcm_locals_dict_table[] = { // Methods { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pdm_pcm_init_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_pdm_pcm_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_gain), MP_ROM_PTR(&machine_pdm_pcm_set_gain_obj) }, + #if MICROPY_PY_MACHINE_PDM_PCM_FINALISER { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&machine_pdm_pcm_deinit_obj) }, #endif @@ -515,7 +584,7 @@ MP_REGISTER_ROOT_POINTER(struct _machine_pdm_pcm_obj_t *machine_pdm_pcm_obj[MICR MP_DEFINE_CONST_OBJ_TYPE( machine_pdm_pcm_type, MP_QSTR_PDM_PCM, - MP_TYPE_FLAG_NONE, + MP_TYPE_FLAG_ITER_IS_STREAM, make_new, machine_pdm_pcm_make_new, print, machine_pdm_pcm_print, protocol, &pdm_pcm_stream_p, diff --git a/ports/psoc6/machine_pdm_pcm.h b/ports/psoc6/machine_pdm_pcm.h index 928208959c0d3..6e762d6f4ba8e 100644 --- a/ports/psoc6/machine_pdm_pcm.h +++ b/ports/psoc6/machine_pdm_pcm.h @@ -98,7 +98,7 @@ static void mp_machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, mp_arg_v static machine_pdm_pcm_obj_t *mp_machine_pdm_pcm_make_new_instance(mp_int_t pdm_pcm_id); static void mp_machine_pdm_pcm_init(machine_pdm_pcm_obj_t *self); static void mp_machine_pdm_pcm_deinit(machine_pdm_pcm_obj_t *self); - +static void mp_machine_pdm_pcm_set_gain(machine_pdm_pcm_obj_t *self, int16_t left_gain, int16_t right_gain); static const int8_t pdm_pcm_frame_map[4][PDM_PCM_RX_FRAME_SIZE_IN_BYTES] = { { 0, 1, -1, -1, -1, -1, -1, -1 }, // Mono, 16-bits From 675c177ad679919665d4c7ce20c822eeeefd9aa1 Mon Sep 17 00:00:00 2001 From: NikhitaR-IFX Date: Thu, 10 Oct 2024 12:37:35 +0530 Subject: [PATCH 4/6] ports/psoc6: Enable all functions for PDM_PCM. Signed-off-by: NikhitaR-IFX --- docs/psoc6/quickref.rst | 18 ++++- ports/psoc6/machine_pdm_pcm.c | 133 ++++++++++++++++++++++++---------- ports/psoc6/machine_pdm_pcm.h | 8 +- 3 files changed, 117 insertions(+), 42 deletions(-) diff --git a/docs/psoc6/quickref.rst b/docs/psoc6/quickref.rst index 42a08530cbf52..94f465cd311c4 100644 --- a/docs/psoc6/quickref.rst +++ b/docs/psoc6/quickref.rst @@ -633,9 +633,9 @@ Constructor Methods ------- -.. method:: PDM_PCM.init(clk, ...) +.. method:: PDM_PCM.init() - See constructor for argument descriptions + Starts the PDM_PCM hardware block and conversion operation. .. method:: PDM_PCM.deinit() @@ -643,9 +643,21 @@ Methods .. method:: PDM_PCM.readinto(buf) + Read audio samples into the buffer specified by ``buf``. ``buf`` must support the buffer protocol, such as bytearray or array. + For Stereo format, left channel sample precedes right channel sample. For Mono-left format, + the left channel sample data is used and for Mono-right format, right channel data is used. + Returns number of bytes read + .. method:: PDM_PCM.irq(handler) -.. method:: PDM_PCM.gain(gain_left, gain_right) + Set the callback.``handler`` is called when ``buf`` becomes full (``readinto`` method). + Setting a callback changes the ``readinto`` method to non-blocking operation. + ``handler`` is called in the context of the MicroPython scheduler. + +.. method:: PDM_PCM.gain(left_gain, right_gain) + + Set the gain for single or both microphones. When either of the gain value is not passed, + previously set value or default value of 0dB is set. Constants --------- diff --git a/ports/psoc6/machine_pdm_pcm.c b/ports/psoc6/machine_pdm_pcm.c index 08b5530928784..98250a8db5be3 100644 --- a/ports/psoc6/machine_pdm_pcm.c +++ b/ports/psoc6/machine_pdm_pcm.c @@ -78,7 +78,7 @@ static size_t ringbuf_available_space(ring_buf_t *rbuf) { } static uint32_t fill_appbuf_from_ringbuf(machine_pdm_pcm_obj_t *self, mp_buffer_info_t *appbuf) { - mplogger_print("fill_appbuf_from_ringbuf \r\n"); + printf("fill_appbuf_from_ringbuf \r\n"); uint32_t num_bytes_copied_to_appbuf = 0; uint8_t *app_p = (uint8_t *)appbuf->buf; uint8_t appbuf_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); // !J: Why only 16 or 32? @@ -125,13 +125,51 @@ static uint32_t fill_appbuf_from_ringbuf(machine_pdm_pcm_obj_t *self, mp_buffer_ return num_bytes_copied_to_appbuf; } +// Copy from ringbuf to appbuf as soon as ASYNC_TRANSFER_COMPLETE is triggered +static void fill_appbuf_from_ringbuf_non_blocking(machine_pdm_pcm_obj_t *self) { + uint32_t num_bytes_copied_to_appbuf = 0; + uint8_t *app_p = &(((uint8_t *)self->non_blocking_descriptor.appbuf.buf)[self->non_blocking_descriptor.index]); + + uint8_t appbuf_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); + uint32_t num_bytes_remaining_to_copy_to_appbuf = self->non_blocking_descriptor.appbuf.len - self->non_blocking_descriptor.index; + uint32_t num_bytes_remaining_to_copy_from_ring_buffer = num_bytes_remaining_to_copy_to_appbuf * + (PDM_PCM_RX_FRAME_SIZE_IN_BYTES / appbuf_sample_size_in_bytes); + uint32_t num_bytes_needed_from_ringbuf = MIN(SIZEOF_NON_BLOCKING_COPY_IN_BYTES, num_bytes_remaining_to_copy_from_ring_buffer); + uint8_t discard_byte; + if (ringbuf_available_data(&self->ring_buffer) >= num_bytes_needed_from_ringbuf) { + while (num_bytes_needed_from_ringbuf) { + + uint8_t f_index = get_frame_mapping_index(self->bits, self->format); + + for (uint8_t i = 0; i < PDM_PCM_RX_FRAME_SIZE_IN_BYTES; i++) { + int8_t r_to_a_mapping = pdm_pcm_frame_map[f_index][i]; + if (r_to_a_mapping != -1) { + ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping); + num_bytes_copied_to_appbuf++; + } else { // r_a_mapping == -1 + // discard unused byte from ring buffer + ringbuf_pop(&self->ring_buffer, &discard_byte); + } + num_bytes_needed_from_ringbuf--; + } + app_p += appbuf_sample_size_in_bytes; + } + self->non_blocking_descriptor.index += num_bytes_copied_to_appbuf; + + if (self->non_blocking_descriptor.index >= self->non_blocking_descriptor.appbuf.len) { + self->non_blocking_descriptor.copy_in_progress = false; + mp_sched_schedule(self->callback_for_non_blocking, MP_OBJ_FROM_PTR(self)); + } + } +} + #endif // MICROPY_PY_MACHINE_PDM_PCM_RING_BUF /*========================================================================================================================*/ // PDM_PCM higher level MPY functions (extmod/machine_pdm_pcm.c) MP_NOINLINE static void machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - mplogger_print("machine_pdm_pcm_init_helper \r\n"); + printf("machine_pdm_pcm_init_helper \r\n"); static const mp_arg_t allowed_args[] = { { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_data, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, @@ -172,7 +210,7 @@ static void machine_pdm_pcm_print(const mp_print_t *print, mp_obj_t self_in, mp_ // PDM_PCM(...) Constructor static mp_obj_t machine_pdm_pcm_make_new(const mp_obj_type_t *type, size_t n_pos_args, size_t n_kw_args, const mp_obj_t *args) { - mplogger_print("machine_pdm_pcm_make_new \r\n"); + printf("machine_pdm_pcm_make_new \r\n"); mp_arg_check_num(n_pos_args, n_kw_args, 1, MP_OBJ_FUN_ARGS_MAX, true); mp_int_t pdm_pcm_id = mp_obj_get_int(args[0]); @@ -187,7 +225,7 @@ static mp_obj_t machine_pdm_pcm_make_new(const mp_obj_type_t *type, size_t n_pos // PDM_PCM.init(...) static mp_obj_t machine_pdm_pcm_init(mp_obj_t self_in) { - mplogger_print("machine_pdm_pcm_init \r\n"); + printf("machine_pdm_pcm_init \r\n"); machine_pdm_pcm_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_machine_pdm_pcm_init(self); return mp_const_none; @@ -196,7 +234,7 @@ static MP_DEFINE_CONST_FUN_OBJ_1(machine_pdm_pcm_init_obj, machine_pdm_pcm_init) // PDM_PCM.deinit() static mp_obj_t machine_pdm_pcm_deinit(mp_obj_t self_in) { - mplogger_print("machine_pdm_pcm_deinit \r\n"); + printf("machine_pdm_pcm_deinit \r\n"); machine_pdm_pcm_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_machine_pdm_pcm_deinit(self); return mp_const_none; @@ -205,7 +243,7 @@ static MP_DEFINE_CONST_FUN_OBJ_1(machine_pdm_pcm_deinit_obj, machine_pdm_pcm_dei // PDM_PCM.set_gain() static mp_obj_t machine_pdm_pcm_set_gain(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - mplogger_print("machine_pdm_pcm_set_gain \r\n"); + printf("machine_pdm_pcm_set_gain \r\n"); enum { ARG_left_gain, ARG_right_gain}; static const mp_arg_t allowed_args[] = { @@ -231,11 +269,32 @@ static mp_obj_t machine_pdm_pcm_set_gain(size_t n_args, const mp_obj_t *pos_args } static MP_DEFINE_CONST_FUN_OBJ_KW(machine_pdm_pcm_set_gain_obj, 1, machine_pdm_pcm_set_gain); +// PDM_PCM.irq(handler) +static mp_obj_t machine_pdm_pcm_irq(mp_obj_t self_in, mp_obj_t handler) { + machine_pdm_pcm_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (handler != mp_const_none && !mp_obj_is_callable(handler)) { + mp_raise_ValueError(MP_ERROR_TEXT("invalid callback")); + } + + if (handler != mp_const_none) { + self->io_mode = NON_BLOCKING; + } else { + self->io_mode = BLOCKING; + } + + self->callback_for_non_blocking = handler; + + mp_machine_pdm_pcm_irq_update(self); + + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(machine_pdm_pcm_irq_obj, machine_pdm_pcm_irq); + // ======================================================================================= // Port Private functions for DMA support (ports/psoc6) static inline void _dma_buff_init(machine_pdm_pcm_obj_t *self) { - mplogger_print("_dma_buff_init \r\n"); + printf("_dma_buff_init \r\n"); for (uint32_t i = 0; i < SIZEOF_DMA_BUFFER; i++) { self->dma_active_buffer[i] = 0; self->dma_processing_buffer[i] = 0; @@ -246,14 +305,14 @@ static inline void _dma_buff_init(machine_pdm_pcm_obj_t *self) { } static inline void _dma_swap_active_dmabuf(machine_pdm_pcm_obj_t *self) { - mplogger_print("_dma_swap_active_dmabuf \r\n"); + printf("_dma_swap_active_dmabuf \r\n"); uint32_t *temp = self->dma_active_buf_p; self->dma_active_buf_p = self->dma_processing_buf_p; self->dma_processing_buf_p = temp; } static void _dma_copy_from_dmabuf_to_ringbuf(machine_pdm_pcm_obj_t *self) { - mplogger_print("_dma_copy_from_dmabuf_to_ringbuf \r\n"); + printf("_dma_copy_from_dmabuf_to_ringbuf \r\n"); uint8_t dma_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); uint8_t *dma_buff_p = (uint8_t *)self->dma_processing_buf_p; uint32_t num_bytes_needed_from_ringbuf = SIZEOF_DMA_BUFFER_IN_BYTES * (PDM_PCM_RX_FRAME_SIZE_IN_BYTES / dma_sample_size_in_bytes); @@ -281,7 +340,7 @@ static void _dma_copy_from_dmabuf_to_ringbuf(machine_pdm_pcm_obj_t *self) { // Init hardware block static void pdm_pcm_init(machine_pdm_pcm_obj_t *self, cyhal_clock_t *clock) { - mplogger_print("pdm_pcm_init \r\n"); + printf("pdm_pcm_init \r\n"); cyhal_pdm_pcm_cfg_t config = { .sample_rate = self->sample_rate, @@ -299,7 +358,7 @@ static void pdm_pcm_init(machine_pdm_pcm_obj_t *self, cyhal_clock_t *clock) { // Initialize audio clock void pdm_pcm_audio_clock_init(uint32_t audio_clock_freq_hz) { - mplogger_print("pdm_pcm_audio_clock_init \r\n"); + printf("pdm_pcm_audio_clock_init \r\n"); cyhal_clock_t pll_clock; cy_rslt_t result; @@ -343,20 +402,25 @@ void pdm_pcm_audio_clock_init(uint32_t audio_clock_freq_hz) { // Set PDM_PCM async mode to DMA static void pdm_pcm_set_async_mode_dma(machine_pdm_pcm_obj_t *self) { - mplogger_print("pdm_pcm_set_async_mode_dma \r\n"); + printf("pdm_pcm_set_async_mode_dma \r\n"); cy_rslt_t result = cyhal_pdm_pcm_set_async_mode(&self->pdm_pcm_obj, CYHAL_ASYNC_DMA, CYHAL_DMA_PRIORITY_DEFAULT); pdm_pcm_assert_raise_val("PDM_PCM set DMA mode failed with return code %lx !", result); } -// Read from PDM_PCM reg to provisioned DMA buffer +// Read from PDM_PCM buf to provisioned DMA buffer static void pdm_pcm_read_rxbuf(machine_pdm_pcm_obj_t *self) { - mplogger_print("pdm_pcm_read_rxbuf \r\n"); - // ToDo: Check the value of dma_half_buff_word_size and adapt for PDM-PCM - uint16_t dma_half_buff_word_size = SIZEOF_DMA_BUFFER_IN_BYTES / 2; - cy_rslt_t result = cyhal_pdm_pcm_read_async(&self->pdm_pcm_obj, self->dma_active_buf_p, dma_half_buff_word_size); + printf("pdm_pcm_read_rxbuf \r\n"); + // ToDo: Check the value of dma_buff_word_size and adapt for PDM-PCM + cy_rslt_t result = cyhal_pdm_pcm_read_async(&self->pdm_pcm_obj, self->dma_active_buf_p, SIZEOF_DMA_BUFFER); pdm_pcm_assert_raise_val("PDM_PCM DMA read failed with return code %lx !", result); } +static void pdm_pcm_rx_init(machine_pdm_pcm_obj_t *self) { + pdm_pcm_read_rxbuf(self); + cy_rslt_t result = cyhal_pdm_pcm_start(&self->pdm_pcm_obj); + pdm_pcm_assert_raise_val("PDM_PCM rx start failed with return code %lx !", result); +} + // IRQ Handler static void pdm_pcm_irq_handler(void *arg, cyhal_pdm_pcm_event_t event) { machine_pdm_pcm_obj_t *self = (machine_pdm_pcm_obj_t *)arg; @@ -366,27 +430,19 @@ static void pdm_pcm_irq_handler(void *arg, cyhal_pdm_pcm_event_t event) { pdm_pcm_read_rxbuf(self); _dma_copy_from_dmabuf_to_ringbuf(self); - // ToDo: Implementation placeholder for non-blocking mode - /*if ((self->io_mode == NON_BLOCKING) && (self->non_blocking_descriptor.copy_in_progress)) { + if ((self->io_mode == NON_BLOCKING) && (self->non_blocking_descriptor.copy_in_progress)) { fill_appbuf_from_ringbuf_non_blocking(self); - }*/ + } } } // Configure PDM_PCM IRQ static void pdm_pcm_irq_configure(machine_pdm_pcm_obj_t *self) { - mplogger_print("pdm_pcm_irq_configure \r\n"); + printf("pdm_pcm_irq_configure \r\n"); cyhal_pdm_pcm_register_callback(&self->pdm_pcm_obj, &pdm_pcm_irq_handler, self); cyhal_pdm_pcm_enable_event(&self->pdm_pcm_obj, CYHAL_PDM_PCM_ASYNC_COMPLETE, CYHAL_ISR_PRIORITY_DEFAULT, true); } -// Start PDM_PCM receive operation -static void pdm_pcm_start_rx(machine_pdm_pcm_obj_t *self) { - mplogger_print("pdm_pcm_start_rx \r\n"); - cy_rslt_t result = cyhal_pdm_pcm_start(&self->pdm_pcm_obj); - pdm_pcm_assert_raise_val("PDM_PCM start failed with return code %lx !", result); -} - int8_t get_frame_mapping_index(int8_t bits, format_t format) { if ((format == MONO_LEFT) | (format == MONO_RIGHT)) { if (bits == 16) { @@ -407,7 +463,7 @@ int8_t get_frame_mapping_index(int8_t bits, format_t format) { // constructor() static machine_pdm_pcm_obj_t *mp_machine_pdm_pcm_make_new_instance(mp_int_t pdm_pcm_id) { - mplogger_print("mp_machine_pdm_pcm_make_new_instance \r\n"); + printf("mp_machine_pdm_pcm_make_new_instance \r\n"); (void)pdm_pcm_id; machine_pdm_pcm_obj_t *self = NULL; for (uint8_t i = 0; i < MICROPY_HW_MAX_PDM_PCM; i++) { @@ -426,7 +482,7 @@ static machine_pdm_pcm_obj_t *mp_machine_pdm_pcm_make_new_instance(mp_int_t pdm_ // init.helper() static void mp_machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, mp_arg_val_t *args) { - mplogger_print("mp_machine_pdm_pcm_init_helper \r\n"); + printf("mp_machine_pdm_pcm_init_helper \r\n"); // Assign pins self->clk = pin_addr_by_name(args[ARG_clk].u_obj); self->data = pin_addr_by_name(args[ARG_data].u_obj); @@ -484,20 +540,18 @@ static void mp_machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, mp_arg_v pdm_pcm_init(self, &pdm_pcm_audio_clock); pdm_pcm_irq_configure(self); pdm_pcm_set_async_mode_dma(self); - pdm_pcm_start_rx(self); _dma_buff_init(self); - // pdm_pcm_read_rxbuf(self); } // init() static void mp_machine_pdm_pcm_init(machine_pdm_pcm_obj_t *self) { - mplogger_print("mp_machine_pdm_pcm_init \r\n"); - cyhal_pdm_pcm_start(&self->pdm_pcm_obj); + printf("mp_machine_pdm_pcm_init \r\n"); + pdm_pcm_rx_init(self); } // deinit() static void mp_machine_pdm_pcm_deinit(machine_pdm_pcm_obj_t *self) { - mplogger_print("mp_machine_pdm_pcm_deinit \r\n"); + printf("mp_machine_pdm_pcm_deinit \r\n"); cyhal_pdm_pcm_stop(&self->pdm_pcm_obj); cyhal_pdm_pcm_free(&self->pdm_pcm_obj); MP_STATE_PORT(machine_pdm_pcm_obj[self->pdm_pcm_id]) = NULL; @@ -505,17 +559,20 @@ static void mp_machine_pdm_pcm_deinit(machine_pdm_pcm_obj_t *self) { // set_gain() static void mp_machine_pdm_pcm_set_gain(machine_pdm_pcm_obj_t *self, int16_t left_gain, int16_t right_gain) { - mplogger_print("mp_machine_pdm_pcm_set_gain \r\n"); + printf("mp_machine_pdm_pcm_set_gain \r\n"); mp_printf(&mp_plat_print, "machine.PDM_PCM: Setting left mic gain to %d and right mic gain to %d\n", self->left_gain, self->right_gain); cy_rslt_t result = cyhal_pdm_pcm_set_gain(&self->pdm_pcm_obj, self->left_gain, self->right_gain); pdm_pcm_assert_raise_val("PDM_PCM set gain failed with return code %lx !", result); } +static void mp_machine_pdm_pcm_irq_update(machine_pdm_pcm_obj_t *self) { + (void)self; +} // ======================================================================================= // Implementation for stream protocol (ports/psoc6) static mp_uint_t machine_pdm_pcm_stream_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { - mplogger_print("machine_pdm_pcm_stream_read \r\n"); + printf("machine_pdm_pcm_stream_read \r\n"); machine_pdm_pcm_obj_t *self = MP_OBJ_TO_PTR(self_in); uint8_t appbuf_sample_size_in_bytes = (self->bits / 8) * (self->format == STEREO ? 2: 1); @@ -539,7 +596,6 @@ static mp_uint_t machine_pdm_pcm_stream_read(mp_obj_t self_in, void *buf_in, mp_ appbuf.len = size; #if MICROPY_PY_MACHINE_PDM_PCM_RING_BUF uint32_t num_bytes_read = fill_appbuf_from_ringbuf(self, &appbuf); - #else uint32_t num_bytes_read = fill_appbuf_from_dma(self, &appbuf); #endif @@ -560,6 +616,7 @@ static const mp_rom_map_elem_t machine_pdm_pcm_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_pdm_pcm_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_set_gain), MP_ROM_PTR(&machine_pdm_pcm_set_gain_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_pdm_pcm_irq_obj) }, #if MICROPY_PY_MACHINE_PDM_PCM_FINALISER { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&machine_pdm_pcm_deinit_obj) }, diff --git a/ports/psoc6/machine_pdm_pcm.h b/ports/psoc6/machine_pdm_pcm.h index 6e762d6f4ba8e..c727cd358a310 100644 --- a/ports/psoc6/machine_pdm_pcm.h +++ b/ports/psoc6/machine_pdm_pcm.h @@ -11,6 +11,10 @@ #define SIZEOF_DMA_BUFFER_IN_BYTES (1024 * sizeof(uint32_t)) #define PDM_PCM_RX_FRAME_SIZE_IN_BYTES (8) +#define NON_BLOCKING_RATE_MULTIPLIER (4) +#define SIZEOF_NON_BLOCKING_COPY_IN_BYTES (SIZEOF_DMA_BUFFER * NON_BLOCKING_RATE_MULTIPLIER) + + #define pdm_pcm_assert_raise_val(msg, ret) if (ret != CY_RSLT_SUCCESS) { \ mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT(msg), ret); \ } @@ -83,7 +87,7 @@ typedef struct _machine_pdm_pcm_obj_t { uint8_t decimation_rate; int16_t left_gain; int16_t right_gain; - int32_t ibuf; + int32_t ibuf; // ToDo: Does user needs to calculate this in PDM? mp_obj_t callback_for_non_blocking; uint32_t dma_active_buffer[SIZEOF_DMA_BUFFER]; uint32_t dma_processing_buffer[SIZEOF_DMA_BUFFER]; @@ -99,6 +103,8 @@ static machine_pdm_pcm_obj_t *mp_machine_pdm_pcm_make_new_instance(mp_int_t pdm_ static void mp_machine_pdm_pcm_init(machine_pdm_pcm_obj_t *self); static void mp_machine_pdm_pcm_deinit(machine_pdm_pcm_obj_t *self); static void mp_machine_pdm_pcm_set_gain(machine_pdm_pcm_obj_t *self, int16_t left_gain, int16_t right_gain); +static void mp_machine_pdm_pcm_irq_update(machine_pdm_pcm_obj_t *self); + static const int8_t pdm_pcm_frame_map[4][PDM_PCM_RX_FRAME_SIZE_IN_BYTES] = { { 0, 1, -1, -1, -1, -1, -1, -1 }, // Mono, 16-bits From 313d1e2bb0bd3a252b1590c4fec65abb493c8a99 Mon Sep 17 00:00:00 2001 From: NikhitaR-IFX Date: Mon, 4 Nov 2024 14:12:25 +0530 Subject: [PATCH 5/6] ports/psoc6: PDM_PCM manual testing and refactor. Signed-off-by: NikhitaR-IFX --- docs/psoc6/quickref.rst | 8 +- ports/psoc6/machine_pdm_pcm.c | 200 ++++++++++-------- ports/psoc6/machine_pdm_pcm.h | 31 +-- ports/psoc6/ringbuf.c | 111 ++++++++++ ports/psoc6/ringbuf.h | 29 +++ .../ports/psoc6/board_ext_hw/multi/pdm_pcm.py | 10 + 6 files changed, 276 insertions(+), 113 deletions(-) create mode 100644 ports/psoc6/ringbuf.c create mode 100644 ports/psoc6/ringbuf.h diff --git a/docs/psoc6/quickref.rst b/docs/psoc6/quickref.rst index 94f465cd311c4..c6f28e6121a65 100644 --- a/docs/psoc6/quickref.rst +++ b/docs/psoc6/quickref.rst @@ -579,8 +579,8 @@ Constructor audio_in = I2S(0, sck="P5_4", ws="P5_5", sd="P5_6", mode=I2S.RX, bits=16, format=I2S.STEREO, rate=22050, ibuf=20000) # create I2S object num_read = audio_in.readinto(buf)# fill buffer with audio samples from I2S device -PDM - PCM ------------- +PDM - PCM bus +-------------- PDM/PCM is a asynchronous operation used to connect digital audio devices. At the physical level, a bus consists of 2 lines: CLK, DATA. @@ -611,7 +611,7 @@ PDM objects can be created and initialized using:: Constructor ------------ +^^^^^^^^^^^^ .. class:: PDM_PCM(id, *, clk, data, sample_rate, decimation_rate, bits, format, left_gain, right_gain) @@ -631,7 +631,7 @@ Constructor - ``right_gain`` is PGA in 0.5 dB increment Methods -------- +^^^^^^^^ .. method:: PDM_PCM.init() diff --git a/ports/psoc6/machine_pdm_pcm.c b/ports/psoc6/machine_pdm_pcm.c index 98250a8db5be3..e1773e6ad9af2 100644 --- a/ports/psoc6/machine_pdm_pcm.c +++ b/ports/psoc6/machine_pdm_pcm.c @@ -32,88 +32,48 @@ #include "machine_pin_phy.h" #include "modmachine.h" #include "mplogger.h" - #if MICROPY_PY_MACHINE_PDM_PCM #include "machine_pdm_pcm.h" cyhal_clock_t pdm_pcm_audio_clock; -#if MICROPY_PY_MACHINE_PDM_PCM_RING_BUF - -static void ringbuf_init(ring_buf_t *rbuf, uint8_t *buffer, size_t size) { - rbuf->buffer = buffer; - rbuf->size = size; - rbuf->head = 0; - rbuf->tail = 0; -} - -static bool ringbuf_push(ring_buf_t *rbuf, uint8_t data) { - size_t next_tail = (rbuf->tail + 1) % rbuf->size; - - if (next_tail != rbuf->head) { - rbuf->buffer[rbuf->tail] = data; - rbuf->tail = next_tail; - return true; - } - // full - return false; -} - -static bool ringbuf_pop(ring_buf_t *rbuf, uint8_t *data) { - if (rbuf->head == rbuf->tail) { - // empty - return false; - } - *data = rbuf->buffer[rbuf->head]; - rbuf->head = (rbuf->head + 1) % rbuf->size; - return true; -} - -static size_t ringbuf_available_data(ring_buf_t *rbuf) { - return (rbuf->tail - rbuf->head + rbuf->size) % rbuf->size; -} - -static size_t ringbuf_available_space(ring_buf_t *rbuf) { - return rbuf->size - ringbuf_available_data(rbuf) - 1; -} static uint32_t fill_appbuf_from_ringbuf(machine_pdm_pcm_obj_t *self, mp_buffer_info_t *appbuf) { - printf("fill_appbuf_from_ringbuf \r\n"); uint32_t num_bytes_copied_to_appbuf = 0; uint8_t *app_p = (uint8_t *)appbuf->buf; uint8_t appbuf_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); // !J: Why only 16 or 32? uint32_t num_bytes_needed_from_ringbuf = appbuf->len * (PDM_PCM_RX_FRAME_SIZE_IN_BYTES / appbuf_sample_size_in_bytes); uint8_t discard_byte; - mp_printf(&mp_plat_print, "num_bytes_needed_from_ringbuf: %d \r\n", num_bytes_needed_from_ringbuf); + // mp_printf(&mp_plat_print, "num_bytes_needed_from_ringbuf: %d \r\n", num_bytes_needed_from_ringbuf); while (num_bytes_needed_from_ringbuf) { uint8_t f_index = get_frame_mapping_index(self->bits, self->format); - mp_printf(&mp_plat_print, "f_index: %d \r\n", f_index); + // mp_printf(&mp_plat_print, "f_index: %d \r\n", f_index); for (uint8_t i = 0; i < PDM_PCM_RX_FRAME_SIZE_IN_BYTES; i++) { int8_t r_to_a_mapping = pdm_pcm_frame_map[f_index][i]; if (r_to_a_mapping != -1) { - mp_printf(&mp_plat_print, "r_to_a_mapping: %d \r\n", r_to_a_mapping); + // mp_printf(&mp_plat_print, "r_to_a_mapping: %d \r\n", r_to_a_mapping); if (self->io_mode == BLOCKING) { // poll the ringbuf until a sample becomes available, copy into appbuf using the mapping transform while (ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping) == false) { ; } - printf("Sample available \r\n"); - mp_printf(&mp_plat_print, "app_p + r_to_a_mapping: %d \r\n", app_p + r_to_a_mapping); + // printf("Sample available \r\n"); + // mp_printf(&mp_plat_print, "app_p + r_to_a_mapping: %d \r\n", app_p + r_to_a_mapping); num_bytes_copied_to_appbuf++; } else { return 0; // should never get here (non-blocking mode does not use this function) } } else { // r_a_mapping == -1 - mp_printf(&mp_plat_print, "r_to_a_mapping: %d \r\n", r_to_a_mapping); + // mp_printf(&mp_plat_print, "r_to_a_mapping: %d \r\n", r_to_a_mapping); // discard unused byte from ring buffer if (self->io_mode == BLOCKING) { // poll the ringbuf until a sample becomes available while (ringbuf_pop(&self->ring_buffer, &discard_byte) == false) { - printf("ringbuf_pop in unused byte \r\n"); + // printf("ringbuf_pop in unused byte \r\n"); } - mp_printf(&mp_plat_print, "discard_byte: %d \r\n", discard_byte); + // mp_printf(&mp_plat_print, "discard_byte: %d \r\n", discard_byte); } else { return 0; // should never get here (non-blocking mode does not use this function) } @@ -162,14 +122,11 @@ static void fill_appbuf_from_ringbuf_non_blocking(machine_pdm_pcm_obj_t *self) { } } } - -#endif // MICROPY_PY_MACHINE_PDM_PCM_RING_BUF - /*========================================================================================================================*/ // PDM_PCM higher level MPY functions (extmod/machine_pdm_pcm.c) MP_NOINLINE static void machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - printf("machine_pdm_pcm_init_helper \r\n"); + mplogger_print("machine_pdm_pcm_init_helper \r\n"); static const mp_arg_t allowed_args[] = { { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_data, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, @@ -210,7 +167,7 @@ static void machine_pdm_pcm_print(const mp_print_t *print, mp_obj_t self_in, mp_ // PDM_PCM(...) Constructor static mp_obj_t machine_pdm_pcm_make_new(const mp_obj_type_t *type, size_t n_pos_args, size_t n_kw_args, const mp_obj_t *args) { - printf("machine_pdm_pcm_make_new \r\n"); + mplogger_print("machine_pdm_pcm_make_new \r\n"); mp_arg_check_num(n_pos_args, n_kw_args, 1, MP_OBJ_FUN_ARGS_MAX, true); mp_int_t pdm_pcm_id = mp_obj_get_int(args[0]); @@ -225,7 +182,7 @@ static mp_obj_t machine_pdm_pcm_make_new(const mp_obj_type_t *type, size_t n_pos // PDM_PCM.init(...) static mp_obj_t machine_pdm_pcm_init(mp_obj_t self_in) { - printf("machine_pdm_pcm_init \r\n"); + mplogger_print("machine_pdm_pcm_init \r\n"); machine_pdm_pcm_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_machine_pdm_pcm_init(self); return mp_const_none; @@ -234,7 +191,7 @@ static MP_DEFINE_CONST_FUN_OBJ_1(machine_pdm_pcm_init_obj, machine_pdm_pcm_init) // PDM_PCM.deinit() static mp_obj_t machine_pdm_pcm_deinit(mp_obj_t self_in) { - printf("machine_pdm_pcm_deinit \r\n"); + mplogger_print("machine_pdm_pcm_deinit \r\n"); machine_pdm_pcm_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_machine_pdm_pcm_deinit(self); return mp_const_none; @@ -243,7 +200,7 @@ static MP_DEFINE_CONST_FUN_OBJ_1(machine_pdm_pcm_deinit_obj, machine_pdm_pcm_dei // PDM_PCM.set_gain() static mp_obj_t machine_pdm_pcm_set_gain(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - printf("machine_pdm_pcm_set_gain \r\n"); + mplogger_print("machine_pdm_pcm_set_gain \r\n"); enum { ARG_left_gain, ARG_right_gain}; static const mp_arg_t allowed_args[] = { @@ -294,25 +251,87 @@ static MP_DEFINE_CONST_FUN_OBJ_2(machine_pdm_pcm_irq_obj, machine_pdm_pcm_irq); // Port Private functions for DMA support (ports/psoc6) static inline void _dma_buff_init(machine_pdm_pcm_obj_t *self) { - printf("_dma_buff_init \r\n"); - for (uint32_t i = 0; i < SIZEOF_DMA_BUFFER; i++) { + memset(self->dma_active_buffer, 0, SIZEOF_DMA_BUFFER * sizeof(self->dma_active_buffer[0])); + memset(self->dma_processing_buffer, 0, SIZEOF_DMA_BUFFER * sizeof(self->dma_processing_buffer[0])); + + /*for (uint32_t i = 0; i < SIZEOF_DMA_BUFFER; i++) { self->dma_active_buffer[i] = 0; self->dma_processing_buffer[i] = 0; - } + }*/ self->dma_active_buf_p = self->dma_active_buffer; self->dma_processing_buf_p = self->dma_processing_buffer; } static inline void _dma_swap_active_dmabuf(machine_pdm_pcm_obj_t *self) { - printf("_dma_swap_active_dmabuf \r\n"); uint32_t *temp = self->dma_active_buf_p; self->dma_active_buf_p = self->dma_processing_buf_p; self->dma_processing_buf_p = temp; } static void _dma_copy_from_dmabuf_to_ringbuf(machine_pdm_pcm_obj_t *self) { - printf("_dma_copy_from_dmabuf_to_ringbuf \r\n"); + uint8_t dma_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); + uint8_t *dma_buff_p = (uint8_t *)self->dma_processing_buf_p; + uint32_t num_bytes_needed_from_ringbuf = SIZEOF_HALF_DMA_BUFFER_IN_BYTES * (PDM_PCM_RX_FRAME_SIZE_IN_BYTES / dma_sample_size_in_bytes); + + // when space exists, copy samples into ring buffer + if (ringbuf_available_space(&self->ring_buffer) >= num_bytes_needed_from_ringbuf) { + uint8_t f_index = get_frame_mapping_index(self->bits, self->format); + uint32_t i = 0; + while (i < SIZEOF_HALF_DMA_BUFFER_IN_BYTES) { + for (uint8_t j = 0; j < PDM_PCM_RX_FRAME_SIZE_IN_BYTES; j++) { + int8_t r_to_a_mapping = pdm_pcm_frame_map[f_index][j]; + if (r_to_a_mapping != -1) { + ringbuf_push(&self->ring_buffer, dma_buff_p[i]); + i++; + } else { // r_a_mapping == -1 + ringbuf_push(&self->ring_buffer, -1); + } + } + } + } +} + +/*static void _dma_copy_from_dmabuf_to_ringbuf(machine_pdm_pcm_obj_t *self) { + //uint8_t dma_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); + uint8_t *dma_buff_p = (uint8_t *)self->dma_processing_buf_p; + uint32_t num_bytes_needed_in_ringbuf = SIZEOF_DMA_BUFFER; + + // Check if space exists, copy samples into ring buffer + if (ringbuf_available_space(&self->ring_buffer) >= num_bytes_needed_in_ringbuf) { + for (uint32_t i = 0; i < SIZEOF_DMA_BUFFER; i++) { + bool status = ringbuf_push(&self->ring_buffer, dma_buff_p[i]); + if (!status) { + mp_raise_msg(&mp_type_Exception, "Ring buffer is full\r\n"); + } + } + } + else { + mp_raise_msg(&mp_type_Exception, "Ring buffer is full\r\n"); + } +}*/ + +/*static void _dma_copy_from_dmabuf_to_ringbuf(machine_pdm_pcm_obj_t *self) { + //uint8_t dma_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); + uint8_t *dma_buff_p = (uint8_t *)self->dma_processing_buf_p; + uint32_t num_bytes_needed_in_ringbuf = SIZEOF_DMA_BUFFER; + + // Check if space exists, copy samples into ring buffer + if (ringbuf_available_space(&self->ring_buffer) >= num_bytes_needed_in_ringbuf) { + for (uint32_t i = 0; i < SIZEOF_DMA_BUFFER; i++) { + bool status = ringbuf_push(&self->ring_buffer, dma_buff_p[i]); + if (!status) { + mp_raise_msg(&mp_type_Exception, "Ring buffer is full\r\n"); + } + } + } + else { + mp_raise_msg(&mp_type_Exception, "Ring buffer is full\r\n"); + } +}*/ + +/*static void _dma_copy_from_dmabuf_to_ringbuf(machine_pdm_pcm_obj_t *self) { + mplogger_print("_dma_copy_from_dmabuf_to_ringbuf \r\n"); uint8_t dma_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); uint8_t *dma_buff_p = (uint8_t *)self->dma_processing_buf_p; uint32_t num_bytes_needed_from_ringbuf = SIZEOF_DMA_BUFFER_IN_BYTES * (PDM_PCM_RX_FRAME_SIZE_IN_BYTES / dma_sample_size_in_bytes); @@ -333,14 +352,21 @@ static void _dma_copy_from_dmabuf_to_ringbuf(machine_pdm_pcm_obj_t *self) { } } } -} +}*/ // ======================================================================================= // PDM_PCM low-level abstracted functions (ports/psoc6) - +uint8_t pdm_pcm_get_word_byte_size(machine_pdm_pcm_obj_t *self) { + uint8_t res_bits = self->bits; + if (res_bits == 16) { + return 2; + } else { + return 4; + } +} // Init hardware block static void pdm_pcm_init(machine_pdm_pcm_obj_t *self, cyhal_clock_t *clock) { - printf("pdm_pcm_init \r\n"); + mplogger_print("pdm_pcm_init \r\n"); cyhal_pdm_pcm_cfg_t config = { .sample_rate = self->sample_rate, @@ -358,7 +384,7 @@ static void pdm_pcm_init(machine_pdm_pcm_obj_t *self, cyhal_clock_t *clock) { // Initialize audio clock void pdm_pcm_audio_clock_init(uint32_t audio_clock_freq_hz) { - printf("pdm_pcm_audio_clock_init \r\n"); + mplogger_print("pdm_pcm_audio_clock_init \r\n"); cyhal_clock_t pll_clock; cy_rslt_t result; @@ -402,16 +428,20 @@ void pdm_pcm_audio_clock_init(uint32_t audio_clock_freq_hz) { // Set PDM_PCM async mode to DMA static void pdm_pcm_set_async_mode_dma(machine_pdm_pcm_obj_t *self) { - printf("pdm_pcm_set_async_mode_dma \r\n"); + mplogger_print("pdm_pcm_set_async_mode_dma \r\n"); cy_rslt_t result = cyhal_pdm_pcm_set_async_mode(&self->pdm_pcm_obj, CYHAL_ASYNC_DMA, CYHAL_DMA_PRIORITY_DEFAULT); pdm_pcm_assert_raise_val("PDM_PCM set DMA mode failed with return code %lx !", result); } // Read from PDM_PCM buf to provisioned DMA buffer static void pdm_pcm_read_rxbuf(machine_pdm_pcm_obj_t *self) { - printf("pdm_pcm_read_rxbuf \r\n"); + // mplogger_print("pdm_pcm_read_rxbuf \r\n"); + uint16_t dma_half_buff_word_size = SIZEOF_HALF_DMA_BUFFER_IN_BYTES / pdm_pcm_get_word_byte_size(self); // ToDo: Check the value of dma_buff_word_size and adapt for PDM-PCM - cy_rslt_t result = cyhal_pdm_pcm_read_async(&self->pdm_pcm_obj, self->dma_active_buf_p, SIZEOF_DMA_BUFFER); + while (cyhal_pdm_pcm_is_pending(&self->pdm_pcm_obj)) { + ; + } + cy_rslt_t result = cyhal_pdm_pcm_read_async(&self->pdm_pcm_obj, self->dma_active_buf_p, dma_half_buff_word_size); pdm_pcm_assert_raise_val("PDM_PCM DMA read failed with return code %lx !", result); } @@ -424,11 +454,11 @@ static void pdm_pcm_rx_init(machine_pdm_pcm_obj_t *self) { // IRQ Handler static void pdm_pcm_irq_handler(void *arg, cyhal_pdm_pcm_event_t event) { machine_pdm_pcm_obj_t *self = (machine_pdm_pcm_obj_t *)arg; - if (0u != (event & CYHAL_PDM_PCM_ASYNC_COMPLETE)) { _dma_swap_active_dmabuf(self); pdm_pcm_read_rxbuf(self); _dma_copy_from_dmabuf_to_ringbuf(self); + cyhal_gpio_toggle(CYBSP_USER_LED); if ((self->io_mode == NON_BLOCKING) && (self->non_blocking_descriptor.copy_in_progress)) { fill_appbuf_from_ringbuf_non_blocking(self); @@ -438,7 +468,7 @@ static void pdm_pcm_irq_handler(void *arg, cyhal_pdm_pcm_event_t event) { // Configure PDM_PCM IRQ static void pdm_pcm_irq_configure(machine_pdm_pcm_obj_t *self) { - printf("pdm_pcm_irq_configure \r\n"); + mplogger_print("pdm_pcm_irq_configure \r\n"); cyhal_pdm_pcm_register_callback(&self->pdm_pcm_obj, &pdm_pcm_irq_handler, self); cyhal_pdm_pcm_enable_event(&self->pdm_pcm_obj, CYHAL_PDM_PCM_ASYNC_COMPLETE, CYHAL_ISR_PRIORITY_DEFAULT, true); } @@ -458,12 +488,14 @@ int8_t get_frame_mapping_index(int8_t bits, format_t format) { } } } + + // ======================================================================================= // MPY bindings for PDM_PCM (ports/psoc6) // constructor() static machine_pdm_pcm_obj_t *mp_machine_pdm_pcm_make_new_instance(mp_int_t pdm_pcm_id) { - printf("mp_machine_pdm_pcm_make_new_instance \r\n"); + mplogger_print("mp_machine_pdm_pcm_make_new_instance \r\n"); (void)pdm_pcm_id; machine_pdm_pcm_obj_t *self = NULL; for (uint8_t i = 0; i < MICROPY_HW_MAX_PDM_PCM; i++) { @@ -482,7 +514,7 @@ static machine_pdm_pcm_obj_t *mp_machine_pdm_pcm_make_new_instance(mp_int_t pdm_ // init.helper() static void mp_machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, mp_arg_val_t *args) { - printf("mp_machine_pdm_pcm_init_helper \r\n"); + mplogger_print("mp_machine_pdm_pcm_init_helper \r\n"); // Assign pins self->clk = pin_addr_by_name(args[ARG_clk].u_obj); self->data = pin_addr_by_name(args[ARG_data].u_obj); @@ -526,16 +558,17 @@ static void mp_machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, mp_arg_v } // !ToDo: Check the value of ibuf and if needs to be set by user - int32_t ring_buffer_len = 20000; // !J: How can user calculate this? Easier if we set internally? + int32_t ring_buffer_len = 40000; if (ring_buffer_len < 0) { mp_raise_ValueError(MP_ERROR_TEXT("invalid ibuf")); } self->ibuf = ring_buffer_len; self->callback_for_non_blocking = MP_OBJ_NULL; self->io_mode = BLOCKING; - self->ring_buffer_storage = m_new(uint8_t, ring_buffer_len); + // self->ring_buffer_storage = m_new(uint8_t, ring_buffer_len); + // ringbuf_init(&self->ring_buffer, self->ring_buffer_storage, ring_buffer_len); - ringbuf_init(&self->ring_buffer, self->ring_buffer_storage, ring_buffer_len); + ringbuf_init(&self->ring_buffer, 2, ring_buffer_len); pdm_pcm_audio_clock_init(audio_clock_freq_hz); pdm_pcm_init(self, &pdm_pcm_audio_clock); pdm_pcm_irq_configure(self); @@ -545,13 +578,15 @@ static void mp_machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, mp_arg_v // init() static void mp_machine_pdm_pcm_init(machine_pdm_pcm_obj_t *self) { - printf("mp_machine_pdm_pcm_init \r\n"); + mplogger_print("mp_machine_pdm_pcm_init \r\n"); pdm_pcm_rx_init(self); + cyhal_gpio_init(CYBSP_USER_LED, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG, true); + cyhal_gpio_write(CYBSP_USER_LED, 1); } // deinit() static void mp_machine_pdm_pcm_deinit(machine_pdm_pcm_obj_t *self) { - printf("mp_machine_pdm_pcm_deinit \r\n"); + mplogger_print("mp_machine_pdm_pcm_deinit \r\n"); cyhal_pdm_pcm_stop(&self->pdm_pcm_obj); cyhal_pdm_pcm_free(&self->pdm_pcm_obj); MP_STATE_PORT(machine_pdm_pcm_obj[self->pdm_pcm_id]) = NULL; @@ -559,7 +594,7 @@ static void mp_machine_pdm_pcm_deinit(machine_pdm_pcm_obj_t *self) { // set_gain() static void mp_machine_pdm_pcm_set_gain(machine_pdm_pcm_obj_t *self, int16_t left_gain, int16_t right_gain) { - printf("mp_machine_pdm_pcm_set_gain \r\n"); + mplogger_print("mp_machine_pdm_pcm_set_gain \r\n"); mp_printf(&mp_plat_print, "machine.PDM_PCM: Setting left mic gain to %d and right mic gain to %d\n", self->left_gain, self->right_gain); cy_rslt_t result = cyhal_pdm_pcm_set_gain(&self->pdm_pcm_obj, self->left_gain, self->right_gain); pdm_pcm_assert_raise_val("PDM_PCM set gain failed with return code %lx !", result); @@ -572,24 +607,17 @@ static void mp_machine_pdm_pcm_irq_update(machine_pdm_pcm_obj_t *self) { // Implementation for stream protocol (ports/psoc6) static mp_uint_t machine_pdm_pcm_stream_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { - printf("machine_pdm_pcm_stream_read \r\n"); machine_pdm_pcm_obj_t *self = MP_OBJ_TO_PTR(self_in); uint8_t appbuf_sample_size_in_bytes = (self->bits / 8) * (self->format == STEREO ? 2: 1); - printf("appbuf_sample_size_in_bytes: %d \r\n", appbuf_sample_size_in_bytes); - printf("size: %d \r\n", size); - printf("size by appbuf_sample_size_in_bytes: %d \r\n", size % appbuf_sample_size_in_bytes); - // uint8_t appbuf_sample_size_in_bytes = (self->bits + 7) /8; // round up to higher limit. Consider 20 bits and 18 bits case. if (size % appbuf_sample_size_in_bytes != 0) { // size should be multiple of sample size - printf("Error here! \r\n"); + mplogger_print("Error here! \r\n"); *errcode = MP_EINVAL; return MP_STREAM_ERROR; } - if (size == 0) { return 0; } - if (self->io_mode == BLOCKING) { // blocking mode mp_buffer_info_t appbuf; appbuf.buf = (void *)buf_in; // To store read bits diff --git a/ports/psoc6/machine_pdm_pcm.h b/ports/psoc6/machine_pdm_pcm.h index c727cd358a310..f65e2c358ee71 100644 --- a/ports/psoc6/machine_pdm_pcm.h +++ b/ports/psoc6/machine_pdm_pcm.h @@ -1,5 +1,7 @@ #if MICROPY_PY_MACHINE_PDM_PCM +#include "ringbuf.h" + #define MICROPY_HW_MAX_PDM_PCM 1 #define DEFAULT_LEFT_GAIN 0 #define DEFAULT_RIGHT_GAIN 0 @@ -7,12 +9,14 @@ #define AUDIO_SYS_CLOCK_24_576_000_HZ 24576000u /* (Ideally 24.576 MHz) For sample rates: 8 KHz / 16 KHz / 48 KHz */ #define AUDIO_SYS_CLOCK_22_579_000_HZ 22579000u /* (Ideally 22.579 MHz) For sample rates: 22.05 KHz / 44.1 KHz */ -#define SIZEOF_DMA_BUFFER (1024) -#define SIZEOF_DMA_BUFFER_IN_BYTES (1024 * sizeof(uint32_t)) +#define SIZEOF_DMA_BUFFER (128) +#define SIZEOF_HALF_DMA_BUFFER (SIZEOF_DMA_BUFFER / 2) +#define SIZEOF_DMA_BUFFER_IN_BYTES (SIZEOF_DMA_BUFFER * sizeof(uint32_t)) +#define SIZEOF_HALF_DMA_BUFFER_IN_BYTES (SIZEOF_DMA_BUFFER_IN_BYTES / 2) #define PDM_PCM_RX_FRAME_SIZE_IN_BYTES (8) #define NON_BLOCKING_RATE_MULTIPLIER (4) -#define SIZEOF_NON_BLOCKING_COPY_IN_BYTES (SIZEOF_DMA_BUFFER * NON_BLOCKING_RATE_MULTIPLIER) +#define SIZEOF_NON_BLOCKING_COPY_IN_BYTES (SIZEOF_HALF_DMA_BUFFER * NON_BLOCKING_RATE_MULTIPLIER) #define pdm_pcm_assert_raise_val(msg, ret) if (ret != CY_RSLT_SUCCESS) { \ @@ -49,25 +53,6 @@ typedef enum { NON_BLOCKING, } io_mode_t; -#if MICROPY_PY_MACHINE_PDM_PCM_RING_BUF - -typedef struct _ring_buf_t { - uint8_t *buffer; - size_t head; - size_t tail; - size_t size; -} ring_buf_t; - -static void ringbuf_init(ring_buf_t *rbuf, uint8_t *buffer, size_t size); -static bool ringbuf_push(ring_buf_t *rbuf, uint8_t data); -static bool ringbuf_pop(ring_buf_t *rbuf, uint8_t *data); -static size_t ringbuf_available_data(ring_buf_t *rbuf); -static size_t ringbuf_available_space(ring_buf_t *rbuf); -// static void fill_appbuf_from_ringbuf_non_blocking(machine_pdm_pcm_obj_t *self); - -#endif // MICROPY_PY_MACHINE_PDM_PCM_RING_BUF - - typedef struct _non_blocking_descriptor_t { mp_buffer_info_t appbuf; uint32_t index; @@ -94,7 +79,7 @@ typedef struct _machine_pdm_pcm_obj_t { uint32_t *dma_active_buf_p; uint32_t *dma_processing_buf_p; ring_buf_t ring_buffer; - uint8_t *ring_buffer_storage; + // uint8_t *ring_buffer_storage; non_blocking_descriptor_t non_blocking_descriptor; // For non-blocking mode } machine_pdm_pcm_obj_t; diff --git a/ports/psoc6/ringbuf.c b/ports/psoc6/ringbuf.c new file mode 100644 index 0000000000000..b6baafbdd474d --- /dev/null +++ b/ports/psoc6/ringbuf.c @@ -0,0 +1,111 @@ +#include "ringbuf.h" + +#if MICROPY_PY_MACHINE_PDM_PCM_RING_BUF + +void ringbuf_init(ring_buf_t *rbuf, uint8_t datatype, size_t size) { + /*if(datatype == 1){ + rbuf->buffer = (uint8_t *)m_new(uint8_t, size); + } else if(datatype == 2){ + rbuf->buffer = (uint16_t *)m_new(uint16_t, size); + } else if(datatype == 4){ + rbuf->buffer = (uint32_t *)m_new(uint32_t, size); + }*/ + rbuf->buffer = m_new(uint8_t, size); + // rbuf->buffer = buffer; + rbuf->size = size; + rbuf->head = 0; + rbuf->tail = 0; +} + +bool ringbuf_push(ring_buf_t *rbuf, uint8_t data) { + size_t next_tail = (rbuf->tail + 1) % rbuf->size; + + if (next_tail != rbuf->head) { + rbuf->buffer[rbuf->tail] = data; + rbuf->tail = next_tail; + return true; + } + // full + return false; +} + +bool ringbuf_pop(ring_buf_t *rbuf, uint8_t *data) { + if (rbuf->head == rbuf->tail) { + // empty + return false; + } + *data = rbuf->buffer[rbuf->head]; + rbuf->head = (rbuf->head + 1) % rbuf->size; + return true; +} + +size_t ringbuf_available_data(ring_buf_t *rbuf) { + return (rbuf->tail - rbuf->head + rbuf->size) % rbuf->size; +} + +size_t ringbuf_available_space(ring_buf_t *rbuf) { + return rbuf->size - ringbuf_available_data(rbuf) - 1; +} + +/*uint32_t fill_appbuf_from_ringbuf(ring_buf_t *rbuf, mp_buffer_info_t *appbuf) { + uint32_t num_bytes_copied_to_appbuf = 0; + uint32_t *app_p = (uint32_t *)appbuf->buf; + + uint32_t num_bytes_needed_from_ringbuf = appbuf->len; + + while (num_bytes_needed_from_ringbuf) { + //printf("num_bytes_needed_from_ringbuf: %ld \r\n", num_bytes_needed_from_ringbuf); + // poll the ringbuf until a sample becomes available, copy into appbuf using the mapping transform + while (ringbuf_pop(rbuf, app_p) == false) { + ; + } + //cyhal_gpio_write(CYBSP_USER_LED, 0); + num_bytes_copied_to_appbuf++; + num_bytes_needed_from_ringbuf--; + app_p += num_bytes_copied_to_appbuf; + //printf("num_bytes_copied_to_appbuf: %ld\r\n", num_bytes_copied_to_appbuf); + } + return num_bytes_copied_to_appbuf; +}*/ + +// Copy from ringbuf to appbuf as soon as ASYNC_TRANSFER_COMPLETE is triggered +void fill_appbuf_from_ringbuf_non_blocking(ring_buf_t *rbuf) { + /*uint32_t num_bytes_copied_to_appbuf = 0; + uint8_t *app_p = &(((uint8_t *)self->non_blocking_descriptor.appbuf.buf)[self->non_blocking_descriptor.index]); + + uint8_t appbuf_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); + uint32_t num_bytes_remaining_to_copy_to_appbuf = self->non_blocking_descriptor.appbuf.len - self->non_blocking_descriptor.index; + uint32_t num_bytes_remaining_to_copy_from_ring_buffer = num_bytes_remaining_to_copy_to_appbuf * + (PDM_PCM_RX_FRAME_SIZE_IN_BYTES / appbuf_sample_size_in_bytes); + uint32_t num_bytes_needed_from_ringbuf = MIN(SIZEOF_NON_BLOCKING_COPY_IN_BYTES, num_bytes_remaining_to_copy_from_ring_buffer); + uint8_t discard_byte; + if (ringbuf_available_data(&self->ring_buffer) >= num_bytes_needed_from_ringbuf) { + while (num_bytes_needed_from_ringbuf) { + + uint8_t f_index = get_frame_mapping_index(self->bits, self->format); + + for (uint8_t i = 0; i < PDM_PCM_RX_FRAME_SIZE_IN_BYTES; i++) { + int8_t r_to_a_mapping = pdm_pcm_frame_map[f_index][i]; + if (r_to_a_mapping != -1) { + ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping); + num_bytes_copied_to_appbuf++; + } else { // r_a_mapping == -1 + // discard unused byte from ring buffer + ringbuf_pop(&self->ring_buffer, &discard_byte); + } + num_bytes_needed_from_ringbuf--; + } + app_p += appbuf_sample_size_in_bytes; + } + self->non_blocking_descriptor.index += num_bytes_copied_to_appbuf; + + if (self->non_blocking_descriptor.index >= self->non_blocking_descriptor.appbuf.len) { + self->non_blocking_descriptor.copy_in_progress = false; + mp_sched_schedule(self->callback_for_non_blocking, MP_OBJ_FROM_PTR(self)); + } + }*/ +} + + + +#endif // MICROPY_PY_MACHINE_PDM_PCM_RING_BUF diff --git a/ports/psoc6/ringbuf.h b/ports/psoc6/ringbuf.h new file mode 100644 index 0000000000000..394b453af1213 --- /dev/null +++ b/ports/psoc6/ringbuf.h @@ -0,0 +1,29 @@ +// #if MICROPY_PY_MACHINE_PDM_PCM_RING_BUF +#include +#include + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mphal.h" + +typedef struct _ring_buf_t { + uint8_t *buffer; + size_t head; + size_t tail; + size_t size; +} ring_buf_t; + +void ringbuf_init(ring_buf_t *rbuf, uint8_t datatype, size_t size); +// void ringbuf_init(ring_buf_t *rbuf, uint8_t *buffer, size_t size); +bool ringbuf_push(ring_buf_t *rbuf, uint8_t data); +bool ringbuf_pop(ring_buf_t *rbuf, uint8_t *data); +size_t ringbuf_available_data(ring_buf_t *rbuf); +size_t ringbuf_available_space(ring_buf_t *rbuf); + +/*uint32_t fill_appbuf_from_ringbuf(ring_buf_t *rbuf, mp_buffer_info_t *appbuf); +void fill_appbuf_from_ringbuf_non_blocking(ring_buf_t *rbuf);*/ + +// static uint32_t fill_appbuf_from_ringbuf(machine_pdm_pcm_obj_t *self, mp_buffer_info_t *appbuf); +// static void fill_appbuf_from_ringbuf_non_blocking(machine_pdm_pcm_obj_t *self); + +// #endif // MICROPY_PY_MACHINE_PDM_PCM_RING_BUF diff --git a/tests/ports/psoc6/board_ext_hw/multi/pdm_pcm.py b/tests/ports/psoc6/board_ext_hw/multi/pdm_pcm.py index 7201348a3112d..1ac0b6b46d5c0 100644 --- a/tests/ports/psoc6/board_ext_hw/multi/pdm_pcm.py +++ b/tests/ports/psoc6/board_ext_hw/multi/pdm_pcm.py @@ -13,6 +13,9 @@ clk_pin = "P10_4" data_pin = "P10_5" +rx_buf = bytearray([0] * 4096) + +print("PDM_PCM Tests") pdm_pcm = PDM_PCM( 0, sck=clk_pin, @@ -25,4 +28,11 @@ right_gain=0, ) +pdm_pcm.init() + +# Read PCM data +num_read = pdm_pcm.readinto(rx_buf) +print("num bytes read: ", num_read) +print("Read buff values: ", rx_buf) + pdm_pcm.deinit() From 159ec381af2c898f0ca4eb4426bf6c27a997d584 Mon Sep 17 00:00:00 2001 From: NikhitaR-IFX Date: Fri, 15 Nov 2024 13:59:28 +0530 Subject: [PATCH 6/6] ports/psoc6: PDM_PCM enablement. Signed-off-by: NikhitaR-IFX --- docs/psoc6/quickref.rst | 10 +- ports/psoc6/machine_pdm_pcm.c | 179 ++++++++++++++++------------------ ports/psoc6/machine_pdm_pcm.h | 15 +-- ports/psoc6/ringbuf.c | 111 --------------------- ports/psoc6/ringbuf.h | 29 ------ 5 files changed, 98 insertions(+), 246 deletions(-) delete mode 100644 ports/psoc6/ringbuf.c delete mode 100644 ports/psoc6/ringbuf.h diff --git a/docs/psoc6/quickref.rst b/docs/psoc6/quickref.rst index c6f28e6121a65..e3e411734d575 100644 --- a/docs/psoc6/quickref.rst +++ b/docs/psoc6/quickref.rst @@ -600,7 +600,7 @@ PDM objects can be created and initialized using:: sample_rate=8000, decimation_rate=64, bits=PDM_PCM.BITS_16, - format=PDM_PCM.STEREO, + format=PDM_PCM.MONO_LEFT, left_gain=0, right_gain=0 ) @@ -637,15 +637,19 @@ Methods Starts the PDM_PCM hardware block and conversion operation. +.. note:: + Once the block is started, about 35-45 samples are internally discarded to set the protocol. The actual data should be recorded after a sec to avoid any losses. + .. method:: PDM_PCM.deinit() - Deinitialize PDM_PCM object + Stops the PDM_PCM hardware block deinitializes PDM_PCM object .. method:: PDM_PCM.readinto(buf) Read audio samples into the buffer specified by ``buf``. ``buf`` must support the buffer protocol, such as bytearray or array. For Stereo format, left channel sample precedes right channel sample. For Mono-left format, - the left channel sample data is used and for Mono-right format, right channel data is used. + the left channel sample data is used and for Mono-right format, right channel data is used. Ensure that ``buf`` size should be multiple of sample size. + Sample size can be calculated as (PCM_bits/8) * (format_size); where format_size is 2(stereo mode) and 1(mono mode). Returns number of bytes read .. method:: PDM_PCM.irq(handler) diff --git a/ports/psoc6/machine_pdm_pcm.c b/ports/psoc6/machine_pdm_pcm.c index e1773e6ad9af2..cfb3608a2979e 100644 --- a/ports/psoc6/machine_pdm_pcm.c +++ b/ports/psoc6/machine_pdm_pcm.c @@ -38,42 +38,75 @@ cyhal_clock_t pdm_pcm_audio_clock; +#if MICROPY_PY_MACHINE_PDM_PCM_RING_BUF + + +void ringbuf_init(ring_buf_t *rbuf, size_t size) { + rbuf->buffer = m_new(uint8_t, size); + memset(rbuf->buffer, 0, size); + rbuf->size = size; + rbuf->head = 0; + rbuf->tail = 0; +} + +bool ringbuf_push(ring_buf_t *rbuf, uint8_t data) { + size_t next_tail = (rbuf->tail + 1) % rbuf->size; + if (next_tail != rbuf->head) { + rbuf->buffer[rbuf->tail] = data; + rbuf->tail = next_tail; + return true; + } + // full + return false; +} + +bool ringbuf_pop(ring_buf_t *rbuf, uint8_t *data) { + if (rbuf->head == rbuf->tail) { + // empty + return false; + } + + *data = rbuf->buffer[rbuf->head]; + rbuf->head = (rbuf->head + 1) % rbuf->size; + return true; +} + +size_t ringbuf_available_data(ring_buf_t *rbuf) { + return (rbuf->tail - rbuf->head + rbuf->size) % rbuf->size; +} + +size_t ringbuf_available_space(ring_buf_t *rbuf) { + return rbuf->size - ringbuf_available_data(rbuf) - 1; +} + static uint32_t fill_appbuf_from_ringbuf(machine_pdm_pcm_obj_t *self, mp_buffer_info_t *appbuf) { uint32_t num_bytes_copied_to_appbuf = 0; uint8_t *app_p = (uint8_t *)appbuf->buf; - uint8_t appbuf_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); // !J: Why only 16 or 32? + uint8_t appbuf_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); uint32_t num_bytes_needed_from_ringbuf = appbuf->len * (PDM_PCM_RX_FRAME_SIZE_IN_BYTES / appbuf_sample_size_in_bytes); uint8_t discard_byte; - // mp_printf(&mp_plat_print, "num_bytes_needed_from_ringbuf: %d \r\n", num_bytes_needed_from_ringbuf); while (num_bytes_needed_from_ringbuf) { uint8_t f_index = get_frame_mapping_index(self->bits, self->format); - // mp_printf(&mp_plat_print, "f_index: %d \r\n", f_index); for (uint8_t i = 0; i < PDM_PCM_RX_FRAME_SIZE_IN_BYTES; i++) { int8_t r_to_a_mapping = pdm_pcm_frame_map[f_index][i]; if (r_to_a_mapping != -1) { - // mp_printf(&mp_plat_print, "r_to_a_mapping: %d \r\n", r_to_a_mapping); if (self->io_mode == BLOCKING) { - // poll the ringbuf until a sample becomes available, copy into appbuf using the mapping transform while (ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping) == false) { ; } - // printf("Sample available \r\n"); - // mp_printf(&mp_plat_print, "app_p + r_to_a_mapping: %d \r\n", app_p + r_to_a_mapping); num_bytes_copied_to_appbuf++; } else { return 0; // should never get here (non-blocking mode does not use this function) } } else { // r_a_mapping == -1 - // mp_printf(&mp_plat_print, "r_to_a_mapping: %d \r\n", r_to_a_mapping); // discard unused byte from ring buffer if (self->io_mode == BLOCKING) { // poll the ringbuf until a sample becomes available while (ringbuf_pop(&self->ring_buffer, &discard_byte) == false) { - // printf("ringbuf_pop in unused byte \r\n"); + ; } - // mp_printf(&mp_plat_print, "discard_byte: %d \r\n", discard_byte); } else { return 0; // should never get here (non-blocking mode does not use this function) } @@ -122,6 +155,7 @@ static void fill_appbuf_from_ringbuf_non_blocking(machine_pdm_pcm_obj_t *self) { } } } +#endif // MICROPY_PY_MACHINE_PDM_PCM_RING_BUF /*========================================================================================================================*/ // PDM_PCM higher level MPY functions (extmod/machine_pdm_pcm.c) @@ -251,13 +285,8 @@ static MP_DEFINE_CONST_FUN_OBJ_2(machine_pdm_pcm_irq_obj, machine_pdm_pcm_irq); // Port Private functions for DMA support (ports/psoc6) static inline void _dma_buff_init(machine_pdm_pcm_obj_t *self) { - memset(self->dma_active_buffer, 0, SIZEOF_DMA_BUFFER * sizeof(self->dma_active_buffer[0])); - memset(self->dma_processing_buffer, 0, SIZEOF_DMA_BUFFER * sizeof(self->dma_processing_buffer[0])); - - /*for (uint32_t i = 0; i < SIZEOF_DMA_BUFFER; i++) { - self->dma_active_buffer[i] = 0; - self->dma_processing_buffer[i] = 0; - }*/ + memset(self->dma_active_buffer, 1, SIZEOF_DMA_BUFFER * sizeof(self->dma_active_buffer[0])); + memset(self->dma_processing_buffer, 1, SIZEOF_DMA_BUFFER * sizeof(self->dma_processing_buffer[0])); self->dma_active_buf_p = self->dma_active_buffer; self->dma_processing_buf_p = self->dma_processing_buffer; @@ -292,70 +321,10 @@ static void _dma_copy_from_dmabuf_to_ringbuf(machine_pdm_pcm_obj_t *self) { } } -/*static void _dma_copy_from_dmabuf_to_ringbuf(machine_pdm_pcm_obj_t *self) { - //uint8_t dma_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); - uint8_t *dma_buff_p = (uint8_t *)self->dma_processing_buf_p; - uint32_t num_bytes_needed_in_ringbuf = SIZEOF_DMA_BUFFER; - - // Check if space exists, copy samples into ring buffer - if (ringbuf_available_space(&self->ring_buffer) >= num_bytes_needed_in_ringbuf) { - for (uint32_t i = 0; i < SIZEOF_DMA_BUFFER; i++) { - bool status = ringbuf_push(&self->ring_buffer, dma_buff_p[i]); - if (!status) { - mp_raise_msg(&mp_type_Exception, "Ring buffer is full\r\n"); - } - } - } - else { - mp_raise_msg(&mp_type_Exception, "Ring buffer is full\r\n"); - } -}*/ - -/*static void _dma_copy_from_dmabuf_to_ringbuf(machine_pdm_pcm_obj_t *self) { - //uint8_t dma_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); - uint8_t *dma_buff_p = (uint8_t *)self->dma_processing_buf_p; - uint32_t num_bytes_needed_in_ringbuf = SIZEOF_DMA_BUFFER; - - // Check if space exists, copy samples into ring buffer - if (ringbuf_available_space(&self->ring_buffer) >= num_bytes_needed_in_ringbuf) { - for (uint32_t i = 0; i < SIZEOF_DMA_BUFFER; i++) { - bool status = ringbuf_push(&self->ring_buffer, dma_buff_p[i]); - if (!status) { - mp_raise_msg(&mp_type_Exception, "Ring buffer is full\r\n"); - } - } - } - else { - mp_raise_msg(&mp_type_Exception, "Ring buffer is full\r\n"); - } -}*/ - -/*static void _dma_copy_from_dmabuf_to_ringbuf(machine_pdm_pcm_obj_t *self) { - mplogger_print("_dma_copy_from_dmabuf_to_ringbuf \r\n"); - uint8_t dma_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); - uint8_t *dma_buff_p = (uint8_t *)self->dma_processing_buf_p; - uint32_t num_bytes_needed_from_ringbuf = SIZEOF_DMA_BUFFER_IN_BYTES * (PDM_PCM_RX_FRAME_SIZE_IN_BYTES / dma_sample_size_in_bytes); - - // when space exists, copy samples into ring buffer - if (ringbuf_available_space(&self->ring_buffer) >= num_bytes_needed_from_ringbuf) { - uint8_t f_index = get_frame_mapping_index(self->bits, self->format); - uint32_t i = 0; - while (i < SIZEOF_DMA_BUFFER_IN_BYTES) { - for (uint8_t j = 0; j < PDM_PCM_RX_FRAME_SIZE_IN_BYTES; j++) { - int8_t r_to_a_mapping = pdm_pcm_frame_map[f_index][j]; - if (r_to_a_mapping != -1) { - ringbuf_push(&self->ring_buffer, dma_buff_p[i]); - i++; - } else { // r_a_mapping == -1 - ringbuf_push(&self->ring_buffer, -1); - } - } - } - } -}*/ // ======================================================================================= -// PDM_PCM low-level abstracted functions (ports/psoc6) +// PDM_PCM low-level abstracted functions and helper function (ports/psoc6) + uint8_t pdm_pcm_get_word_byte_size(machine_pdm_pcm_obj_t *self) { uint8_t res_bits = self->bits; if (res_bits == 16) { @@ -364,6 +333,7 @@ uint8_t pdm_pcm_get_word_byte_size(machine_pdm_pcm_obj_t *self) { return 4; } } + // Init hardware block static void pdm_pcm_init(machine_pdm_pcm_obj_t *self, cyhal_clock_t *clock) { mplogger_print("pdm_pcm_init \r\n"); @@ -433,11 +403,9 @@ static void pdm_pcm_set_async_mode_dma(machine_pdm_pcm_obj_t *self) { pdm_pcm_assert_raise_val("PDM_PCM set DMA mode failed with return code %lx !", result); } -// Read from PDM_PCM buf to provisioned DMA buffer +// Move data from PDM_PCM hardware buf to provisioned DMA buffer static void pdm_pcm_read_rxbuf(machine_pdm_pcm_obj_t *self) { - // mplogger_print("pdm_pcm_read_rxbuf \r\n"); uint16_t dma_half_buff_word_size = SIZEOF_HALF_DMA_BUFFER_IN_BYTES / pdm_pcm_get_word_byte_size(self); - // ToDo: Check the value of dma_buff_word_size and adapt for PDM-PCM while (cyhal_pdm_pcm_is_pending(&self->pdm_pcm_obj)) { ; } @@ -445,6 +413,7 @@ static void pdm_pcm_read_rxbuf(machine_pdm_pcm_obj_t *self) { pdm_pcm_assert_raise_val("PDM_PCM DMA read failed with return code %lx !", result); } +// First read and start the hw block static void pdm_pcm_rx_init(machine_pdm_pcm_obj_t *self) { pdm_pcm_read_rxbuf(self); cy_rslt_t result = cyhal_pdm_pcm_start(&self->pdm_pcm_obj); @@ -458,7 +427,6 @@ static void pdm_pcm_irq_handler(void *arg, cyhal_pdm_pcm_event_t event) { _dma_swap_active_dmabuf(self); pdm_pcm_read_rxbuf(self); _dma_copy_from_dmabuf_to_ringbuf(self); - cyhal_gpio_toggle(CYBSP_USER_LED); if ((self->io_mode == NON_BLOCKING) && (self->non_blocking_descriptor.copy_in_progress)) { fill_appbuf_from_ringbuf_non_blocking(self); @@ -477,19 +445,18 @@ int8_t get_frame_mapping_index(int8_t bits, format_t format) { if ((format == MONO_LEFT) | (format == MONO_RIGHT)) { if (bits == 16) { return 0; - } else { // 32 bits + } else { // >16 bits return 1; } } else { // STEREO if (bits == 16) { return 2; - } else { // 32 bits + } else { // >16 bits return 3; } } } - // ======================================================================================= // MPY bindings for PDM_PCM (ports/psoc6) @@ -543,7 +510,8 @@ static void mp_machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, mp_arg_v // Set sampling and decimation rates (as given by user) self->sample_rate = args[ARG_sample_rate].u_int; self->decimation_rate = args[ARG_decimation_rate].u_int; - // Set clock values #ToDo: To be verified for each possible values + + // Set clock values uint32_t audio_clock_freq_hz; uint32_t rate = args[ARG_sample_rate].u_int; if (rate == 8000 || @@ -557,18 +525,15 @@ static void mp_machine_pdm_pcm_init_helper(machine_pdm_pcm_obj_t *self, mp_arg_v mp_raise_ValueError(MP_ERROR_TEXT("rate not supported")); } - // !ToDo: Check the value of ibuf and if needs to be set by user - int32_t ring_buffer_len = 40000; + int32_t ring_buffer_len = 20000; // 2048 if (ring_buffer_len < 0) { mp_raise_ValueError(MP_ERROR_TEXT("invalid ibuf")); } self->ibuf = ring_buffer_len; self->callback_for_non_blocking = MP_OBJ_NULL; self->io_mode = BLOCKING; - // self->ring_buffer_storage = m_new(uint8_t, ring_buffer_len); - // ringbuf_init(&self->ring_buffer, self->ring_buffer_storage, ring_buffer_len); - ringbuf_init(&self->ring_buffer, 2, ring_buffer_len); + ringbuf_init(&self->ring_buffer, ring_buffer_len); pdm_pcm_audio_clock_init(audio_clock_freq_hz); pdm_pcm_init(self, &pdm_pcm_audio_clock); pdm_pcm_irq_configure(self); @@ -600,27 +565,39 @@ static void mp_machine_pdm_pcm_set_gain(machine_pdm_pcm_obj_t *self, int16_t lef pdm_pcm_assert_raise_val("PDM_PCM set gain failed with return code %lx !", result); } +// irq update static void mp_machine_pdm_pcm_irq_update(machine_pdm_pcm_obj_t *self) { (void)self; } + // ======================================================================================= // Implementation for stream protocol (ports/psoc6) +void read_appbuf_value(uint8_t value, mp_buffer_info_t appbuf) { + if (value == 1) { + mp_printf(&mp_plat_print, "\nAppbuf Before : "); + } else { + mp_printf(&mp_plat_print, "\nAppbuf After : "); + } + for (uint32_t i = 0; i < appbuf.len; i++) { + mp_printf(&mp_plat_print, "0x%x ", ((uint8_t *)appbuf.buf)[i]); + } +} static mp_uint_t machine_pdm_pcm_stream_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { machine_pdm_pcm_obj_t *self = MP_OBJ_TO_PTR(self_in); uint8_t appbuf_sample_size_in_bytes = (self->bits / 8) * (self->format == STEREO ? 2: 1); if (size % appbuf_sample_size_in_bytes != 0) { // size should be multiple of sample size - mplogger_print("Error here! \r\n"); *errcode = MP_EINVAL; return MP_STREAM_ERROR; } if (size == 0) { return 0; } - if (self->io_mode == BLOCKING) { // blocking mode + + if (self->io_mode == BLOCKING) { mp_buffer_info_t appbuf; - appbuf.buf = (void *)buf_in; // To store read bits + appbuf.buf = (void *)buf_in; appbuf.len = size; #if MICROPY_PY_MACHINE_PDM_PCM_RING_BUF uint32_t num_bytes_read = fill_appbuf_from_ringbuf(self, &appbuf); @@ -628,7 +605,17 @@ static mp_uint_t machine_pdm_pcm_stream_read(mp_obj_t self_in, void *buf_in, mp_ uint32_t num_bytes_read = fill_appbuf_from_dma(self, &appbuf); #endif return num_bytes_read; - } else { // // ToDo: Placeholder for non-blocking mode + } else { + #if MICROPY_PY_MACHINE_PDM_PCM_RING_BUF + self->non_blocking_descriptor.appbuf.buf = (void *)buf_in; + self->non_blocking_descriptor.appbuf.len = size; + self->non_blocking_descriptor.index = 0; + self->non_blocking_descriptor.copy_in_progress = true; + #else + mp_raise_msg(&mp_type_Exception, MP_ERROR_TEXT("Implementation only through ringbuffer is supported.")); + #endif + + return size; return 0; } } diff --git a/ports/psoc6/machine_pdm_pcm.h b/ports/psoc6/machine_pdm_pcm.h index f65e2c358ee71..60858d19ff005 100644 --- a/ports/psoc6/machine_pdm_pcm.h +++ b/ports/psoc6/machine_pdm_pcm.h @@ -72,14 +72,13 @@ typedef struct _machine_pdm_pcm_obj_t { uint8_t decimation_rate; int16_t left_gain; int16_t right_gain; - int32_t ibuf; // ToDo: Does user needs to calculate this in PDM? + int32_t ibuf; // Private variable mp_obj_t callback_for_non_blocking; uint32_t dma_active_buffer[SIZEOF_DMA_BUFFER]; uint32_t dma_processing_buffer[SIZEOF_DMA_BUFFER]; uint32_t *dma_active_buf_p; uint32_t *dma_processing_buf_p; ring_buf_t ring_buffer; - // uint8_t *ring_buffer_storage; non_blocking_descriptor_t non_blocking_descriptor; // For non-blocking mode } machine_pdm_pcm_obj_t; @@ -90,13 +89,15 @@ static void mp_machine_pdm_pcm_deinit(machine_pdm_pcm_obj_t *self); static void mp_machine_pdm_pcm_set_gain(machine_pdm_pcm_obj_t *self, int16_t left_gain, int16_t right_gain); static void mp_machine_pdm_pcm_irq_update(machine_pdm_pcm_obj_t *self); +int8_t get_frame_mapping_index(int8_t bits, format_t format); +// Should change to MONO_LEFT and MONO_RIGHT when right mic works static const int8_t pdm_pcm_frame_map[4][PDM_PCM_RX_FRAME_SIZE_IN_BYTES] = { - { 0, 1, -1, -1, -1, -1, -1, -1 }, // Mono, 16-bits - { 0, 1, 2, 3, -1, -1, -1, -1 }, // Mono, 32-bits - { 0, 1, -1, -1, 2, 3, -1, -1 }, // Stereo, 16-bits - { 0, 1, 2, 3, 4, 5, 6, 7 }, // Stereo, 32-bits + { 0, 1, -1, -1, -1, -1, -1, -1 }, // Mono, 16-bits + { 0, 1, 2, -1, -1, -1, -1, -1 }, // Mono, >16-bits + { 0, 1, -1, -1, 2, 3, -1, -1 }, // Stereo, 16-bits + { 0, 1, 2, -1, 3, 4, 5, -1 }, // Stereo, >16-bits }; -int8_t get_frame_mapping_index(int8_t bits, format_t format); + #endif // MICROPY_PY_MACHINE_PDM_PCM diff --git a/ports/psoc6/ringbuf.c b/ports/psoc6/ringbuf.c deleted file mode 100644 index b6baafbdd474d..0000000000000 --- a/ports/psoc6/ringbuf.c +++ /dev/null @@ -1,111 +0,0 @@ -#include "ringbuf.h" - -#if MICROPY_PY_MACHINE_PDM_PCM_RING_BUF - -void ringbuf_init(ring_buf_t *rbuf, uint8_t datatype, size_t size) { - /*if(datatype == 1){ - rbuf->buffer = (uint8_t *)m_new(uint8_t, size); - } else if(datatype == 2){ - rbuf->buffer = (uint16_t *)m_new(uint16_t, size); - } else if(datatype == 4){ - rbuf->buffer = (uint32_t *)m_new(uint32_t, size); - }*/ - rbuf->buffer = m_new(uint8_t, size); - // rbuf->buffer = buffer; - rbuf->size = size; - rbuf->head = 0; - rbuf->tail = 0; -} - -bool ringbuf_push(ring_buf_t *rbuf, uint8_t data) { - size_t next_tail = (rbuf->tail + 1) % rbuf->size; - - if (next_tail != rbuf->head) { - rbuf->buffer[rbuf->tail] = data; - rbuf->tail = next_tail; - return true; - } - // full - return false; -} - -bool ringbuf_pop(ring_buf_t *rbuf, uint8_t *data) { - if (rbuf->head == rbuf->tail) { - // empty - return false; - } - *data = rbuf->buffer[rbuf->head]; - rbuf->head = (rbuf->head + 1) % rbuf->size; - return true; -} - -size_t ringbuf_available_data(ring_buf_t *rbuf) { - return (rbuf->tail - rbuf->head + rbuf->size) % rbuf->size; -} - -size_t ringbuf_available_space(ring_buf_t *rbuf) { - return rbuf->size - ringbuf_available_data(rbuf) - 1; -} - -/*uint32_t fill_appbuf_from_ringbuf(ring_buf_t *rbuf, mp_buffer_info_t *appbuf) { - uint32_t num_bytes_copied_to_appbuf = 0; - uint32_t *app_p = (uint32_t *)appbuf->buf; - - uint32_t num_bytes_needed_from_ringbuf = appbuf->len; - - while (num_bytes_needed_from_ringbuf) { - //printf("num_bytes_needed_from_ringbuf: %ld \r\n", num_bytes_needed_from_ringbuf); - // poll the ringbuf until a sample becomes available, copy into appbuf using the mapping transform - while (ringbuf_pop(rbuf, app_p) == false) { - ; - } - //cyhal_gpio_write(CYBSP_USER_LED, 0); - num_bytes_copied_to_appbuf++; - num_bytes_needed_from_ringbuf--; - app_p += num_bytes_copied_to_appbuf; - //printf("num_bytes_copied_to_appbuf: %ld\r\n", num_bytes_copied_to_appbuf); - } - return num_bytes_copied_to_appbuf; -}*/ - -// Copy from ringbuf to appbuf as soon as ASYNC_TRANSFER_COMPLETE is triggered -void fill_appbuf_from_ringbuf_non_blocking(ring_buf_t *rbuf) { - /*uint32_t num_bytes_copied_to_appbuf = 0; - uint8_t *app_p = &(((uint8_t *)self->non_blocking_descriptor.appbuf.buf)[self->non_blocking_descriptor.index]); - - uint8_t appbuf_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1); - uint32_t num_bytes_remaining_to_copy_to_appbuf = self->non_blocking_descriptor.appbuf.len - self->non_blocking_descriptor.index; - uint32_t num_bytes_remaining_to_copy_from_ring_buffer = num_bytes_remaining_to_copy_to_appbuf * - (PDM_PCM_RX_FRAME_SIZE_IN_BYTES / appbuf_sample_size_in_bytes); - uint32_t num_bytes_needed_from_ringbuf = MIN(SIZEOF_NON_BLOCKING_COPY_IN_BYTES, num_bytes_remaining_to_copy_from_ring_buffer); - uint8_t discard_byte; - if (ringbuf_available_data(&self->ring_buffer) >= num_bytes_needed_from_ringbuf) { - while (num_bytes_needed_from_ringbuf) { - - uint8_t f_index = get_frame_mapping_index(self->bits, self->format); - - for (uint8_t i = 0; i < PDM_PCM_RX_FRAME_SIZE_IN_BYTES; i++) { - int8_t r_to_a_mapping = pdm_pcm_frame_map[f_index][i]; - if (r_to_a_mapping != -1) { - ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping); - num_bytes_copied_to_appbuf++; - } else { // r_a_mapping == -1 - // discard unused byte from ring buffer - ringbuf_pop(&self->ring_buffer, &discard_byte); - } - num_bytes_needed_from_ringbuf--; - } - app_p += appbuf_sample_size_in_bytes; - } - self->non_blocking_descriptor.index += num_bytes_copied_to_appbuf; - - if (self->non_blocking_descriptor.index >= self->non_blocking_descriptor.appbuf.len) { - self->non_blocking_descriptor.copy_in_progress = false; - mp_sched_schedule(self->callback_for_non_blocking, MP_OBJ_FROM_PTR(self)); - } - }*/ -} - - - -#endif // MICROPY_PY_MACHINE_PDM_PCM_RING_BUF diff --git a/ports/psoc6/ringbuf.h b/ports/psoc6/ringbuf.h deleted file mode 100644 index 394b453af1213..0000000000000 --- a/ports/psoc6/ringbuf.h +++ /dev/null @@ -1,29 +0,0 @@ -// #if MICROPY_PY_MACHINE_PDM_PCM_RING_BUF -#include -#include - -#include "py/runtime.h" -#include "py/stream.h" -#include "py/mphal.h" - -typedef struct _ring_buf_t { - uint8_t *buffer; - size_t head; - size_t tail; - size_t size; -} ring_buf_t; - -void ringbuf_init(ring_buf_t *rbuf, uint8_t datatype, size_t size); -// void ringbuf_init(ring_buf_t *rbuf, uint8_t *buffer, size_t size); -bool ringbuf_push(ring_buf_t *rbuf, uint8_t data); -bool ringbuf_pop(ring_buf_t *rbuf, uint8_t *data); -size_t ringbuf_available_data(ring_buf_t *rbuf); -size_t ringbuf_available_space(ring_buf_t *rbuf); - -/*uint32_t fill_appbuf_from_ringbuf(ring_buf_t *rbuf, mp_buffer_info_t *appbuf); -void fill_appbuf_from_ringbuf_non_blocking(ring_buf_t *rbuf);*/ - -// static uint32_t fill_appbuf_from_ringbuf(machine_pdm_pcm_obj_t *self, mp_buffer_info_t *appbuf); -// static void fill_appbuf_from_ringbuf_non_blocking(machine_pdm_pcm_obj_t *self); - -// #endif // MICROPY_PY_MACHINE_PDM_PCM_RING_BUF