From 2262efc31155cfb498c5ecbfb64be16839cf4641 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 16 Oct 2018 11:05:02 -0400 Subject: [PATCH 1/2] PulseOut working --- ports/nrf/Makefile | 2 + ports/nrf/common-hal/analogio/AnalogOut.c | 9 +- ports/nrf/common-hal/board/__init__.c | 2 +- ports/nrf/common-hal/busio/I2C.c | 1 + ports/nrf/common-hal/busio/UART.c | 4 +- ports/nrf/common-hal/pulseio/PWMOut.c | 4 +- ports/nrf/common-hal/pulseio/PulseOut.c | 123 ++++++++++++++++++++-- ports/nrf/common-hal/pulseio/PulseOut.h | 6 +- ports/nrf/nrfx_config.h | 24 ++++- ports/nrf/peripherals/nrf/pins.h | 2 +- ports/nrf/peripherals/nrf/timers.c | 88 ++++++++++++++++ ports/nrf/peripherals/nrf/timers.h | 32 ++++++ ports/nrf/supervisor/port.c | 19 ++-- shared-bindings/pulseio/PulseOut.c | 7 +- 14 files changed, 281 insertions(+), 42 deletions(-) create mode 100644 ports/nrf/peripherals/nrf/timers.c create mode 100644 ports/nrf/peripherals/nrf/timers.h diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 93ca783760..8b84f43df4 100755 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -90,6 +90,7 @@ LIBS += -L $(dir $(LIBGCC_FILE_NAME)) -lgcc SRC_NRFX = $(addprefix nrfx/,\ drivers/src/nrfx_power.c \ drivers/src/nrfx_spim.c \ + drivers/src/nrfx_timer.c \ drivers/src/nrfx_twim.c \ drivers/src/nrfx_uarte.c \ ) @@ -123,6 +124,7 @@ SRC_C += \ peripherals/nrf/clocks.c \ peripherals/nrf/$(MCU_CHIP)/pins.c \ peripherals/nrf/$(MCU_CHIP)/power.c \ + peripherals/nrf/timers.c \ supervisor/shared/memory.c DRIVERS_SRC_C += $(addprefix modules/,\ diff --git a/ports/nrf/common-hal/analogio/AnalogOut.c b/ports/nrf/common-hal/analogio/AnalogOut.c index dc0f53740d..7c60e324df 100644 --- a/ports/nrf/common-hal/analogio/AnalogOut.c +++ b/ports/nrf/common-hal/analogio/AnalogOut.c @@ -3,14 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Copyright (c) 2018 Dan Halbert for Adafruit Industries * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. diff --git a/ports/nrf/common-hal/board/__init__.c b/ports/nrf/common-hal/board/__init__.c index 287f546d5c..350f2eea5e 100644 --- a/ports/nrf/common-hal/board/__init__.c +++ b/ports/nrf/common-hal/board/__init__.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2018 Dan Halbert for Adafruit Industries * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/ports/nrf/common-hal/busio/I2C.c b/ports/nrf/common-hal/busio/I2C.c index c2a6cab702..4c42e58cdf 100644 --- a/ports/nrf/common-hal/busio/I2C.c +++ b/ports/nrf/common-hal/busio/I2C.c @@ -56,6 +56,7 @@ STATIC twim_peripheral_t twim_peripherals[] = { void i2c_reset(void) { for (size_t i = 0 ; i < MP_ARRAY_SIZE(twim_peripherals); i++) { + nrf_twim_disable(twim_peripherals[i].twim.p_twim); twim_peripherals[i].in_use = false; } } diff --git a/ports/nrf/common-hal/busio/UART.c b/ports/nrf/common-hal/busio/UART.c index b2dbb56a1f..b9e79381ab 100644 --- a/ports/nrf/common-hal/busio/UART.c +++ b/ports/nrf/common-hal/busio/UART.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2016 Damien P. George + * Copyright (c) 2018 Ha Thach for Adafruit Industries * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -179,7 +179,7 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t self->rx_count = -1; _VERIFY_ERR(nrfx_uarte_rx(&self->uarte, self->buffer, cnt)); } - + // queue 1-byte transfer for rx_characters_available() if ( self->rx_count == 0 ) { self->rx_count = -1; diff --git a/ports/nrf/common-hal/pulseio/PWMOut.c b/ports/nrf/common-hal/pulseio/PWMOut.c index 5d94bab794..f321f848d3 100644 --- a/ports/nrf/common-hal/pulseio/PWMOut.c +++ b/ports/nrf/common-hal/pulseio/PWMOut.c @@ -3,8 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries - * Copyright (c) 2016 Damien P. George + * Copyright (c) 2018 Dan Halbert for Adafruit Industries * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -168,6 +167,7 @@ void common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, self->frequency = frequency; self->variable_frequency = variable_frequency; + // Note this is standard, not strong drive. nrf_gpio_cfg_output(self->pin_number); // disable before mapping pin channel diff --git a/ports/nrf/common-hal/pulseio/PulseOut.c b/ports/nrf/common-hal/pulseio/PulseOut.c index 3495f38f7d..044c4d3a8d 100644 --- a/ports/nrf/common-hal/pulseio/PulseOut.c +++ b/ports/nrf/common-hal/pulseio/PulseOut.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2016 Damien P. George + * Copyright (c) 2018 Dan Halbert for Adafruit Industries * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,31 +29,136 @@ #include #include "mpconfigport.h" +#include "nrf/pins.h" +#include "nrf/timers.h" #include "py/gc.h" #include "py/runtime.h" - #include "shared-bindings/pulseio/PulseOut.h" +#include "shared-bindings/pulseio/PWMOut.h" +#include "supervisor/shared/translate.h" -//void pulse_finish(struct tc_module *const module) { -// -//} +// A single timer is shared amongst all PulseOut objects under the assumption that +// the code is single threaded. +static uint8_t refcount = 0; -void pulseout_reset() { +static nrfx_timer_t *timer = NULL; +static uint16_t *pulse_array = NULL; +static volatile uint16_t pulse_array_index = 0; +static uint16_t pulse_array_length; + +static void turn_on(pulseio_pulseout_obj_t *pulseout) { + pulseout->pwmout->pwm->PSEL.OUT[0] = pulseout->pwmout->pin_number; } -void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, const pulseio_pwmout_obj_t* carrier) { - mp_raise_NotImplementedError(NULL); +static void turn_off(pulseio_pulseout_obj_t *pulseout) { + // Disconnect pin from PWM. + pulseout->pwmout->pwm->PSEL.OUT[0] = 0xffffffff; + // Make sure pin is low. + nrf_gpio_pin_clear(pulseout->pwmout->pin_number); +} + +static void start_timer(void) { + nrfx_timer_clear(timer); + // true enables interrupt. + nrfx_timer_compare(timer, NRF_TIMER_CC_CHANNEL0, pulse_array[pulse_array_index], true); + nrfx_timer_resume(timer); +} + +static void pulseout_event_handler(nrf_timer_event_t event_type, void *p_context) { + pulseio_pulseout_obj_t *pulseout = (pulseio_pulseout_obj_t*) p_context; + if (event_type != NRF_TIMER_EVENT_COMPARE0) { + // Spurious event. + return; + } + nrfx_timer_pause(timer); + + pulse_array_index++; + + // No more pulses. Turn off output and don't restart. + if (pulse_array_index >= pulse_array_length) { + turn_off(pulseout); + return; + } + + // Alternate on and off, starting with on. + if (pulse_array_index % 2 == 0) { + turn_on(pulseout); + } else { + turn_off(pulseout); + } + + // Count up to the next given value. + start_timer(); +} + +void pulseout_reset() { + if (timer != NULL) { + nrf_peripherals_free_timer(timer); + } + refcount = 0; +} + +void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, + const pulseio_pwmout_obj_t* carrier) { + if (refcount == 0) { + timer = nrf_peripherals_allocate_timer(); + if (timer == NULL) { + mp_raise_RuntimeError(translate("All timers in use")); + } + } + refcount++; + + nrfx_timer_config_t timer_config = { + // PulseOut durations are in microseconds, so this is convenient. + .frequency = NRF_TIMER_FREQ_1MHz, + .mode = NRF_TIMER_MODE_TIMER, + .bit_width = NRF_TIMER_BIT_WIDTH_32, + .interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY, + .p_context = self, + }; + + self->pwmout = carrier; + + nrfx_timer_init(timer, &timer_config, &pulseout_event_handler); + turn_off(self); } bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t* self) { - return 1; + return self->pwmout == NULL; } void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) { + if (common_hal_pulseio_pulseout_deinited(self)) { + return; + } + turn_on(self); + self->pwmout = NULL; + refcount--; + if (refcount == 0) { + nrf_peripherals_free_timer(timer); + } } void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pulses, uint16_t length) { + pulse_array = pulses; + pulse_array_index = 0; + pulse_array_length = length; + nrfx_timer_enable(timer); + + turn_on(self); + // Count up to the next given value. + start_timer(); + + while(pulse_array_index < length) { + // Do other things while we wait. The interrupts will handle sending the + // signal. + #ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP + #endif + } + + nrfx_timer_disable(timer); } diff --git a/ports/nrf/common-hal/pulseio/PulseOut.h b/ports/nrf/common-hal/pulseio/PulseOut.h index 9a764e3023..42ec52e30e 100644 --- a/ports/nrf/common-hal/pulseio/PulseOut.h +++ b/ports/nrf/common-hal/pulseio/PulseOut.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * Copyright (c) 2018 Dan Halbert for Adafruit Industries * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,13 +28,13 @@ #define MICROPY_INCLUDED_NRF_COMMON_HAL_PULSEIO_PULSEOUT_H #include "common-hal/microcontroller/Pin.h" +#include "common-hal/pulseio/PWMOut.h" #include "py/obj.h" typedef struct { mp_obj_base_t base; -// __IO PORT_PINCFG_Type *pincfg; - uint8_t pin; + const pulseio_pwmout_obj_t *pwmout; } pulseio_pulseout_obj_t; void pulseout_reset(void); diff --git a/ports/nrf/nrfx_config.h b/ports/nrf/nrfx_config.h index f217cb0534..69b8e6a0cb 100644 --- a/ports/nrf/nrfx_config.h +++ b/ports/nrf/nrfx_config.h @@ -27,8 +27,10 @@ // Enable SPIM2 and SPIM3 (if available) #define NRFX_SPIM2_ENABLED 1 -#ifdef NRF52840_XXAA +#ifdef NRF_SPIM3 #define NRFX_SPIM3_ENABLED 1 +#else + #define NRFX_SPIM3_ENABLED 0 #endif @@ -59,4 +61,24 @@ #define NRFX_PWM3_ENABLED 0 #endif +// TIMERS +#define NRFX_TIMER_ENABLED 1 +// Don't enable TIMER0: it's used by the SoftDevice. +#define NRFX_TIMER1_ENABLED 1 +#define NRFX_TIMER2_ENABLED 1 + +#ifdef NRFX_TIMER3 +#define NRFX_TIMER3_ENABLED 1 +#else +#define NRFX_TIMER3_ENABLED 0 +#endif + +#ifdef NRFX_TIMER4 +#define NRFX_TIMER4_ENABLED 1 +#else +#define NRFX_TIMER4_ENABLED 0 +#endif + +#define NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY 7 + #endif // NRFX_CONFIG_H__ diff --git a/ports/nrf/peripherals/nrf/pins.h b/ports/nrf/peripherals/nrf/pins.h index 01aa9e956e..33462d7114 100644 --- a/ports/nrf/peripherals/nrf/pins.h +++ b/ports/nrf/peripherals/nrf/pins.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2018 Dan Halbert for Adafruit Industries * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/ports/nrf/peripherals/nrf/timers.c b/ports/nrf/peripherals/nrf/timers.c new file mode 100644 index 0000000000..0027d526f4 --- /dev/null +++ b/ports/nrf/peripherals/nrf/timers.c @@ -0,0 +1,88 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "common-hal/pulseio/PulseOut.h" + +#include + +#include "nrfx.h" +#include "nrfx_timer.h" + +#include "mpconfigport.h" +#include "py/runtime.h" + +STATIC nrfx_timer_t nrfx_timers[] = { +#if NRFX_CHECK(NRFX_TIMER0_ENABLED) + // Note that TIMER0 is reserved for use by the SoftDevice, so it should not usually be enabled. + NRFX_TIMER_INSTANCE(0), +#endif +#if NRFX_CHECK(NRFX_TIMER1_ENABLED) + NRFX_TIMER_INSTANCE(1), +#endif +#if NRFX_CHECK(NRFX_TIMER2_ENABLED) + NRFX_TIMER_INSTANCE(2), +#endif +#if NRFX_CHECK(NRFX_TIMER3_ENABLED) + NRFX_TIMER_INSTANCE(3), +#endif +#if NRFX_CHECK(NRFX_TIMER4_ENABLED) + NRFX_TIMER_INSTANCE(4), +#endif +}; + +static bool nrfx_timer_allocated[ARRAY_SIZE(nrfx_timers)]; + +void timers_reset(void) { + for (size_t i = 0; i < ARRAY_SIZE(nrfx_timers); i ++) { + nrfx_timer_uninit(&nrfx_timers[i]); + nrfx_timer_allocated[i] = false; + } +} + +// Returns a free nrfx_timer instance, and marks it as allocated. +// The caller should init as with the desired config. +// Returns NULL if no timer is available. +nrfx_timer_t* nrf_peripherals_allocate_timer(void) { + for (size_t i = 0; i < ARRAY_SIZE(nrfx_timers); i ++) { + if (!nrfx_timer_allocated[i]) { + nrfx_timer_allocated[i] = true; + return &nrfx_timers[i]; + } + } + return NULL; +} + +// Free a timer, which may or may not have been initialized. +void nrf_peripherals_free_timer(nrfx_timer_t* timer) { + for (size_t i = 0; i < ARRAY_SIZE(nrfx_timers); i ++) { + if (timer == &nrfx_timers[i]) { + nrfx_timer_allocated[i] = false; + // Safe to call even if not initialized. + nrfx_timer_uninit(timer); + return; + } + } +} diff --git a/ports/nrf/peripherals/nrf/timers.h b/ports/nrf/peripherals/nrf/timers.h new file mode 100644 index 0000000000..7d3815579a --- /dev/null +++ b/ports/nrf/peripherals/nrf/timers.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "nrfx.h" +#include "nrfx_timer.h" + +void timers_reset(void); +nrfx_timer_t* nrf_peripherals_allocate_timer(void); +void nrf_peripherals_free_timer(nrfx_timer_t* timer); diff --git a/ports/nrf/supervisor/port.c b/ports/nrf/supervisor/port.c index c858a36485..f98b05f5a4 100644 --- a/ports/nrf/supervisor/port.c +++ b/ports/nrf/supervisor/port.c @@ -31,12 +31,14 @@ #include "nrf/cache.h" #include "nrf/clocks.h" #include "nrf/power.h" +#include "nrf/timers.h" #include "shared-module/gamepad/__init__.h" #include "common-hal/microcontroller/Pin.h" #include "common-hal/busio/I2C.h" #include "common-hal/busio/SPI.h" #include "common-hal/pulseio/PWMOut.h" +#include "common-hal/pulseio/PulseOut.h" #include "tick.h" safe_mode_t port_init(void) { @@ -81,6 +83,8 @@ void reset_port(void) { i2c_reset(); spi_reset(); pwmout_reset(); + pulseout_reset(); + timers_reset(); reset_all_pins(); } @@ -88,16 +92,7 @@ void reset_port(void) { void HardFault_Handler(void) { -// static volatile uint32_t reg; -// static volatile uint32_t reg2; -// static volatile uint32_t bfar; -// reg = SCB->HFSR; -// reg2 = SCB->CFSR; -// bfar = SCB->BFAR; -// for (int i = 0; i < 0; i++) -// { -// (void)reg; -// (void)reg2; -// (void)bfar; -// } + while (true) { + asm(""); + } } diff --git a/shared-bindings/pulseio/PulseOut.c b/shared-bindings/pulseio/PulseOut.c index 1c97c37c36..e9834c12a7 100644 --- a/shared-bindings/pulseio/PulseOut.c +++ b/shared-bindings/pulseio/PulseOut.c @@ -47,7 +47,7 @@ //| //| .. class:: PulseOut(carrier) //| -//| Create a PulseOut object associated with the given PWM out experience. +//| Create a PulseOut object associated with the given PWMout object. //| //| :param ~pulseio.PWMOut carrier: PWMOut that is set to output on the desired pin. //| @@ -57,9 +57,10 @@ //| import pulseio //| import board //| -//| pwm = pulseio.PWMOut(board.D13, duty_cycle=2 ** 15) +//| # 50% duty cycle at 38kHz. +//| pwm = pulseio.PWMOut(board.D13, frequency=38000, duty_cycle=32768) //| pulse = pulseio.PulseOut(pwm) -//| # on off on off on +//| # on off on off on //| pulses = array.array('H', [65000, 1000, 65000, 65000, 1000]) //| pulse.send(pulses) //| From b3c7746a7f48d5fa47a26a745f39b9a3e9656d2b Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 16 Oct 2018 11:09:37 -0400 Subject: [PATCH 2/2] fix copyright notice --- ports/nrf/common-hal/analogio/AnalogOut.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ports/nrf/common-hal/analogio/AnalogOut.c b/ports/nrf/common-hal/analogio/AnalogOut.c index 7c60e324df..adafa15d5c 100644 --- a/ports/nrf/common-hal/analogio/AnalogOut.c +++ b/ports/nrf/common-hal/analogio/AnalogOut.c @@ -5,6 +5,13 @@ * * Copyright (c) 2018 Dan Halbert for Adafruit Industries * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. *