diff options
| author | Jeff Epler <jepler@gmail.com> | 2019-08-15 19:31:42 -0500 |
|---|---|---|
| committer | jepler <jepler@gmail.com> | 2019-08-18 15:58:04 -0500 |
| commit | 912fd7759debe40bc8bc7c94316eeb34f0591ef1 (patch) | |
| tree | 7633dc5a5ebb7953bc414e6eb13684553e3d99fb /ports | |
| parent | 79f8a857865d8b2ae1b491cb6d58f91246920d91 (diff) | |
nrf: PDMIn: Implement
So far, this supports only 16kHz and 16-bit samples with a fixed gain.
This is enough to support the basic functionality of e.g., sensing
ambient audio levels.
Diffstat (limited to 'ports')
| -rw-r--r-- | ports/nrf/common-hal/audiobusio/PDMIn.c | 84 | ||||
| -rw-r--r-- | ports/nrf/common-hal/audiobusio/PDMIn.h | 7 |
2 files changed, 77 insertions, 14 deletions
diff --git a/ports/nrf/common-hal/audiobusio/PDMIn.c b/ports/nrf/common-hal/audiobusio/PDMIn.c index 5dab75354..a7f9c9d74 100644 --- a/ports/nrf/common-hal/audiobusio/PDMIn.c +++ b/ports/nrf/common-hal/audiobusio/PDMIn.c @@ -25,9 +25,15 @@ */ #include "common-hal/audiobusio/PDMIn.h" +#include "shared-bindings/microcontroller/Pin.h" #include "py/runtime.h" +__attribute__((used)) +NRF_PDM_Type *nrf_pdm = NRF_PDM; + +static uint32_t dummy_buffer[4]; + void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t* self, const mcu_pin_obj_t* clock_pin, const mcu_pin_obj_t* data_pin, @@ -35,30 +41,90 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t* self, uint8_t bit_depth, bool mono, uint8_t oversample) { - mp_raise_RuntimeError(translate("not implemented")); + assert_pin_free(clock_pin); + assert_pin_free(data_pin); + claim_pin(clock_pin); + claim_pin(data_pin); + + self->mono = mono; + self->clock_pin_number = clock_pin->number; + self->data_pin_number = data_pin->number; + + if (sample_rate != 16000) { + mp_raise_ValueError(translate("only sample_rate=16000 is supported")); + } + if (bit_depth != 16) { + mp_raise_ValueError(translate("only bit_depth=16 is supported")); + } + nrf_pdm->PSEL.CLK = self->clock_pin_number; + nrf_pdm->PSEL.DIN = self->data_pin_number; + nrf_pdm->PDMCLKCTRL = PDM_PDMCLKCTRL_FREQ_Default; // For Ratio64 + nrf_pdm->RATIO = PDM_RATIO_RATIO_Ratio64; + nrf_pdm->GAINL = PDM_GAINL_GAINL_DefaultGain; + nrf_pdm->GAINR = PDM_GAINR_GAINR_DefaultGain; + nrf_pdm->ENABLE = 1; + + nrf_pdm->SAMPLE.PTR = (uintptr_t)&dummy_buffer; + nrf_pdm->SAMPLE.MAXCNT = 1; + nrf_pdm->TASKS_START = 1; } bool common_hal_audiobusio_pdmin_deinited(audiobusio_pdmin_obj_t* self) { - mp_raise_RuntimeError(translate("not implemented")); + return !self->clock_pin_number; } void common_hal_audiobusio_pdmin_deinit(audiobusio_pdmin_obj_t* self) { - mp_raise_RuntimeError(translate("not implemented")); + nrf_pdm->ENABLE = 0; + + reset_pin_number(self->clock_pin_number); + self->clock_pin_number = 0; + reset_pin_number(self->data_pin_number); + self->data_pin_number = 0; } uint8_t common_hal_audiobusio_pdmin_get_bit_depth(audiobusio_pdmin_obj_t* self) { - return self->bit_depth; + return 16; } uint32_t common_hal_audiobusio_pdmin_get_sample_rate(audiobusio_pdmin_obj_t* self) { - return self->sample_rate; + return 16000; } uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* self, uint16_t* output_buffer, uint32_t output_buffer_length) { - mp_raise_RuntimeError(translate("not implemented")); -} + // Note: Adafruit's module has SELECT pulled to GND, which makes the DATA + // valid when the CLK is low, therefore it must be sampled on the rising edge. + if (self->mono) { + nrf_pdm->MODE = PDM_MODE_OPERATION_Stereo | PDM_MODE_EDGE_LeftRising; + } else { + nrf_pdm->MODE = PDM_MODE_OPERATION_Mono | PDM_MODE_EDGE_LeftRising; + } + + // step 1. Redirect to real buffer + nrf_pdm->SAMPLE.PTR = (uintptr_t)output_buffer; + nrf_pdm->SAMPLE.MAXCNT = output_buffer_length; + + // a delay is the safest simple way to ensure that the above requested sample has started + mp_hal_delay_us(200); + nrf_pdm->EVENTS_END = 0; + + // step 2. Registers are double buffered, so pre-redirect back to dummy buffer + nrf_pdm->SAMPLE.PTR = (uintptr_t)&dummy_buffer; + nrf_pdm->SAMPLE.MAXCNT = 1; + + // Step 3. wait for PDM to end + while (!nrf_pdm->EVENTS_END) { + MICROPY_VM_HOOK_LOOP; + } + + // Step 4. They want unsigned + for (uint32_t i=0; i<output_buffer_length; i++) { + output_buffer[i] += 32768; + } -void common_hal_audiobusio_pdmin_record_to_file(audiobusio_pdmin_obj_t* self, uint8_t* buffer, uint32_t length) { - mp_raise_RuntimeError(translate("not implemented")); + if (self->mono) { + return (output_buffer_length / 2) * 2; + } else { + return (output_buffer_length / 4) * 4; + } } diff --git a/ports/nrf/common-hal/audiobusio/PDMIn.h b/ports/nrf/common-hal/audiobusio/PDMIn.h index c43d53d0d..d921e42ff 100644 --- a/ports/nrf/common-hal/audiobusio/PDMIn.h +++ b/ports/nrf/common-hal/audiobusio/PDMIn.h @@ -33,11 +33,8 @@ typedef struct { mp_obj_base_t base; - const mcu_pin_obj_t *clock_pin; - const mcu_pin_obj_t *data_pin; - uint32_t sample_rate; - uint8_t bytes_per_sample; - uint8_t bit_depth; + uint8_t clock_pin_number, data_pin_number; + bool mono; } audiobusio_pdmin_obj_t; #endif |
