Dave Hylands
10 years ago
23 changed files with 2055 additions and 86 deletions
@ -0,0 +1,201 @@ |
|||
/*
|
|||
* This file is part of the Micro Python project, http://micropython.org/
|
|||
* |
|||
* The MIT License (MIT) |
|||
* |
|||
* Copyright (c) 2013, 2014 Damien P. George |
|||
* |
|||
* 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 <stdint.h> |
|||
#include <mk20dx128.h> |
|||
#include "teensy_hal.h" |
|||
|
|||
void HAL_FTM_Base_Init(FTM_HandleTypeDef *hftm) { |
|||
/* Check the parameters */ |
|||
FTM_TypeDef *FTMx = hftm->Instance; |
|||
assert_param(IS_FTM_INSTANCE(FTMx)); |
|||
assert_param(IS_FTM_PRESCALERSHIFT(hftm->Init.PrescalerShift)); |
|||
assert_param(IS_FTM_COUNTERMODE(hftm->Init.CounterMode)); |
|||
assert_param(IS_FTM_PERIOD(hftm->Init.Period)); |
|||
|
|||
hftm->State = HAL_FTM_STATE_BUSY; |
|||
|
|||
FTMx->MODE = FTM_MODE_WPDIS; |
|||
FTMx->SC = 0; |
|||
FTMx->MOD = hftm->Init.Period; |
|||
uint32_t sc = FTM_SC_PS(hftm->Init.PrescalerShift); |
|||
if (hftm->Init.CounterMode == FTM_COUNTERMODE_CENTER) { |
|||
sc |= FTM_SC_CPWMS; |
|||
} |
|||
FTMx->SC = sc; |
|||
|
|||
hftm->State = HAL_FTM_STATE_READY; |
|||
} |
|||
|
|||
void HAL_FTM_Base_Start(FTM_HandleTypeDef *hftm) { |
|||
FTM_TypeDef *FTMx = hftm->Instance; |
|||
assert_param(IS_FTM_INSTANCE(FTMx)); |
|||
|
|||
hftm->State = HAL_FTM_STATE_BUSY; |
|||
|
|||
FTMx->CNT = 0; |
|||
FTMx->SC &= ~FTM_SC_CLKS(3); |
|||
FTMx->SC |= FTM_SC_CLKS(1); |
|||
|
|||
hftm->State = HAL_FTM_STATE_READY; |
|||
} |
|||
|
|||
void HAL_FTM_Base_Start_IT(FTM_HandleTypeDef *hftm) { |
|||
FTM_TypeDef *FTMx = hftm->Instance; |
|||
assert_param(IS_FTM_INSTANCE(FTMx)); |
|||
|
|||
hftm->State = HAL_FTM_STATE_BUSY; |
|||
|
|||
FTMx->CNT = 0; |
|||
FTMx->SC |= FTM_SC_CLKS(1) | FTM_SC_TOIE; |
|||
|
|||
hftm->State = HAL_FTM_STATE_READY; |
|||
} |
|||
|
|||
void HAL_FTM_Base_DeInit(FTM_HandleTypeDef *hftm) { |
|||
assert_param(IS_FTM_INSTANCE(hftm->Instance)); |
|||
|
|||
hftm->State = HAL_FTM_STATE_BUSY; |
|||
|
|||
__HAL_FTM_DISABLE_TOF_IT(hftm); |
|||
|
|||
hftm->State = HAL_FTM_STATE_RESET; |
|||
} |
|||
|
|||
void HAL_FTM_OC_Init(FTM_HandleTypeDef *hftm) { |
|||
HAL_FTM_Base_Init(hftm); |
|||
} |
|||
|
|||
void HAL_FTM_OC_ConfigChannel(FTM_HandleTypeDef *hftm, FTM_OC_InitTypeDef* sConfig, uint32_t channel) { |
|||
FTM_TypeDef *FTMx = hftm->Instance; |
|||
assert_param(IS_FTM_INSTANCE(FTMx)); |
|||
assert_param(IS_FTM_CHANNEL(channel)); |
|||
assert_param(IS_FTM_OC_MODE(sConfig->OCMode)); |
|||
assert_param(IS_FTM_OC_PULSE(sConfig->Pulse)); |
|||
assert_param(IS_FTM_OC_POLARITY(sConfig->OCPolarity)); |
|||
|
|||
hftm->State = HAL_FTM_STATE_BUSY; |
|||
|
|||
FTMx->channel[channel].CSC = sConfig->OCMode; |
|||
FTMx->channel[channel].CV = sConfig->Pulse; |
|||
if (sConfig->OCPolarity & 1) { |
|||
FTMx->POL |= (1 << channel); |
|||
} else { |
|||
FTMx->POL &= ~(1 << channel); |
|||
} |
|||
|
|||
hftm->State = HAL_FTM_STATE_READY; |
|||
} |
|||
|
|||
void HAL_FTM_OC_Start(FTM_HandleTypeDef *hftm, uint32_t channel) { |
|||
// Nothing else to do
|
|||
} |
|||
|
|||
void HAL_FTM_OC_Start_IT(FTM_HandleTypeDef *hftm, uint32_t channel) { |
|||
FTM_TypeDef *FTMx = hftm->Instance; |
|||
assert_param(IS_FTM_INSTANCE(FTMx)); |
|||
|
|||
FTMx->channel[channel].CSC |= FTM_CSC_CHIE; |
|||
} |
|||
|
|||
void HAL_FTM_OC_DeInit(FTM_HandleTypeDef *hftm) { |
|||
HAL_FTM_Base_DeInit(hftm); |
|||
} |
|||
|
|||
void HAL_FTM_PWM_Init(FTM_HandleTypeDef *hftm) { |
|||
HAL_FTM_Base_Init(hftm); |
|||
} |
|||
|
|||
void HAL_FTM_PWM_ConfigChannel(FTM_HandleTypeDef *hftm, FTM_OC_InitTypeDef* sConfig, uint32_t channel) { |
|||
FTM_TypeDef *FTMx = hftm->Instance; |
|||
assert_param(IS_FTM_INSTANCE(FTMx)); |
|||
assert_param(IS_FTM_CHANNEL(channel)); |
|||
assert_param(IS_FTM_PWM_MODE(sConfig->OCMode)); |
|||
assert_param(IS_FTM_OC_PULSE(sConfig->Pulse)); |
|||
assert_param(IS_FTM_OC_POLARITY(sConfig->OCPolarity)); |
|||
|
|||
hftm->State = HAL_FTM_STATE_BUSY; |
|||
|
|||
FTMx->channel[channel].CSC = sConfig->OCMode; |
|||
FTMx->channel[channel].CV = sConfig->Pulse; |
|||
if (sConfig->OCPolarity & 1) { |
|||
FTMx->POL |= (1 << channel); |
|||
} else { |
|||
FTMx->POL &= ~(1 << channel); |
|||
} |
|||
|
|||
hftm->State = HAL_FTM_STATE_READY; |
|||
} |
|||
|
|||
void HAL_FTM_PWM_Start(FTM_HandleTypeDef *hftm, uint32_t channel) { |
|||
// Nothing else to do
|
|||
} |
|||
|
|||
void HAL_FTM_PWM_Start_IT(FTM_HandleTypeDef *hftm, uint32_t channel) { |
|||
FTM_TypeDef *FTMx = hftm->Instance; |
|||
assert_param(IS_FTM_INSTANCE(FTMx)); |
|||
|
|||
FTMx->channel[channel].CSC |= FTM_CSC_CHIE; |
|||
} |
|||
|
|||
void HAL_FTM_PWM_DeInit(FTM_HandleTypeDef *hftm) { |
|||
HAL_FTM_Base_DeInit(hftm); |
|||
} |
|||
|
|||
void HAL_FTM_IC_Init(FTM_HandleTypeDef *hftm) { |
|||
HAL_FTM_Base_Init(hftm); |
|||
} |
|||
|
|||
void HAL_FTM_IC_ConfigChannel(FTM_HandleTypeDef *hftm, FTM_IC_InitTypeDef* sConfig, uint32_t channel) { |
|||
FTM_TypeDef *FTMx = hftm->Instance; |
|||
assert_param(IS_FTM_INSTANCE(FTMx)); |
|||
assert_param(IS_FTM_CHANNEL(channel)); |
|||
assert_param(IS_FTM_IC_POLARITY(sConfig->ICPolarity)); |
|||
|
|||
hftm->State = HAL_FTM_STATE_BUSY; |
|||
|
|||
FTMx->channel[channel].CSC = sConfig->ICPolarity; |
|||
|
|||
hftm->State = HAL_FTM_STATE_READY; |
|||
} |
|||
|
|||
void HAL_FTM_IC_Start(FTM_HandleTypeDef *hftm, uint32_t channel) { |
|||
//FTM_TypeDef *FTMx = hftm->Instance;
|
|||
//assert_param(IS_FTM_INSTANCE(FTMx));
|
|||
|
|||
// Nothing else to do
|
|||
} |
|||
|
|||
void HAL_FTM_IC_Start_IT(FTM_HandleTypeDef *hftm, uint32_t channel) { |
|||
FTM_TypeDef *FTMx = hftm->Instance; |
|||
assert_param(IS_FTM_INSTANCE(FTMx)); |
|||
|
|||
FTMx->channel[channel].CSC |= FTM_CSC_CHIE; |
|||
} |
|||
|
|||
void HAL_FTM_IC_DeInit(FTM_HandleTypeDef *hftm) { |
|||
HAL_FTM_Base_DeInit(hftm); |
|||
} |
@ -0,0 +1,184 @@ |
|||
/*
|
|||
* This file is part of the Micro Python project, http://micropython.org/
|
|||
* |
|||
* The MIT License (MIT) |
|||
* |
|||
* Copyright (c) 2013, 2014 Damien P. George |
|||
* |
|||
* 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. |
|||
*/ |
|||
|
|||
#define FTM0 ((FTM_TypeDef *)&FTM0_SC) |
|||
#define FTM1 ((FTM_TypeDef *)&FTM1_SC) |
|||
#define FTM2 ((FTM_TypeDef *)&FTM2_SC) |
|||
|
|||
typedef struct { |
|||
volatile uint32_t CSC; // Channel x Status And Control
|
|||
volatile uint32_t CV; // Channel x Value
|
|||
} FTM_ChannelTypeDef; |
|||
|
|||
typedef struct { |
|||
volatile uint32_t SC; // Status And Control
|
|||
volatile uint32_t CNT; // Counter
|
|||
volatile uint32_t MOD; // Modulo
|
|||
FTM_ChannelTypeDef channel[8]; |
|||
volatile uint32_t CNTIN; // Counter Initial Value
|
|||
volatile uint32_t STATUS; // Capture And Compare Status
|
|||
volatile uint32_t MODE; // Features Mode Selection
|
|||
volatile uint32_t SYNC; // Synchronization
|
|||
volatile uint32_t OUTINIT; // Initial State For Channels Output
|
|||
volatile uint32_t OUTMASK; // Output Mask
|
|||
volatile uint32_t COMBINE; // Function For Linked Channels
|
|||
volatile uint32_t DEADTIME; // Deadtime Insertion Control
|
|||
volatile uint32_t EXTTRIG; // FTM External Trigger
|
|||
volatile uint32_t POL; // Channels Polarity
|
|||
volatile uint32_t FMS; // Fault Mode Status
|
|||
volatile uint32_t FILTER; // Input Capture Filter Control
|
|||
volatile uint32_t FLTCTRL; // Fault Control
|
|||
volatile uint32_t QDCTRL; // Quadrature Decoder Control And Status
|
|||
volatile uint32_t CONF; // Configuration
|
|||
volatile uint32_t FLTPOL; // FTM Fault Input Polarity
|
|||
volatile uint32_t SYNCONF; // Synchronization Configuration
|
|||
volatile uint32_t INVCTRL; // FTM Inverting Control
|
|||
volatile uint32_t SWOCTRL; // FTM Software Output Control
|
|||
volatile uint32_t PWMLOAD; // FTM PWM Load
|
|||
} FTM_TypeDef; |
|||
|
|||
typedef struct { |
|||
uint32_t PrescalerShift; // Sets the prescaler to 1 << PrescalerShift
|
|||
uint32_t CounterMode; // One of FTM_COUNTERMODE_xxx
|
|||
uint32_t Period; // Specifies the Period for determining timer overflow
|
|||
} FTM_Base_InitTypeDef; |
|||
|
|||
typedef struct { |
|||
uint32_t OCMode; // One of FTM_OCMODE_xxx
|
|||
uint32_t Pulse; // Specifies initial pulse width (0-0xffff)
|
|||
uint32_t OCPolarity; // One of FTM_OCPOLRITY_xxx
|
|||
} FTM_OC_InitTypeDef; |
|||
|
|||
typedef struct { |
|||
uint32_t ICPolarity; // Specifies Rising/Falling/Both
|
|||
} FTM_IC_InitTypeDef; |
|||
|
|||
#define IS_FTM_INSTANCE(INSTANCE) (((INSTANCE) == FTM0) || \ |
|||
((INSTANCE) == FTM1) || \ |
|||
((INSTANCE) == FTM2)) |
|||
|
|||
#define IS_FTM_PRESCALERSHIFT(PRESCALERSHIFT) (((PRESCALERSHIFT) & ~7) == 0) |
|||
|
|||
#define FTM_COUNTERMODE_UP (0) |
|||
#define FTM_COUNTERMODE_CENTER (FTM_SC_CPWMS) |
|||
|
|||
#define IS_FTM_COUNTERMODE(MODE) (((MODE) == FTM_COUNTERMODE_UP) ||\ |
|||
((MODE) == FTM_COUNTERMODE_CENTER)) |
|||
|
|||
#define IS_FTM_PERIOD(PERIOD) (((PERIOD) & 0xFFFF0000) == 0) |
|||
|
|||
#define FTM_CSC_CHF 0x80 |
|||
#define FTM_CSC_CHIE 0x40 |
|||
#define FTM_CSC_MSB 0x20 |
|||
#define FTM_CSC_MSA 0x10 |
|||
#define FTM_CSC_ELSB 0x08 |
|||
#define FTM_CSC_ELSA 0x04 |
|||
#define FTM_CSC_DMA 0x01 |
|||
|
|||
#define FTM_OCMODE_TIMING (0) |
|||
#define FTM_OCMODE_ACTIVE (FTM_CSC_MSA | FTM_CSC_ELSB | FTM_CSC_ELSA) |
|||
#define FTM_OCMODE_INACTIVE (FTM_CSC_MSA | FTM_CSC_ELSB) |
|||
#define FTM_OCMODE_TOGGLE (FTM_CSC_MSA | FTM_CSC_ELSA) |
|||
#define FTM_OCMODE_PWM1 (FTM_CSC_MSB | FTM_CSC_ELSB) |
|||
#define FTM_OCMODE_PWM2 (FTM_CSC_MSB | FTM_CSC_ELSA) |
|||
|
|||
#define IS_FTM_OC_MODE(mode) ((mode) == FTM_OCMODE_TIMING || \ |
|||
(mode) == FTM_OCMODE_ACTIVE || \ |
|||
(mode) == FTM_OCMODE_INACTIVE || \ |
|||
(mode) == FTM_OCMODE_TOGGLE ) |
|||
|
|||
#define IS_FTM_PWM_MODE(mode) ((mode) == FTM_OCMODE_PWM1 || \ |
|||
(mode) == FTM_OCMODE_PWM2) |
|||
|
|||
#define IS_FTM_CHANNEL(channel) (((channel) & ~7) == 0) |
|||
|
|||
#define IS_FTM_PULSE(pulse) (((pulse) & ~0xffff) == 0) |
|||
|
|||
#define FTM_OCPOLARITY_HIGH (0) |
|||
#define FTM_OCPOLARITY_LOW (1) |
|||
|
|||
#define IS_FTM_OC_POLARITY(polarity) ((polarity) == FTM_OCPOLARITY_HIGH || \ |
|||
(polarity) == FTM_OCPOLARITY_LOW) |
|||
|
|||
#define FTM_ICPOLARITY_RISING (FTM_CSC_ELSA) |
|||
#define FTM_ICPOLARITY_FALLING (FTM_CSC_ELSB) |
|||
#define FTM_ICPOLARITY_BOTH (FTM_CSC_ELSA | FTM_CSC_ELSB) |
|||
|
|||
#define IS_FTM_IC_POLARITY(polarity) ((polarity) == FTM_ICPOLARITY_RISING || \ |
|||
(polarity) == FTM_ICPOLARITY_FALLING || \ |
|||
(polarity) == FTM_ICPOLARITY_BOTH) |
|||
|
|||
typedef enum { |
|||
HAL_FTM_STATE_RESET = 0x00, |
|||
HAL_FTM_STATE_READY = 0x01, |
|||
HAL_FTM_STATE_BUSY = 0x02, |
|||
} HAL_FTM_State; |
|||
|
|||
typedef struct { |
|||
FTM_TypeDef *Instance; |
|||
FTM_Base_InitTypeDef Init; |
|||
HAL_FTM_State State; |
|||
|
|||
} FTM_HandleTypeDef; |
|||
|
|||
#define __HAL_FTM_GET_TOF_FLAG(HANDLE) (((HANDLE)->Instance->SC & FTM_SC_TOF) != 0) |
|||
#define __HAL_FTM_CLEAR_TOF_FLAG(HANDLE) ((HANDLE)->Instance->SC &= ~FTM_SC_TOF) |
|||
|
|||
#define __HAL_FTM_GET_TOF_IT(HANDLE) (((HANDLE)->Instance->SC & FTM_SC_TOIE) != 0) |
|||
#define __HAL_FTM_ENABLE_TOF_IT(HANDLE) ((HANDLE)->Instance->SC |= FTM_SC_TOIE) |
|||
#define __HAL_FTM_DISABLE_TOF_IT(HANDLE) ((HANDLE)->Instance->SC &= ~FTM_SC_TOIE) |
|||
|
|||
#define __HAL_FTM_GET_CH_FLAG(HANDLE, CH) (((HANDLE)->Instance->channel[CH].CSC & FTM_CSC_CHF) != 0) |
|||
#define __HAL_FTM_CLEAR_CH_FLAG(HANDLE, CH) ((HANDLE)->Instance->channel[CH].CSC &= ~FTM_CSC_CHF) |
|||
|
|||
#define __HAL_FTM_GET_CH_IT(HANDLE, CH) (((HANDLE)->Instance->channel[CH].CSC & FTM_CSC_CHIE) != 0) |
|||
#define __HAL_FTM_ENABLE_CH_IT(HANDLE, CH) ((HANDLE)->Instance->channel[CH].CSC |= FTM_CSC_CHIE) |
|||
#define __HAL_FTM_DISABLE_CH_IT(HANDLE, CH) ((HANDLE)->Instance->channel[CH].CSC &= ~FTM_CSC_CHIE) |
|||
|
|||
void HAL_FTM_Base_Init(FTM_HandleTypeDef *hftm); |
|||
void HAL_FTM_Base_Start(FTM_HandleTypeDef *hftm); |
|||
void HAL_FTM_Base_Start_IT(FTM_HandleTypeDef *hftm); |
|||
void HAL_FTM_Base_DeInit(FTM_HandleTypeDef *hftm); |
|||
|
|||
void HAL_FTM_OC_Init(FTM_HandleTypeDef *hftm); |
|||
void HAL_FTM_OC_ConfigChannel(FTM_HandleTypeDef *hftm, FTM_OC_InitTypeDef* sConfig, uint32_t channel); |
|||
void HAL_FTM_OC_Start(FTM_HandleTypeDef *hftm, uint32_t channel); |
|||
void HAL_FTM_OC_Start_IT(FTM_HandleTypeDef *hftm, uint32_t channel); |
|||
void HAL_FTM_OC_DeInit(FTM_HandleTypeDef *hftm); |
|||
|
|||
void HAL_FTM_PWM_Init(FTM_HandleTypeDef *hftm); |
|||
void HAL_FTM_PWM_ConfigChannel(FTM_HandleTypeDef *hftm, FTM_OC_InitTypeDef* sConfig, uint32_t channel); |
|||
void HAL_FTM_PWM_Start(FTM_HandleTypeDef *hftm, uint32_t channel); |
|||
void HAL_FTM_PWM_Start_IT(FTM_HandleTypeDef *hftm, uint32_t channel); |
|||
void HAL_FTM_PWM_DeInit(FTM_HandleTypeDef *hftm); |
|||
|
|||
void HAL_FTM_IC_Init(FTM_HandleTypeDef *hftm); |
|||
void HAL_FTM_IC_ConfigChannel(FTM_HandleTypeDef *hftm, FTM_IC_InitTypeDef* sConfig, uint32_t channel); |
|||
void HAL_FTM_IC_Start(FTM_HandleTypeDef *hftm, uint32_t channel); |
|||
void HAL_FTM_IC_Start_IT(FTM_HandleTypeDef *hftm, uint32_t channel); |
|||
void HAL_FTM_IC_DeInit(FTM_HandleTypeDef *hftm); |
|||
|
|||
|
Can't render this file because it has a wrong number of fields in line 34.
|
@ -0,0 +1,52 @@ |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
#include "mpconfig.h" |
|||
#include "nlr.h" |
|||
#include "misc.h" |
|||
#include "qstr.h" |
|||
#include "obj.h" |
|||
#include "runtime.h" |
|||
#include "reg.h" |
|||
|
|||
#if MICROPY_REG |
|||
|
|||
mp_obj_t reg_cmd(void *base, reg_t *reg, mp_uint_t num_regs, uint n_args, const mp_obj_t *args) { |
|||
if (n_args == 0) { |
|||
// dump all regs
|
|||
|
|||
for (mp_uint_t reg_idx = 0; reg_idx < num_regs; reg_idx++, reg++) { |
|||
printf(" %-8s @0x%08x = 0x%08lx\n", |
|||
reg->name, (mp_uint_t)base + reg->offset, *(uint32_t *)((uint8_t *)base + reg->offset)); |
|||
} |
|||
return mp_const_none; |
|||
} |
|||
|
|||
mp_uint_t addr = 0; |
|||
|
|||
if (MP_OBJ_IS_STR(args[0])) { |
|||
const char *name = mp_obj_str_get_str(args[0]); |
|||
mp_uint_t reg_idx; |
|||
for (reg_idx = 0; reg_idx < num_regs; reg_idx++, reg++) { |
|||
if (strcmp(name, reg->name) == 0) { |
|||
break; |
|||
} |
|||
} |
|||
if (reg_idx >= num_regs) { |
|||
printf("Unknown register: '%s'\n", name); |
|||
return mp_const_none; |
|||
} |
|||
addr = (mp_uint_t)base + reg->offset; |
|||
} else { |
|||
addr = (mp_uint_t)base + mp_obj_get_int(args[0]); |
|||
} |
|||
|
|||
if (n_args < 2) { |
|||
// get
|
|||
printf("0x%08lx\n", *(uint32_t *)addr); |
|||
} else { |
|||
*(uint32_t *)addr = mp_obj_get_int(args[1]); |
|||
} |
|||
return mp_const_none; |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,8 @@ |
|||
typedef struct { |
|||
const char *name; |
|||
mp_uint_t offset; |
|||
} reg_t; |
|||
|
|||
#define REG_ENTRY(st, name) { #name, offsetof(st, name) } |
|||
|
|||
mp_obj_t reg_cmd(void *base, reg_t *reg, mp_uint_t num_reg, uint n_args, const mp_obj_t *args); |
|
@ -0,0 +1,897 @@ |
|||
/*
|
|||
* This file is part of the Micro Python project, http://micropython.org/
|
|||
* |
|||
* The MIT License (MIT) |
|||
* |
|||
* Copyright (c) 2013, 2014 Damien P. George |
|||
* |
|||
* 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 <stdio.h> |
|||
#include <stdint.h> |
|||
#include <string.h> |
|||
#include <stddef.h> |
|||
|
|||
#include "mpconfig.h" |
|||
#include "nlr.h" |
|||
#include "misc.h" |
|||
#include "qstr.h" |
|||
#include "obj.h" |
|||
#include "runtime.h" |
|||
#include MICROPY_HAL_H |
|||
#include "gc.h" |
|||
#include "pin.h" |
|||
#include "reg.h" |
|||
|
|||
#include "timer.h" |
|||
|
|||
|
|||
typedef enum { |
|||
CHANNEL_MODE_PWM_NORMAL, |
|||
CHANNEL_MODE_PWM_INVERTED, |
|||
CHANNEL_MODE_OC_TIMING, |
|||
CHANNEL_MODE_OC_ACTIVE, |
|||
CHANNEL_MODE_OC_INACTIVE, |
|||
CHANNEL_MODE_OC_TOGGLE, |
|||
// CHANNEL_MODE_OC_FORCED_ACTIVE,
|
|||
// CHANNEL_MODE_OC_FORCED_INACTIVE,
|
|||
CHANNEL_MODE_IC, |
|||
} pyb_channel_mode; |
|||
|
|||
STATIC const struct { |
|||
qstr name; |
|||
uint32_t oc_mode; |
|||
} gChannelMode[] = { |
|||
{ MP_QSTR_PWM, FTM_OCMODE_PWM1 }, |
|||
{ MP_QSTR_PWM_INVERTED, FTM_OCMODE_PWM2 }, |
|||
{ MP_QSTR_OC_TIMING, FTM_OCMODE_TIMING }, |
|||
{ MP_QSTR_OC_ACTIVE, FTM_OCMODE_ACTIVE }, |
|||
{ MP_QSTR_OC_INACTIVE, FTM_OCMODE_INACTIVE }, |
|||
{ MP_QSTR_OC_TOGGLE, FTM_OCMODE_TOGGLE }, |
|||
// { MP_QSTR_OC_FORCED_ACTIVE, FTM_OCMODE_FORCED_ACTIVE },
|
|||
// { MP_QSTR_OC_FORCED_INACTIVE, FTM_OCMODE_FORCED_INACTIVE },
|
|||
{ MP_QSTR_IC, 0 }, |
|||
}; |
|||
|
|||
struct _pyb_timer_obj_t; |
|||
|
|||
typedef struct _pyb_timer_channel_obj_t { |
|||
mp_obj_base_t base; |
|||
struct _pyb_timer_obj_t *timer; |
|||
uint8_t channel; |
|||
uint8_t mode; |
|||
mp_obj_t callback; |
|||
struct _pyb_timer_channel_obj_t *next; |
|||
} pyb_timer_channel_obj_t; |
|||
|
|||
typedef struct _pyb_timer_obj_t { |
|||
mp_obj_base_t base; |
|||
uint8_t tim_id; |
|||
uint8_t irqn; |
|||
mp_obj_t callback; |
|||
FTM_HandleTypeDef ftm; |
|||
pyb_timer_channel_obj_t *channel; |
|||
} pyb_timer_obj_t; |
|||
|
|||
// Used to do callbacks to Python code on interrupt
|
|||
STATIC pyb_timer_obj_t *pyb_timer_obj_all[3]; |
|||
#define PYB_TIMER_OBJ_ALL_NUM MP_ARRAY_SIZE(pyb_timer_obj_all) |
|||
|
|||
STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in); |
|||
STATIC mp_obj_t pyb_timer_callback(mp_obj_t self_in, mp_obj_t callback); |
|||
STATIC mp_obj_t pyb_timer_channel_callback(mp_obj_t self_in, mp_obj_t callback); |
|||
|
|||
void timer_init0(void) { |
|||
for (uint i = 0; i < PYB_TIMER_OBJ_ALL_NUM; i++) { |
|||
pyb_timer_obj_all[i] = NULL; |
|||
} |
|||
} |
|||
|
|||
// unregister all interrupt sources
|
|||
void timer_deinit(void) { |
|||
for (uint i = 0; i < PYB_TIMER_OBJ_ALL_NUM; i++) { |
|||
pyb_timer_obj_t *tim = pyb_timer_obj_all[i]; |
|||
if (tim != NULL) { |
|||
pyb_timer_deinit(tim); |
|||
} |
|||
} |
|||
} |
|||
|
|||
mp_uint_t get_prescaler_shift(mp_int_t prescaler) { |
|||
mp_uint_t prescaler_shift; |
|||
for (prescaler_shift = 0; prescaler_shift < 8; prescaler_shift++) { |
|||
if (prescaler == (1 << prescaler_shift)) { |
|||
return prescaler_shift; |
|||
} |
|||
} |
|||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "prescaler must be a power of 2 between 1 and 128, not %d", prescaler)); |
|||
} |
|||
|
|||
/******************************************************************************/ |
|||
/* Micro Python bindings */ |
|||
|
|||
STATIC void pyb_timer_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { |
|||
pyb_timer_obj_t *self = self_in; |
|||
|
|||
if (self->ftm.State == HAL_FTM_STATE_RESET) { |
|||
print(env, "Timer(%u)", self->tim_id); |
|||
} else { |
|||
print(env, "Timer(%u, prescaler=%u, period=%u, mode=%s)", |
|||
self->tim_id, |
|||
1 << self->ftm.Init.PrescalerShift, |
|||
self->ftm.Init.Period, |
|||
self->ftm.Init.CounterMode == FTM_COUNTERMODE_UP ? "tUP" : "CENTER"); |
|||
} |
|||
} |
|||
|
|||
/// \method init(*, freq, prescaler, period)
|
|||
/// Initialise the timer. Initialisation must be either by frequency (in Hz)
|
|||
/// or by prescaler and period:
|
|||
///
|
|||
/// tim.init(freq=100) # set the timer to trigger at 100Hz
|
|||
/// tim.init(prescaler=83, period=999) # set the prescaler and period directly
|
|||
///
|
|||
/// Keyword arguments:
|
|||
///
|
|||
/// - `freq` - specifies the periodic frequency of the timer. You migh also
|
|||
/// view this as the frequency with which the timer goes through
|
|||
/// one complete cycle.
|
|||
///
|
|||
/// - `prescaler` 1, 2, 4, 8 16 32, 64 or 128 - specifies the value to be loaded into the
|
|||
/// timer's prescaler. The timer clock source is divided by
|
|||
/// (`prescaler`) to arrive at the timer clock.
|
|||
///
|
|||
/// - `period` [0-0xffff] - Specifies the value to be loaded into the timer's
|
|||
/// Modulo Register (MOD). This determines the period of the timer (i.e.
|
|||
/// when the counter cycles). The timer counter will roll-over after
|
|||
/// `period + 1` timer clock cycles.
|
|||
///
|
|||
/// - `mode` can be one of:
|
|||
/// - `Timer.UP` - configures the timer to count from 0 to MOD (default)
|
|||
/// - `Timer.CENTER` - confgures the timer to count from 0 to MOD and
|
|||
/// then back down to 0.
|
|||
///
|
|||
/// - `callback` - as per Timer.callback()
|
|||
///
|
|||
/// You must either specify freq or both of period and prescaler.
|
|||
STATIC const mp_arg_t pyb_timer_init_args[] = { |
|||
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, |
|||
{ MP_QSTR_prescaler, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, |
|||
{ MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, |
|||
{ MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = FTM_COUNTERMODE_UP} }, |
|||
{ MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, |
|||
}; |
|||
#define PYB_TIMER_INIT_NUM_ARGS MP_ARRAY_SIZE(pyb_timer_init_args) |
|||
|
|||
STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { |
|||
// parse args
|
|||
mp_arg_val_t vals[PYB_TIMER_INIT_NUM_ARGS]; |
|||
mp_arg_parse_all(n_args, args, kw_args, PYB_TIMER_INIT_NUM_ARGS, pyb_timer_init_args, vals); |
|||
|
|||
FTM_HandleTypeDef *ftm = &self->ftm; |
|||
|
|||
// set the TIM configuration values
|
|||
FTM_Base_InitTypeDef *init = &ftm->Init; |
|||
|
|||
if (vals[0].u_int != 0xffffffff) { |
|||
// set prescaler and period from frequency
|
|||
|
|||
if (vals[0].u_int == 0) { |
|||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "can't have 0 frequency")); |
|||
} |
|||
|
|||
uint32_t period = MAX(1, F_BUS / vals[0].u_int); |
|||
uint32_t prescaler_shift = 0; |
|||
while (period > 0x10000 && prescaler_shift < 7) { |
|||
period >>= 1; |
|||
prescaler_shift++; |
|||
} |
|||
if (period > 0x10000) { |
|||
period = 0x10000; |
|||
} |
|||
init->PrescalerShift = prescaler_shift; |
|||
init->Period = period - 1; |
|||
} else if (vals[1].u_int != 0xffffffff && vals[2].u_int != 0xffffffff) { |
|||
// set prescaler and period directly
|
|||
init->PrescalerShift = get_prescaler_shift(vals[1].u_int); |
|||
init->Period = vals[2].u_int; |
|||
if (!IS_FTM_PERIOD(init->Period)) { |
|||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "period must be between 0 and 65535, not %d", init->Period)); |
|||
} |
|||
} else { |
|||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "must specify either freq, or prescaler and period")); |
|||
} |
|||
|
|||
init->CounterMode = vals[3].u_int; |
|||
if (!IS_FTM_COUNTERMODE(init->CounterMode)) { |
|||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "invalid counter mode: %d", init->CounterMode)); |
|||
} |
|||
|
|||
// Currently core/mk20dx128.c sets SIM_SCGC6_FTM0, SIM_SCGC6_FTM1, SIM_SCGC3_FTM2
|
|||
// so we don't need to do it here.
|
|||
|
|||
NVIC_SET_PRIORITY(self->irqn, 0xe); // next-to lowest priority
|
|||
|
|||
HAL_FTM_Base_Init(ftm); |
|||
if (vals[4].u_obj == mp_const_none) { |
|||
HAL_FTM_Base_Start(ftm); |
|||
} else { |
|||
pyb_timer_callback(self, vals[4].u_obj); |
|||
} |
|||
|
|||
return mp_const_none; |
|||
} |
|||
|
|||
/// \classmethod \constructor(id, ...)
|
|||
/// Construct a new timer object of the given id. If additional
|
|||
/// arguments are given, then the timer is initialised by `init(...)`.
|
|||
/// `id` can be 1 to 14, excluding 3.
|
|||
STATIC mp_obj_t pyb_timer_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { |
|||
// check arguments
|
|||
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); |
|||
|
|||
// create new Timer object
|
|||
pyb_timer_obj_t *tim = m_new_obj(pyb_timer_obj_t); |
|||
memset(tim, 0, sizeof(*tim)); |
|||
|
|||
tim->base.type = &pyb_timer_type; |
|||
tim->callback = mp_const_none; |
|||
tim->channel = NULL; |
|||
|
|||
// get FTM number
|
|||
tim->tim_id = mp_obj_get_int(args[0]); |
|||
|
|||
switch (tim->tim_id) { |
|||
case 0: tim->ftm.Instance = FTM0; tim->irqn = IRQ_FTM0; break; |
|||
case 1: tim->ftm.Instance = FTM1; tim->irqn = IRQ_FTM1; break; |
|||
case 2: tim->ftm.Instance = FTM2; tim->irqn = IRQ_FTM2; break; |
|||
default: nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Timer %d does not exist", tim->tim_id)); |
|||
} |
|||
|
|||
if (n_args > 1 || n_kw > 0) { |
|||
// start the peripheral
|
|||
mp_map_t kw_args; |
|||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); |
|||
pyb_timer_init_helper(tim, n_args - 1, args + 1, &kw_args); |
|||
} |
|||
|
|||
// set the global variable for interrupt callbacks
|
|||
if (tim->tim_id < PYB_TIMER_OBJ_ALL_NUM) { |
|||
pyb_timer_obj_all[tim->tim_id] = tim; |
|||
} |
|||
|
|||
return (mp_obj_t)tim; |
|||
} |
|||
|
|||
STATIC mp_obj_t pyb_timer_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { |
|||
return pyb_timer_init_helper(args[0], n_args - 1, args + 1, kw_args); |
|||
} |
|||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_init_obj, 1, pyb_timer_init); |
|||
|
|||
/// \method deinit()
|
|||
/// Deinitialises the timer.
|
|||
///
|
|||
/// Disables the callback (and the associated irq).
|
|||
/// Stops the timer, and disables the timer peripheral.
|
|||
STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in) { |
|||
pyb_timer_obj_t *self = self_in; |
|||
|
|||
// Disable the interrupt
|
|||
pyb_timer_callback(self_in, mp_const_none); |
|||
|
|||
pyb_timer_channel_obj_t *chan = self->channel; |
|||
self->channel = NULL; |
|||
|
|||
// Disable the channel interrupts
|
|||
while (chan != NULL) { |
|||
pyb_timer_channel_callback(chan, mp_const_none); |
|||
pyb_timer_channel_obj_t *prev_chan = chan; |
|||
chan = chan->next; |
|||
prev_chan->next = NULL; |
|||
} |
|||
|
|||
HAL_FTM_Base_DeInit(&self->ftm); |
|||
return mp_const_none; |
|||
} |
|||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit); |
|||
|
|||
/// \method channel(channel, ...)
|
|||
///
|
|||
/// If only a channel nunber is passed, then a previously initialized channel
|
|||
/// object is returned.
|
|||
///
|
|||
/// Othwerwise, a TimerChannel object is initialized and returned.
|
|||
///
|
|||
/// Each channel can be configured to perform pwm, output compare, or
|
|||
/// input capture. All channels share the same underlying timer, which means
|
|||
/// that they share the same timer clock.
|
|||
///
|
|||
/// Keyword arguments:
|
|||
///
|
|||
/// - `mode` can be one of:
|
|||
/// - `Timer.PWM` - configure the timer in PWM mode (active high).
|
|||
/// - `Timer.PWM_INVERTED` - configure the timer in PWM mode (active low).
|
|||
/// - `Timer.OC_TIMING` - indicates that no pin is driven.
|
|||
/// - `Timer.OC_ACTIVE` - the pin will be made active when a compare
|
|||
/// match occurs (active is determined by polarity)
|
|||
/// - `Timer.OC_INACTIVE` - the pin will be made inactive when a compare
|
|||
/// match occurs.
|
|||
/// - `Timer.OC_TOGGLE` - the pin will be toggled when an compare match occurs.
|
|||
/// - `Timer.IC` - configure the timer in Input Capture mode.
|
|||
///
|
|||
/// - `callback` - as per TimerChannel.callback()
|
|||
///
|
|||
/// - `pin` None (the default) or a Pin object. If specified (and not None)
|
|||
/// this will cause the alternate function of the the indicated pin
|
|||
/// to be configured for this timer channel. An error will be raised if
|
|||
/// the pin doesn't support any alternate functions for this timer channel.
|
|||
///
|
|||
/// Keyword arguments for Timer.PWM modes:
|
|||
///
|
|||
/// - 'pulse_width' - determines the initial pulse width to use.
|
|||
///
|
|||
/// Keyword arguments for Timer.OC modes:
|
|||
///
|
|||
/// - `compare` - determines the initial value of the compare register.
|
|||
///
|
|||
/// - `polarity` can be one of:
|
|||
/// - `Timer.HIGH` - output is active high
|
|||
/// - `Timer.LOW` - output is acive low
|
|||
///
|
|||
/// Optional keyword arguments for Timer.IC modes:
|
|||
///
|
|||
/// - `polarity` can be one of:
|
|||
/// - `Timer.RISING` - captures on rising edge.
|
|||
/// - `Timer.FALLING` - captures on falling edge.
|
|||
/// - `Timer.BOTH` - captures on both edges.
|
|||
///
|
|||
/// PWM Example:
|
|||
///
|
|||
/// timer = pyb.Timer(0, prescaler=128, period=37500, counter_mode=pyb.Timer.COUNTER_MODE_CENTER)
|
|||
/// ch0 = t0.channel(0, pyb.Timer.PWM, pin=pyb.Pin.board.D22, pulse_width=(t0.period() + 1) // 4)
|
|||
/// ch1 = t0.channel(1, pyb.Timer.PWM, pin=pyb.Pin.board.D23, pulse_width=(t0.period() + 1) // 2)
|
|||
STATIC const mp_arg_t pyb_timer_channel_args[] = { |
|||
{ MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, |
|||
{ MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, |
|||
{ MP_QSTR_pulse_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, |
|||
{ MP_QSTR_compare, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, |
|||
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, |
|||
}; |
|||
#define PYB_TIMER_CHANNEL_NUM_ARGS MP_ARRAY_SIZE(pyb_timer_channel_args) |
|||
|
|||
STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { |
|||
mp_arg_check_num(n_args, n_args - 2, 2, MP_OBJ_FUN_ARGS_MAX, true); |
|||
|
|||
pyb_timer_obj_t *self = args[0]; |
|||
mp_int_t channel = mp_obj_get_int(args[1]); |
|||
|
|||
if (channel < 0 || channel > 7) { |
|||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid channel (%d)", channel)); |
|||
} |
|||
|
|||
pyb_timer_channel_obj_t *chan = self->channel; |
|||
pyb_timer_channel_obj_t *prev_chan = NULL; |
|||
|
|||
while (chan != NULL) { |
|||
if (chan->channel == channel) { |
|||
break; |
|||
} |
|||
prev_chan = chan; |
|||
chan = chan->next; |
|||
} |
|||
if (kw_args->used == 0) { |
|||
// Return the previously allocated channel
|
|||
if (chan) { |
|||
return chan; |
|||
} |
|||
return mp_const_none; |
|||
} |
|||
|
|||
// If there was already a channel, then remove it from the list. Note that
|
|||
// the order we do things here is important so as to appear atomic to
|
|||
// the IRQ handler.
|
|||
if (chan) { |
|||
// Turn off any IRQ associated with the channel.
|
|||
pyb_timer_channel_callback(chan, mp_const_none); |
|||
|
|||
// Unlink the channel from the list.
|
|||
if (prev_chan) { |
|||
prev_chan->next = chan->next; |
|||
} |
|||
self->channel = chan->next; |
|||
chan->next = NULL; |
|||
} |
|||
|
|||
// Allocate and initialize a new channel
|
|||
mp_arg_val_t vals[PYB_TIMER_CHANNEL_NUM_ARGS]; |
|||
mp_arg_parse_all(n_args - 3, args + 3, kw_args, PYB_TIMER_CHANNEL_NUM_ARGS, pyb_timer_channel_args, vals); |
|||
|
|||
chan = m_new_obj(pyb_timer_channel_obj_t); |
|||
memset(chan, 0, sizeof(*chan)); |
|||
chan->base.type = &pyb_timer_channel_type; |
|||
chan->timer = self; |
|||
chan->channel = channel; |
|||
chan->mode = mp_obj_get_int(args[2]); |
|||
chan->callback = vals[0].u_obj; |
|||
|
|||
mp_obj_t pin_obj = vals[1].u_obj; |
|||
if (pin_obj != mp_const_none) { |
|||
if (!MP_OBJ_IS_TYPE(pin_obj, &pin_type)) { |
|||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "pin argument needs to be be a Pin type")); |
|||
} |
|||
const pin_obj_t *pin = pin_obj; |
|||
const pin_af_obj_t *af = pin_find_af(pin, AF_FN_FTM, self->tim_id); |
|||
if (af == NULL) { |
|||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %s doesn't have an af for TIM%d", qstr_str(pin->name), self->tim_id)); |
|||
} |
|||
// pin.init(mode=AF_PP, af=idx)
|
|||
const mp_obj_t args[6] = { |
|||
(mp_obj_t)&pin_init_obj, |
|||
pin_obj, |
|||
MP_OBJ_NEW_QSTR(MP_QSTR_mode), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_AF_PP), |
|||
MP_OBJ_NEW_QSTR(MP_QSTR_af), MP_OBJ_NEW_SMALL_INT(af->idx) |
|||
}; |
|||
mp_call_method_n_kw(0, 2, args); |
|||
} |
|||
|
|||
// Link the channel to the timer before we turn the channel on.
|
|||
// Note that this needs to appear atomic to the IRQ handler (the write
|
|||
// to self->channel is atomic, so we're good, but I thought I'd mention
|
|||
// in case this was ever changed in the future).
|
|||
chan->next = self->channel; |
|||
self->channel = chan; |
|||
|
|||
switch (chan->mode) { |
|||
|
|||
case CHANNEL_MODE_PWM_NORMAL: |
|||
case CHANNEL_MODE_PWM_INVERTED: { |
|||
FTM_OC_InitTypeDef oc_config; |
|||
oc_config.OCMode = gChannelMode[chan->mode].oc_mode; |
|||
oc_config.Pulse = vals[2].u_int; |
|||
oc_config.OCPolarity = FTM_OCPOLARITY_HIGH; |
|||
|
|||
HAL_FTM_PWM_ConfigChannel(&self->ftm, &oc_config, channel); |
|||
if (chan->callback == mp_const_none) { |
|||
HAL_FTM_PWM_Start(&self->ftm, channel); |
|||
} else { |
|||
HAL_FTM_PWM_Start_IT(&self->ftm, channel); |
|||
} |
|||
break; |
|||
} |
|||
|
|||
case CHANNEL_MODE_OC_TIMING: |
|||
case CHANNEL_MODE_OC_ACTIVE: |
|||
case CHANNEL_MODE_OC_INACTIVE: |
|||
case CHANNEL_MODE_OC_TOGGLE: { |
|||
FTM_OC_InitTypeDef oc_config; |
|||
oc_config.OCMode = gChannelMode[chan->mode].oc_mode; |
|||
oc_config.Pulse = vals[3].u_int; |
|||
oc_config.OCPolarity = vals[4].u_int; |
|||
if (oc_config.OCPolarity == 0xffffffff) { |
|||
oc_config.OCPolarity = FTM_OCPOLARITY_HIGH; |
|||
} |
|||
|
|||
if (!IS_FTM_OC_POLARITY(oc_config.OCPolarity)) { |
|||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid polarity (%d)", oc_config.OCPolarity)); |
|||
} |
|||
HAL_FTM_OC_ConfigChannel(&self->ftm, &oc_config, channel); |
|||
if (chan->callback == mp_const_none) { |
|||
HAL_FTM_OC_Start(&self->ftm, channel); |
|||
} else { |
|||
HAL_FTM_OC_Start_IT(&self->ftm, channel); |
|||
} |
|||
break; |
|||
} |
|||
|
|||
case CHANNEL_MODE_IC: { |
|||
FTM_IC_InitTypeDef ic_config; |
|||
|
|||
ic_config.ICPolarity = vals[4].u_int; |
|||
if (ic_config.ICPolarity == 0xffffffff) { |
|||
ic_config.ICPolarity = FTM_ICPOLARITY_RISING; |
|||
} |
|||
|
|||
if (!IS_FTM_IC_POLARITY(ic_config.ICPolarity)) { |
|||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid polarity (%d)", ic_config.ICPolarity)); |
|||
} |
|||
HAL_FTM_IC_ConfigChannel(&self->ftm, &ic_config, chan->channel); |
|||
if (chan->callback == mp_const_none) { |
|||
HAL_FTM_IC_Start(&self->ftm, channel); |
|||
} else { |
|||
HAL_FTM_IC_Start_IT(&self->ftm, channel); |
|||
} |
|||
break; |
|||
} |
|||
|
|||
default: |
|||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid mode (%d)", chan->mode)); |
|||
} |
|||
return chan; |
|||
} |
|||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_obj, 3, pyb_timer_channel); |
|||
|
|||
/// \method counter([value])
|
|||
/// Get or set the timer counter.
|
|||
mp_obj_t pyb_timer_counter(uint n_args, const mp_obj_t *args) { |
|||
pyb_timer_obj_t *self = args[0]; |
|||
if (n_args == 1) { |
|||
// get
|
|||
return mp_obj_new_int(self->ftm.Instance->CNT); |
|||
} |
|||
// set - In order to write to CNT we need to set CNTIN
|
|||
self->ftm.Instance->CNTIN = mp_obj_get_int(args[1]); |
|||
self->ftm.Instance->CNT = 0; // write any value to load CNTIN into CNT
|
|||
return mp_const_none; |
|||
} |
|||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_counter_obj, 1, 2, pyb_timer_counter); |
|||
|
|||
/// \method prescaler([value])
|
|||
/// Get or set the prescaler for the timer.
|
|||
mp_obj_t pyb_timer_prescaler(uint n_args, const mp_obj_t *args) { |
|||
pyb_timer_obj_t *self = args[0]; |
|||
if (n_args == 1) { |
|||
// get
|
|||
return mp_obj_new_int(1 << (self->ftm.Instance->SC & 7)); |
|||
} |
|||
|
|||
// set
|
|||
mp_uint_t prescaler_shift = get_prescaler_shift(mp_obj_get_int(args[1])); |
|||
|
|||
mp_uint_t sc = self->ftm.Instance->SC; |
|||
sc &= ~7; |
|||
sc |= FTM_SC_PS(prescaler_shift); |
|||
self->ftm.Instance->SC = sc; |
|||
|
|||
return mp_const_none; |
|||
} |
|||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_prescaler_obj, 1, 2, pyb_timer_prescaler); |
|||
|
|||
/// \method period([value])
|
|||
/// Get or set the period of the timer.
|
|||
mp_obj_t pyb_timer_period(uint n_args, const mp_obj_t *args) { |
|||
pyb_timer_obj_t *self = args[0]; |
|||
if (n_args == 1) { |
|||
// get
|
|||
return mp_obj_new_int(self->ftm.Instance->MOD & 0xffff); |
|||
} |
|||
|
|||
// set
|
|||
mp_int_t period = mp_obj_get_int(args[1]) & 0xffff; |
|||
self->ftm.Instance->CNT = 0; |
|||
self->ftm.Instance->MOD = period; |
|||
return mp_const_none; |
|||
} |
|||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_period_obj, 1, 2, pyb_timer_period); |
|||
|
|||
/// \method callback(fun)
|
|||
/// Set the function to be called when the timer triggers.
|
|||
/// `fun` is passed 1 argument, the timer object.
|
|||
/// If `fun` is `None` then the callback will be disabled.
|
|||
STATIC mp_obj_t pyb_timer_callback(mp_obj_t self_in, mp_obj_t callback) { |
|||
pyb_timer_obj_t *self = self_in; |
|||
if (callback == mp_const_none) { |
|||
// stop interrupt (but not timer)
|
|||
__HAL_FTM_DISABLE_TOF_IT(&self->ftm); |
|||
self->callback = mp_const_none; |
|||
} else if (mp_obj_is_callable(callback)) { |
|||
self->callback = callback; |
|||
HAL_NVIC_EnableIRQ(self->irqn); |
|||
// start timer, so that it interrupts on overflow
|
|||
HAL_FTM_Base_Start_IT(&self->ftm); |
|||
} else { |
|||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "callback must be None or a callable object")); |
|||
} |
|||
return mp_const_none; |
|||
} |
|||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_timer_callback_obj, pyb_timer_callback); |
|||
|
|||
#if MICROPY_TIMER_REG |
|||
reg_t timer_reg[] = { |
|||
REG_ENTRY(FTM_TypeDef, SC), |
|||
REG_ENTRY(FTM_TypeDef, CNT), |
|||
REG_ENTRY(FTM_TypeDef, MOD), |
|||
REG_ENTRY(FTM_TypeDef, CNTIN), |
|||
REG_ENTRY(FTM_TypeDef, STATUS), |
|||
REG_ENTRY(FTM_TypeDef, MODE), |
|||
REG_ENTRY(FTM_TypeDef, SYNC), |
|||
REG_ENTRY(FTM_TypeDef, OUTINIT), |
|||
REG_ENTRY(FTM_TypeDef, OUTMASK), |
|||
REG_ENTRY(FTM_TypeDef, COMBINE), |
|||
REG_ENTRY(FTM_TypeDef, DEADTIME), |
|||
REG_ENTRY(FTM_TypeDef, EXTTRIG), |
|||
REG_ENTRY(FTM_TypeDef, POL), |
|||
REG_ENTRY(FTM_TypeDef, FMS), |
|||
REG_ENTRY(FTM_TypeDef, FILTER), |
|||
REG_ENTRY(FTM_TypeDef, FLTCTRL), |
|||
REG_ENTRY(FTM_TypeDef, QDCTRL), |
|||
REG_ENTRY(FTM_TypeDef, CONF), |
|||
REG_ENTRY(FTM_TypeDef, FLTPOL), |
|||
REG_ENTRY(FTM_TypeDef, SYNCONF), |
|||
REG_ENTRY(FTM_TypeDef, INVCTRL), |
|||
REG_ENTRY(FTM_TypeDef, SWOCTRL), |
|||
REG_ENTRY(FTM_TypeDef, PWMLOAD), |
|||
}; |
|||
|
|||
mp_obj_t pyb_timer_reg(uint n_args, const mp_obj_t *args) { |
|||
pyb_timer_obj_t *self = args[0]; |
|||
return reg_cmd(self->ftm.Instance, timer_reg, MP_ARRAY_SIZE(timer_reg), n_args - 1, args + 1); |
|||
} |
|||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_reg_obj, 1, 3, pyb_timer_reg); |
|||
#endif // MICROPY_TIMER_REG
|
|||
|
|||
STATIC const mp_map_elem_t pyb_timer_locals_dict_table[] = { |
|||
// instance methods
|
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_timer_init_obj }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_timer_deinit_obj }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_channel), (mp_obj_t)&pyb_timer_channel_obj }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_counter), (mp_obj_t)&pyb_timer_counter_obj }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_prescaler), (mp_obj_t)&pyb_timer_prescaler_obj }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_period), (mp_obj_t)&pyb_timer_period_obj }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_timer_callback_obj }, |
|||
#if MICROPY_TIMER_REG |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_reg), (mp_obj_t)&pyb_timer_reg_obj }, |
|||
#endif |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_UP), MP_OBJ_NEW_SMALL_INT(FTM_COUNTERMODE_UP) }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_CENTER), MP_OBJ_NEW_SMALL_INT(FTM_COUNTERMODE_CENTER) }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PWM), MP_OBJ_NEW_SMALL_INT(CHANNEL_MODE_PWM_NORMAL) }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PWM_INVERTED), MP_OBJ_NEW_SMALL_INT(CHANNEL_MODE_PWM_INVERTED) }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_OC_TIMING), MP_OBJ_NEW_SMALL_INT(CHANNEL_MODE_OC_TIMING) }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_OC_ACTIVE), MP_OBJ_NEW_SMALL_INT(CHANNEL_MODE_OC_ACTIVE) }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_OC_INACTIVE), MP_OBJ_NEW_SMALL_INT(CHANNEL_MODE_OC_INACTIVE) }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_OC_TOGGLE), MP_OBJ_NEW_SMALL_INT(CHANNEL_MODE_OC_TOGGLE) }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IC), MP_OBJ_NEW_SMALL_INT(CHANNEL_MODE_IC) }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_HIGH), MP_OBJ_NEW_SMALL_INT(FTM_OCPOLARITY_HIGH) }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_LOW), MP_OBJ_NEW_SMALL_INT(FTM_OCPOLARITY_LOW) }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RISING), MP_OBJ_NEW_SMALL_INT(FTM_ICPOLARITY_RISING) }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_FALLING), MP_OBJ_NEW_SMALL_INT(FTM_ICPOLARITY_FALLING) }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BOTH), MP_OBJ_NEW_SMALL_INT(FTM_ICPOLARITY_BOTH) }, |
|||
}; |
|||
|
|||
STATIC MP_DEFINE_CONST_DICT(pyb_timer_locals_dict, pyb_timer_locals_dict_table); |
|||
|
|||
const mp_obj_type_t pyb_timer_type = { |
|||
{ &mp_type_type }, |
|||
.name = MP_QSTR_Timer, |
|||
.print = pyb_timer_print, |
|||
.make_new = pyb_timer_make_new, |
|||
.locals_dict = (mp_obj_t)&pyb_timer_locals_dict, |
|||
}; |
|||
|
|||
/// \moduleref pyb
|
|||
/// \class TimerChannel - setup a channel for a timer.
|
|||
///
|
|||
/// Timer channels are used to generate/capture a signal using a timer.
|
|||
///
|
|||
/// TimerChannel objects are created using the Timer.channel() method.
|
|||
STATIC void pyb_timer_channel_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { |
|||
pyb_timer_channel_obj_t *self = self_in; |
|||
|
|||
print(env, "TimerChannel(timer=%u, channel=%u mode=%s)", |
|||
self->timer->tim_id, |
|||
self->channel, |
|||
qstr_str(gChannelMode[self->mode].name)); |
|||
} |
|||
|
|||
/// \method capture([value])
|
|||
/// Get or set the capture value associated with a channel.
|
|||
/// capture, compare, and pulse_width are all aliases for the same function.
|
|||
/// capture is the logical name to use when the channel is in input capture mode.
|
|||
|
|||
/// \method compare([value])
|
|||
/// Get or set the compare value associated with a channel.
|
|||
/// capture, compare, and pulse_width are all aliases for the same function.
|
|||
/// compare is the logical name to use when the channel is in output compare mode.
|
|||
|
|||
/// \method pulse_width([value])
|
|||
/// Get or set the pulse width value associated with a channel.
|
|||
/// capture, compare, and pulse_width are all aliases for the same function.
|
|||
/// pulse_width is the logical name to use when the channel is in PWM mode.
|
|||
STATIC mp_obj_t pyb_timer_channel_capture_compare(uint n_args, const mp_obj_t *args) { |
|||
pyb_timer_channel_obj_t *self = args[0]; |
|||
if (self->channel == 0xffffffff) { |
|||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Timer %d no channel specified", self->timer->tim_id)); |
|||
} |
|||
FTM_TypeDef *FTMx = self->timer->ftm.Instance; |
|||
if (n_args == 1) { |
|||
// get
|
|||
return mp_obj_new_int(FTMx->channel[self->channel].CV); |
|||
} |
|||
|
|||
mp_int_t pw = mp_obj_get_int(args[1]); |
|||
|
|||
// set
|
|||
FTMx->channel[self->channel].CV = pw; |
|||
return mp_const_none; |
|||
} |
|||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_capture_compare_obj, 1, 2, pyb_timer_channel_capture_compare); |
|||
|
|||
/// \method callback(fun)
|
|||
/// Set the function to be called when the timer channel triggers.
|
|||
/// `fun` is passed 1 argument, the timer object.
|
|||
/// If `fun` is `None` then the callback will be disabled.
|
|||
STATIC mp_obj_t pyb_timer_channel_callback(mp_obj_t self_in, mp_obj_t callback) { |
|||
pyb_timer_channel_obj_t *self = self_in; |
|||
if (callback == mp_const_none) { |
|||
// stop interrupt (but not timer)
|
|||
__HAL_FTM_DISABLE_CH_IT(&self->timer->ftm, self->channel); |
|||
self->callback = mp_const_none; |
|||
} else if (mp_obj_is_callable(callback)) { |
|||
self->callback = callback; |
|||
HAL_NVIC_EnableIRQ(self->timer->irqn); |
|||
// start timer, so that it interrupts on overflow
|
|||
switch (self->mode) { |
|||
case CHANNEL_MODE_PWM_NORMAL: |
|||
case CHANNEL_MODE_PWM_INVERTED: |
|||
HAL_FTM_PWM_Start_IT(&self->timer->ftm, self->channel); |
|||
break; |
|||
case CHANNEL_MODE_OC_TIMING: |
|||
case CHANNEL_MODE_OC_ACTIVE: |
|||
case CHANNEL_MODE_OC_INACTIVE: |
|||
case CHANNEL_MODE_OC_TOGGLE: |
|||
HAL_FTM_OC_Start_IT(&self->timer->ftm, self->channel); |
|||
break; |
|||
case CHANNEL_MODE_IC: |
|||
HAL_FTM_IC_Start_IT(&self->timer->ftm, self->channel); |
|||
break; |
|||
} |
|||
} else { |
|||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "callback must be None or a callable object")); |
|||
} |
|||
return mp_const_none; |
|||
} |
|||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_timer_channel_callback_obj, pyb_timer_channel_callback); |
|||
|
|||
#if MICROPY_TIMER_REG |
|||
reg_t timer_channel_reg[] = { |
|||
REG_ENTRY(FTM_ChannelTypeDef, CSC), |
|||
REG_ENTRY(FTM_ChannelTypeDef, CV), |
|||
}; |
|||
|
|||
mp_obj_t pyb_timer_channel_reg(uint n_args, const mp_obj_t *args) { |
|||
pyb_timer_channel_obj_t *self = args[0]; |
|||
return reg_cmd(&self->timer->ftm.Instance->channel[self->channel], |
|||
timer_channel_reg, MP_ARRAY_SIZE(timer_channel_reg), |
|||
n_args - 1, args + 1); |
|||
} |
|||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_reg_obj, 1, 3, pyb_timer_channel_reg); |
|||
#endif |
|||
|
|||
STATIC const mp_map_elem_t pyb_timer_channel_locals_dict_table[] = { |
|||
// instance methods
|
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_timer_channel_callback_obj }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_pulse_width), (mp_obj_t)&pyb_timer_channel_capture_compare_obj }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_capture), (mp_obj_t)&pyb_timer_channel_capture_compare_obj }, |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_compare), (mp_obj_t)&pyb_timer_channel_capture_compare_obj }, |
|||
#if MICROPY_TIMER_REG |
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_reg), (mp_obj_t)&pyb_timer_channel_reg_obj }, |
|||
#endif |
|||
}; |
|||
STATIC MP_DEFINE_CONST_DICT(pyb_timer_channel_locals_dict, pyb_timer_channel_locals_dict_table); |
|||
|
|||
const mp_obj_type_t pyb_timer_channel_type = { |
|||
{ &mp_type_type }, |
|||
.name = MP_QSTR_TimerChannel, |
|||
.print = pyb_timer_channel_print, |
|||
.locals_dict = (mp_obj_t)&pyb_timer_channel_locals_dict, |
|||
}; |
|||
|
|||
STATIC bool ftm_handle_irq_callback(pyb_timer_obj_t *self, mp_uint_t channel, mp_obj_t callback) { |
|||
// execute callback if it's set
|
|||
if (callback == mp_const_none) { |
|||
return false; |
|||
} |
|||
bool handled = false; |
|||
|
|||
// When executing code within a handler we must lock the GC to prevent
|
|||
// any memory allocations. We must also catch any exceptions.
|
|||
gc_lock(); |
|||
nlr_buf_t nlr; |
|||
if (nlr_push(&nlr) == 0) { |
|||
mp_call_function_1(callback, self); |
|||
nlr_pop(); |
|||
handled = true; |
|||
} else { |
|||
// Uncaught exception; disable the callback so it doesn't run again.
|
|||
self->callback = mp_const_none; |
|||
if (channel == 0xffffffff) { |
|||
printf("Uncaught exception in Timer(" UINT_FMT |
|||
") interrupt handler\n", self->tim_id); |
|||
} else { |
|||
printf("Uncaught exception in Timer(" UINT_FMT ") channel " |
|||
UINT_FMT " interrupt handler\n", self->tim_id, channel); |
|||
} |
|||
mp_obj_print_exception((mp_obj_t)nlr.ret_val); |
|||
} |
|||
gc_unlock(); |
|||
return handled; |
|||
} |
|||
|
|||
STATIC void ftm_irq_handler(uint tim_id) { |
|||
if (tim_id >= PYB_TIMER_OBJ_ALL_NUM) { |
|||
return; |
|||
} |
|||
// get the timer object
|
|||
pyb_timer_obj_t *self = pyb_timer_obj_all[tim_id]; |
|||
if (self == NULL) { |
|||
// timer object has not been set, so we can't do anything
|
|||
printf("No timer object for id=%d\n", tim_id); |
|||
return; |
|||
} |
|||
FTM_HandleTypeDef *hftm = &self->ftm; |
|||
|
|||
bool handled = false; |
|||
|
|||
// Check for timer (versus timer channel) interrupt.
|
|||
if (__HAL_FTM_GET_TOF_IT(hftm) && __HAL_FTM_GET_TOF_FLAG(hftm)) { |
|||
__HAL_FTM_CLEAR_TOF_FLAG(hftm); |
|||
if (ftm_handle_irq_callback(self, 0xffffffff, self->callback)) { |
|||
handled = true; |
|||
} else { |
|||
__HAL_FTM_DISABLE_TOF_IT(&self->ftm); |
|||
printf("No callback for Timer %d TOF (now disabled)\n", tim_id); |
|||
} |
|||
} |
|||
|
|||
uint32_t processed = 0; |
|||
|
|||
// Check to see if a timer channel interrupt is pending
|
|||
pyb_timer_channel_obj_t *chan = self->channel; |
|||
while (chan != NULL) { |
|||
processed |= (1 << chan->channel); |
|||
if (__HAL_FTM_GET_CH_IT(&self->ftm, chan->channel) && __HAL_FTM_GET_CH_FLAG(&self->ftm, chan->channel)) { |
|||
__HAL_FTM_CLEAR_CH_FLAG(&self->ftm, chan->channel); |
|||
if (ftm_handle_irq_callback(self, chan->channel, chan->callback)) { |
|||
handled = true; |
|||
} else { |
|||
__HAL_FTM_DISABLE_CH_IT(&self->ftm, chan->channel); |
|||
printf("No callback for Timer %d channel %u (now disabled)\n", |
|||
self->tim_id, chan->channel); |
|||
} |
|||
} |
|||
chan = chan->next; |
|||
} |
|||
|
|||
if (!handled) { |
|||
// An interrupt occurred for a channel we didn't process. Find it and
|
|||
// turn it off.
|
|||
for (mp_uint_t channel = 0; channel < 8; channel++) { |
|||
if ((processed & (1 << channel)) == 0) { |
|||
if (__HAL_FTM_GET_CH_FLAG(&self->ftm, channel) != 0) { |
|||
__HAL_FTM_CLEAR_CH_FLAG(&self->ftm, channel); |
|||
__HAL_FTM_DISABLE_CH_IT(&self->ftm, channel); |
|||
printf("Unhandled interrupt Timer %d channel %u (now disabled)\n", |
|||
tim_id, channel); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
void ftm0_isr(void) { |
|||
ftm_irq_handler(0); |
|||
} |
|||
|
|||
void ftm1_isr(void) { |
|||
ftm_irq_handler(1); |
|||
} |
|||
|
|||
void ftm2_isr(void) { |
|||
ftm_irq_handler(2); |
|||
} |
@ -0,0 +1,31 @@ |
|||
/*
|
|||
* This file is part of the Micro Python project, http://micropython.org/
|
|||
* |
|||
* The MIT License (MIT) |
|||
* |
|||
* Copyright (c) 2013, 2014 Damien P. George |
|||
* |
|||
* 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. |
|||
*/ |
|||
|
|||
extern const mp_obj_type_t pyb_timer_type; |
|||
extern const mp_obj_type_t pyb_timer_channel_type; |
|||
|
|||
void timer_init0(void); |
|||
void timer_deinit(void); |
Loading…
Reference in new issue