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"
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
msgid "Prefix buffer must be on the heap"
msgstr ""

View File

@ -103,13 +103,15 @@ void pulseout_reset() {
}
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 (!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) {
// Find a spare timer.
@ -155,7 +157,7 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self,
}
refcount++;
self->pin = carrier->pin->number;
self->pin = pin->number;
PortGroup *const port_base = &PORT->Group[GPIO_PORT(self->pin)];
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) {
return self->pin == NO_PIN;
return common_hal_pwmio_pwmout_deinited(&self->pwmout);
}
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;
}
self->pin = NO_PIN;
common_hal_pwmio_pwmout_deinit(&self->pwmout);
#ifdef SAMD21
rtc_end_pulse();
#endif

View File

@ -30,10 +30,12 @@
#include "common-hal/microcontroller/Pin.h"
#include "py/obj.h"
#include "shared-bindings/pwmio/PWMOut.h"
typedef struct {
mp_obj_base_t base;
__IO PORT_PINCFG_Type *pincfg;
pwmio_pwmout_obj_t pwmout;
uint8_t pin;
} 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) {
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,
const pwmio_pwmout_obj_t *carrier,
const mcu_pin_obj_t *pin,
uint32_t frequency,
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) {
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"));
}
self->pwm_num = carrier->number;
self->pwm_num = self->pwmout.number;
}
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);
pulse_fd = -1;
common_hal_pwmio_pwmout_deinit(&self->pwmout);
pulse_buffer = NULL;
}

View File

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

View File

@ -157,3 +157,7 @@ void pwmout_start(uint8_t pwm_num) {
void pwmout_stop(uint8_t pwm_num) {
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
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 (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();
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;
}
self->variable_frequency = variable_frequency;
self->pin_number = pin->number;
self->pin = pin;
self->deinited = false;
self->duty_resolution = duty_bits;
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_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) {
@ -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
varfreq_timers[self->tim_handle.timer_num] = false;
}
reset_pin_number(self->pin_number);
common_hal_reset_pin(self->pin);
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) {
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;
ledc_timer_config_t tim_handle;
ledc_channel_config_t chan_handle;
uint16_t pin_number;
const mcu_pin_obj_t *pin;
uint8_t duty_resolution;
bool variable_frequency : 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_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) {
// 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) {
// 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) {
// // 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)
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) {
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_AUDIOBUSIO = 0
CIRCUITPY_BUSDEVICE = 1
CIRCUITPY_COUNTIO = 0
CIRCUITPY_FREQUENCYIO = 0
CIRCUITPY_I2CPERIPHERAL = 0
CIRCUITPY_NVM = 0
CIRCUITPY_PULSEIO = 0
CIRCUITPY_ROTARYIO = 0
CIRCUITPY_COUNTIO = 0
CIRCUITPY_USB_MIDI = 1
LONGINT_IMPL = MPZ

View File

@ -37,8 +37,6 @@
#include "fsl_device_registers.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/rtc/RTC.h"
#include "common-hal/busio/SPI.h"
@ -289,9 +287,6 @@ void reset_port(void) {
// eic_reset();
#if CIRCUITPY_PULSEIO
pulseout_reset();
#endif
#if CIRCUITPY_PWMIO
pwmout_reset();
#endif

View File

@ -48,14 +48,14 @@ 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;
pulseout->pwmout.pwm->PSEL.OUT[0] = pulseout->pwmout.pin->number;
}
static void turn_off(pulseio_pulseout_obj_t *pulseout) {
// Disconnect pin from PWM.
pulseout->pwmout->pwm->PSEL.OUT[0] = 0xffffffff;
pulseout->pwmout.pwm->PSEL.OUT[0] = 0xffffffff;
// 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) {
@ -100,13 +100,15 @@ void pulseout_reset() {
}
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 (!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) {
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,
};
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 self->pwmout == NULL;
return common_hal_pwmio_pwmout_deinited(&self->pwmout);
}
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;
}
turn_on(self);
self->pwmout = NULL;
common_hal_pwmio_pwmout_deinit(&self->pwmout);
refcount--;
if (refcount == 0) {

View File

@ -34,7 +34,7 @@
typedef struct {
mp_obj_base_t base;
const pwmio_pwmout_obj_t *pwmout;
pwmio_pwmout_obj_t pwmout;
} pulseio_pulseout_obj_t;
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) {
@ -232,14 +232,14 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
}
self->channel = channel;
self->pin_number = pin->number;
self->pin = pin;
claim_pin(pin);
self->frequency = 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
nrf_pwm_disable(self->pwm);
@ -267,15 +267,15 @@ void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t *self) {
return;
}
nrf_gpio_cfg_default(self->pin_number);
nrf_gpio_cfg_default(self->pin->number);
NRF_PWM_Type *pwm = self->pwm;
self->pwm = NULL;
pwmout_free_channel(pwm, self->channel);
reset_pin_number(self->pin_number);
self->pin_number = NO_PIN;
common_hal_reset_pin(self->pin);
self->pin = NULL;
}
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) {
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 "py/obj.h"
#include "shared-bindings/microcontroller/Pin.h"
typedef struct {
mp_obj_base_t base;
NRF_PWM_Type *pwm;
uint8_t pin_number;
uint8_t channel : 7;
bool variable_frequency : 1;
const mcu_pin_obj_t *pin;
uint16_t duty_cycle;
uint32_t frequency;
} pwmio_pwmout_obj_t;

View File

@ -42,23 +42,28 @@ static uint8_t refcount = 0;
volatile alarm_id_t cur_alarm = 0;
void turn_off(uint8_t slice) {
pwm_hw->slice[slice].ctr = 0;
pwm_hw->slice[slice].cc = 0;
pwm_hw->slice[slice].top = 0;
pwm_hw->slice[slice].div = 1u << PWM_CH0_DIV_INT_LSB;
// Set the current counter value near the top so that the output is low. The
// - 2 gives us a little wiggle room for enabling and disabling the slice.
// The top + 1 ensure we don't end up lower than the cc (and therefore high.)
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 = 0;
common_hal_mcu_enable_interrupts();
}
void pulse_finish(pulseio_pulseout_obj_t *self) {
self->pulse_index++;
// 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) {
return;
}
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];
if (delay < self->min_pulse) {
@ -78,24 +83,26 @@ int64_t pulseout_interrupt_handler(alarm_id_t id, void *user_data) {
}
void pulseout_reset() {
refcount = 0;
}
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) {
refcount++;
self->carrier = (pwmio_pwmout_obj_t *)carrier;
self->current_duty_cycle = common_hal_pwmio_pwmout_get_duty_cycle(self->carrier);
pwm_set_enabled(self->carrier->slice,false);
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);
pwmout_result_t result = common_hal_pwmio_pwmout_construct(
&self->carrier, pin, duty_cycle, frequency, false);
// This will raise an exception and not return if needed.
common_hal_pwmio_pwmout_raise_error(result);
self->current_duty_cycle = duty_cycle;
pwm_set_enabled(self->carrier.slice, false);
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) {
@ -106,7 +113,7 @@ void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t *self) {
if (common_hal_pulseio_pulseout_deinited(self)) {
return;
}
refcount--;
common_hal_pwmio_pwmout_deinit(&self->carrier);
self->pin = NO_PIN;
}
@ -115,7 +122,7 @@ void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t *self, uint16_t *pu
self->pulse_index = 0;
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);
uint64_t delay = self->pulse_buffer[0];
if (delay < self->min_pulse) {

View File

@ -39,7 +39,7 @@ typedef struct {
mp_obj_base_t base;
uint8_t pin;
uint8_t slice;
pwmio_pwmout_obj_t *carrier;
pwmio_pwmout_obj_t carrier;
uint16_t *pulse_buffer;
uint16_t pulse_length;
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) {
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) {
// 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) {
// 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.
HAL_GPIO_WritePin(pin_port(pulseout->pwmout->tim->pin->port),
pin_mask(pulseout->pwmout->tim->pin->number), 0);
HAL_GPIO_WritePin(pin_port(pulseout->pwmout.tim->pin->port),
pin_mask(pulseout->pwmout.tim->pin->number), 0);
}
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_IT_SOURCE(&tim_handle, TIM_IT_UPDATE) != RESET) {
__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
}
@ -111,13 +111,12 @@ void pulseout_reset() {
}
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 (!carrier || pin || frequency) {
mp_raise_NotImplementedError(translate("Port does not accept pins or frequency. Construct and pass a PWMOut Carrier instead"));
}
const mcu_pin_obj_t *pin, uint32_t frequency, uint16_t duty_cycle) {
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);
// Add to active PulseOuts
refcount++;
@ -139,13 +138,12 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self,
HAL_TIM_Base_Init(&tim_handle);
tim_handle.Instance->SR = 0;
// The HAL can't work with const, recast required.
self->pwmout = (pwmio_pwmout_obj_t *)carrier;
turn_off(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) {
@ -153,7 +151,7 @@ void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t *self) {
return;
}
turn_on(self);
self->pwmout = NULL;
common_hal_pwmio_pwmout_deinit(&self->pwmout);
refcount--;
if (refcount == 0) {

View File

@ -34,7 +34,7 @@
typedef struct {
mp_obj_base_t base;
pwmio_pwmout_obj_t *pwmout;
pwmio_pwmout_obj_t pwmout;
} pulseio_pulseout_obj_t;
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++) {
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_channel = l_tim->channel_index - 1;
uint8_t l_tim_index = l_tim->tim_index;
uint8_t l_tim_channel = l_tim->channel_index;
// if pin is same
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
if (self->tim != NULL) {
// create instance
TIMx = mcu_tim_banks[self->tim->tim_index - 1];
TIMx = mcu_tim_banks[self->tim->tim_index];
// reserve timer/channel
if (variable_frequency) {
reserved_tim[self->tim->tim_index - 1] = 0x0F;
reserved_tim[self->tim->tim_index] = 0x0F;
} 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);
} else { // no match found
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_InitStruct.Pin = pin_mask(pin->number);
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.Alternate = self->tim->altfn_index;
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
self->channel = 4 * (self->tim->channel_index - 1);
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;
}
self->channel = 4 * self->tim->channel_index;
// Timer init
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++) {
if (mcu_tim_banks[i] == self->handle.Instance) {
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;
}
}
@ -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
if (self->variable_frequency) {
reserved_tim[self->tim->tim_index - 1] = 0x00;
reserved_tim[self->tim->tim_index] = 0x00;
} 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);
}
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_tim[self->tim->tim_index - 1]) {
tim_frequencies[self->tim->tim_index - 1] = 0x00;
if (reserved_tim[self->tim->tim_index] == 0) {
tim_frequencies[self->tim->tim_index] = 0x00;
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"));
}
tim_frequencies[self->tim->tim_index - 1] = frequency;
tim_frequencies[self->tim->tim_index] = frequency;
self->frequency = frequency;
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) {
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;
uint32_t frequency;
uint32_t period;
const mcu_pin_obj_t *pin;
} pwmio_pwmout_obj_t;
void pwmout_reset(void);

View File

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

View File

@ -41,7 +41,11 @@
static bool stm_timer_reserved[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);
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
TIM1_CC_IRQn,
@ -182,7 +186,7 @@ static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
// Find each timer instance on the given bank
for (size_t j = 0; j < MP_ARRAY_SIZE(mcu_tim_pin_list); j++) {
// 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)) {
// Search whether any pins in the package array match it
for (size_t k = 0; k < mcu_pin_globals.map.alloc; k++) {
@ -240,14 +244,17 @@ static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
size_t tim_idx = stm_peripherals_timer_get_index(instance);
stm_timer_never_reset[tim_idx] = true;
}
void stm_peripherals_timer_reset_ok(TIM_TypeDef *instance) {
size_t tim_idx = stm_peripherals_timer_get_index(instance);
stm_timer_never_reset[tim_idx] = false;
}
bool stm_peripherals_timer_is_never_reset(TIM_TypeDef *instance) {
size_t tim_idx = stm_peripherals_timer_get_index(instance);
return stm_timer_never_reset[tim_idx];
}
bool stm_peripherals_timer_is_reserved(TIM_TypeDef *instance) {
size_t tim_idx = stm_peripherals_timer_get_index(instance);
return stm_timer_reserved[tim_idx];
@ -399,24 +406,31 @@ static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
void TIM1_CC_IRQHandler(void) { // Advanced timer
callback_router(1);
}
void TIM2_IRQHandler(void) {
callback_router(2);
}
void TIM3_IRQHandler(void) {
callback_router(3);
}
void TIM4_IRQHandler(void) {
callback_router(4);
}
void TIM5_IRQHandler(void) {
callback_router(5);
}
void TIM6_DAC_IRQHandler(void) { // Basic timer (DAC)
callback_router(6);
}
void TIM7_IRQHandler(void) { // Basic timer
callback_router(7);
}
void TIM8_CC_IRQHandler(void) { // Advanced timer
callback_router(8);
}
@ -425,18 +439,23 @@ static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
void TIM1_BRK_TIM9_IRQHandler(void) {
callback_router(9);
}
void TIM1_UP_TIM10_IRQHandler(void) {
callback_router(10);
}
void TIM1_TRG_COM_TIM11_IRQHandler(void) {
callback_router(11);
}
void TIM8_BRK_TIM12_IRQHandler(void) {
callback_router(12);
}
void TIM8_UP_TIM13_IRQHandler(void) {
callback_router(13);
}
void TIM8_TRG_COM_TIM14_IRQHandler(void) {
callback_router(14);
}
@ -445,9 +464,11 @@ static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
void TIM15_IRQHandler(void) {
callback_router(15);
}
void TIM16_IRQHandler(void) {
callback_router(16);
}
void TIM17_IRQHandler(void) {
callback_router(17);
}

View File

@ -41,10 +41,15 @@
//| pulsed signal consists of timed on and off periods. Unlike PWM, there is no set duration
//| 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.
//|
//| :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::
//|
@ -54,8 +59,7 @@
//| import board
//|
//| # 50% duty cycle at 38kHz.
//| pwm = pwmio.PWMOut(board.D13, frequency=38000, duty_cycle=32768)
//| pulse = pulseio.PulseOut(pwm)
//| pwm = pulseio.PulseOut(board.D13, frequency=38000, duty_cycle=32768)
//| # on off on off on
//| pulses = array.array('H', [65000, 1000, 65000, 65000, 1000])
//| 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) {
pulseio_pulseout_obj_t *self = m_new_obj(pulseio_pulseout_obj_t);
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};
enum { ARG_pin, ARG_frequency, ARG_duty_cycle};
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ 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_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);
}

View File

@ -34,7 +34,6 @@
extern const mp_obj_type_t pulseio_pulseout_type;
extern 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);

View File

@ -35,6 +35,39 @@
#include "shared-bindings/util.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:
//| """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);
self->base.type = &pwmio_pwmout_type;
pwmout_result_t result = common_hal_pwmio_pwmout_construct(self, pin, duty_cycle, frequency, variable_frequency);
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;
}
common_hal_pwmio_pwmout_raise_error(result);
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 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.
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_raise_error(pwmout_result_t result);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_PWMIO_PWMOUT_H