Merge pull request #1277 from dhalbert/nrf-pulseout

PulseOut working
This commit is contained in:
Scott Shawcroft 2018-10-16 10:19:55 -07:00 committed by GitHub
commit c69b67f453
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 281 additions and 35 deletions

View File

@ -90,6 +90,7 @@ LIBS += -L $(dir $(LIBGCC_FILE_NAME)) -lgcc
SRC_NRFX = $(addprefix nrfx/,\ SRC_NRFX = $(addprefix nrfx/,\
drivers/src/nrfx_power.c \ drivers/src/nrfx_power.c \
drivers/src/nrfx_spim.c \ drivers/src/nrfx_spim.c \
drivers/src/nrfx_timer.c \
drivers/src/nrfx_twim.c \ drivers/src/nrfx_twim.c \
drivers/src/nrfx_uarte.c \ drivers/src/nrfx_uarte.c \
) )
@ -123,6 +124,7 @@ SRC_C += \
peripherals/nrf/clocks.c \ peripherals/nrf/clocks.c \
peripherals/nrf/$(MCU_CHIP)/pins.c \ peripherals/nrf/$(MCU_CHIP)/pins.c \
peripherals/nrf/$(MCU_CHIP)/power.c \ peripherals/nrf/$(MCU_CHIP)/power.c \
peripherals/nrf/timers.c \
supervisor/shared/memory.c supervisor/shared/memory.c
DRIVERS_SRC_C += $(addprefix modules/,\ DRIVERS_SRC_C += $(addprefix modules/,\

View File

@ -3,7 +3,7 @@
* *
* The MIT License (MIT) * 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View File

@ -3,7 +3,7 @@
* *
* The MIT License (MIT) * 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View File

@ -56,6 +56,7 @@ STATIC twim_peripheral_t twim_peripherals[] = {
void i2c_reset(void) { void i2c_reset(void) {
for (size_t i = 0 ; i < MP_ARRAY_SIZE(twim_peripherals); i++) { 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; twim_peripherals[i].in_use = false;
} }
} }

View File

@ -3,7 +3,7 @@
* *
* The MIT License (MIT) * 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View File

@ -3,8 +3,7 @@
* *
* The MIT License (MIT) * The MIT License (MIT)
* *
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries * Copyright (c) 2018 Dan Halbert for Adafruit Industries
* Copyright (c) 2016 Damien P. George
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * 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->frequency = frequency;
self->variable_frequency = variable_frequency; self->variable_frequency = variable_frequency;
// Note this is standard, not strong drive.
nrf_gpio_cfg_output(self->pin_number); nrf_gpio_cfg_output(self->pin_number);
// disable before mapping pin channel // disable before mapping pin channel

View File

@ -3,7 +3,7 @@
* *
* The MIT License (MIT) * 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -29,31 +29,136 @@
#include <stdint.h> #include <stdint.h>
#include "mpconfigport.h" #include "mpconfigport.h"
#include "nrf/pins.h"
#include "nrf/timers.h"
#include "py/gc.h" #include "py/gc.h"
#include "py/runtime.h" #include "py/runtime.h"
#include "shared-bindings/pulseio/PulseOut.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) { static void turn_off(pulseio_pulseout_obj_t *pulseout) {
mp_raise_NotImplementedError(NULL); // 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) { 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) { 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) { 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);
} }

View File

@ -3,7 +3,7 @@
* *
* The MIT License (MIT) * 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -28,13 +28,13 @@
#define MICROPY_INCLUDED_NRF_COMMON_HAL_PULSEIO_PULSEOUT_H #define MICROPY_INCLUDED_NRF_COMMON_HAL_PULSEIO_PULSEOUT_H
#include "common-hal/microcontroller/Pin.h" #include "common-hal/microcontroller/Pin.h"
#include "common-hal/pulseio/PWMOut.h"
#include "py/obj.h" #include "py/obj.h"
typedef struct { typedef struct {
mp_obj_base_t base; mp_obj_base_t base;
// __IO PORT_PINCFG_Type *pincfg; const pulseio_pwmout_obj_t *pwmout;
uint8_t pin;
} pulseio_pulseout_obj_t; } pulseio_pulseout_obj_t;
void pulseout_reset(void); void pulseout_reset(void);

View File

@ -27,8 +27,10 @@
// Enable SPIM2 and SPIM3 (if available) // Enable SPIM2 and SPIM3 (if available)
#define NRFX_SPIM2_ENABLED 1 #define NRFX_SPIM2_ENABLED 1
#ifdef NRF52840_XXAA #ifdef NRF_SPIM3
#define NRFX_SPIM3_ENABLED 1 #define NRFX_SPIM3_ENABLED 1
#else
#define NRFX_SPIM3_ENABLED 0
#endif #endif
@ -59,4 +61,24 @@
#define NRFX_PWM3_ENABLED 0 #define NRFX_PWM3_ENABLED 0
#endif #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__ #endif // NRFX_CONFIG_H__

View File

@ -3,7 +3,7 @@
* *
* The MIT License (MIT) * 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View File

@ -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 <stdint.h>
#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;
}
}
}

View File

@ -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);

View File

@ -31,12 +31,14 @@
#include "nrf/cache.h" #include "nrf/cache.h"
#include "nrf/clocks.h" #include "nrf/clocks.h"
#include "nrf/power.h" #include "nrf/power.h"
#include "nrf/timers.h"
#include "shared-module/gamepad/__init__.h" #include "shared-module/gamepad/__init__.h"
#include "common-hal/microcontroller/Pin.h" #include "common-hal/microcontroller/Pin.h"
#include "common-hal/busio/I2C.h" #include "common-hal/busio/I2C.h"
#include "common-hal/busio/SPI.h" #include "common-hal/busio/SPI.h"
#include "common-hal/pulseio/PWMOut.h" #include "common-hal/pulseio/PWMOut.h"
#include "common-hal/pulseio/PulseOut.h"
#include "tick.h" #include "tick.h"
safe_mode_t port_init(void) { safe_mode_t port_init(void) {
@ -81,6 +83,8 @@ void reset_port(void) {
i2c_reset(); i2c_reset();
spi_reset(); spi_reset();
pwmout_reset(); pwmout_reset();
pulseout_reset();
timers_reset();
reset_all_pins(); reset_all_pins();
} }
@ -88,16 +92,7 @@ void reset_port(void) {
void HardFault_Handler(void) void HardFault_Handler(void)
{ {
// static volatile uint32_t reg; while (true) {
// static volatile uint32_t reg2; asm("");
// 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;
// }
} }

View File

@ -47,7 +47,7 @@
//| //|
//| .. class:: PulseOut(carrier) //| .. 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. //| :param ~pulseio.PWMOut carrier: PWMOut that is set to output on the desired pin.
//| //|
@ -57,7 +57,8 @@
//| import pulseio //| import pulseio
//| import board //| 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) //| pulse = pulseio.PulseOut(pwm)
//| # on off on off on //| # on off on off on
//| pulses = array.array('H', [65000, 1000, 65000, 65000, 1000]) //| pulses = array.array('H', [65000, 1000, 65000, 65000, 1000])