Add timer allocator, adjust pulsio to use general purpose timers

This commit is contained in:
Lucian Copeland 2020-07-01 10:07:45 -04:00
parent 6c91af7d56
commit ab9a64eafa
8 changed files with 253 additions and 304 deletions

View File

@ -207,6 +207,7 @@ SRC_C += \
mphalport.c \
boards/$(BOARD)/board.c \
boards/$(BOARD)/pins.c \
peripherals/timers.c \
peripherals/stm32$(MCU_SERIES_LOWER)/clocks.c \
peripherals/stm32$(MCU_SERIES_LOWER)/$(MCU_VARIANT_LOWER)/pins.c \
peripherals/stm32$(MCU_SERIES_LOWER)/$(MCU_VARIANT_LOWER)/gpio.c \

View File

@ -35,38 +35,14 @@
#include STM32_HAL_H
#include "common-hal/microcontroller/Pin.h"
#include "timers.h"
#define ALL_CLOCKS 0xFFFF
STATIC uint8_t reserved_tim[TIM_BANK_ARRAY_LEN];
STATIC uint32_t tim_frequencies[TIM_BANK_ARRAY_LEN];
STATIC bool never_reset_tim[TIM_BANK_ARRAY_LEN];
STATIC void tim_clock_enable(uint16_t mask);
STATIC void tim_clock_disable(uint16_t mask);
// Get the frequency (in Hz) of the source clock for the given timer.
// On STM32F405/407/415/417 there are 2 cases for how the clock freq is set.
// 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.
STATIC uint32_t timer_get_source_freq(uint32_t tim_id) {
uint32_t source, clk_div;
if (tim_id == 1 || (8 <= tim_id && tim_id <= 11)) {
// TIM{1,8,9,10,11} are on APB2
source = HAL_RCC_GetPCLK2Freq();
clk_div = RCC->CFGR & RCC_CFGR_PPRE2;
} else {
// TIM{2,3,4,5,6,7,12,13,14} are on APB1
source = HAL_RCC_GetPCLK1Freq();
clk_div = RCC->CFGR & RCC_CFGR_PPRE1;
}
if (clk_div != 0) {
// APB prescaler for this timer is > 1
source *= 2;
}
return source;
}
STATIC uint32_t timer_get_internal_duty(uint16_t duty, uint32_t period) {
//duty cycle is duty/0xFFFF fraction x (number of pulses per period)
return (duty*period) / ((1 << 16) - 1);
@ -97,7 +73,6 @@ void pwmout_reset(void) {
never_reset_mask |= 1 << i;
}
}
tim_clock_disable(ALL_CLOCKS & ~(never_reset_mask));
}
pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
@ -107,6 +82,7 @@ pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
bool variable_frequency) {
TIM_TypeDef * TIMx;
uint8_t tim_num = MP_ARRAY_SIZE(mcu_tim_pin_list);
bool tim_taken_internal = false;
bool tim_chan_taken = false;
bool tim_taken_f_mismatch = false;
bool var_freq_mismatch = false;
@ -119,8 +95,13 @@ pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
//if pin is same
if (l_tim->pin == pin) {
//check if the timer has a channel active
//check if the timer has a channel active, or is reserved by main timer system
if (reserved_tim[l_tim_index] != 0) {
// Timer has already been reserved by an internal module
if (stm_peripherals_timer_is_reserved(mcu_tim_banks[l_tim_index])) {
tim_taken_internal = true;
continue; //keep looking
}
//is it the same channel? (or all channels reserved by a var-freq)
if (reserved_tim[l_tim_index] & 1 << (l_tim_channel)) {
tim_chan_taken = true;
@ -155,9 +136,12 @@ pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
reserved_tim[self->tim->tim_index - 1] |= 1 << (self->tim->channel_index - 1);
}
tim_frequencies[self->tim->tim_index - 1] = frequency;
stm_peripherals_timer_reserve(TIMx);
} else { //no match found
if (tim_chan_taken) {
mp_raise_ValueError(translate("No more timers available on this pin."));
} else if (tim_taken_internal) {
mp_raise_ValueError(translate("Timer was reserved for internal use - declare PWM pins earlier in the program"));
} else if (tim_taken_f_mismatch) {
mp_raise_ValueError(translate("Frequency must match existing PWMOut using this timer"));
} else if (var_freq_mismatch) {
@ -182,8 +166,8 @@ pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
uint32_t prescaler = 0; //prescaler is 15 bit
uint32_t period = 0; //period is 16 bit
timer_get_optimal_divisors(&period, &prescaler, frequency,
timer_get_source_freq(self->tim->tim_index));
uint32_t source_freq = stm_peripherals_timer_get_source_freq(TIMx);
timer_get_optimal_divisors(&period, &prescaler, frequency, source_freq);
//Timer init
self->handle.Instance = TIMx;
@ -282,8 +266,8 @@ void common_hal_pulseio_pwmout_set_frequency(pulseio_pwmout_obj_t* self, uint32_
uint32_t prescaler = 0;
uint32_t period = 0;
timer_get_optimal_divisors(&period, &prescaler, frequency,
timer_get_source_freq(self->tim->tim_index));
uint32_t source_freq = stm_peripherals_timer_get_source_freq(self->handle.Instance);
timer_get_optimal_divisors(&period, &prescaler, frequency, source_freq);
//shut down
HAL_TIM_PWM_Stop(&self->handle, self->channel);
@ -318,131 +302,3 @@ uint32_t common_hal_pulseio_pwmout_get_frequency(pulseio_pwmout_obj_t* self) {
bool common_hal_pulseio_pwmout_get_variable_frequency(pulseio_pwmout_obj_t* self) {
return self->variable_frequency;
}
STATIC void tim_clock_enable(uint16_t mask) {
#ifdef TIM1
if (mask & (1 << 0)) {
__HAL_RCC_TIM1_CLK_ENABLE();
}
#endif
#ifdef TIM2
if (mask & (1 << 1)) {
__HAL_RCC_TIM2_CLK_ENABLE();
}
#endif
#ifdef TIM3
if (mask & (1 << 2)) {
__HAL_RCC_TIM3_CLK_ENABLE();
}
#endif
#ifdef TIM4
if (mask & (1 << 3)) {
__HAL_RCC_TIM4_CLK_ENABLE();
}
#endif
#ifdef TIM5
if (mask & (1 << 4)) {
__HAL_RCC_TIM5_CLK_ENABLE();
}
#endif
//6 and 7 are reserved ADC timers
#ifdef TIM8
if (mask & (1 << 7)) {
__HAL_RCC_TIM8_CLK_ENABLE();
}
#endif
#ifdef TIM9
if (mask & (1 << 8)) {
__HAL_RCC_TIM9_CLK_ENABLE();
}
#endif
#ifdef TIM10
if (mask & (1 << 9)) {
__HAL_RCC_TIM10_CLK_ENABLE();
}
#endif
#ifdef TIM11
if (mask & (1 << 10)) {
__HAL_RCC_TIM11_CLK_ENABLE();
}
#endif
#ifdef TIM12
if (mask & (1 << 11)) {
__HAL_RCC_TIM12_CLK_ENABLE();
}
#endif
#ifdef TIM13
if (mask & (1 << 12)) {
__HAL_RCC_TIM13_CLK_ENABLE();
}
#endif
#ifdef TIM14
if (mask & (1 << 13)) {
__HAL_RCC_TIM14_CLK_ENABLE();
}
#endif
}
STATIC void tim_clock_disable(uint16_t mask) {
#ifdef TIM1
if (mask & (1 << 0)) {
__HAL_RCC_TIM1_CLK_DISABLE();
}
#endif
#ifdef TIM2
if (mask & (1 << 1)) {
__HAL_RCC_TIM2_CLK_DISABLE();
}
#endif
#ifdef TIM3
if (mask & (1 << 2)) {
__HAL_RCC_TIM3_CLK_DISABLE();
}
#endif
#ifdef TIM4
if (mask & (1 << 3)) {
__HAL_RCC_TIM4_CLK_DISABLE();
}
#endif
#ifdef TIM5
if (mask & (1 << 4)) {
__HAL_RCC_TIM5_CLK_DISABLE();
}
#endif
//6 and 7 are reserved ADC timers
#ifdef TIM8
if (mask & (1 << 7)) {
__HAL_RCC_TIM8_CLK_DISABLE();
}
#endif
#ifdef TIM9
if (mask & (1 << 8)) {
__HAL_RCC_TIM9_CLK_DISABLE();
}
#endif
#ifdef TIM10
if (mask & (1 << 9)) {
__HAL_RCC_TIM10_CLK_DISABLE();
}
#endif
#ifdef TIM11
if (mask & (1 << 10)) {
__HAL_RCC_TIM11_CLK_DISABLE();
}
#endif
#ifdef TIM12
if (mask & (1 << 11)) {
__HAL_RCC_TIM12_CLK_DISABLE();
}
#endif
#ifdef TIM13
if (mask & (1 << 12)) {
__HAL_RCC_TIM13_CLK_DISABLE();
}
#endif
#ifdef TIM14
if (mask & (1 << 13)) {
__HAL_RCC_TIM14_CLK_DISABLE();
}
#endif
}

View File

@ -32,39 +32,36 @@
#include "py/runtime.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/pulseio/PulseIn.h"
#include "timers.h"
#include STM32_HAL_H
#define STM32_GPIO_PORT_SIZE 16
static pulseio_pulsein_obj_t* _objs[STM32_GPIO_PORT_SIZE];
STATIC TIM_HandleTypeDef t6_handle;
STATIC TIM_HandleTypeDef tim_handle;
static uint32_t overflow_count = 0;
STATIC uint8_t refcount = 0;
static void assign_EXTI_Interrupt(pulseio_pulsein_obj_t* self, uint8_t num);
void TIM6_IRQHandler(void)
void pulsein_timer_event_handler(void)
{
// Detect TIM Update event
if (__HAL_TIM_GET_FLAG(&t6_handle, TIM_FLAG_UPDATE) != RESET)
if (__HAL_TIM_GET_FLAG(&tim_handle, TIM_FLAG_UPDATE) != RESET)
{
if (__HAL_TIM_GET_IT_SOURCE(&t6_handle, TIM_IT_UPDATE) != RESET)
if (__HAL_TIM_GET_IT_SOURCE(&tim_handle, TIM_IT_UPDATE) != RESET)
{
__HAL_TIM_CLEAR_IT(&t6_handle, TIM_IT_UPDATE);
__HAL_TIM_CLEAR_IT(&tim_handle, TIM_IT_UPDATE);
overflow_count++;
}
}
}
static void pulsein_handler(uint8_t num) {
static void pulsein_exti_event_handler(uint8_t num) {
// Grab the current time first.
uint32_t current_overflow = overflow_count;
uint32_t current_count = 0;
#if HAS_BASIC_TIM
current_count = TIM6->CNT;
#endif
uint32_t current_count = tim_handle.Instance->CNT;
// Interrupt register must be cleared manually
EXTI->PR = 1 << num;
@ -105,17 +102,12 @@ void pulsein_reset(void) {
}
memset(_objs, 0, sizeof(_objs));
#if HAS_BASIC_TIM
__HAL_RCC_TIM6_CLK_DISABLE();
tim_clock_disable(stm_peripherals_timer_get_index(tim_handle.Instance));
refcount = 0;
#endif
}
void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, const mcu_pin_obj_t* pin,
uint16_t maxlen, bool idle_state) {
#if !(HAS_BASIC_TIM)
mp_raise_NotImplementedError(translate("PulseIn not supported on this chip"));
#else
// STM32 has one shared EXTI for each pin number, 0-15
uint8_t p_num = pin->number;
if(_objs[p_num]) {
@ -141,24 +133,33 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, const mcu
self->last_count = 0;
self->last_overflow = 0;
if (HAL_TIM_Base_GetState(&t6_handle) == HAL_TIM_STATE_RESET) {
// Set the new period
t6_handle.Instance = TIM6;
t6_handle.Init.Prescaler = 168; // HCLK is 168 mhz so divide down to 1mhz
t6_handle.Init.Period = 0xffff;
HAL_TIM_Base_Init(&t6_handle);
if (HAL_TIM_Base_GetState(&tim_handle) == HAL_TIM_STATE_RESET) {
// Find a suitable timer
TIM_TypeDef * tim_instance = stm_peripherals_find_timer();
stm_peripherals_timer_reserve(tim_instance);
// TIM6 has limited HAL support, set registers manually
t6_handle.Instance->SR = 0; // Prevent the SR from triggering an interrupt
t6_handle.Instance->CR1 |= TIM_CR1_CEN; // Resume timer
t6_handle.Instance->CR1 |= TIM_CR1_URS; // Disable non-overflow interrupts
__HAL_TIM_ENABLE_IT(&t6_handle, TIM_IT_UPDATE);
// Calculate a 1ms period
uint32_t source = stm_peripherals_timer_get_source_freq(tim_instance);
uint32_t prescaler = source/1000000; // 1us intervals
stm_peripherals_timer_preinit(tim_instance, 4, pulsein_timer_event_handler);
// Set the new period
tim_handle.Instance = tim_instance;
tim_handle.Init.Prescaler = prescaler; // divide down to 1mhz
tim_handle.Init.Period = 0xffff;
HAL_TIM_Base_Init(&tim_handle);
// Set registers manually
tim_handle.Instance->SR = 0; // Prevent the SR from triggering an interrupt
tim_handle.Instance->CR1 |= TIM_CR1_CEN; // Resume timer
tim_handle.Instance->CR1 |= TIM_CR1_URS; // Disable non-overflow interrupts
__HAL_TIM_ENABLE_IT(&tim_handle, TIM_IT_UPDATE);
overflow_count = 0;
}
// Add to active PulseIns
refcount++;
#endif
// EXTI pins can also be read as an input
GPIO_InitTypeDef GPIO_InitStruct = {0};
@ -189,9 +190,7 @@ void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t* self) {
refcount--;
if (refcount == 0) {
#if HAS_BASIC_TIM
__HAL_RCC_TIM6_CLK_DISABLE();
#endif
tim_clock_disable(1<< stm_peripherals_timer_get_index(tim_handle.Instance));
}
}
@ -299,23 +298,23 @@ static void assign_EXTI_Interrupt(pulseio_pulsein_obj_t* self, uint8_t num) {
void EXTI0_IRQHandler(void)
{
pulsein_handler(0);
pulsein_exti_event_handler(0);
}
void EXTI1_IRQHandler(void)
{
pulsein_handler(1);
pulsein_exti_event_handler(1);
}
void EXTI2_IRQHandler(void)
{
pulsein_handler(2);
pulsein_exti_event_handler(2);
}
void EXTI3_IRQHandler(void)
{
pulsein_handler(3);
pulsein_exti_event_handler(3);
}
void EXTI4_IRQHandler(void)
{
pulsein_handler(4);
pulsein_exti_event_handler(4);
}
void EXTI9_5_IRQHandler(void)
@ -323,7 +322,7 @@ void EXTI9_5_IRQHandler(void)
uint32_t pending = EXTI->PR;
for (uint i = 5; i <= 9; i++) {
if(pending & (1 << i)) {
pulsein_handler(i);
pulsein_exti_event_handler(i);
}
}
}
@ -333,7 +332,7 @@ void EXTI15_10_IRQHandler(void)
uint32_t pending = EXTI->PR;
for (uint i = 10; i <= 15; i++) {
if(pending & (1 << i)) {
pulsein_handler(i);
pulsein_exti_event_handler(i);
}
}
}

View File

@ -37,19 +37,19 @@
#include STM32_HAL_H
#include "common-hal/microcontroller/Pin.h"
#include "timers.h"
// A single timer is shared amongst all PulseOut objects under the assumption that
// the code is single threaded.
STATIC uint8_t refcount = 0;
STATIC uint16_t *pulse_array = NULL;
STATIC volatile uint16_t pulse_array_index = 0;
STATIC uint16_t pulse_array_length;
//Timer is shared, must be accessible by interrupt
STATIC TIM_HandleTypeDef t7_handle;
STATIC TIM_HandleTypeDef tim_handle;
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);
@ -65,88 +65,79 @@ STATIC void turn_off(pulseio_pulseout_obj_t *pulseout) {
STATIC void start_timer(void) {
// Set the new period
t7_handle.Init.Period = pulse_array[pulse_array_index] - 1;
HAL_TIM_Base_Init(&t7_handle);
tim_handle.Init.Period = pulse_array[pulse_array_index] - 1;
HAL_TIM_Base_Init(&tim_handle);
// TIM7 has limited HAL support, set registers manually
t7_handle.Instance->SR = 0; // Prevent the SR from triggering an interrupt
t7_handle.Instance->CR1 |= TIM_CR1_CEN; // Resume timer
t7_handle.Instance->CR1 |= TIM_CR1_URS; // Disable non-overflow interrupts
__HAL_TIM_ENABLE_IT(&t7_handle, TIM_IT_UPDATE);
tim_handle.Instance->SR = 0; // Prevent the SR from triggering an interrupt
tim_handle.Instance->CR1 |= TIM_CR1_CEN; // Resume timer
tim_handle.Instance->CR1 |= TIM_CR1_URS; // Disable non-overflow interrupts
__HAL_TIM_ENABLE_IT(&tim_handle, TIM_IT_UPDATE);
}
STATIC void pulseout_event_handler(void) {
if (curr_pulseout->pwmout == NULL) {
return; //invalid interrupt
// Detect TIM Update event
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) {
return; //invalid interrupt
}
pulse_array_index++;
// No more pulses. Turn off output and don't restart.
if (pulse_array_index >= pulse_array_length) {
turn_off(curr_pulseout);
return;
}
// Alternate on and off, starting with on.
if (pulse_array_index % 2 == 0) {
turn_on(curr_pulseout);
} else {
turn_off(curr_pulseout);
}
// Count up to the next given value.
start_timer();
}
}
pulse_array_index++;
// No more pulses. Turn off output and don't restart.
if (pulse_array_index >= pulse_array_length) {
turn_off(curr_pulseout);
return;
}
// Alternate on and off, starting with on.
if (pulse_array_index % 2 == 0) {
turn_on(curr_pulseout);
} else {
turn_off(curr_pulseout);
}
// Count up to the next given value.
start_timer();
}
void pulseout_reset() {
#if HAS_BASIC_TIM
__HAL_RCC_TIM7_CLK_DISABLE();
stm_peripherals_timer_free(tim_handle.Instance);
refcount = 0;
#endif
}
void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self,
const pulseio_pwmout_obj_t* carrier) {
#if !(HAS_BASIC_TIM)
mp_raise_NotImplementedError(translate("PulseOut not supported on this chip"));
#else
// Add to active PulseOuts
refcount++;
TIM_TypeDef * tim_instance = stm_peripherals_find_timer();
stm_peripherals_timer_reserve(tim_instance);
// Calculate a 1 ms period
uint32_t source, clk_div;
source = HAL_RCC_GetPCLK1Freq(); // TIM7 is on APB1
clk_div = RCC->CFGR & RCC_CFGR_PPRE1;
// APB quirk, see See DM00031020 Rev 4, page 115.
if (clk_div != 0) {
// APB prescaler for this timer is > 1
source *= 2;
}
//calculate a 1ms period
uint32_t source = stm_peripherals_timer_get_source_freq(tim_instance);
uint32_t prescaler = source/1000000; //1us intervals
__HAL_RCC_TIM7_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM7_IRQn, 4, 0);
HAL_NVIC_EnableIRQ(TIM7_IRQn);
stm_peripherals_timer_preinit(tim_instance, 4, pulseout_event_handler);
tim_handle.Instance = tim_instance;
tim_handle.Init.Period = 100; //immediately replaced.
tim_handle.Init.Prescaler = prescaler - 1;
tim_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
tim_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
// Timers 6 and 7 have no pins, so using them doesn't affect PWM availability
t7_handle.Instance = TIM7;
t7_handle.Init.Period = 100; //immediately replaced.
t7_handle.Init.Prescaler = prescaler - 1;
t7_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
t7_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
t7_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&t7_handle);
t7_handle.Instance->SR = 0;
HAL_TIM_Base_Init(&tim_handle);
tim_handle.Instance->SR = 0;
// The HAL can't work with const, recast required.
self->pwmout = (pulseio_pwmout_obj_t*)carrier;
turn_off(self);
#endif
}
bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t* self) {
@ -162,9 +153,7 @@ void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) {
refcount--;
if (refcount == 0) {
#if HAS_BASIC_TIM
__HAL_RCC_TIM7_CLK_DISABLE();
#endif
tim_clock_disable(1<< stm_peripherals_timer_get_index(tim_handle.Instance));
}
}
@ -187,24 +176,11 @@ void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pu
// signal.
RUN_BACKGROUND_TASKS;
// Use when debugging, or issues are irrecoverable
// // Use when debugging, or issues are irrecoverable
// if ((supervisor_ticks_ms64() - starttime ) > timeout ) {
// mp_raise_RuntimeError(translate("Error: Send Timeout"));
// }
}
//turn off timer counter.
t7_handle.Instance->CR1 &= ~TIM_CR1_CEN;
}
void TIM7_IRQHandler(void)
{
// Detect TIM Update event
if (__HAL_TIM_GET_FLAG(&t7_handle, TIM_FLAG_UPDATE) != RESET)
{
if (__HAL_TIM_GET_IT_SOURCE(&t7_handle, TIM_IT_UPDATE) != RESET)
{
__HAL_TIM_CLEAR_IT(&t7_handle, TIM_IT_UPDATE);
pulseout_event_handler();
}
}
tim_handle.Instance->CR1 &= ~TIM_CR1_CEN;
}

View File

@ -4,8 +4,8 @@ INTERNAL_LIBM ?= 1
USB_SERIAL_NUMBER_LENGTH ?= 24
ifeq ($(MCU_VARIANT),STM32F405xx)
CIRCUITPY_FRAMEBUFFERIO ?= 1
CIRCUITPY_RGBMATRIX ?= 1
CIRCUITPY_FRAMEBUFFERIO ?= 0
CIRCUITPY_RGBMATRIX ?= 0
endif
ifeq ($(MCU_SERIES),F4)

View File

@ -23,20 +23,51 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "timers.h"
#include "py/mpconfig.h"
#include "py/gc.h"
#include "py/obj.h"
#include "py/runtime.h"
#include "supervisor/shared/translate.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/microcontroller/Pin.h"
#define ALL_CLOCKS 0xFFFF
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 void tim_clock_enable(uint16_t mask);
STATIC void tim_clock_disable(uint16_t mask);
static void (*stm_timer_callback[MP_ARRAY_SIZE(mcu_tim_banks)])(void);
static size_t irq_map[] = {
TIM1_CC_IRQn,
TIM2_IRQn,
TIM3_IRQn,
TIM4_IRQn,
TIM5_IRQn,
TIM6_DAC_IRQn,
TIM7_IRQn,
TIM8_CC_IRQn,
TIM1_BRK_TIM9_IRQn,
TIM1_UP_TIM10_IRQn,
TIM1_TRG_COM_TIM11_IRQn,
TIM8_BRK_TIM12_IRQn,
TIM8_UP_TIM13_IRQn,
TIM8_TRG_COM_TIM14_IRQn,
#if (CPY_STM32H7)
TIM15_IRQn,
TIM16_IRQn,
TIM17_IRQn,
#endif
};
// Get the frequency (in Hz) of the source clock for the given timer.
// On STM32F405/407/415/417 there are 2 cases for how the clock freq is set.
// 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.
STATIC uint32_t timer_get_source_freq(uint32_t tim_id) {
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)) {
// TIM{1,8,9,10,11} are on APB2
@ -54,11 +85,44 @@ STATIC uint32_t timer_get_source_freq(uint32_t tim_id) {
return source;
}
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]) {
stm_timer_reserved[i] = false;
} else {
never_reset_mask |= 1 << i;
}
}
tim_clock_disable(ALL_CLOCKS & ~(never_reset_mask));
}
TIM_TypeDef * stm_peripherals_find_timer(void) {
// TODO: check for unreserved timers from already claimed pins
// 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)
// && (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++) {
// if ( (mcu_tim_pin_list[j].pin == (mcu_pin_obj_t*)(mcu_pin_globals.map.table[k].value)) ) {
// timer_in_package = true;
// }
// }
// }
// }
// // If no results are found, no unclaimed pins with this timer are in this package,
// // and it is safe to pick
// if (timer_in_package == false && mcu_tim_banks[i] != NULL) {
// return mcu_tim_banks[i];
// }
// }
// Work backwards - higher index timers have fewer pin allocations
for (size_t i = MP_ARRAY_SIZE(stm_timer_reserved); i>=0; i--) {
for (size_t i = (MP_ARRAY_SIZE(mcu_tim_banks) - 1); i>=0; i--) {
if ((!stm_timer_reserved[i]) && (mcu_tim_banks[i] != NULL)) {
return mcu_tim_banks[i];
}
@ -67,20 +131,58 @@ TIM_TypeDef * stm_peripherals_find_timer(void) {
return NULL;
}
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);
HAL_NVIC_SetPriority(irq_map[tim_idx], prio, 0);
HAL_NVIC_EnableIRQ(irq_map[tim_idx]);
}
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) {
stm_timer_callback[stm_peripherals_timer_get_index]
stm_timer_callback[stm_peripherals_timer_get_index(timer)] = callback;
}
void stm_peripherals_timer_free(TIM_TypeDef * instance) {
size_t tim_idx = stm_peripherals_timer_get_index(instance);
stm_timer_callback[tim_idx] = NULL;
tim_clock_disable(1 << tim_idx);
stm_timer_reserved[tim_idx] = false;
stm_timer_never_reset[tim_idx] = false;
}
void stm_peripherals_timer_never_reset(TIM_TypeDef * instance);
void stm_peripherals_timer_reset_ok(TIM_TypeDef * instance);
void stm_peripherals_timer_is_never_reset(TIM_TypeDef * instance);
void stm_peripherals_timer_is_reserved(TIM_TypeDef * instance);
size_t stm_peripherals_timer_get_index(TIM_TypeDef * instance);
STATIC void tim_clock_enable(uint16_t mask) {
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) {
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];
}
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;
}
}
return ~(size_t)0;
}
void tim_clock_enable(uint16_t mask) {
#ifdef TIM1
if (mask & (1 << 0)) {
__HAL_RCC_TIM1_CLK_ENABLE();
@ -144,7 +246,7 @@ STATIC void tim_clock_enable(uint16_t mask) {
#endif
}
STATIC 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();
@ -209,8 +311,8 @@ STATIC void tim_clock_disable(uint16_t mask) {
}
STATIC void callback_router(size_t index) {
if (stm_timer_callback[index]) {
(*stm_timer_callback[index])();
if (stm_timer_callback[index - 1]) {
(*stm_timer_callback[index - 1])();
}
}

View File

@ -24,17 +24,30 @@
* THE SOFTWARE.
*/
typedef struct {
TIM_TypeDef * p_reg;
uint8_t instance_id;
uint8_t cc_channel_count;
} nrfx_timer_t;
// typedef struct {
// TIM_TypeDef * timer;
// bool reserved;
// bool never_reset;
// void (*stm_timer_callback)(void);
// size_t irq;
// } stm_timer_t;
#include <stdint.h>
#include "py/mphal.h"
#include "peripherals/periph.h"
#include STM32_HAL_H
void tim_clock_enable(uint16_t mask);
void tim_clock_disable(uint16_t mask);
uint32_t stm_peripherals_timer_get_source_freq(TIM_TypeDef * timer);
void timers_reset(void);
TIM_TypeDef * stm_peripherals_find_timer(void);
void stm_peripherals_timer_preinit(TIM_TypeDef * instance, uint8_t prio, void (*callback)(void));
void stm_peripherals_timer_reserve(TIM_TypeDef * instance);
void stm_peripherals_timer_free(TIM_TypeDef * instance);
void stm_peripherals_timer_never_reset(TIM_TypeDef * instance);
void stm_peripherals_timer_reset_ok(TIM_TypeDef * instance);
void stm_peripherals_timer_is_never_reset(TIM_TypeDef * instance);
void stm_peripherals_timer_is_reserved(TIM_TypeDef * instance);
bool stm_peripherals_timer_is_never_reset(TIM_TypeDef * instance);
bool stm_peripherals_timer_is_reserved(TIM_TypeDef * instance);
size_t stm_peripherals_timer_get_index(TIM_TypeDef * instance);

View File

@ -41,6 +41,7 @@
#include "common-hal/pulseio/PWMOut.h"
#include "common-hal/pulseio/PulseOut.h"
#include "common-hal/pulseio/PulseIn.h"
#include "timers.h"
#endif
#include "clocks.h"
@ -224,6 +225,7 @@ void reset_port(void) {
uart_reset();
#endif
#if CIRCUITPY_PULSEIO
timers_reset();
pwmout_reset();
pulseout_reset();
pulsein_reset();