summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--stmhal/boards/PYBLITEV10/mpconfigboard.h3
-rw-r--r--stmhal/boards/PYBV10/mpconfigboard.h3
-rw-r--r--stmhal/boards/PYBV11/mpconfigboard.h3
-rw-r--r--stmhal/boards/PYBV4/mpconfigboard.h3
-rw-r--r--stmhal/led.c158
-rw-r--r--stmhal/timer.c3
-rw-r--r--stmhal/timer.h3
7 files changed, 161 insertions, 15 deletions
diff --git a/stmhal/boards/PYBLITEV10/mpconfigboard.h b/stmhal/boards/PYBLITEV10/mpconfigboard.h
index fb839888cb..452d3061ad 100644
--- a/stmhal/boards/PYBLITEV10/mpconfigboard.h
+++ b/stmhal/boards/PYBLITEV10/mpconfigboard.h
@@ -70,7 +70,8 @@
#define MICROPY_HW_LED2 (pin_A14) // green
#define MICROPY_HW_LED3 (pin_A15) // yellow
#define MICROPY_HW_LED4 (pin_B4) // blue
-#define MICROPY_HW_LED4_PWM (0) // TIM3 is now a user timer
+#define MICROPY_HW_LED3_PWM { TIM2, 2, GPIO_AF1_TIM2 }
+#define MICROPY_HW_LED4_PWM { TIM3, 3, GPIO_AF2_TIM3 }
#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP)
#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask)
#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask)
diff --git a/stmhal/boards/PYBV10/mpconfigboard.h b/stmhal/boards/PYBV10/mpconfigboard.h
index 34207be560..f8cb14b518 100644
--- a/stmhal/boards/PYBV10/mpconfigboard.h
+++ b/stmhal/boards/PYBV10/mpconfigboard.h
@@ -81,7 +81,8 @@
#define MICROPY_HW_LED2 (pin_A14) // green
#define MICROPY_HW_LED3 (pin_A15) // yellow
#define MICROPY_HW_LED4 (pin_B4) // blue
-#define MICROPY_HW_LED4_PWM (1)
+#define MICROPY_HW_LED3_PWM { TIM2, 2, GPIO_AF1_TIM2 }
+#define MICROPY_HW_LED4_PWM { TIM3, 3, GPIO_AF2_TIM3 }
#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP)
#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask)
#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask)
diff --git a/stmhal/boards/PYBV11/mpconfigboard.h b/stmhal/boards/PYBV11/mpconfigboard.h
index 7bc48e8b8a..30a14badec 100644
--- a/stmhal/boards/PYBV11/mpconfigboard.h
+++ b/stmhal/boards/PYBV11/mpconfigboard.h
@@ -81,7 +81,8 @@
#define MICROPY_HW_LED2 (pin_A14) // green
#define MICROPY_HW_LED3 (pin_A15) // yellow
#define MICROPY_HW_LED4 (pin_B4) // blue
-#define MICROPY_HW_LED4_PWM (1)
+#define MICROPY_HW_LED3_PWM { TIM2, 2, GPIO_AF1_TIM2 }
+#define MICROPY_HW_LED4_PWM { TIM3, 3, GPIO_AF2_TIM3 }
#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP)
#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask)
#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask)
diff --git a/stmhal/boards/PYBV4/mpconfigboard.h b/stmhal/boards/PYBV4/mpconfigboard.h
index 48e328604d..663564eb98 100644
--- a/stmhal/boards/PYBV4/mpconfigboard.h
+++ b/stmhal/boards/PYBV4/mpconfigboard.h
@@ -78,7 +78,8 @@
#define MICROPY_HW_LED2 (pin_A14) // green
#define MICROPY_HW_LED3 (pin_A15) // yellow
#define MICROPY_HW_LED4 (pin_B4) // blue
-#define MICROPY_HW_LED4_PWM (1)
+#define MICROPY_HW_LED3_PWM { TIM2, 2, GPIO_AF1_TIM2 }
+#define MICROPY_HW_LED4_PWM { TIM3, 3, GPIO_AF2_TIM3 }
#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP)
#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask)
#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask)
diff --git a/stmhal/led.c b/stmhal/led.c
index ee03d3fd00..fcdb88c9c3 100644
--- a/stmhal/led.c
+++ b/stmhal/led.c
@@ -1,9 +1,9 @@
/*
- * This file is part of the Micro Python project, http://micropython.org/
+ * This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
- * Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2013-2016 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
@@ -36,11 +36,6 @@
#if defined(MICROPY_HW_LED1)
-// default is to not PWM LED4
-#if !defined(MICROPY_HW_LED4_PWM)
-#define MICROPY_HW_LED4_PWM (0)
-#endif
-
/// \moduleref pyb
/// \class LED - LED object
///
@@ -85,10 +80,120 @@ void led_init(void) {
}
}
+#if defined(MICROPY_HW_LED1_PWM) \
+ || defined(MICROPY_HW_LED2_PWM) \
+ || defined(MICROPY_HW_LED3_PWM) \
+ || defined(MICROPY_HW_LED4_PWM)
+
+// The following is semi-generic code to control LEDs using PWM.
+// It currently supports TIM2 and TIM3, channel 1 only.
+// Configure by defining the relevant MICROPY_HW_LEDx_PWM macros in mpconfigboard.h.
+// If they are not defined then PWM will not be available for that LED.
+
+#define LED_PWM_ENABLED (1)
+
+#ifndef MICROPY_HW_LED1_PWM
+#define MICROPY_HW_LED1_PWM { NULL, 0, 0 }
+#endif
+#ifndef MICROPY_HW_LED2_PWM
+#define MICROPY_HW_LED2_PWM { NULL, 0, 0 }
+#endif
+#ifndef MICROPY_HW_LED3_PWM
+#define MICROPY_HW_LED3_PWM { NULL, 0, 0 }
+#endif
+#ifndef MICROPY_HW_LED4_PWM
+#define MICROPY_HW_LED4_PWM { NULL, 0, 0 }
+#endif
+
+#define LED_PWM_TIM_PERIOD (10000) // TIM runs at 1MHz and fires every 10ms
+
+typedef struct _led_pwm_config_t {
+ TIM_TypeDef *tim;
+ uint8_t tim_id;
+ uint8_t alt_func;
+} led_pwm_config_t;
+
+STATIC const led_pwm_config_t led_pwm_config[] = {
+ MICROPY_HW_LED1_PWM,
+ MICROPY_HW_LED2_PWM,
+ MICROPY_HW_LED3_PWM,
+ MICROPY_HW_LED4_PWM,
+};
+
+STATIC uint8_t led_pwm_state = 0;
+
+static inline bool led_pwm_is_enabled(int led) {
+ return (led_pwm_state & (1 << led)) != 0;
+}
+
+// this function has a large stack so it should not be inlined
+STATIC void led_pwm_init(int led) __attribute__((noinline));
+STATIC void led_pwm_init(int led) {
+ const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin;
+ const led_pwm_config_t *pwm_cfg = &led_pwm_config[led - 1];
+
+ // GPIO configuration
+ GPIO_InitTypeDef gpio_init;
+ gpio_init.Pin = led_pin->pin_mask;
+ gpio_init.Mode = GPIO_MODE_AF_PP;
+ gpio_init.Speed = GPIO_SPEED_FAST;
+ gpio_init.Pull = GPIO_NOPULL;
+ gpio_init.Alternate = pwm_cfg->alt_func;
+ HAL_GPIO_Init(led_pin->gpio, &gpio_init);
+
+ // TIM configuration
+ switch (pwm_cfg->tim_id) {
+ case 2: __TIM2_CLK_ENABLE(); break;
+ case 3: __TIM3_CLK_ENABLE(); break;
+ default: assert(0);
+ }
+ TIM_HandleTypeDef tim;
+ tim.Instance = pwm_cfg->tim;
+ tim.Init.Period = LED_PWM_TIM_PERIOD - 1;
+ tim.Init.Prescaler = timer_get_source_freq(pwm_cfg->tim_id) / 1000000 - 1; // TIM runs at 1MHz
+ tim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
+ tim.Init.CounterMode = TIM_COUNTERMODE_UP;
+ HAL_TIM_PWM_Init(&tim);
+
+ // PWM configuration (only channel 1 supported at the moment)
+ TIM_OC_InitTypeDef oc_init;
+ oc_init.OCMode = TIM_OCMODE_PWM1;
+ oc_init.Pulse = 0; // off
+ oc_init.OCPolarity = TIM_OCPOLARITY_HIGH;
+ oc_init.OCFastMode = TIM_OCFAST_DISABLE;
+ /* needed only for TIM1 and TIM8
+ oc_init.OCNPolarity = TIM_OCNPOLARITY_HIGH;
+ oc_init.OCIdleState = TIM_OCIDLESTATE_SET;
+ oc_init.OCNIdleState = TIM_OCNIDLESTATE_SET;
+ */
+ HAL_TIM_PWM_ConfigChannel(&tim, &oc_init, TIM_CHANNEL_1);
+ HAL_TIM_PWM_Start(&tim, TIM_CHANNEL_1);
+
+ // indicate that this LED is using PWM
+ led_pwm_state |= 1 << led;
+}
+
+STATIC void led_pwm_deinit(int led) {
+ // make the LED's pin a standard GPIO output pin
+ const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin;
+ GPIO_TypeDef *g = led_pin->gpio;
+ uint32_t pin = led_pin->pin;
+ static const int mode = 1; // output
+ static const int alt = 0; // no alt func
+ g->MODER = (g->MODER & ~(3 << (2 * pin))) | (mode << (2 * pin));
+ g->AFR[pin >> 3] = (g->AFR[pin >> 3] & ~(15 << (4 * (pin & 7)))) | (alt << (4 * (pin & 7)));
+ led_pwm_state &= ~(1 << led);
+}
+
+#else
+#define LED_PWM_ENABLED (0)
+#endif
+
void led_state(pyb_led_t led, int state) {
if (led < 1 || led > NUM_LEDS) {
return;
}
+
const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin;
//printf("led_state(%d,%d)\n", led, state);
if (state == 0) {
@@ -98,6 +203,12 @@ void led_state(pyb_led_t led, int state) {
// turn LED on
MICROPY_HW_LED_ON(led_pin);
}
+
+ #if LED_PWM_ENABLED
+ if (led_pwm_is_enabled(led)) {
+ led_pwm_deinit(led);
+ }
+ #endif
}
void led_toggle(pyb_led_t led) {
@@ -105,6 +216,14 @@ void led_toggle(pyb_led_t led) {
return;
}
+ #if LED_PWM_ENABLED
+ if (led_pwm_is_enabled(led)) {
+ // if PWM is enabled then LED has non-zero intensity, so turn it off
+ led_state(led, 0);
+ return;
+ }
+ #endif
+
// toggle the output data register to toggle the LED state
const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin;
led_pin->gpio->ODR ^= led_pin->pin_mask;
@@ -115,6 +234,17 @@ int led_get_intensity(pyb_led_t led) {
return 0;
}
+ #if LED_PWM_ENABLED
+ if (led_pwm_is_enabled(led)) {
+ TIM_TypeDef *tim = led_pwm_config[led - 1].tim;
+ mp_uint_t i = (tim->CCR1 * 255 + LED_PWM_TIM_PERIOD - 2) / (LED_PWM_TIM_PERIOD - 1);
+ if (i > 255) {
+ i = 255;
+ }
+ return i;
+ }
+ #endif
+
const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin;
GPIO_TypeDef *gpio = led_pin->gpio;
@@ -129,6 +259,20 @@ int led_get_intensity(pyb_led_t led) {
}
void led_set_intensity(pyb_led_t led, mp_int_t intensity) {
+ #if LED_PWM_ENABLED
+ if (intensity > 0 && intensity < 255) {
+ TIM_TypeDef *tim = led_pwm_config[led - 1].tim;
+ if (tim != NULL) {
+ // set intensity using PWM pulse width
+ if (!led_pwm_is_enabled(led)) {
+ led_pwm_init(led);
+ }
+ tim->CCR1 = intensity * (LED_PWM_TIM_PERIOD - 1) / 255;
+ return;
+ }
+ }
+ #endif
+
// intensity not supported for this LED; just turn it on/off
led_state(led, intensity > 0);
}
diff --git a/stmhal/timer.c b/stmhal/timer.c
index 9caa056a2f..8d462975e1 100644
--- a/stmhal/timer.c
+++ b/stmhal/timer.c
@@ -147,7 +147,6 @@ TIM_HandleTypeDef TIM6_Handle;
#define PYB_TIMER_OBJ_ALL_NUM MP_ARRAY_SIZE(MP_STATE_PORT(pyb_timer_obj_all))
-STATIC uint32_t timer_get_source_freq(uint32_t tim_id);
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);
@@ -229,7 +228,7 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
// 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 timer_get_source_freq(uint32_t tim_id) {
uint32_t source;
if (tim_id == 1 || (8 <= tim_id && tim_id <= 11)) {
// TIM{1,8,9,10,11} are on APB2
diff --git a/stmhal/timer.h b/stmhal/timer.h
index 89b3c79f4f..a18d7cf104 100644
--- a/stmhal/timer.h
+++ b/stmhal/timer.h
@@ -31,9 +31,8 @@ extern const mp_obj_type_t pyb_timer_type;
void timer_init0(void);
void timer_tim5_init(void);
TIM_HandleTypeDef *timer_tim6_init(uint freq);
-
void timer_deinit(void);
-
+uint32_t timer_get_source_freq(uint32_t tim_id);
void timer_irq_handler(uint tim_id);
TIM_HandleTypeDef *pyb_timer_get_handle(mp_obj_t timer);