Switch to pin, frequency and duty_cycle PulseOut

Passing in a PWMOut still works but is deprecated. It will be
removed in CircuitPython 8.0.0

This also switches STM32 timer indices and channel indices to
0-based in our pin data rather than `- 1` everywhere. The latter is
more bug prone.

Most of the way for #3264

Tested on Metro M0, Metro M4, Feather S2, Feather nRF52840, Feather
STM32F4 and Arduino RP2040.
This commit is contained in:
Scott Shawcroft 2021-07-21 16:27:09 -07:00
parent 5fbe6d4805
commit 412eb87080
No known key found for this signature in database
GPG Key ID: 0DFD512649C052DA
35 changed files with 272 additions and 848 deletions

View File

@ -1877,21 +1877,6 @@ msgstr ""
msgid "Polygon needs at least 3 points" msgid "Polygon needs at least 3 points"
msgstr "" msgstr ""
#: ports/esp32s2/common-hal/pulseio/PulseOut.c
msgid ""
"Port does not accept PWM carrier. Pass a pin, frequency and duty cycle "
"instead"
msgstr ""
#: ports/atmel-samd/common-hal/pulseio/PulseOut.c
#: ports/cxd56/common-hal/pulseio/PulseOut.c
#: ports/nrf/common-hal/pulseio/PulseOut.c
#: ports/stm/common-hal/pulseio/PulseOut.c
msgid ""
"Port does not accept pins or frequency. Construct and pass a PWMOut Carrier "
"instead"
msgstr ""
#: shared-bindings/_bleio/Adapter.c #: shared-bindings/_bleio/Adapter.c
msgid "Prefix buffer must be on the heap" msgid "Prefix buffer must be on the heap"
msgstr "" msgstr ""

View File

@ -103,13 +103,15 @@ void pulseout_reset() {
} }
void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self, void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self,
const pwmio_pwmout_obj_t *carrier,
const mcu_pin_obj_t *pin, const mcu_pin_obj_t *pin,
uint32_t frequency, uint32_t frequency,
uint16_t duty_cycle) { uint16_t duty_cycle) {
if (!carrier || pin || frequency) {
mp_raise_NotImplementedError(translate("Port does not accept pins or frequency. Construct and pass a PWMOut Carrier instead")); pwmout_result_t result = common_hal_pwmio_pwmout_construct(
} &self->pwmout, pin, duty_cycle, frequency, false);
// This will raise an exception and not return if needed.
common_hal_pwmio_pwmout_raise_error(result);
if (refcount == 0) { if (refcount == 0) {
// Find a spare timer. // Find a spare timer.
@ -155,7 +157,7 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self,
} }
refcount++; refcount++;
self->pin = carrier->pin->number; self->pin = pin->number;
PortGroup *const port_base = &PORT->Group[GPIO_PORT(self->pin)]; PortGroup *const port_base = &PORT->Group[GPIO_PORT(self->pin)];
self->pincfg = &port_base->PINCFG[self->pin % 32]; self->pincfg = &port_base->PINCFG[self->pin % 32];
@ -173,7 +175,7 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self,
} }
bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t *self) { bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t *self) {
return self->pin == NO_PIN; return common_hal_pwmio_pwmout_deinited(&self->pwmout);
} }
void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t *self) { void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t *self) {
@ -191,6 +193,7 @@ void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t *self) {
pulseout_tc_index = 0xff; pulseout_tc_index = 0xff;
} }
self->pin = NO_PIN; self->pin = NO_PIN;
common_hal_pwmio_pwmout_deinit(&self->pwmout);
#ifdef SAMD21 #ifdef SAMD21
rtc_end_pulse(); rtc_end_pulse();
#endif #endif

View File

@ -30,10 +30,12 @@
#include "common-hal/microcontroller/Pin.h" #include "common-hal/microcontroller/Pin.h"
#include "py/obj.h" #include "py/obj.h"
#include "shared-bindings/pwmio/PWMOut.h"
typedef struct { typedef struct {
mp_obj_base_t base; mp_obj_base_t base;
__IO PORT_PINCFG_Type *pincfg; __IO PORT_PINCFG_Type *pincfg;
pwmio_pwmout_obj_t pwmout;
uint8_t pin; uint8_t pin;
} pulseio_pulseout_obj_t; } pulseio_pulseout_obj_t;

View File

@ -493,3 +493,7 @@ uint32_t common_hal_pwmio_pwmout_get_frequency(pwmio_pwmout_obj_t *self) {
bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t *self) { bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t *self) {
return self->variable_frequency; return self->variable_frequency;
} }
const mcu_pin_obj_t *common_hal_pwmio_pwmout_get_pin(pwmio_pwmout_obj_t *self) {
return self->pin;
}

View File

@ -58,13 +58,15 @@ static bool pulseout_timer_handler(unsigned int *next_interval_us, void *arg) {
} }
void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self, void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self,
const pwmio_pwmout_obj_t *carrier,
const mcu_pin_obj_t *pin, const mcu_pin_obj_t *pin,
uint32_t frequency, uint32_t frequency,
uint16_t duty_cycle) { uint16_t duty_cycle) {
if (!carrier || pin || frequency) {
mp_raise_NotImplementedError(translate("Port does not accept pins or frequency. Construct and pass a PWMOut Carrier instead")); pwmout_result_t result = common_hal_pwmio_pwmout_construct(
} &self->pwmout, pin, duty_cycle, frequency, false);
// This will raise an exception and not return if needed.
common_hal_pwmio_pwmout_raise_error(result);
if (pulse_fd < 0) { if (pulse_fd < 0) {
pulse_fd = open("/dev/timer0", O_RDONLY); pulse_fd = open("/dev/timer0", O_RDONLY);
@ -74,7 +76,7 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self,
mp_raise_RuntimeError(translate("All timers in use")); mp_raise_RuntimeError(translate("All timers in use"));
} }
self->pwm_num = carrier->number; self->pwm_num = self->pwmout.number;
} }
void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t *self) { void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t *self) {
@ -86,6 +88,8 @@ void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t *self) {
close(pulse_fd); close(pulse_fd);
pulse_fd = -1; pulse_fd = -1;
common_hal_pwmio_pwmout_deinit(&self->pwmout);
pulse_buffer = NULL; pulse_buffer = NULL;
} }

View File

@ -29,9 +29,12 @@
#include "py/obj.h" #include "py/obj.h"
#include "shared-bindings/pwmio/PWMOut.h"
typedef struct { typedef struct {
mp_obj_base_t base; mp_obj_base_t base;
uint8_t pwm_num; uint8_t pwm_num;
pwmio_pwmout_obj_t pwmout;
} pulseio_pulseout_obj_t; } pulseio_pulseout_obj_t;
void pulseout_reset(void); void pulseout_reset(void);

View File

@ -157,3 +157,7 @@ void pwmout_start(uint8_t pwm_num) {
void pwmout_stop(uint8_t pwm_num) { void pwmout_stop(uint8_t pwm_num) {
ioctl(pwmout_dev[pwm_num].fd, PWMIOC_STOP, 0); ioctl(pwmout_dev[pwm_num].fd, PWMIOC_STOP, 0);
} }
const mcu_pin_obj_t *common_hal_pwmio_pwmout_get_pin(pwmio_pwmout_obj_t *self) {
return self->pin;
}

View File

@ -32,13 +32,9 @@
// Requires rmt.c void esp32s2_peripherals_reset_all(void) to reset // Requires rmt.c void esp32s2_peripherals_reset_all(void) to reset
void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self, void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self,
const pwmio_pwmout_obj_t *carrier,
const mcu_pin_obj_t *pin, const mcu_pin_obj_t *pin,
uint32_t frequency, uint32_t frequency,
uint16_t duty_cycle) { uint16_t duty_cycle) {
if (carrier || !pin || !frequency) {
mp_raise_NotImplementedError(translate("Port does not accept PWM carrier. Pass a pin, frequency and duty cycle instead"));
}
rmt_channel_t channel = esp32s2_peripherals_find_and_reserve_rmt(); rmt_channel_t channel = esp32s2_peripherals_find_and_reserve_rmt();
if (channel == RMT_CHANNEL_MAX) { if (channel == RMT_CHANNEL_MAX) {

View File

@ -152,7 +152,7 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
varfreq_timers[timer_index] = true; varfreq_timers[timer_index] = true;
} }
self->variable_frequency = variable_frequency; self->variable_frequency = variable_frequency;
self->pin_number = pin->number; self->pin = pin;
self->deinited = false; self->deinited = false;
self->duty_resolution = duty_bits; self->duty_resolution = duty_bits;
claim_pin(pin); claim_pin(pin);
@ -167,7 +167,7 @@ void common_hal_pwmio_pwmout_never_reset(pwmio_pwmout_obj_t *self) {
never_reset_tim[self->tim_handle.timer_num] = true; never_reset_tim[self->tim_handle.timer_num] = true;
never_reset_chan[self->chan_handle.channel] = true; never_reset_chan[self->chan_handle.channel] = true;
never_reset_pin_number(self->pin_number); never_reset_pin_number(self->pin->number);
} }
void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self) { void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self) {
@ -202,7 +202,7 @@ void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t *self) {
// if timer isn't varfreq this will be off aleady // if timer isn't varfreq this will be off aleady
varfreq_timers[self->tim_handle.timer_num] = false; varfreq_timers[self->tim_handle.timer_num] = false;
} }
reset_pin_number(self->pin_number); common_hal_reset_pin(self->pin);
self->deinited = true; self->deinited = true;
} }
@ -232,3 +232,7 @@ uint32_t common_hal_pwmio_pwmout_get_frequency(pwmio_pwmout_obj_t *self) {
bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t *self) { bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t *self) {
return self->variable_frequency; return self->variable_frequency;
} }
const mcu_pin_obj_t *common_hal_pwmio_pwmout_get_pin(pwmio_pwmout_obj_t *self) {
return self->pin;
}

View File

@ -34,7 +34,7 @@ typedef struct {
mp_obj_base_t base; mp_obj_base_t base;
ledc_timer_config_t tim_handle; ledc_timer_config_t tim_handle;
ledc_channel_config_t chan_handle; ledc_channel_config_t chan_handle;
uint16_t pin_number; const mcu_pin_obj_t *pin;
uint8_t duty_resolution; uint8_t duty_resolution;
bool variable_frequency : 1; bool variable_frequency : 1;
bool deinited : 1; bool deinited : 1;

View File

@ -1,246 +0,0 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017-2018 Scott Shawcroft for Adafruit Industries
* Copyright (c) 2019 Artur Pacholec
*
* 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/PulseIn.h"
#include <stdint.h>
#include "background.h"
#include "mpconfigport.h"
#include "py/gc.h"
#include "py/runtime.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/pulseio/PulseIn.h"
#include "supervisor/shared/translate.h"
// TODO
// static void pulsein_set_config(pulseio_pulsein_obj_t* self, bool first_edge) {
// uint32_t sense_setting;
// if (!first_edge) {
// sense_setting = EIC_CONFIG_SENSE0_BOTH_Val;
// configure_eic_channel(self->channel, sense_setting);
// return;
// } else if (self->idle_state) {
// sense_setting = EIC_CONFIG_SENSE0_FALL_Val;
// } else {
// sense_setting = EIC_CONFIG_SENSE0_RISE_Val;
// }
// set_eic_handler(self->channel, EIC_HANDLER_PULSEIN);
// turn_on_eic_channel(self->channel, sense_setting);
// }
// void pulsein_interrupt_handler(uint8_t channel) {
// // Grab the current time first.
// uint32_t current_us;
// uint64_t current_ms;
// current_tick(&current_ms, &current_us);
//
// // current_tick gives us the remaining us until the next tick but we want the number since the
// // last ms.
// current_us = 1000 - current_us;
// pulseio_pulsein_obj_t* self = get_eic_channel_data(channel);
// if (!supervisor_background_tasks_ok() || self->errored_too_fast) {
// self->errored_too_fast = true;
// common_hal_pulseio_pulsein_pause(self);
// return;
// }
// if (self->first_edge) {
// self->first_edge = false;
// pulsein_set_config(self, false);
// } else {
// uint32_t ms_diff = current_ms - self->last_ms;
// uint16_t us_diff = current_us - self->last_us;
// uint32_t total_diff = us_diff;
// if (self->last_us > current_us) {
// total_diff = 1000 + current_us - self->last_us;
// if (ms_diff > 1) {
// total_diff += (ms_diff - 1) * 1000;
// }
// } else {
// total_diff += ms_diff * 1000;
// }
// uint16_t duration = 0xffff;
// if (total_diff < duration) {
// duration = total_diff;
// }
//
// uint16_t i = (self->start + self->len) % self->maxlen;
// self->buffer[i] = duration;
// if (self->len < self->maxlen) {
// self->len++;
// } else {
// self->start++;
// }
// }
// self->last_ms = current_ms;
// self->last_us = current_us;
// }
void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t *self,
const mcu_pin_obj_t *pin, uint16_t maxlen, bool idle_state) {
// if (!pin->has_extint) {
// mp_raise_RuntimeError(translate("No hardware support on pin"));
// }
// if (eic_get_enable() && !eic_channel_free(pin->extint_channel)) {
// mp_raise_RuntimeError(translate("EXTINT channel already in use"));
// }
//
// self->buffer = (uint16_t *) m_malloc(maxlen * sizeof(uint16_t), false);
// if (self->buffer == NULL) {
// mp_raise_msg_varg(&mp_type_MemoryError, translate("Failed to allocate RX buffer of %d bytes"), maxlen * sizeof(uint16_t));
// }
// self->channel = pin->extint_channel;
// self->pin = pin->number;
// self->maxlen = maxlen;
// self->idle_state = idle_state;
// self->start = 0;
// self->len = 0;
// self->first_edge = true;
// self->last_us = 0;
// self->last_ms = 0;
// self->errored_too_fast = false;
//
// set_eic_channel_data(pin->extint_channel, (void*) self);
//
// // Check to see if the EIC is enabled and start it up if its not.'
// if (eic_get_enable() == 0) {
// turn_on_external_interrupt_controller();
// }
//
// gpio_set_pin_function(pin->number, GPIO_PIN_FUNCTION_A);
//
// turn_on_cpu_interrupt(self->channel);
//
// claim_pin(pin);
//
// // Set config will enable the EIC.
// pulsein_set_config(self, true);
}
bool common_hal_pulseio_pulsein_deinited(pulseio_pulsein_obj_t *self) {
// return self->pin == NO_PIN;
return true;
}
void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t *self) {
// if (common_hal_pulseio_pulsein_deinited(self)) {
// return;
// }
// set_eic_handler(self->channel, EIC_HANDLER_NO_INTERRUPT);
// turn_off_eic_channel(self->channel);
// reset_pin_number(self->pin);
// self->pin = NO_PIN;
}
void common_hal_pulseio_pulsein_pause(pulseio_pulsein_obj_t *self) {
// uint32_t mask = 1 << self->channel;
// EIC->INTENCLR.reg = mask << EIC_INTENSET_EXTINT_Pos;
}
void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t *self,
uint16_t trigger_duration) {
// // Make sure we're paused.
// common_hal_pulseio_pulsein_pause(self);
//
// // Reset erroring
// self->errored_too_fast = false;
//
// // Send the trigger pulse.
// if (trigger_duration > 0) {
// gpio_set_pin_pull_mode(self->pin, GPIO_PULL_OFF);
// gpio_set_pin_direction(self->pin, GPIO_DIRECTION_OUT);
// gpio_set_pin_level(self->pin, !self->idle_state);
// common_hal_mcu_delay_us((uint32_t)trigger_duration);
// gpio_set_pin_level(self->pin, self->idle_state);
// }
//
// // Reconfigure the pin and make sure its set to detect the first edge.
// self->first_edge = true;
// self->last_ms = 0;
// self->last_us = 0;
// gpio_set_pin_function(self->pin, GPIO_PIN_FUNCTION_A);
// uint32_t mask = 1 << self->channel;
// // Clear previous interrupt state and re-enable it.
// EIC->INTFLAG.reg = mask << EIC_INTFLAG_EXTINT_Pos;
// EIC->INTENSET.reg = mask << EIC_INTENSET_EXTINT_Pos;
//
// pulsein_set_config(self, true);
}
void common_hal_pulseio_pulsein_clear(pulseio_pulsein_obj_t *self) {
// common_hal_mcu_disable_interrupts();
// self->start = 0;
// self->len = 0;
// common_hal_mcu_enable_interrupts();
}
uint16_t common_hal_pulseio_pulsein_popleft(pulseio_pulsein_obj_t *self) {
// if (self->len == 0) {
// mp_raise_IndexError_varg(translate("pop from empty %q"), MP_QSTR_PulseIn);
// }
// common_hal_mcu_disable_interrupts();
// uint16_t value = self->buffer[self->start];
// self->start = (self->start + 1) % self->maxlen;
// self->len--;
// common_hal_mcu_enable_interrupts();
//
// return value;
return 0;
}
uint16_t common_hal_pulseio_pulsein_get_maxlen(pulseio_pulsein_obj_t *self) {
// return self->maxlen;
return 0;
}
uint16_t common_hal_pulseio_pulsein_get_len(pulseio_pulsein_obj_t *self) {
// return self->len;
return 0;
}
bool common_hal_pulseio_pulsein_get_paused(pulseio_pulsein_obj_t *self) {
// uint32_t mask = 1 << self->channel;
// return (EIC->INTENSET.reg & (mask << EIC_INTENSET_EXTINT_Pos)) == 0;
return true;
}
uint16_t common_hal_pulseio_pulsein_get_item(pulseio_pulsein_obj_t *self,
int16_t index) {
// common_hal_mcu_disable_interrupts();
// if (index < 0) {
// index += self->len;
// }
// if (index < 0 || index >= self->len) {
// common_hal_mcu_enable_interrupts();
// mp_raise_IndexError_varg(translate("%q index out of range"), MP_QSTR_PulseIn);
// }
// uint16_t value = self->buffer[(self->start + index) % self->maxlen];
// common_hal_mcu_enable_interrupts();
// return value;
return 0;
}

View File

@ -1,55 +0,0 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
* Copyright (c) 2019 Artur Pacholec
*
* 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.
*/
#ifndef MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_PULSEIO_PULSEIN_H
#define MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_PULSEIO_PULSEIN_H
#include "common-hal/microcontroller/Pin.h"
#include "py/obj.h"
// TODO
typedef struct {
mp_obj_base_t base;
// uint8_t channel;
// uint8_t pin;
// uint16_t* buffer;
// uint16_t maxlen;
// bool idle_state;
// volatile uint16_t start;
// volatile uint16_t len;
// volatile bool first_edge;
// volatile uint64_t last_ms;
// volatile uint16_t last_us;
// volatile bool errored_too_fast;
} pulseio_pulsein_obj_t;
// void pulsein_reset(void);
//
// void pulsein_interrupt_handler(uint8_t channel);
#endif // MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_PULSEIO_PULSEIN_H

View File

@ -1,210 +0,0 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George
* Copyright (c) 2019 Artur Pacholec
*
* 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 "mpconfigport.h"
#include "py/gc.h"
#include "py/runtime.h"
#include "shared-bindings/pulseio/PulseOut.h"
#include "supervisor/shared/translate.h"
// TODO
// This timer is shared amongst all PulseOut objects under the assumption that
// the code is single threaded.
// static uint8_t refcount = 0;
//
// static uint8_t pulseout_tc_index = 0xff;
//
// static __IO PORT_PINCFG_Type *active_pincfg = NULL;
// static uint16_t *pulse_buffer = NULL;
// static volatile uint16_t pulse_index = 0;
// static uint16_t pulse_length;
// static volatile uint32_t current_compare = 0;
//
// static void turn_on(__IO PORT_PINCFG_Type * pincfg) {
// pincfg->reg = PORT_PINCFG_PMUXEN;
// }
//
// static void turn_off(__IO PORT_PINCFG_Type * pincfg) {
// pincfg->reg = PORT_PINCFG_RESETVALUE;
// }
//
// void pulse_finish(void) {
// pulse_index++;
//
// if (active_pincfg == NULL) {
// return;
// }
// // Always turn it off.
// turn_off(active_pincfg);
// if (pulse_index >= pulse_length) {
// return;
// }
// current_compare = (current_compare + pulse_buffer[pulse_index] * 3 / 4) & 0xffff;
// Tc* tc = tc_insts[pulseout_tc_index];
// tc->COUNT16.CC[0].reg = current_compare;
// if (pulse_index % 2 == 0) {
// turn_on(active_pincfg);
// }
// }
void pulseout_interrupt_handler(uint8_t index) {
// if (index != pulseout_tc_index) return;
// Tc* tc = tc_insts[index];
// if (!tc->COUNT16.INTFLAG.bit.MC0) return;
//
// pulse_finish();
//
// // Clear the interrupt bit.
// tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0;
}
void pulseout_reset() {
// refcount = 0;
// pulseout_tc_index = 0xff;
// active_pincfg = NULL;
}
void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self,
const pwmio_pwmout_obj_t *carrier,
const mcu_pin_obj_t *pin,
uint32_t frequency,
uint16_t duty_cycle) {
// if (refcount == 0) {
// // Find a spare timer.
// Tc *tc = NULL;
// int8_t index = TC_INST_NUM - 1;
// for (; index >= 0; index--) {
// if (tc_insts[index]->COUNT16.CTRLA.bit.ENABLE == 0) {
// tc = tc_insts[index];
// break;
// }
// }
// if (tc == NULL) {
// mp_raise_RuntimeError(translate("All timers in use"));
// }
//
// pulseout_tc_index = index;
//
// set_timer_handler(true, index, TC_HANDLER_PULSEOUT);
// // We use GCLK0 for SAMD21 and GCLK1 for SAMD51 because they both run at 48mhz making our
// // math the same across the boards.
// #ifdef SAMD21
// turn_on_clocks(true, index, 0);
// #endif
// #ifdef SAMD51
// turn_on_clocks(true, index, 1);
// #endif
//
//
// #ifdef SAMD21
// tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 |
// TC_CTRLA_PRESCALER_DIV64 |
// TC_CTRLA_WAVEGEN_NFRQ;
// #endif
// #ifdef SAMD51
// tc_reset(tc);
// tc_set_enable(tc, false);
// tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_PRESCALER_DIV64;
// tc->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_NFRQ;
// #endif
//
// tc_set_enable(tc, true);
// tc->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_STOP;
// }
// refcount++;
//
// self->pin = carrier->pin->number;
//
// PortGroup *const port_base = &PORT->Group[GPIO_PORT(self->pin)];
// self->pincfg = &port_base->PINCFG[self->pin % 32];
//
// // Set the port to output a zero.
// port_base->OUTCLR.reg = 1 << (self->pin % 32);
// port_base->DIRSET.reg = 1 << (self->pin % 32);
//
// // Turn off the pinmux which should connect the port output.
// turn_off(self->pincfg);
}
bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t *self) {
// return self->pin == NO_PIN;
return false;
}
void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t *self) {
// if (common_hal_pulseio_pulseout_deinited(self)) {
// return;
// }
// PortGroup *const port_base = &PORT->Group[GPIO_PORT(self->pin)];
// port_base->DIRCLR.reg = 1 << (self->pin % 32);
//
// turn_on(self->pincfg);
//
// refcount--;
// if (refcount == 0) {
// tc_reset(tc_insts[pulseout_tc_index]);
// pulseout_tc_index = 0xff;
// }
// self->pin = NO_PIN;
}
void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t *self, uint16_t *pulses, uint16_t length) {
// if (active_pincfg != NULL) {
// mp_raise_RuntimeError(translate("Another send is already active"));
// }
// active_pincfg = self->pincfg;
// pulse_buffer = pulses;
// pulse_index = 0;
// pulse_length = length;
//
// current_compare = pulses[0] * 3 / 4;
// Tc* tc = tc_insts[pulseout_tc_index];
// tc->COUNT16.CC[0].reg = current_compare;
//
// // Clear our interrupt in case it was set earlier
// tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0;
// tc->COUNT16.INTENSET.reg = TC_INTENSET_MC0;
// tc_enable_interrupts(pulseout_tc_index);
// turn_on(active_pincfg);
// tc->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_RETRIGGER;
//
// while(pulse_index < length) {
// // Do other things while we wait. The interrupts will handle sending the
// // signal.
// RUN_BACKGROUND_TASKS;
// }
//
// tc->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_STOP;
// tc->COUNT16.INTENCLR.reg = TC_INTENCLR_MC0;
// tc_disable_interrupts(pulseout_tc_index);
// active_pincfg = NULL;
}

View File

@ -1,45 +0,0 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
* Copyright (c) 2019 Artur Pacholec
*
* 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.
*/
#ifndef MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_PULSEIO_PULSEOUT_H
#define MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_PULSEIO_PULSEOUT_H
#include "common-hal/microcontroller/Pin.h"
#include "py/obj.h"
// TODO
typedef struct {
mp_obj_base_t base;
// __IO PORT_PINCFG_Type *pincfg;
// uint8_t pin;
} pulseio_pulseout_obj_t;
void pulseout_reset(void);
// void pulseout_interrupt_handler(uint8_t index);
#endif // MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_PULSEIO_PULSEOUT_H

View File

@ -1 +0,0 @@
// No pulseio module functions.

View File

@ -56,97 +56,16 @@ static void config_periph_pin(const mcu_pwm_obj_t *periph) {
| IOMUXC_SW_PAD_CTL_PAD_DSE(6) | IOMUXC_SW_PAD_CTL_PAD_DSE(6)
| IOMUXC_SW_PAD_CTL_PAD_SRE(0)); | IOMUXC_SW_PAD_CTL_PAD_SRE(0));
} }
// TODO
// #include "samd/pins.h"
// #undef ENABLE
//
// # define _TCC_SIZE(unused, n) TCC ## n ## _SIZE,
// # define TCC_SIZES { REPEAT_MACRO(_TCC_SIZE, 0, TCC_INST_NUM) }
//
// static uint32_t tcc_periods[TCC_INST_NUM];
// static uint32_t tc_periods[TC_INST_NUM];
//
// uint32_t target_tcc_frequencies[TCC_INST_NUM];
// uint8_t tcc_refcount[TCC_INST_NUM];
//
//// This bitmask keeps track of which channels of a TCC are currently claimed.
// #ifdef SAMD21
// uint8_t tcc_channels[3]; // Set by pwmout_reset() to {0xf0, 0xfc, 0xfc} initially.
// #endif
// #ifdef SAMD51
// uint8_t tcc_channels[5]; // Set by pwmout_reset() to {0xc0, 0xf0, 0xf8, 0xfc, 0xfc} initially.
// #endif
//
// static uint8_t never_reset_tc_or_tcc[TC_INST_NUM + TCC_INST_NUM];
void common_hal_pwmio_pwmout_never_reset(pwmio_pwmout_obj_t *self) { void common_hal_pwmio_pwmout_never_reset(pwmio_pwmout_obj_t *self) {
// if (self->timer->is_tc) {
// never_reset_tc_or_tcc[self->timer->index] += 1;
// } else {
// never_reset_tc_or_tcc[TC_INST_NUM + self->timer->index] += 1;
// }
//
// never_reset_pin_number(self->pin->number);
} }
void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self) { void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self) {
// if (self->timer->is_tc) {
// never_reset_tc_or_tcc[self->timer->index] -= 1;
// } else {
// never_reset_tc_or_tcc[TC_INST_NUM + self->timer->index] -= 1;
// }
} }
void pwmout_reset(void) { void pwmout_reset(void) {
// // Reset all timers
// for (int i = 0; i < TCC_INST_NUM; i++) {
// target_tcc_frequencies[i] = 0;
// tcc_refcount[i] = 0;
// }
// Tcc *tccs[TCC_INST_NUM] = TCC_INSTS;
// for (int i = 0; i < TCC_INST_NUM; i++) {
// if (never_reset_tc_or_tcc[TC_INST_NUM + i] > 0) {
// continue;
// }
// // Disable the module before resetting it.
// if (tccs[i]->CTRLA.bit.ENABLE == 1) {
// tccs[i]->CTRLA.bit.ENABLE = 0;
// while (tccs[i]->SYNCBUSY.bit.ENABLE == 1) {
// }
// }
// uint8_t mask = 0xff;
// for (uint8_t j = 0; j < tcc_cc_num[i]; j++) {
// mask <<= 1;
// }
// tcc_channels[i] = mask;
// tccs[i]->CTRLA.bit.SWRST = 1;
// while (tccs[i]->CTRLA.bit.SWRST == 1) {
// }
// }
// Tc *tcs[TC_INST_NUM] = TC_INSTS;
// for (int i = 0; i < TC_INST_NUM; i++) {
// if (never_reset_tc_or_tcc[i] > 0) {
// continue;
// }
// tcs[i]->COUNT16.CTRLA.bit.SWRST = 1;
// while (tcs[i]->COUNT16.CTRLA.bit.SWRST == 1) {
// }
// }
} }
// static uint8_t tcc_channel(const pin_timer_t* t) {
// // For the SAMD51 this hardcodes the use of OTMX == 0x0, the output matrix mapping, which uses
// // SAMD21-style modulo mapping.
// return t->wave_output % tcc_cc_num[t->index];
// }
// bool channel_ok(const pin_timer_t* t) {
// uint8_t channel_bit = 1 << tcc_channel(t);
// return (!t->is_tc && ((tcc_channels[t->index] & channel_bit) == 0)) ||
// t->is_tc;
// }
#define PWM_SRC_CLK_FREQ CLOCK_GetFreq(kCLOCK_IpgClk) #define PWM_SRC_CLK_FREQ CLOCK_GetFreq(kCLOCK_IpgClk)
static int calculate_pulse_count(uint32_t frequency, uint8_t *prescaler) { static int calculate_pulse_count(uint32_t frequency, uint8_t *prescaler) {
@ -325,3 +244,7 @@ uint32_t common_hal_pwmio_pwmout_get_frequency(pwmio_pwmout_obj_t *self) {
bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t *self) { bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t *self) {
return self->variable_frequency; return self->variable_frequency;
} }
const mcu_pin_obj_t *common_hal_pwmio_pwmout_get_pin(pwmio_pwmout_obj_t *self) {
return self->pin;
}

View File

@ -24,10 +24,11 @@ INTERNAL_FLASH_FILESYSTEM = 1
CIRCUITPY_AUDIOIO = 0 CIRCUITPY_AUDIOIO = 0
CIRCUITPY_AUDIOBUSIO = 0 CIRCUITPY_AUDIOBUSIO = 0
CIRCUITPY_BUSDEVICE = 1 CIRCUITPY_BUSDEVICE = 1
CIRCUITPY_COUNTIO = 0
CIRCUITPY_FREQUENCYIO = 0 CIRCUITPY_FREQUENCYIO = 0
CIRCUITPY_I2CPERIPHERAL = 0 CIRCUITPY_I2CPERIPHERAL = 0
CIRCUITPY_NVM = 0 CIRCUITPY_NVM = 0
CIRCUITPY_PULSEIO = 0
CIRCUITPY_ROTARYIO = 0 CIRCUITPY_ROTARYIO = 0
CIRCUITPY_COUNTIO = 0
CIRCUITPY_USB_MIDI = 1 CIRCUITPY_USB_MIDI = 1
LONGINT_IMPL = MPZ LONGINT_IMPL = MPZ

View File

@ -37,8 +37,6 @@
#include "fsl_device_registers.h" #include "fsl_device_registers.h"
#include "common-hal/microcontroller/Pin.h" #include "common-hal/microcontroller/Pin.h"
#include "common-hal/pulseio/PulseIn.h"
#include "common-hal/pulseio/PulseOut.h"
#include "common-hal/pwmio/PWMOut.h" #include "common-hal/pwmio/PWMOut.h"
#include "common-hal/rtc/RTC.h" #include "common-hal/rtc/RTC.h"
#include "common-hal/busio/SPI.h" #include "common-hal/busio/SPI.h"
@ -289,9 +287,6 @@ void reset_port(void) {
// eic_reset(); // eic_reset();
#if CIRCUITPY_PULSEIO
pulseout_reset();
#endif
#if CIRCUITPY_PWMIO #if CIRCUITPY_PWMIO
pwmout_reset(); pwmout_reset();
#endif #endif

View File

@ -48,14 +48,14 @@ static volatile uint16_t pulse_array_index = 0;
static uint16_t pulse_array_length; static uint16_t pulse_array_length;
static void turn_on(pulseio_pulseout_obj_t *pulseout) { static void turn_on(pulseio_pulseout_obj_t *pulseout) {
pulseout->pwmout->pwm->PSEL.OUT[0] = pulseout->pwmout->pin_number; pulseout->pwmout.pwm->PSEL.OUT[0] = pulseout->pwmout.pin->number;
} }
static void turn_off(pulseio_pulseout_obj_t *pulseout) { static void turn_off(pulseio_pulseout_obj_t *pulseout) {
// Disconnect pin from PWM. // Disconnect pin from PWM.
pulseout->pwmout->pwm->PSEL.OUT[0] = 0xffffffff; pulseout->pwmout.pwm->PSEL.OUT[0] = 0xffffffff;
// Make sure pin is low. // Make sure pin is low.
nrf_gpio_pin_clear(pulseout->pwmout->pin_number); nrf_gpio_pin_clear(pulseout->pwmout.pin->number);
} }
static void start_timer(void) { static void start_timer(void) {
@ -100,13 +100,15 @@ void pulseout_reset() {
} }
void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self, void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self,
const pwmio_pwmout_obj_t *carrier,
const mcu_pin_obj_t *pin, const mcu_pin_obj_t *pin,
uint32_t frequency, uint32_t frequency,
uint16_t duty_cycle) { uint16_t duty_cycle) {
if (!carrier || pin || frequency) {
mp_raise_NotImplementedError(translate("Port does not accept pins or frequency. Construct and pass a PWMOut Carrier instead")); pwmout_result_t result = common_hal_pwmio_pwmout_construct(
} &self->pwmout, pin, duty_cycle, frequency, false);
// This will raise an exception and not return if needed.
common_hal_pwmio_pwmout_raise_error(result);
if (refcount == 0) { if (refcount == 0) {
timer = nrf_peripherals_allocate_timer_or_throw(); timer = nrf_peripherals_allocate_timer_or_throw();
@ -122,14 +124,12 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self,
.p_context = self, .p_context = self,
}; };
self->pwmout = carrier;
nrfx_timer_init(timer, &timer_config, &pulseout_event_handler); nrfx_timer_init(timer, &timer_config, &pulseout_event_handler);
turn_off(self); 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 self->pwmout == NULL; return common_hal_pwmio_pwmout_deinited(&self->pwmout);
} }
void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t *self) { void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t *self) {
@ -137,7 +137,7 @@ void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t *self) {
return; return;
} }
turn_on(self); turn_on(self);
self->pwmout = NULL; common_hal_pwmio_pwmout_deinit(&self->pwmout);
refcount--; refcount--;
if (refcount == 0) { if (refcount == 0) {

View File

@ -34,7 +34,7 @@
typedef struct { typedef struct {
mp_obj_base_t base; mp_obj_base_t base;
const pwmio_pwmout_obj_t *pwmout; pwmio_pwmout_obj_t pwmout;
} pulseio_pulseout_obj_t; } pulseio_pulseout_obj_t;
void pulseout_reset(void); void pulseout_reset(void);

View File

@ -74,7 +74,7 @@ void common_hal_pwmio_pwmout_never_reset(pwmio_pwmout_obj_t *self) {
} }
} }
never_reset_pin_number(self->pin_number); common_hal_never_reset_pin(self->pin);
} }
void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self) { void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self) {
@ -232,14 +232,14 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
} }
self->channel = channel; self->channel = channel;
self->pin_number = pin->number; self->pin = pin;
claim_pin(pin); claim_pin(pin);
self->frequency = frequency; self->frequency = frequency;
self->variable_frequency = variable_frequency; self->variable_frequency = variable_frequency;
// Note this is standard, not strong drive. // 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
nrf_pwm_disable(self->pwm); nrf_pwm_disable(self->pwm);
@ -267,15 +267,15 @@ void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t *self) {
return; return;
} }
nrf_gpio_cfg_default(self->pin_number); nrf_gpio_cfg_default(self->pin->number);
NRF_PWM_Type *pwm = self->pwm; NRF_PWM_Type *pwm = self->pwm;
self->pwm = NULL; self->pwm = NULL;
pwmout_free_channel(pwm, self->channel); pwmout_free_channel(pwm, self->channel);
reset_pin_number(self->pin_number); common_hal_reset_pin(self->pin);
self->pin_number = NO_PIN; self->pin = NULL;
} }
void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t *self, uint16_t duty_cycle) { void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t *self, uint16_t duty_cycle) {
@ -313,3 +313,7 @@ uint32_t common_hal_pwmio_pwmout_get_frequency(pwmio_pwmout_obj_t *self) {
bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t *self) { bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t *self) {
return self->variable_frequency; return self->variable_frequency;
} }
const mcu_pin_obj_t *common_hal_pwmio_pwmout_get_pin(pwmio_pwmout_obj_t *self) {
return self->pin;
}

View File

@ -29,13 +29,14 @@
#include "nrfx_pwm.h" #include "nrfx_pwm.h"
#include "py/obj.h" #include "py/obj.h"
#include "shared-bindings/microcontroller/Pin.h"
typedef struct { typedef struct {
mp_obj_base_t base; mp_obj_base_t base;
NRF_PWM_Type *pwm; NRF_PWM_Type *pwm;
uint8_t pin_number;
uint8_t channel : 7; uint8_t channel : 7;
bool variable_frequency : 1; bool variable_frequency : 1;
const mcu_pin_obj_t *pin;
uint16_t duty_cycle; uint16_t duty_cycle;
uint32_t frequency; uint32_t frequency;
} pwmio_pwmout_obj_t; } pwmio_pwmout_obj_t;

View File

@ -42,23 +42,28 @@ static uint8_t refcount = 0;
volatile alarm_id_t cur_alarm = 0; volatile alarm_id_t cur_alarm = 0;
void turn_off(uint8_t slice) { void turn_off(uint8_t slice) {
pwm_hw->slice[slice].ctr = 0; // Set the current counter value near the top so that the output is low. The
pwm_hw->slice[slice].cc = 0; // - 2 gives us a little wiggle room for enabling and disabling the slice.
pwm_hw->slice[slice].top = 0; // The top + 1 ensure we don't end up lower than the cc (and therefore high.)
pwm_hw->slice[slice].div = 1u << PWM_CH0_DIV_INT_LSB; uint32_t top = MAX(pwm_hw->slice[slice].cc + 1, pwm_hw->slice[slice].top - 2);
// Disable interrupts so this happens as fast as possible.
common_hal_mcu_disable_interrupts();
pwm_hw->slice[slice].ctr = top;
// Enable for at least one cycle so that the new counter value takes effect.
pwm_hw->slice[slice].csr = PWM_CH0_CSR_EN_BITS; pwm_hw->slice[slice].csr = PWM_CH0_CSR_EN_BITS;
pwm_hw->slice[slice].csr = 0; pwm_hw->slice[slice].csr = 0;
common_hal_mcu_enable_interrupts();
} }
void pulse_finish(pulseio_pulseout_obj_t *self) { void pulse_finish(pulseio_pulseout_obj_t *self) {
self->pulse_index++; self->pulse_index++;
// Turn pwm pin off by setting duty cyle to 1. // Turn pwm pin off by setting duty cyle to 1.
common_hal_pwmio_pwmout_set_duty_cycle(self->carrier,1); common_hal_pwmio_pwmout_set_duty_cycle(&self->carrier, 1);
if (self->pulse_index >= self->pulse_length) { if (self->pulse_index >= self->pulse_length) {
return; return;
} }
if (self->pulse_index % 2 == 0) { if (self->pulse_index % 2 == 0) {
common_hal_pwmio_pwmout_set_duty_cycle(self->carrier,self->current_duty_cycle); common_hal_pwmio_pwmout_set_duty_cycle(&self->carrier, self->current_duty_cycle);
} }
uint64_t delay = self->pulse_buffer[self->pulse_index]; uint64_t delay = self->pulse_buffer[self->pulse_index];
if (delay < self->min_pulse) { if (delay < self->min_pulse) {
@ -78,24 +83,26 @@ int64_t pulseout_interrupt_handler(alarm_id_t id, void *user_data) {
} }
void pulseout_reset() { void pulseout_reset() {
refcount = 0;
} }
void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self, void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self,
const pwmio_pwmout_obj_t *carrier,
const mcu_pin_obj_t *pin, const mcu_pin_obj_t *pin,
uint32_t frequency, uint32_t frequency,
uint16_t duty_cycle) { uint16_t duty_cycle) {
refcount++; pwmout_result_t result = common_hal_pwmio_pwmout_construct(
self->carrier = (pwmio_pwmout_obj_t *)carrier; &self->carrier, pin, duty_cycle, frequency, false);
self->current_duty_cycle = common_hal_pwmio_pwmout_get_duty_cycle(self->carrier);
pwm_set_enabled(self->carrier->slice,false); // This will raise an exception and not return if needed.
turn_off(self->carrier->slice); common_hal_pwmio_pwmout_raise_error(result);
common_hal_pwmio_pwmout_set_duty_cycle(self->carrier,1);
self->pin = self->carrier->pin->number; self->current_duty_cycle = duty_cycle;
self->slice = self->carrier->slice; pwm_set_enabled(self->carrier.slice, false);
self->min_pulse = (1000000 / self->carrier->actual_frequency); turn_off(self->carrier.slice);
common_hal_pwmio_pwmout_set_duty_cycle(&self->carrier, 1);
self->pin = self->carrier.pin->number;
self->slice = self->carrier.slice;
self->min_pulse = (1000000 / self->carrier.actual_frequency);
} }
bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t *self) { bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t *self) {
@ -106,7 +113,7 @@ void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t *self) {
if (common_hal_pulseio_pulseout_deinited(self)) { if (common_hal_pulseio_pulseout_deinited(self)) {
return; return;
} }
refcount--; common_hal_pwmio_pwmout_deinit(&self->carrier);
self->pin = NO_PIN; self->pin = NO_PIN;
} }
@ -115,8 +122,8 @@ void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t *self, uint16_t *pu
self->pulse_index = 0; self->pulse_index = 0;
self->pulse_length = length; self->pulse_length = length;
common_hal_pwmio_pwmout_set_duty_cycle(self->carrier,self->current_duty_cycle); common_hal_pwmio_pwmout_set_duty_cycle(&self->carrier, self->current_duty_cycle);
pwm_set_enabled(self->slice,true); pwm_set_enabled(self->slice, true);
uint64_t delay = self->pulse_buffer[0]; uint64_t delay = self->pulse_buffer[0];
if (delay < self->min_pulse) { if (delay < self->min_pulse) {
delay = self->min_pulse; delay = self->min_pulse;

View File

@ -39,7 +39,7 @@ typedef struct {
mp_obj_base_t base; mp_obj_base_t base;
uint8_t pin; uint8_t pin;
uint8_t slice; uint8_t slice;
pwmio_pwmout_obj_t *carrier; pwmio_pwmout_obj_t carrier;
uint16_t *pulse_buffer; uint16_t *pulse_buffer;
uint16_t pulse_length; uint16_t pulse_length;
uint16_t current_duty_cycle; uint16_t current_duty_cycle;

View File

@ -292,3 +292,7 @@ uint32_t common_hal_pwmio_pwmout_get_frequency(pwmio_pwmout_obj_t *self) {
bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t *self) { bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t *self) {
return self->variable_frequency; return self->variable_frequency;
} }
const mcu_pin_obj_t *common_hal_pwmio_pwmout_get_pin(pwmio_pwmout_obj_t *self) {
return self->pin;
}

View File

@ -52,15 +52,15 @@ STATIC pulseio_pulseout_obj_t *curr_pulseout = NULL;
STATIC void turn_on(pulseio_pulseout_obj_t *pulseout) { STATIC void turn_on(pulseio_pulseout_obj_t *pulseout) {
// Turn on PWM // Turn on PWM
HAL_TIM_PWM_Start(&(pulseout->pwmout->handle), pulseout->pwmout->channel); HAL_TIM_PWM_Start(&(pulseout->pwmout.handle), pulseout->pwmout.channel);
} }
STATIC void turn_off(pulseio_pulseout_obj_t *pulseout) { STATIC void turn_off(pulseio_pulseout_obj_t *pulseout) {
// Turn off PWM // Turn off PWM
HAL_TIM_PWM_Stop(&(pulseout->pwmout->handle), pulseout->pwmout->channel); HAL_TIM_PWM_Stop(&(pulseout->pwmout.handle), pulseout->pwmout.channel);
// Make sure pin is low. // Make sure pin is low.
HAL_GPIO_WritePin(pin_port(pulseout->pwmout->tim->pin->port), HAL_GPIO_WritePin(pin_port(pulseout->pwmout.tim->pin->port),
pin_mask(pulseout->pwmout->tim->pin->number), 0); pin_mask(pulseout->pwmout.tim->pin->number), 0);
} }
STATIC void start_timer(void) { STATIC void start_timer(void) {
@ -80,7 +80,7 @@ STATIC void pulseout_event_handler(void) {
if (__HAL_TIM_GET_FLAG(&tim_handle, TIM_FLAG_UPDATE) != RESET) { if (__HAL_TIM_GET_FLAG(&tim_handle, TIM_FLAG_UPDATE) != RESET) {
if (__HAL_TIM_GET_IT_SOURCE(&tim_handle, TIM_IT_UPDATE) != RESET) { if (__HAL_TIM_GET_IT_SOURCE(&tim_handle, TIM_IT_UPDATE) != RESET) {
__HAL_TIM_CLEAR_IT(&tim_handle, TIM_IT_UPDATE); __HAL_TIM_CLEAR_IT(&tim_handle, TIM_IT_UPDATE);
if (curr_pulseout->pwmout == NULL) { if (common_hal_pulseio_pulseout_deinited(curr_pulseout)) {
return; // invalid interrupt return; // invalid interrupt
} }
@ -111,13 +111,12 @@ void pulseout_reset() {
} }
void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self, void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self,
const pwmio_pwmout_obj_t *carrier, const mcu_pin_obj_t *pin, uint32_t frequency, uint16_t duty_cycle) {
const mcu_pin_obj_t *pin, pwmout_result_t result = common_hal_pwmio_pwmout_construct(
uint32_t frequency, &self->pwmout, pin, duty_cycle, frequency, false);
uint16_t duty_cycle) {
if (!carrier || pin || frequency) { // This will raise an exception and not return if needed.
mp_raise_NotImplementedError(translate("Port does not accept pins or frequency. Construct and pass a PWMOut Carrier instead")); common_hal_pwmio_pwmout_raise_error(result);
}
// Add to active PulseOuts // Add to active PulseOuts
refcount++; refcount++;
@ -139,13 +138,12 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self,
HAL_TIM_Base_Init(&tim_handle); HAL_TIM_Base_Init(&tim_handle);
tim_handle.Instance->SR = 0; tim_handle.Instance->SR = 0;
// The HAL can't work with const, recast required.
self->pwmout = (pwmio_pwmout_obj_t *)carrier;
turn_off(self); 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 self->pwmout == NULL; return common_hal_pwmio_pwmout_deinited(&self->pwmout);
} }
void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t *self) { void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t *self) {
@ -153,7 +151,7 @@ void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t *self) {
return; return;
} }
turn_on(self); turn_on(self);
self->pwmout = NULL; common_hal_pwmio_pwmout_deinit(&self->pwmout);
refcount--; refcount--;
if (refcount == 0) { if (refcount == 0) {

View File

@ -34,7 +34,7 @@
typedef struct { typedef struct {
mp_obj_base_t base; mp_obj_base_t base;
pwmio_pwmout_obj_t *pwmout; pwmio_pwmout_obj_t pwmout;
} pulseio_pulseout_obj_t; } pulseio_pulseout_obj_t;
void pulseout_reset(void); void pulseout_reset(void);

View File

@ -89,8 +89,8 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
for (uint i = 0; i < tim_num; i++) { for (uint i = 0; i < tim_num; i++) {
const mcu_tim_pin_obj_t *l_tim = &mcu_tim_pin_list[i]; const mcu_tim_pin_obj_t *l_tim = &mcu_tim_pin_list[i];
uint8_t l_tim_index = l_tim->tim_index - 1; uint8_t l_tim_index = l_tim->tim_index;
uint8_t l_tim_channel = l_tim->channel_index - 1; uint8_t l_tim_channel = l_tim->channel_index;
// if pin is same // if pin is same
if (l_tim->pin == pin) { if (l_tim->pin == pin) {
@ -127,14 +127,14 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
// handle valid/invalid timer instance // handle valid/invalid timer instance
if (self->tim != NULL) { if (self->tim != NULL) {
// create instance // create instance
TIMx = mcu_tim_banks[self->tim->tim_index - 1]; TIMx = mcu_tim_banks[self->tim->tim_index];
// reserve timer/channel // reserve timer/channel
if (variable_frequency) { if (variable_frequency) {
reserved_tim[self->tim->tim_index - 1] = 0x0F; reserved_tim[self->tim->tim_index] = 0x0F;
} else { } else {
reserved_tim[self->tim->tim_index - 1] |= 1 << (self->tim->channel_index - 1); reserved_tim[self->tim->tim_index] |= 1 << self->tim->channel_index;
} }
tim_frequencies[self->tim->tim_index - 1] = frequency; tim_frequencies[self->tim->tim_index] = frequency;
stm_peripherals_timer_reserve(TIMx); stm_peripherals_timer_reserve(TIMx);
} else { // no match found } else { // no match found
if (tim_chan_taken || tim_taken_internal) { if (tim_chan_taken || tim_taken_internal) {
@ -148,6 +148,13 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
} }
} }
uint32_t prescaler = 0; // prescaler is 15 bit
uint32_t period = 0; // period is 16 bit
uint32_t source_freq = stm_peripherals_timer_get_source_freq(TIMx);
if (!timer_get_optimal_divisors(&period, &prescaler, frequency, source_freq)) {
return PWMOUT_INVALID_FREQUENCY;
}
GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = pin_mask(pin->number); GPIO_InitStruct.Pin = pin_mask(pin->number);
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
@ -155,18 +162,12 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = self->tim->altfn_index; GPIO_InitStruct.Alternate = self->tim->altfn_index;
HAL_GPIO_Init(pin_port(pin->port), &GPIO_InitStruct); HAL_GPIO_Init(pin_port(pin->port), &GPIO_InitStruct);
self->pin = pin;
tim_clock_enable(1 << (self->tim->tim_index - 1)); tim_clock_enable(1 << (self->tim->tim_index));
// translate channel into handle value // translate channel into handle value
self->channel = 4 * (self->tim->channel_index - 1); self->channel = 4 * self->tim->channel_index;
uint32_t prescaler = 0; // prescaler is 15 bit
uint32_t period = 0; // period is 16 bit
uint32_t source_freq = stm_peripherals_timer_get_source_freq(TIMx);
if (!timer_get_optimal_divisors(&period, &prescaler, frequency, source_freq)) {
return PWMOUT_INVALID_FREQUENCY;
}
// Timer init // Timer init
self->handle.Instance = TIMx; self->handle.Instance = TIMx;
@ -207,7 +208,7 @@ void common_hal_pwmio_pwmout_never_reset(pwmio_pwmout_obj_t *self) {
for (size_t i = 0; i < TIM_BANK_ARRAY_LEN; i++) { for (size_t i = 0; i < TIM_BANK_ARRAY_LEN; i++) {
if (mcu_tim_banks[i] == self->handle.Instance) { if (mcu_tim_banks[i] == self->handle.Instance) {
never_reset_tim[i] = true; never_reset_tim[i] = true;
never_reset_pin_number(self->tim->pin->port, self->tim->pin->number); common_hal_never_reset_pin(self->pin);
break; break;
} }
} }
@ -232,16 +233,16 @@ void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t *self) {
} }
// var freq shuts down entire timer, others just their channel // var freq shuts down entire timer, others just their channel
if (self->variable_frequency) { if (self->variable_frequency) {
reserved_tim[self->tim->tim_index - 1] = 0x00; reserved_tim[self->tim->tim_index] = 0x00;
} else { } else {
reserved_tim[self->tim->tim_index - 1] &= ~(1 << self->tim->channel_index); reserved_tim[self->tim->tim_index] &= ~(1 << self->tim->channel_index);
HAL_TIM_PWM_Stop(&self->handle, self->channel); HAL_TIM_PWM_Stop(&self->handle, self->channel);
} }
reset_pin_number(self->tim->pin->port,self->tim->pin->number); common_hal_reset_pin(self->pin);
// if reserved timer has no active channels, we can disable it // if reserved timer has no active channels, we can disable it
if (!reserved_tim[self->tim->tim_index - 1]) { if (reserved_tim[self->tim->tim_index] == 0) {
tim_frequencies[self->tim->tim_index - 1] = 0x00; tim_frequencies[self->tim->tim_index] = 0x00;
stm_peripherals_timer_free(self->handle.Instance); stm_peripherals_timer_free(self->handle.Instance);
} }
@ -290,7 +291,7 @@ void common_hal_pwmio_pwmout_set_frequency(pwmio_pwmout_obj_t *self, uint32_t fr
mp_raise_ValueError(translate("Could not restart PWM")); mp_raise_ValueError(translate("Could not restart PWM"));
} }
tim_frequencies[self->tim->tim_index - 1] = frequency; tim_frequencies[self->tim->tim_index] = frequency;
self->frequency = frequency; self->frequency = frequency;
self->period = period; self->period = period;
} }
@ -302,3 +303,7 @@ uint32_t common_hal_pwmio_pwmout_get_frequency(pwmio_pwmout_obj_t *self) {
bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t *self) { bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t *self) {
return self->variable_frequency; return self->variable_frequency;
} }
const mcu_pin_obj_t *common_hal_pwmio_pwmout_get_pin(pwmio_pwmout_obj_t *self) {
return self->pin;
}

View File

@ -44,6 +44,7 @@ typedef struct {
uint16_t duty_cycle; uint16_t duty_cycle;
uint32_t frequency; uint32_t frequency;
uint32_t period; uint32_t period;
const mcu_pin_obj_t *pin;
} pwmio_pwmout_obj_t; } pwmio_pwmout_obj_t;
void pwmout_reset(void); void pwmout_reset(void);

View File

@ -59,9 +59,9 @@ typedef struct {
#define TIM(index, alt, channel, tim_pin) \ #define TIM(index, alt, channel, tim_pin) \
{ \ { \
.tim_index = index, \ .tim_index = index - 1, \
.altfn_index = alt, \ .altfn_index = alt, \
.channel_index = channel, \ .channel_index = channel - 1, \
.pin = tim_pin, \ .pin = tim_pin, \
} }

View File

@ -41,8 +41,12 @@
static bool stm_timer_reserved[MP_ARRAY_SIZE(mcu_tim_banks)]; static bool stm_timer_reserved[MP_ARRAY_SIZE(mcu_tim_banks)];
static bool stm_timer_never_reset[MP_ARRAY_SIZE(mcu_tim_banks)]; static bool stm_timer_never_reset[MP_ARRAY_SIZE(mcu_tim_banks)];
static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
static size_t irq_map[] = { typedef void (*stm_timer_callback_t)(void);
// Array of function pointers.
static stm_timer_callback_t stm_timer_callback[MP_ARRAY_SIZE(mcu_tim_banks)];
static size_t irq_map[] = {
#ifdef TIM1 #ifdef TIM1
TIM1_CC_IRQn, TIM1_CC_IRQn,
#else #else
@ -139,7 +143,7 @@ static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
// If the APB prescaler is 1, then the timer clock is equal to its respective // If the APB prescaler is 1, then the timer clock is equal to its respective
// APB clock. Otherwise (APB prescaler > 1) the timer clock is twice its // APB clock. Otherwise (APB prescaler > 1) the timer clock is twice its
// respective APB clock. See DM00031020 Rev 4, page 115. // respective APB clock. See DM00031020 Rev 4, page 115.
uint32_t stm_peripherals_timer_get_source_freq(TIM_TypeDef *timer) { uint32_t stm_peripherals_timer_get_source_freq(TIM_TypeDef *timer) {
size_t tim_id = stm_peripherals_timer_get_index(timer); size_t tim_id = stm_peripherals_timer_get_index(timer);
uint32_t source, clk_div; uint32_t source, clk_div;
if (tim_id == 1 || (8 <= tim_id && tim_id <= 11)) { if (tim_id == 1 || (8 <= tim_id && tim_id <= 11)) {
@ -158,12 +162,12 @@ static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
return source; return source;
} }
size_t stm_peripherals_timer_get_irqnum(TIM_TypeDef *instance) { size_t stm_peripherals_timer_get_irqnum(TIM_TypeDef *instance) {
size_t tim_id = stm_peripherals_timer_get_index(instance); size_t tim_id = stm_peripherals_timer_get_index(instance);
return irq_map[tim_id]; return irq_map[tim_id];
} }
void timers_reset(void) { void timers_reset(void) {
uint16_t never_reset_mask = 0x00; uint16_t never_reset_mask = 0x00;
for (size_t i = 0; i < MP_ARRAY_SIZE(mcu_tim_banks); i++) { for (size_t i = 0; i < MP_ARRAY_SIZE(mcu_tim_banks); i++) {
if (!stm_timer_never_reset[i]) { if (!stm_timer_never_reset[i]) {
@ -175,14 +179,14 @@ static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
tim_clock_disable(ALL_CLOCKS & ~(never_reset_mask)); tim_clock_disable(ALL_CLOCKS & ~(never_reset_mask));
} }
TIM_TypeDef *stm_peripherals_find_timer(void) { TIM_TypeDef *stm_peripherals_find_timer(void) {
// Check for timers on pins outside the package size // Check for timers on pins outside the package size
for (size_t i = 0; i < MP_ARRAY_SIZE(mcu_tim_banks); i++) { for (size_t i = 0; i < MP_ARRAY_SIZE(mcu_tim_banks); i++) {
bool timer_in_package = false; bool timer_in_package = false;
// Find each timer instance on the given bank // Find each timer instance on the given bank
for (size_t j = 0; j < MP_ARRAY_SIZE(mcu_tim_pin_list); j++) { for (size_t j = 0; j < MP_ARRAY_SIZE(mcu_tim_pin_list); j++) {
// If a pin is claimed, we skip it // If a pin is claimed, we skip it
if ((mcu_tim_pin_list[j].tim_index == i + 1) if ((mcu_tim_pin_list[j].tim_index == i)
&& (common_hal_mcu_pin_is_free(mcu_tim_pin_list[j].pin) == true)) { && (common_hal_mcu_pin_is_free(mcu_tim_pin_list[j].pin) == true)) {
// Search whether any pins in the package array match it // Search whether any pins in the package array match it
for (size_t k = 0; k < mcu_pin_globals.map.alloc; k++) { for (size_t k = 0; k < mcu_pin_globals.map.alloc; k++) {
@ -210,7 +214,7 @@ static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
return NULL; return NULL;
} }
void stm_peripherals_timer_preinit(TIM_TypeDef *instance, uint8_t prio, void (*callback)(void)) { void stm_peripherals_timer_preinit(TIM_TypeDef *instance, uint8_t prio, void (*callback)(void)) {
size_t tim_idx = stm_peripherals_timer_get_index(instance); size_t tim_idx = stm_peripherals_timer_get_index(instance);
stm_timer_callback[tim_idx] = callback; stm_timer_callback[tim_idx] = callback;
tim_clock_enable(1 << tim_idx); tim_clock_enable(1 << tim_idx);
@ -218,16 +222,16 @@ static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
HAL_NVIC_EnableIRQ(irq_map[tim_idx]); HAL_NVIC_EnableIRQ(irq_map[tim_idx]);
} }
void stm_peripherals_timer_reserve(TIM_TypeDef *instance) { void stm_peripherals_timer_reserve(TIM_TypeDef *instance) {
size_t tim_idx = stm_peripherals_timer_get_index(instance); size_t tim_idx = stm_peripherals_timer_get_index(instance);
stm_timer_reserved[tim_idx] = true; stm_timer_reserved[tim_idx] = true;
} }
void stm_peripherals_timer_set_callback(void (*callback)(void), TIM_TypeDef *timer) { void stm_peripherals_timer_set_callback(void (*callback)(void), TIM_TypeDef *timer) {
stm_timer_callback[stm_peripherals_timer_get_index(timer)] = callback; stm_timer_callback[stm_peripherals_timer_get_index(timer)] = callback;
} }
void stm_peripherals_timer_free(TIM_TypeDef *instance) { void stm_peripherals_timer_free(TIM_TypeDef *instance) {
size_t tim_idx = stm_peripherals_timer_get_index(instance); size_t tim_idx = stm_peripherals_timer_get_index(instance);
HAL_NVIC_DisableIRQ(irq_map[tim_idx]); HAL_NVIC_DisableIRQ(irq_map[tim_idx]);
stm_timer_callback[tim_idx] = NULL; stm_timer_callback[tim_idx] = NULL;
@ -236,24 +240,27 @@ static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
stm_timer_never_reset[tim_idx] = false; stm_timer_never_reset[tim_idx] = false;
} }
void stm_peripherals_timer_never_reset(TIM_TypeDef *instance) { void stm_peripherals_timer_never_reset(TIM_TypeDef *instance) {
size_t tim_idx = stm_peripherals_timer_get_index(instance); size_t tim_idx = stm_peripherals_timer_get_index(instance);
stm_timer_never_reset[tim_idx] = true; stm_timer_never_reset[tim_idx] = true;
} }
void stm_peripherals_timer_reset_ok(TIM_TypeDef *instance) {
void stm_peripherals_timer_reset_ok(TIM_TypeDef *instance) {
size_t tim_idx = stm_peripherals_timer_get_index(instance); size_t tim_idx = stm_peripherals_timer_get_index(instance);
stm_timer_never_reset[tim_idx] = false; stm_timer_never_reset[tim_idx] = false;
} }
bool stm_peripherals_timer_is_never_reset(TIM_TypeDef *instance) {
bool stm_peripherals_timer_is_never_reset(TIM_TypeDef *instance) {
size_t tim_idx = stm_peripherals_timer_get_index(instance); size_t tim_idx = stm_peripherals_timer_get_index(instance);
return stm_timer_never_reset[tim_idx]; return stm_timer_never_reset[tim_idx];
} }
bool stm_peripherals_timer_is_reserved(TIM_TypeDef *instance) {
bool stm_peripherals_timer_is_reserved(TIM_TypeDef *instance) {
size_t tim_idx = stm_peripherals_timer_get_index(instance); size_t tim_idx = stm_peripherals_timer_get_index(instance);
return stm_timer_reserved[tim_idx]; return stm_timer_reserved[tim_idx];
} }
size_t stm_peripherals_timer_get_index(TIM_TypeDef *instance) { size_t stm_peripherals_timer_get_index(TIM_TypeDef *instance) {
for (size_t i = 0; i < MP_ARRAY_SIZE(mcu_tim_banks); i++) { for (size_t i = 0; i < MP_ARRAY_SIZE(mcu_tim_banks); i++) {
if (instance == mcu_tim_banks[i]) { if (instance == mcu_tim_banks[i]) {
return i; return i;
@ -262,7 +269,7 @@ static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
return ~(size_t)0; return ~(size_t)0;
} }
void tim_clock_enable(uint16_t mask) { void tim_clock_enable(uint16_t mask) {
#ifdef TIM1 #ifdef TIM1
if (mask & (1 << 0)) { if (mask & (1 << 0)) {
__HAL_RCC_TIM1_CLK_ENABLE(); __HAL_RCC_TIM1_CLK_ENABLE();
@ -326,7 +333,7 @@ static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
#endif #endif
} }
void tim_clock_disable(uint16_t mask) { void tim_clock_disable(uint16_t mask) {
#ifdef TIM1 #ifdef TIM1
if (mask & (1 << 0)) { if (mask & (1 << 0)) {
__HAL_RCC_TIM1_CLK_DISABLE(); __HAL_RCC_TIM1_CLK_DISABLE();
@ -390,65 +397,79 @@ static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
#endif #endif
} }
STATIC void callback_router(size_t index) { STATIC void callback_router(size_t index) {
if (stm_timer_callback[index - 1]) { if (stm_timer_callback[index - 1]) {
(*stm_timer_callback[index - 1])(); (*stm_timer_callback[index - 1])();
} }
} }
void TIM1_CC_IRQHandler(void) { // Advanced timer void TIM1_CC_IRQHandler(void) { // Advanced timer
callback_router(1); callback_router(1);
} }
void TIM2_IRQHandler(void) {
void TIM2_IRQHandler(void) {
callback_router(2); callback_router(2);
} }
void TIM3_IRQHandler(void) {
void TIM3_IRQHandler(void) {
callback_router(3); callback_router(3);
} }
void TIM4_IRQHandler(void) {
void TIM4_IRQHandler(void) {
callback_router(4); callback_router(4);
} }
void TIM5_IRQHandler(void) {
void TIM5_IRQHandler(void) {
callback_router(5); callback_router(5);
} }
void TIM6_DAC_IRQHandler(void) { // Basic timer (DAC)
void TIM6_DAC_IRQHandler(void) { // Basic timer (DAC)
callback_router(6); callback_router(6);
} }
void TIM7_IRQHandler(void) { // Basic timer
void TIM7_IRQHandler(void) { // Basic timer
callback_router(7); callback_router(7);
} }
void TIM8_CC_IRQHandler(void) { // Advanced timer
void TIM8_CC_IRQHandler(void) { // Advanced timer
callback_router(8); callback_router(8);
} }
// Advanced timer interrupts are currently unused. // Advanced timer interrupts are currently unused.
void TIM1_BRK_TIM9_IRQHandler(void) { void TIM1_BRK_TIM9_IRQHandler(void) {
callback_router(9); callback_router(9);
} }
void TIM1_UP_TIM10_IRQHandler(void) {
void TIM1_UP_TIM10_IRQHandler(void) {
callback_router(10); callback_router(10);
} }
void TIM1_TRG_COM_TIM11_IRQHandler(void) {
void TIM1_TRG_COM_TIM11_IRQHandler(void) {
callback_router(11); callback_router(11);
} }
void TIM8_BRK_TIM12_IRQHandler(void) {
void TIM8_BRK_TIM12_IRQHandler(void) {
callback_router(12); callback_router(12);
} }
void TIM8_UP_TIM13_IRQHandler(void) {
void TIM8_UP_TIM13_IRQHandler(void) {
callback_router(13); callback_router(13);
} }
void TIM8_TRG_COM_TIM14_IRQHandler(void) {
void TIM8_TRG_COM_TIM14_IRQHandler(void) {
callback_router(14); callback_router(14);
} }
#if (CPY_STM32H7) #if (CPY_STM32H7)
void TIM15_IRQHandler(void) { void TIM15_IRQHandler(void) {
callback_router(15); callback_router(15);
} }
void TIM16_IRQHandler(void) {
void TIM16_IRQHandler(void) {
callback_router(16); callback_router(16);
} }
void TIM17_IRQHandler(void) {
void TIM17_IRQHandler(void) {
callback_router(17); callback_router(17);
} }
#endif #endif

View File

@ -41,10 +41,15 @@
//| pulsed signal consists of timed on and off periods. Unlike PWM, there is no set duration //| pulsed signal consists of timed on and off periods. Unlike PWM, there is no set duration
//| for on and off pairs.""" //| for on and off pairs."""
//| //|
//| def __init__(self, carrier: pwmio.PWMOut) -> None: //| def __init__(self, pin: microcontroller.Pin, *, frequency: int = 38000, duty_cycle: int = 1 << 15) -> None:
//| """Create a PulseOut object associated with the given PWMout object. //| """Create a PulseOut object associated with the given PWMout object.
//| //|
//| :param ~pwmio.PWMOut carrier: PWMOut that is set to output on the desired pin. //| :param ~microcontroller.Pin pin: PWMOut that is set to output on the desired pin.
//| :param int frequency: Carrier signal frequency in Hertz
//| :param int duty_cycle: 16-bit duty cycle of carrier frequency (0 - 65536)
//|
//| For backwards compatibility, ``pin`` may be a PWMOut object used as the carrier. This
//| compatibility will be removed in CircuitPython 8.0.0.
//| //|
//| Send a short series of pulses:: //| Send a short series of pulses::
//| //|
@ -54,8 +59,7 @@
//| import board //| import board
//| //|
//| # 50% duty cycle at 38kHz. //| # 50% duty cycle at 38kHz.
//| pwm = pwmio.PWMOut(board.D13, frequency=38000, duty_cycle=32768) //| pwm = pulseio.PulseOut(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]) //| pulses = array.array('H', [65000, 1000, 65000, 65000, 1000])
//| pulse.send(pulses) //| pulse.send(pulses)
@ -66,17 +70,7 @@
//| ... //| ...
//| //|
STATIC mp_obj_t pulseio_pulseout_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { STATIC mp_obj_t pulseio_pulseout_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
pulseio_pulseout_obj_t *self = m_new_obj(pulseio_pulseout_obj_t); enum { ARG_pin, ARG_frequency, ARG_duty_cycle};
self->base.type = &pulseio_pulseout_type;
mp_obj_t carrier_obj = pos_args[0];
if (mp_obj_is_type(carrier_obj, &pwmio_pwmout_type)) {
// Use a PWMOut Carrier
mp_arg_check_num(n_args, kw_args, 1, 1, false);
common_hal_pulseio_pulseout_construct(self, (pwmio_pwmout_obj_t *)MP_OBJ_TO_PTR(carrier_obj), NULL, 0, 0);
} else {
// Use a Pin, frequency, and duty cycle
enum { ARG_pin, ARG_frequency};
static const mp_arg_t allowed_args[] = { static const mp_arg_t allowed_args[] = {
{ MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 38000} }, { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 38000} },
@ -84,9 +78,22 @@ STATIC mp_obj_t pulseio_pulseout_make_new(const mp_obj_type_t *type, size_t n_ar
}; };
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj);
common_hal_pulseio_pulseout_construct(self, NULL, pin, args[ARG_frequency].u_int, args[ARG_frequency].u_int); const mcu_pin_obj_t *pin = args[ARG_pin].u_obj;
mp_int_t frequency = args[ARG_frequency].u_int;
mp_int_t duty_cycle = args[ARG_duty_cycle].u_int;
if (mp_obj_is_type(args[ARG_pin].u_obj, &pwmio_pwmout_type)) {
pwmio_pwmout_obj_t *pwmout = args[ARG_pin].u_obj;
duty_cycle = common_hal_pwmio_pwmout_get_duty_cycle(pwmout);
frequency = common_hal_pwmio_pwmout_get_frequency(pwmout);
pin = common_hal_pwmio_pwmout_get_pin(pwmout);
// Deinit the pin so we can use it.
common_hal_pwmio_pwmout_deinit(pwmout);
} }
validate_obj_is_free_pin(MP_OBJ_FROM_PTR(pin));
pulseio_pulseout_obj_t *self = m_new_obj(pulseio_pulseout_obj_t);
self->base.type = &pulseio_pulseout_type;
common_hal_pulseio_pulseout_construct(self, pin, frequency, duty_cycle);
return MP_OBJ_FROM_PTR(self); return MP_OBJ_FROM_PTR(self);
} }

View File

@ -34,7 +34,6 @@
extern const mp_obj_type_t pulseio_pulseout_type; extern const mp_obj_type_t pulseio_pulseout_type;
extern void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self, extern void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self,
const pwmio_pwmout_obj_t *carrier,
const mcu_pin_obj_t *pin, const mcu_pin_obj_t *pin,
uint32_t frequency, uint32_t frequency,
uint16_t duty_cycle); uint16_t duty_cycle);

View File

@ -35,6 +35,39 @@
#include "shared-bindings/util.h" #include "shared-bindings/util.h"
#include "supervisor/shared/translate.h" #include "supervisor/shared/translate.h"
void common_hal_pwmio_pwmout_raise_error(pwmout_result_t result) {
switch (result) {
case PWMOUT_OK:
break;
case PWMOUT_INVALID_PIN:
mp_raise_ValueError(translate("Invalid pin"));
break;
case PWMOUT_INVALID_FREQUENCY:
mp_raise_ValueError(translate("Invalid PWM frequency"));
break;
case PWMOUT_INVALID_FREQUENCY_ON_PIN:
mp_raise_ValueError(translate("Frequency must match existing PWMOut using this timer"));
break;
case PWMOUT_VARIABLE_FREQUENCY_NOT_AVAILABLE:
mp_raise_ValueError(translate("Cannot vary frequency on a timer that is already in use"));
break;
case PWMOUT_ALL_TIMERS_ON_PIN_IN_USE:
mp_raise_ValueError(translate("All timers for this pin are in use"));
break;
case PWMOUT_ALL_TIMERS_IN_USE:
mp_raise_RuntimeError(translate("All timers in use"));
break;
case PWMOUT_ALL_CHANNELS_IN_USE:
mp_raise_RuntimeError(translate("All channels in use"));
break;
default:
case PWMOUT_INITIALIZATION_ERROR:
mp_raise_RuntimeError(translate("Could not start PWM"));
break;
}
}
//| class PWMOut: //| class PWMOut:
//| """Output a Pulse Width Modulated signal on a given pin.""" //| """Output a Pulse Width Modulated signal on a given pin."""
//| //|
@ -102,35 +135,7 @@ STATIC mp_obj_t pwmio_pwmout_make_new(const mp_obj_type_t *type, size_t n_args,
pwmio_pwmout_obj_t *self = m_new_obj(pwmio_pwmout_obj_t); pwmio_pwmout_obj_t *self = m_new_obj(pwmio_pwmout_obj_t);
self->base.type = &pwmio_pwmout_type; self->base.type = &pwmio_pwmout_type;
pwmout_result_t result = common_hal_pwmio_pwmout_construct(self, pin, duty_cycle, frequency, variable_frequency); pwmout_result_t result = common_hal_pwmio_pwmout_construct(self, pin, duty_cycle, frequency, variable_frequency);
switch (result) { common_hal_pwmio_pwmout_raise_error(result);
case PWMOUT_OK:
break;
case PWMOUT_INVALID_PIN:
mp_raise_ValueError(translate("Invalid pin"));
break;
case PWMOUT_INVALID_FREQUENCY:
mp_raise_ValueError(translate("Invalid PWM frequency"));
break;
case PWMOUT_INVALID_FREQUENCY_ON_PIN:
mp_raise_ValueError(translate("Frequency must match existing PWMOut using this timer"));
break;
case PWMOUT_VARIABLE_FREQUENCY_NOT_AVAILABLE:
mp_raise_ValueError(translate("Cannot vary frequency on a timer that is already in use"));
break;
case PWMOUT_ALL_TIMERS_ON_PIN_IN_USE:
mp_raise_ValueError(translate("All timers for this pin are in use"));
break;
case PWMOUT_ALL_TIMERS_IN_USE:
mp_raise_RuntimeError(translate("All timers in use"));
break;
case PWMOUT_ALL_CHANNELS_IN_USE:
mp_raise_RuntimeError(translate("All channels in use"));
break;
default:
case PWMOUT_INITIALIZATION_ERROR:
mp_raise_RuntimeError(translate("Could not start PWM"));
break;
}
return MP_OBJ_FROM_PTR(self); return MP_OBJ_FROM_PTR(self);
} }

View File

@ -55,8 +55,13 @@ extern void common_hal_pwmio_pwmout_set_frequency(pwmio_pwmout_obj_t *self, uint
extern uint32_t common_hal_pwmio_pwmout_get_frequency(pwmio_pwmout_obj_t *self); extern uint32_t common_hal_pwmio_pwmout_get_frequency(pwmio_pwmout_obj_t *self);
extern bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t *self); extern bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t *self);
// Don't use this! It is only used internally for backwards compatibility.
extern const mcu_pin_obj_t *common_hal_pwmio_pwmout_get_pin(pwmio_pwmout_obj_t *self);
// This is used by the supervisor to claim PWMOut devices indefinitely. // This is used by the supervisor to claim PWMOut devices indefinitely.
extern void common_hal_pwmio_pwmout_never_reset(pwmio_pwmout_obj_t *self); extern void common_hal_pwmio_pwmout_never_reset(pwmio_pwmout_obj_t *self);
extern void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self); extern void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self);
extern void common_hal_pwmio_pwmout_raise_error(pwmout_result_t result);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_PWMIO_PWMOUT_H #endif // MICROPY_INCLUDED_SHARED_BINDINGS_PWMIO_PWMOUT_H