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:
parent
5fbe6d4805
commit
412eb87080
|
@ -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 ""
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(¤t_ms, ¤t_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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
// No pulseio module functions.
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,8 +122,8 @@ 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);
|
||||
pwm_set_enabled(self->slice,true);
|
||||
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) {
|
||||
delay = self->min_pulse;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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, \
|
||||
}
|
||||
|
||||
|
|
|
@ -41,8 +41,12 @@
|
|||
|
||||
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);
|
||||
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
|
||||
TIM1_CC_IRQn,
|
||||
#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
|
||||
// APB clock. Otherwise (APB prescaler > 1) the timer clock is twice its
|
||||
// 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);
|
||||
uint32_t source, clk_div;
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
return irq_map[tim_id];
|
||||
}
|
||||
|
||||
void timers_reset(void) {
|
||||
void timers_reset(void) {
|
||||
uint16_t never_reset_mask = 0x00;
|
||||
for (size_t i = 0; i < MP_ARRAY_SIZE(mcu_tim_banks); 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_TypeDef *stm_peripherals_find_timer(void) {
|
||||
TIM_TypeDef *stm_peripherals_find_timer(void) {
|
||||
// Check for timers on pins outside the package size
|
||||
for (size_t i = 0; i < MP_ARRAY_SIZE(mcu_tim_banks); i++) {
|
||||
bool timer_in_package = false;
|
||||
// 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++) {
|
||||
|
@ -210,7 +214,7 @@ static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
|
|||
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);
|
||||
stm_timer_callback[tim_idx] = callback;
|
||||
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]);
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
HAL_NVIC_DisableIRQ(irq_map[tim_idx]);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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++) {
|
||||
if (instance == mcu_tim_banks[i]) {
|
||||
return i;
|
||||
|
@ -262,7 +269,7 @@ static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
|
|||
return ~(size_t)0;
|
||||
}
|
||||
|
||||
void tim_clock_enable(uint16_t mask) {
|
||||
void tim_clock_enable(uint16_t mask) {
|
||||
#ifdef TIM1
|
||||
if (mask & (1 << 0)) {
|
||||
__HAL_RCC_TIM1_CLK_ENABLE();
|
||||
|
@ -326,7 +333,7 @@ static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
|
|||
#endif
|
||||
}
|
||||
|
||||
void tim_clock_disable(uint16_t mask) {
|
||||
void tim_clock_disable(uint16_t mask) {
|
||||
#ifdef TIM1
|
||||
if (mask & (1 << 0)) {
|
||||
__HAL_RCC_TIM1_CLK_DISABLE();
|
||||
|
@ -390,65 +397,79 @@ static void (*stm_timer_callback[MP_ARRAY_SIZE (mcu_tim_banks)])(void);
|
|||
#endif
|
||||
}
|
||||
|
||||
STATIC void callback_router(size_t index) {
|
||||
STATIC void callback_router(size_t index) {
|
||||
if (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);
|
||||
}
|
||||
void TIM2_IRQHandler(void) {
|
||||
|
||||
void TIM2_IRQHandler(void) {
|
||||
callback_router(2);
|
||||
}
|
||||
void TIM3_IRQHandler(void) {
|
||||
|
||||
void TIM3_IRQHandler(void) {
|
||||
callback_router(3);
|
||||
}
|
||||
void TIM4_IRQHandler(void) {
|
||||
|
||||
void TIM4_IRQHandler(void) {
|
||||
callback_router(4);
|
||||
}
|
||||
void TIM5_IRQHandler(void) {
|
||||
|
||||
void TIM5_IRQHandler(void) {
|
||||
callback_router(5);
|
||||
}
|
||||
void TIM6_DAC_IRQHandler(void) { // Basic timer (DAC)
|
||||
|
||||
void TIM6_DAC_IRQHandler(void) { // Basic timer (DAC)
|
||||
callback_router(6);
|
||||
}
|
||||
void TIM7_IRQHandler(void) { // Basic timer
|
||||
|
||||
void TIM7_IRQHandler(void) { // Basic timer
|
||||
callback_router(7);
|
||||
}
|
||||
void TIM8_CC_IRQHandler(void) { // Advanced timer
|
||||
|
||||
void TIM8_CC_IRQHandler(void) { // Advanced timer
|
||||
callback_router(8);
|
||||
}
|
||||
|
||||
// Advanced timer interrupts are currently unused.
|
||||
void TIM1_BRK_TIM9_IRQHandler(void) {
|
||||
void TIM1_BRK_TIM9_IRQHandler(void) {
|
||||
callback_router(9);
|
||||
}
|
||||
void TIM1_UP_TIM10_IRQHandler(void) {
|
||||
|
||||
void TIM1_UP_TIM10_IRQHandler(void) {
|
||||
callback_router(10);
|
||||
}
|
||||
void TIM1_TRG_COM_TIM11_IRQHandler(void) {
|
||||
|
||||
void TIM1_TRG_COM_TIM11_IRQHandler(void) {
|
||||
callback_router(11);
|
||||
}
|
||||
void TIM8_BRK_TIM12_IRQHandler(void) {
|
||||
|
||||
void TIM8_BRK_TIM12_IRQHandler(void) {
|
||||
callback_router(12);
|
||||
}
|
||||
void TIM8_UP_TIM13_IRQHandler(void) {
|
||||
|
||||
void TIM8_UP_TIM13_IRQHandler(void) {
|
||||
callback_router(13);
|
||||
}
|
||||
void TIM8_TRG_COM_TIM14_IRQHandler(void) {
|
||||
|
||||
void TIM8_TRG_COM_TIM14_IRQHandler(void) {
|
||||
callback_router(14);
|
||||
}
|
||||
|
||||
#if (CPY_STM32H7)
|
||||
void TIM15_IRQHandler(void) {
|
||||
void TIM15_IRQHandler(void) {
|
||||
callback_router(15);
|
||||
}
|
||||
void TIM16_IRQHandler(void) {
|
||||
|
||||
void TIM16_IRQHandler(void) {
|
||||
callback_router(16);
|
||||
}
|
||||
void TIM17_IRQHandler(void) {
|
||||
|
||||
void TIM17_IRQHandler(void) {
|
||||
callback_router(17);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue