Skip to content

Commit

Permalink
ports/psoc6: Enable all functions for PDM_PCM.
Browse files Browse the repository at this point in the history
Signed-off-by: NikhitaR-IFX <Nikhita.Rajasekhar@infineon.com>
  • Loading branch information
NikhitaR-IFX committed Oct 10, 2024
1 parent 14f2faa commit 675c177
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 42 deletions.
18 changes: 15 additions & 3 deletions docs/psoc6/quickref.rst
Original file line number Diff line number Diff line change
Expand Up @@ -633,19 +633,31 @@ 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()

Deinitialize 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.
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
---------
Expand Down
133 changes: 95 additions & 38 deletions ports/psoc6/machine_pdm_pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down Expand Up @@ -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} },
Expand Down Expand Up @@ -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]);

Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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[] = {
Expand All @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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,
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand All @@ -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++) {
Expand All @@ -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);
Expand Down Expand Up @@ -484,38 +540,39 @@ 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;
}

// 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);
Expand All @@ -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
Expand All @@ -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) },
Expand Down
8 changes: 7 additions & 1 deletion ports/psoc6/machine_pdm_pcm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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); \
}
Expand Down Expand Up @@ -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];
Expand All @@ -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
Expand Down

0 comments on commit 675c177

Please sign in to comment.