diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 04f16be3b4..83662734a1 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-10-09 13:56-0700\n" +"POT-Creation-Date: 2018-10-09 20:51-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -413,7 +413,8 @@ msgstr "" #: ports/atmel-samd/common-hal/pulseio/PWMOut.c:120 #: ports/atmel-samd/common-hal/pulseio/PWMOut.c:369 -#: ports/nrf/common-hal/pulseio/PWMOut.c:227 +#: ports/nrf/common-hal/pulseio/PWMOut.c:120 +#: ports/nrf/common-hal/pulseio/PWMOut.c:232 msgid "Invalid PWM frequency" msgstr "" @@ -728,6 +729,10 @@ msgstr "" msgid "Can not get temperature. status: 0x%02x" msgstr "" +#: ports/nrf/common-hal/pulseio/PWMOut.c:162 +msgid "All PWM peripherals are in use" +msgstr "" + #: ports/nrf/drivers/bluetooth/ble_drv.c:199 msgid "Cannot apply GAP parameters." msgstr "" @@ -2239,7 +2244,7 @@ msgstr "" #: shared-bindings/pulseio/PWMOut.c:195 msgid "" -"PWM frequency not writeable when variable_frequency is False on construction." +"PWM frequency not writable when variable_frequency is False on construction." msgstr "" #: shared-bindings/pulseio/PulseIn.c:275 diff --git a/locale/de_DE.po b/locale/de_DE.po index 51c3c45049..de9a21e960 100644 --- a/locale/de_DE.po +++ b/locale/de_DE.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-10-07 02:07+0300\n" +"POT-Creation-Date: 2018-10-09 20:51-0400\n" "PO-Revision-Date: 2018-07-27 11:55-0700\n" "Last-Translator: Sebastian Plamauer\n" "Language-Team: \n" @@ -422,7 +422,8 @@ msgstr "Reset zum bootloader nicht möglich da bootloader nicht vorhanden" #: ports/atmel-samd/common-hal/pulseio/PWMOut.c:120 #: ports/atmel-samd/common-hal/pulseio/PWMOut.c:369 -#: ports/nrf/common-hal/pulseio/PWMOut.c:227 +#: ports/nrf/common-hal/pulseio/PWMOut.c:120 +#: ports/nrf/common-hal/pulseio/PWMOut.c:232 msgid "Invalid PWM frequency" msgstr "Ungültige PWM Frequenz" @@ -741,6 +742,11 @@ msgstr "" msgid "Can not get temperature. status: 0x%02x" msgstr "" +#: ports/nrf/common-hal/pulseio/PWMOut.c:162 +#, fuzzy +msgid "All PWM peripherals are in use" +msgstr "Alle timer werden benutzt" + #: ports/nrf/drivers/bluetooth/ble_drv.c:199 msgid "Cannot apply GAP parameters." msgstr "" @@ -2257,7 +2263,7 @@ msgstr "" #: shared-bindings/pulseio/PWMOut.c:195 msgid "" -"PWM frequency not writeable when variable_frequency is False on construction." +"PWM frequency not writable when variable_frequency is False on construction." msgstr "" #: shared-bindings/pulseio/PulseIn.c:275 diff --git a/locale/en_US.po b/locale/en_US.po index 4b4ee2415f..15c97e3299 100644 --- a/locale/en_US.po +++ b/locale/en_US.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-10-07 02:07+0300\n" +"POT-Creation-Date: 2018-10-09 20:51-0400\n" "PO-Revision-Date: 2018-07-27 11:55-0700\n" "Last-Translator: \n" "Language-Team: \n" @@ -413,7 +413,8 @@ msgstr "" #: ports/atmel-samd/common-hal/pulseio/PWMOut.c:120 #: ports/atmel-samd/common-hal/pulseio/PWMOut.c:369 -#: ports/nrf/common-hal/pulseio/PWMOut.c:227 +#: ports/nrf/common-hal/pulseio/PWMOut.c:120 +#: ports/nrf/common-hal/pulseio/PWMOut.c:232 msgid "Invalid PWM frequency" msgstr "" @@ -728,6 +729,10 @@ msgstr "" msgid "Can not get temperature. status: 0x%02x" msgstr "" +#: ports/nrf/common-hal/pulseio/PWMOut.c:162 +msgid "All PWM peripherals are in use" +msgstr "" + #: ports/nrf/drivers/bluetooth/ble_drv.c:199 msgid "Cannot apply GAP parameters." msgstr "" @@ -2239,7 +2244,7 @@ msgstr "" #: shared-bindings/pulseio/PWMOut.c:195 msgid "" -"PWM frequency not writeable when variable_frequency is False on construction." +"PWM frequency not writable when variable_frequency is False on construction." msgstr "" #: shared-bindings/pulseio/PulseIn.c:275 diff --git a/locale/es.po b/locale/es.po index bc70f1d81a..324fe0720e 100644 --- a/locale/es.po +++ b/locale/es.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-10-07 02:07+0300\n" +"POT-Creation-Date: 2018-10-09 20:51-0400\n" "PO-Revision-Date: 2018-08-24 22:56-0500\n" "Last-Translator: \n" "Language-Team: \n" @@ -428,7 +428,8 @@ msgstr "No se puede reiniciar en bootloader porque no hay bootloader presente." #: ports/atmel-samd/common-hal/pulseio/PWMOut.c:120 #: ports/atmel-samd/common-hal/pulseio/PWMOut.c:369 -#: ports/nrf/common-hal/pulseio/PWMOut.c:227 +#: ports/nrf/common-hal/pulseio/PWMOut.c:120 +#: ports/nrf/common-hal/pulseio/PWMOut.c:232 msgid "Invalid PWM frequency" msgstr "Frecuencia PWM inválida" @@ -745,6 +746,11 @@ msgstr "busio.UART no disponible" msgid "Can not get temperature. status: 0x%02x" msgstr "No se puede obtener la temperatura. status: 0x%02x" +#: ports/nrf/common-hal/pulseio/PWMOut.c:162 +#, fuzzy +msgid "All PWM peripherals are in use" +msgstr "Todos los timers están siendo utilizados" + #: ports/nrf/drivers/bluetooth/ble_drv.c:199 msgid "Cannot apply GAP parameters." msgstr "No se pueden aplicar los parámetros GAP." @@ -2285,7 +2291,7 @@ msgstr "" #: shared-bindings/pulseio/PWMOut.c:195 msgid "" -"PWM frequency not writeable when variable_frequency is False on construction." +"PWM frequency not writable when variable_frequency is False on construction." msgstr "" #: shared-bindings/pulseio/PulseIn.c:275 diff --git a/locale/fil.po b/locale/fil.po index 192ec58a52..e4f3105c92 100644 --- a/locale/fil.po +++ b/locale/fil.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-10-07 02:07+0300\n" +"POT-Creation-Date: 2018-10-09 20:51-0400\n" "PO-Revision-Date: 2018-08-30 23:04-0700\n" "Last-Translator: Timothy \n" "Language-Team: fil\n" @@ -425,7 +425,8 @@ msgstr "Hindi ma-reset sa bootloader dahil walang bootloader." #: ports/atmel-samd/common-hal/pulseio/PWMOut.c:120 #: ports/atmel-samd/common-hal/pulseio/PWMOut.c:369 -#: ports/nrf/common-hal/pulseio/PWMOut.c:227 +#: ports/nrf/common-hal/pulseio/PWMOut.c:120 +#: ports/nrf/common-hal/pulseio/PWMOut.c:232 msgid "Invalid PWM frequency" msgstr "Mali ang PWM frequency" @@ -747,6 +748,11 @@ msgstr "" msgid "Can not get temperature. status: 0x%02x" msgstr "Hindi makuha ang temperatura. status 0x%02x" +#: ports/nrf/common-hal/pulseio/PWMOut.c:162 +#, fuzzy +msgid "All PWM peripherals are in use" +msgstr "Lahat ng timer ginagamit" + #: ports/nrf/drivers/bluetooth/ble_drv.c:199 msgid "Cannot apply GAP parameters." msgstr "Hindi ma-apply ang GAP parameters." @@ -2301,8 +2307,9 @@ msgid "" msgstr "PWM duty_cycle ay dapat sa loob ng 0 at 65535 (16 bit resolution)" #: shared-bindings/pulseio/PWMOut.c:195 +#, fuzzy msgid "" -"PWM frequency not writeable when variable_frequency is False on construction." +"PWM frequency not writable when variable_frequency is False on construction." msgstr "" "PWM frequency hindi maisulat kapag variable_frequency ay False sa pag buo." diff --git a/locale/fr.po b/locale/fr.po index 1a5af3fefc..02beae6d07 100644 --- a/locale/fr.po +++ b/locale/fr.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-10-09 13:56-0700\n" +"POT-Creation-Date: 2018-10-09 20:51-0400\n" "PO-Revision-Date: 2018-08-14 11:01+0200\n" "Last-Translator: Pierrick Couturier \n" "Language-Team: fr\n" @@ -421,7 +421,8 @@ msgstr "" #: ports/atmel-samd/common-hal/pulseio/PWMOut.c:120 #: ports/atmel-samd/common-hal/pulseio/PWMOut.c:369 -#: ports/nrf/common-hal/pulseio/PWMOut.c:227 +#: ports/nrf/common-hal/pulseio/PWMOut.c:120 +#: ports/nrf/common-hal/pulseio/PWMOut.c:232 msgid "Invalid PWM frequency" msgstr "Fréquence de PWM invalide" @@ -744,6 +745,11 @@ msgstr "busio.UART n'est pas disponible" msgid "Can not get temperature. status: 0x%02x" msgstr "Impossible de lire la température. status: 0x%02x" +#: ports/nrf/common-hal/pulseio/PWMOut.c:162 +#, fuzzy +msgid "All PWM peripherals are in use" +msgstr "Tous les timers sont utilisés" + #: ports/nrf/drivers/bluetooth/ble_drv.c:199 msgid "Cannot apply GAP parameters." msgstr "Impossible d'appliquer les paramètres GAP" @@ -2296,8 +2302,9 @@ msgstr "" "bits)" #: shared-bindings/pulseio/PWMOut.c:195 +#, fuzzy msgid "" -"PWM frequency not writeable when variable_frequency is False on construction." +"PWM frequency not writable when variable_frequency is False on construction." msgstr "" "La fréquence de PWM n'est pas modifiable quand variable_frequency est False " "à laconstruction." diff --git a/locale/it_IT.po b/locale/it_IT.po index 9318952c29..5490c699c7 100644 --- a/locale/it_IT.po +++ b/locale/it_IT.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-10-09 13:56-0700\n" +"POT-Creation-Date: 2018-10-09 20:51-0400\n" "PO-Revision-Date: 2018-10-02 16:27+0200\n" "Last-Translator: Enrico Paganin \n" "Language-Team: \n" @@ -429,7 +429,8 @@ msgstr "" #: ports/atmel-samd/common-hal/pulseio/PWMOut.c:120 #: ports/atmel-samd/common-hal/pulseio/PWMOut.c:369 -#: ports/nrf/common-hal/pulseio/PWMOut.c:227 +#: ports/nrf/common-hal/pulseio/PWMOut.c:120 +#: ports/nrf/common-hal/pulseio/PWMOut.c:232 msgid "Invalid PWM frequency" msgstr "Frequenza PWM non valida" @@ -748,6 +749,11 @@ msgstr "busio.UART non ancora implementato" msgid "Can not get temperature. status: 0x%02x" msgstr "Impossibile leggere la temperatura. status: 0x%02x" +#: ports/nrf/common-hal/pulseio/PWMOut.c:162 +#, fuzzy +msgid "All PWM peripherals are in use" +msgstr "Tutte le periferiche SPI sono in uso" + #: ports/nrf/drivers/bluetooth/ble_drv.c:199 msgid "Cannot apply GAP parameters." msgstr "Impossibile applicare i parametri GAP." @@ -2286,8 +2292,9 @@ msgstr "" "a 16 bit)" #: shared-bindings/pulseio/PWMOut.c:195 +#, fuzzy msgid "" -"PWM frequency not writeable when variable_frequency is False on construction." +"PWM frequency not writable when variable_frequency is False on construction." msgstr "" "frequenza PWM frequency non è scrivibile quando variable_frequency è " "impostato nel costruttore a False." diff --git a/locale/pt_BR.po b/locale/pt_BR.po index 9b92333fc7..f3d055c08c 100644 --- a/locale/pt_BR.po +++ b/locale/pt_BR.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-10-07 02:07+0300\n" +"POT-Creation-Date: 2018-10-09 20:51-0400\n" "PO-Revision-Date: 2018-10-02 21:14-0000\n" "Last-Translator: \n" "Language-Team: \n" @@ -413,7 +413,8 @@ msgstr "" #: ports/atmel-samd/common-hal/pulseio/PWMOut.c:120 #: ports/atmel-samd/common-hal/pulseio/PWMOut.c:369 -#: ports/nrf/common-hal/pulseio/PWMOut.c:227 +#: ports/nrf/common-hal/pulseio/PWMOut.c:120 +#: ports/nrf/common-hal/pulseio/PWMOut.c:232 msgid "Invalid PWM frequency" msgstr "Frequência PWM inválida" @@ -730,6 +731,11 @@ msgstr "busio.UART não disponível" msgid "Can not get temperature. status: 0x%02x" msgstr "Não pode obter a temperatura. status: 0x%02x" +#: ports/nrf/common-hal/pulseio/PWMOut.c:162 +#, fuzzy +msgid "All PWM peripherals are in use" +msgstr "Todos os temporizadores em uso" + #: ports/nrf/drivers/bluetooth/ble_drv.c:199 msgid "Cannot apply GAP parameters." msgstr "Não é possível aplicar parâmetros GAP." @@ -2245,7 +2251,7 @@ msgstr "" #: shared-bindings/pulseio/PWMOut.c:195 msgid "" -"PWM frequency not writeable when variable_frequency is False on construction." +"PWM frequency not writable when variable_frequency is False on construction." msgstr "" #: shared-bindings/pulseio/PulseIn.c:275 diff --git a/ports/nrf/common-hal/busio/SPI.c b/ports/nrf/common-hal/busio/SPI.c index 405d19c233..f094b7f240 100644 --- a/ports/nrf/common-hal/busio/SPI.c +++ b/ports/nrf/common-hal/busio/SPI.c @@ -61,7 +61,7 @@ STATIC spim_peripheral_t spim_peripherals[] = { void spi_reset(void) { for (size_t i = 0 ; i < MP_ARRAY_SIZE(spim_peripherals); i++) { - nrfx_spim_uninit(&spim_peripherals[i].spim); + nrf_spim_disable(spim_peripherals[i].spim.p_reg); } } diff --git a/ports/nrf/common-hal/pulseio/PWMOut.c b/ports/nrf/common-hal/pulseio/PWMOut.c index c3c51d5669..7b5741e35c 100644 --- a/ports/nrf/common-hal/pulseio/PWMOut.c +++ b/ports/nrf/common-hal/pulseio/PWMOut.c @@ -30,154 +30,159 @@ #include "py/runtime.h" #include "common-hal/pulseio/PWMOut.h" -#include "nrf_gpio.h" #include "shared-bindings/pulseio/PWMOut.h" #include "supervisor/shared/translate.h" -#define PWM_MAX_MODULE 3 -#define PWM_MAX_CHANNEL 4 +#include "nrf_gpio.h" #define PWM_MAX_FREQ (16000000) -NRF_PWM_Type* const pwm_arr[PWM_MAX_MODULE] = { NRF_PWM0, NRF_PWM1, NRF_PWM2 }; +STATIC NRF_PWM_Type* pwms[] = { +#if NRFX_CHECK(NRFX_PWM0_ENABLED) + NRF_PWM0, +#endif +#if NRFX_CHECK(NRFX_PWM1_ENABLED) + NRF_PWM1, +#endif +#if NRFX_CHECK(NRFX_PWM2_ENABLED) + NRF_PWM2, +#endif +#if NRFX_CHECK(NRFX_PWM3_ENABLED) + NRF_PWM3, +#endif +}; -uint16_t _seq0[PWM_MAX_MODULE][PWM_MAX_CHANNEL]; +#define CHANNELS_PER_PWM 4 +STATIC uint16_t pwm_seq[MP_ARRAY_SIZE(pwms)][CHANNELS_PER_PWM]; -static int pin2channel(NRF_PWM_Type* pwm, uint8_t pin) -{ - for(int i=0; i < PWM_MAX_CHANNEL; i++) - { - if ( pwm->PSEL.OUT[i] == ((uint32_t)pin) ) return i; - } +void pwmout_reset(void) { + for(int i=0; i < MP_ARRAY_SIZE(pwms); i++) { + NRF_PWM_Type* pwm = pwms[i]; - return -1; + pwm->ENABLE = 0; + pwm->MODE = PWM_MODE_UPDOWN_Up; + pwm->DECODER = PWM_DECODER_LOAD_Individual; + pwm->LOOP = 0; + pwm->PRESCALER = PWM_PRESCALER_PRESCALER_DIV_1; // default is 500 hz + pwm->COUNTERTOP = (PWM_MAX_FREQ/500); // default is 500 hz + + pwm->SEQ[0].PTR = (uint32_t) pwm_seq[i]; + pwm->SEQ[0].CNT = CHANNELS_PER_PWM; // default mode is Individual --> count must be 4 + pwm->SEQ[0].REFRESH = 0; + pwm->SEQ[0].ENDDELAY = 0; + + pwm->SEQ[1].PTR = 0; + pwm->SEQ[1].CNT = 0; + pwm->SEQ[1].REFRESH = 0; + pwm->SEQ[1].ENDDELAY = 0; + + for(int ch =0; ch < CHANNELS_PER_PWM; ch++) { + pwm_seq[i][ch] = (1 << 15); // polarity = 0 + } + } } -static int find_free_channel(NRF_PWM_Type* pwm) -{ - for(int i=0; i < PWM_MAX_CHANNEL; i++) - { - if (pwm->PSEL.OUT[i] == 0xFFFFFFFFUL) - { - return i; +// Find the smallest prescaler value that will allow the divisor to be in range. +// This allows the most accuracy. +bool convert_frequency(uint32_t frequency, uint16_t *countertop, nrf_pwm_clk_t *base_clock) { + uint32_t divisor = 1; + // Use a 32-bit number so we don't overflow the uint16_t; + uint32_t tentative_countertop; + for (*base_clock = PWM_PRESCALER_PRESCALER_DIV_1; + *base_clock <= PWM_PRESCALER_PRESCALER_DIV_128; + (*base_clock)++) { + tentative_countertop = PWM_MAX_FREQ / divisor / frequency; + // COUNTERTOP must be 3..32767, according to datasheet, but 3 doesn't work. 4 does. + if (tentative_countertop <= 32767 && tentative_countertop >= 4) { + // In range, OK to return. + *countertop = tentative_countertop; + return true; + } + divisor *= 2; } - } - return -1; -} - -static bool pwm_is_unused(NRF_PWM_Type* pwm) -{ - for(int i=0; i < PWM_MAX_CHANNEL; i++) - { - if (pwm->PSEL.OUT[i] != 0xFFFFFFFFUL) - { - return false; - } - } - - return true; -} - -static void find_new_pwm(pulseio_pwmout_obj_t* self) -{ - // First find unused PWM module - for(int i=0; ipwm = pwm_arr[i]; - self->channel = 0; - return; - } - } - - // Find available channel in a using PWM - for(int i=0; i= 0 ) - { - self->pwm = pwm_arr[i]; - self->channel = (uint8_t) ch; - return; - } - } -} - -void pwmout_reset(void) -{ - for(int i=0; iMODE = PWM_MODE_UPDOWN_Up; - pwm->DECODER = PWM_DECODER_LOAD_Individual; - pwm->LOOP = 0; - pwm->PRESCALER = PWM_PRESCALER_PRESCALER_DIV_1; // default is 500 hz - pwm->COUNTERTOP = (PWM_MAX_FREQ/500); // default is 500 hz - - pwm->SEQ[0].PTR = (uint32_t) _seq0[i]; - pwm->SEQ[0].CNT = PWM_MAX_CHANNEL; // default mode is Individual --> count must be 4 - pwm->SEQ[0].REFRESH = 0; - pwm->SEQ[0].ENDDELAY = 0; - - pwm->SEQ[1].PTR = 0; - pwm->SEQ[1].CNT = 0; - pwm->SEQ[1].REFRESH = 0; - pwm->SEQ[1].ENDDELAY = 0; - - for(int ch =0; ch < PWM_MAX_CHANNEL; ch++) - { - _seq0[i][ch] = (1UL << 15); // polarity = 0 - } - } + return false; } void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, - const mcu_pin_obj_t* pin, - uint16_t duty, - uint32_t frequency, - bool variable_frequency) { - self->pwm = NULL; - self->pin = pin; + const mcu_pin_obj_t* pin, + uint16_t duty, + uint32_t frequency, + bool variable_frequency) { - // check if mapped to PWM channel already - for(int i=0; inumber); - if ( ch >= 0 ) - { - self->pwm = pwm_arr[i]; - self->channel = (uint8_t) ch; - break; + // We don't use the nrfx driver here because we want to dynamically allocate channels + // as needed in an already-enabled PWM. + + uint16_t countertop; + nrf_pwm_clk_t base_clock; + if (frequency == 0 || !convert_frequency(frequency, &countertop, &base_clock)) { + mp_raise_ValueError(translate("Invalid PWM frequency")); } - } - // Haven't mapped before - if ( !self->pwm ) - { - find_new_pwm(self); - } + self->pwm = NULL; + self->channel = CHANNELS_PER_PWM; // out-of-range value. + bool pwm_already_in_use; + NRF_PWM_Type* pwm; - if (self->pwm) - { - nrf_gpio_cfg_output(pin->number); + for (size_t i = 0 ; i < MP_ARRAY_SIZE(pwms); i++) { + pwm = pwms[i]; + pwm_already_in_use = pwm->ENABLE & SPIM_ENABLE_ENABLE_Msk; + if (pwm_already_in_use) { + if (variable_frequency) { + // Variable frequency requires exclusive use of a PWM, so try the next one. + continue; + } + + // PWM is in use, but see if it's set to the same frequency we need. If so, + // look for a free channel. + if (pwm->COUNTERTOP == countertop && pwm->PRESCALER == base_clock) { + for (size_t chan = 0; chan < CHANNELS_PER_PWM; chan++) { + if (pwm->PSEL.OUT[chan] == 0xFFFFFFFF) { + // Channel is free. + self->pwm = pwm; + self->channel = chan; + break; + } + } + // Did we find a channel? If not, loop and check the next pwm. + if (self->pwm != NULL) { + break; + } + } + } else { + // PWM not yet in use, so we can start to use it. Use channel 0. + self->pwm = pwm; + self->channel = 0; + break; + } + } + + if (self->pwm == NULL) { + mp_raise_ValueError(translate("All PWM peripherals are in use")); + } + + self->pin_number = pin->number; + claim_pin(pin); + + self->frequency = frequency; + self->variable_frequency = variable_frequency; + + nrf_gpio_cfg_output(self->pin_number); // disable before mapping pin channel - self->pwm->ENABLE = 0; + nrf_pwm_disable(pwm); - self->pwm->PSEL.OUT[self->channel] = pin->number; + if (!pwm_already_in_use) { + nrf_pwm_configure(pwm, base_clock, NRF_PWM_MODE_UP, countertop); + } - self->pwm->COUNTERTOP = (PWM_MAX_FREQ/frequency); - self->freq = frequency; - self->variable_freq = variable_frequency; + // Connect channel to pin, without disturbing other channels. + pwm->PSEL.OUT[self->channel] = pin->number; - self->pwm->ENABLE = 1; + nrf_pwm_enable(pwm); common_hal_pulseio_pwmout_set_duty_cycle(self, duty); - } } bool common_hal_pulseio_pwmout_deinited(pulseio_pwmout_obj_t* self) { @@ -185,57 +190,59 @@ bool common_hal_pulseio_pwmout_deinited(pulseio_pwmout_obj_t* self) { } void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t* self) { - if (common_hal_pulseio_pwmout_deinited(self)) { - return; - } - - self->pwm->ENABLE = 0; - - self->pwm->PSEL.OUT[self->channel] = 0xFFFFFFFFUL; - - // re-enable PWM module if there is other active channel - for(int i=0; i < PWM_MAX_CHANNEL; i++) - { - if (self->pwm->PSEL.OUT[i] != 0xFFFFFFFFUL) - { - self->pwm->ENABLE = 1; - break; + if (common_hal_pulseio_pwmout_deinited(self)) { + return; } - } - nrf_gpio_cfg_default(self->pin->number); + nrf_gpio_cfg_default(self->pin_number); - self->pwm = NULL; - self->pin = mp_const_none; + nrf_pwm_disable(self->pwm); + + self->pwm->PSEL.OUT[self->channel] = 0xFFFFFFFF; + + // Re-enable PWM module if there is another active channel. + for(int i=0; i < CHANNELS_PER_PWM; i++) { + if (self->pwm->PSEL.OUT[i] != 0xFFFFFFFF) { + nrf_pwm_enable(self->pwm); + break; + } + } + + self->pwm = NULL; } -void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t* self, uint16_t duty) { - self->duty = duty; +void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t* self, uint16_t duty_cycle) { + self->duty_cycle = duty_cycle; - uint16_t* p_value = ((uint16_t*)self->pwm->SEQ[0].PTR) + self->channel; - *p_value = ((duty * self->pwm->COUNTERTOP) / 0xFFFF) | (1 << 15); + uint16_t* p_value = ((uint16_t*)self->pwm->SEQ[0].PTR) + self->channel; + *p_value = ((duty_cycle * self->pwm->COUNTERTOP) / 0xFFFF) | (1 << 15); - self->pwm->TASKS_SEQSTART[0] = 1; + self->pwm->TASKS_SEQSTART[0] = 1; } uint16_t common_hal_pulseio_pwmout_get_duty_cycle(pulseio_pwmout_obj_t* self) { - return self->duty; + return self->duty_cycle; } void common_hal_pulseio_pwmout_set_frequency(pulseio_pwmout_obj_t* self, uint32_t frequency) { - if (frequency == 0 || frequency > 16000000) { - mp_raise_ValueError(translate("Invalid PWM frequency")); - } + // COUNTERTOP is 3..32767, so highest available frequency is PWM_MAX_FREQ / 3. + uint16_t countertop; + nrf_pwm_clk_t base_clock; + if (frequency == 0 || !convert_frequency(frequency, &countertop, &base_clock)) { + mp_raise_ValueError(translate("Invalid PWM frequency")); + } + self->frequency = frequency; - self->freq = frequency; - self->pwm->COUNTERTOP = (PWM_MAX_FREQ/frequency); - self->pwm->TASKS_SEQSTART[0] = 1; + nrf_pwm_configure(self->pwm, base_clock, NRF_PWM_MODE_UP, countertop); + // Set the duty cycle again, because it depends on COUNTERTOP, which probably changed. + // Setting the duty cycle will also do a SEQSTART. + common_hal_pulseio_pwmout_set_duty_cycle(self, self->duty_cycle); } uint32_t common_hal_pulseio_pwmout_get_frequency(pulseio_pwmout_obj_t* self) { - return self->freq; + return self->frequency; } bool common_hal_pulseio_pwmout_get_variable_frequency(pulseio_pwmout_obj_t* self) { - return self->variable_freq; + return self->variable_frequency; } diff --git a/ports/nrf/common-hal/pulseio/PWMOut.h b/ports/nrf/common-hal/pulseio/PWMOut.h index 9de127ac7b..a4e58dc1a5 100644 --- a/ports/nrf/common-hal/pulseio/PWMOut.h +++ b/ports/nrf/common-hal/pulseio/PWMOut.h @@ -27,19 +27,17 @@ #ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_PULSEIO_PWMOUT_H #define MICROPY_INCLUDED_NRF_COMMON_HAL_PULSEIO_PWMOUT_H -#include "common-hal/microcontroller/Pin.h" - +#include "nrfx_pwm.h" #include "py/obj.h" typedef struct { mp_obj_base_t base; - const mcu_pin_obj_t *pin; NRF_PWM_Type* pwm; - - uint8_t channel; - bool variable_freq; - uint16_t duty; - uint32_t freq; + uint8_t pin_number; + uint8_t channel: 7; + bool variable_frequency: 1; + uint16_t duty_cycle; + uint32_t frequency; } pulseio_pwmout_obj_t; void pwmout_reset(void); diff --git a/shared-bindings/pulseio/PWMOut.c b/shared-bindings/pulseio/PWMOut.c index 9b7094b4ef..362b8123d8 100644 --- a/shared-bindings/pulseio/PWMOut.c +++ b/shared-bindings/pulseio/PWMOut.c @@ -192,7 +192,7 @@ STATIC mp_obj_t pulseio_pwmout_obj_set_frequency(mp_obj_t self_in, mp_obj_t freq raise_error_if_deinited(common_hal_pulseio_pwmout_deinited(self)); if (!common_hal_pulseio_pwmout_get_variable_frequency(self)) { mp_raise_AttributeError(translate( - "PWM frequency not writeable when variable_frequency is False on " + "PWM frequency not writable when variable_frequency is False on " "construction.")); } common_hal_pulseio_pwmout_set_frequency(self, mp_obj_get_int(frequency));