Skip to content

Commit 1dc2862

Browse files
committed
stmhal/led: Allow LEDs to be in PWM mode with TIM1 and channels 1-4.
This allows PYBv3 to use PWM for LED(1) and LED(2).
1 parent 68a7a92 commit 1dc2862

6 files changed

Lines changed: 41 additions & 30 deletions

File tree

stmhal/boards/PYBLITEV10/mpconfigboard.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@
7171
#define MICROPY_HW_LED2 (pin_A14) // green
7272
#define MICROPY_HW_LED3 (pin_A15) // yellow
7373
#define MICROPY_HW_LED4 (pin_B4) // blue
74-
#define MICROPY_HW_LED3_PWM { TIM2, 2, GPIO_AF1_TIM2 }
75-
#define MICROPY_HW_LED4_PWM { TIM3, 3, GPIO_AF2_TIM3 }
74+
#define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 }
75+
#define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 }
7676
#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP)
7777
#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask)
7878
#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask)

stmhal/boards/PYBV10/mpconfigboard.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@
8282
#define MICROPY_HW_LED2 (pin_A14) // green
8383
#define MICROPY_HW_LED3 (pin_A15) // yellow
8484
#define MICROPY_HW_LED4 (pin_B4) // blue
85-
#define MICROPY_HW_LED3_PWM { TIM2, 2, GPIO_AF1_TIM2 }
86-
#define MICROPY_HW_LED4_PWM { TIM3, 3, GPIO_AF2_TIM3 }
85+
#define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 }
86+
#define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 }
8787
#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP)
8888
#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask)
8989
#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask)

stmhal/boards/PYBV11/mpconfigboard.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@
8282
#define MICROPY_HW_LED2 (pin_A14) // green
8383
#define MICROPY_HW_LED3 (pin_A15) // yellow
8484
#define MICROPY_HW_LED4 (pin_B4) // blue
85-
#define MICROPY_HW_LED3_PWM { TIM2, 2, GPIO_AF1_TIM2 }
86-
#define MICROPY_HW_LED4_PWM { TIM3, 3, GPIO_AF2_TIM3 }
85+
#define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 }
86+
#define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 }
8787
#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP)
8888
#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask)
8989
#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask)

stmhal/boards/PYBV3/mpconfigboard.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,13 @@
6666
#define MICROPY_HW_USRSW_PRESSED (0)
6767

6868
// LEDs
69+
#define MICROPY_HW_LED_INVERTED (1) // LEDs are on when pin is driven low
6970
#define MICROPY_HW_LED1 (pin_A8) // R1 - red
7071
#define MICROPY_HW_LED2 (pin_A10) // R2 - red
7172
#define MICROPY_HW_LED3 (pin_C4) // G1 - green
7273
#define MICROPY_HW_LED4 (pin_C5) // G2 - green
74+
#define MICROPY_HW_LED1_PWM { TIM1, 1, TIM_CHANNEL_1, GPIO_AF1_TIM1 }
75+
#define MICROPY_HW_LED2_PWM { TIM1, 1, TIM_CHANNEL_3, GPIO_AF1_TIM1 }
7376
#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP)
7477
#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRH = pin->pin_mask)
7578
#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRL = pin->pin_mask)

stmhal/boards/PYBV4/mpconfigboard.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@
7979
#define MICROPY_HW_LED2 (pin_A14) // green
8080
#define MICROPY_HW_LED3 (pin_A15) // yellow
8181
#define MICROPY_HW_LED4 (pin_B4) // blue
82-
#define MICROPY_HW_LED3_PWM { TIM2, 2, GPIO_AF1_TIM2 }
83-
#define MICROPY_HW_LED4_PWM { TIM3, 3, GPIO_AF2_TIM3 }
82+
#define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 }
83+
#define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 }
8484
#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP)
8585
#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask)
8686
#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask)

stmhal/led.c

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@
4141
///
4242
/// The LED object controls an individual LED (Light Emitting Diode).
4343

44+
// the default is that LEDs are not inverted, and pin driven high turns them on
45+
#ifndef MICROPY_HW_LED_INVERTED
46+
#define MICROPY_HW_LED_INVERTED (0)
47+
#endif
48+
4449
typedef struct _pyb_led_obj_t {
4550
mp_obj_base_t base;
4651
mp_uint_t led_id;
@@ -86,30 +91,34 @@ void led_init(void) {
8691
|| defined(MICROPY_HW_LED4_PWM)
8792

8893
// The following is semi-generic code to control LEDs using PWM.
89-
// It currently supports TIM2 and TIM3, channel 1 only.
94+
// It currently supports TIM1, TIM2 and TIM3, channels 1-4.
9095
// Configure by defining the relevant MICROPY_HW_LEDx_PWM macros in mpconfigboard.h.
9196
// If they are not defined then PWM will not be available for that LED.
9297

9398
#define LED_PWM_ENABLED (1)
9499

95100
#ifndef MICROPY_HW_LED1_PWM
96-
#define MICROPY_HW_LED1_PWM { NULL, 0, 0 }
101+
#define MICROPY_HW_LED1_PWM { NULL, 0, 0, 0 }
97102
#endif
98103
#ifndef MICROPY_HW_LED2_PWM
99-
#define MICROPY_HW_LED2_PWM { NULL, 0, 0 }
104+
#define MICROPY_HW_LED2_PWM { NULL, 0, 0, 0 }
100105
#endif
101106
#ifndef MICROPY_HW_LED3_PWM
102-
#define MICROPY_HW_LED3_PWM { NULL, 0, 0 }
107+
#define MICROPY_HW_LED3_PWM { NULL, 0, 0, 0 }
103108
#endif
104109
#ifndef MICROPY_HW_LED4_PWM
105-
#define MICROPY_HW_LED4_PWM { NULL, 0, 0 }
110+
#define MICROPY_HW_LED4_PWM { NULL, 0, 0, 0 }
106111
#endif
107112

108113
#define LED_PWM_TIM_PERIOD (10000) // TIM runs at 1MHz and fires every 10ms
109114

115+
// this gives the address of the CCR register for channels 1-4
116+
#define LED_PWM_CCR(pwm_cfg) ((volatile uint32_t*)&(pwm_cfg)->tim->CCR1 + ((pwm_cfg)->tim_channel >> 2))
117+
110118
typedef struct _led_pwm_config_t {
111119
TIM_TypeDef *tim;
112120
uint8_t tim_id;
121+
uint8_t tim_channel;
113122
uint8_t alt_func;
114123
} led_pwm_config_t;
115124

@@ -143,6 +152,7 @@ STATIC void led_pwm_init(int led) {
143152

144153
// TIM configuration
145154
switch (pwm_cfg->tim_id) {
155+
case 1: __TIM1_CLK_ENABLE(); break;
146156
case 2: __TIM2_CLK_ENABLE(); break;
147157
case 3: __TIM3_CLK_ENABLE(); break;
148158
default: assert(0);
@@ -153,21 +163,20 @@ STATIC void led_pwm_init(int led) {
153163
tim.Init.Prescaler = timer_get_source_freq(pwm_cfg->tim_id) / 1000000 - 1; // TIM runs at 1MHz
154164
tim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
155165
tim.Init.CounterMode = TIM_COUNTERMODE_UP;
166+
tim.Init.RepetitionCounter = 0;
156167
HAL_TIM_PWM_Init(&tim);
157168

158-
// PWM configuration (only channel 1 supported at the moment)
169+
// PWM configuration
159170
TIM_OC_InitTypeDef oc_init;
160171
oc_init.OCMode = TIM_OCMODE_PWM1;
161172
oc_init.Pulse = 0; // off
162-
oc_init.OCPolarity = TIM_OCPOLARITY_HIGH;
173+
oc_init.OCPolarity = MICROPY_HW_LED_INVERTED ? TIM_OCPOLARITY_LOW : TIM_OCPOLARITY_HIGH;
163174
oc_init.OCFastMode = TIM_OCFAST_DISABLE;
164-
/* needed only for TIM1 and TIM8
165-
oc_init.OCNPolarity = TIM_OCNPOLARITY_HIGH;
166-
oc_init.OCIdleState = TIM_OCIDLESTATE_SET;
167-
oc_init.OCNIdleState = TIM_OCNIDLESTATE_SET;
168-
*/
169-
HAL_TIM_PWM_ConfigChannel(&tim, &oc_init, TIM_CHANNEL_1);
170-
HAL_TIM_PWM_Start(&tim, TIM_CHANNEL_1);
175+
oc_init.OCNPolarity = TIM_OCNPOLARITY_HIGH; // needed for TIM1 and TIM8
176+
oc_init.OCIdleState = TIM_OCIDLESTATE_SET; // needed for TIM1 and TIM8
177+
oc_init.OCNIdleState = TIM_OCNIDLESTATE_SET; // needed for TIM1 and TIM8
178+
HAL_TIM_PWM_ConfigChannel(&tim, &oc_init, pwm_cfg->tim_channel);
179+
HAL_TIM_PWM_Start(&tim, pwm_cfg->tim_channel);
171180

172181
// indicate that this LED is using PWM
173182
led_pwm_state |= 1 << led;
@@ -236,8 +245,8 @@ int led_get_intensity(pyb_led_t led) {
236245

237246
#if LED_PWM_ENABLED
238247
if (led_pwm_is_enabled(led)) {
239-
TIM_TypeDef *tim = led_pwm_config[led - 1].tim;
240-
mp_uint_t i = (tim->CCR1 * 255 + LED_PWM_TIM_PERIOD - 2) / (LED_PWM_TIM_PERIOD - 1);
248+
const led_pwm_config_t *pwm_cfg = &led_pwm_config[led - 1];
249+
mp_uint_t i = (*LED_PWM_CCR(pwm_cfg) * 255 + LED_PWM_TIM_PERIOD - 2) / (LED_PWM_TIM_PERIOD - 1);
241250
if (i > 255) {
242251
i = 255;
243252
}
@@ -248,26 +257,25 @@ int led_get_intensity(pyb_led_t led) {
248257
const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin;
249258
GPIO_TypeDef *gpio = led_pin->gpio;
250259

251-
// TODO convert high/low to on/off depending on board
252260
if (gpio->ODR & led_pin->pin_mask) {
253261
// pin is high
254-
return 255;
262+
return MICROPY_HW_LED_INVERTED ? 0 : 255;
255263
} else {
256264
// pin is low
257-
return 0;
265+
return MICROPY_HW_LED_INVERTED ? 255 : 0;
258266
}
259267
}
260268

261269
void led_set_intensity(pyb_led_t led, mp_int_t intensity) {
262270
#if LED_PWM_ENABLED
263271
if (intensity > 0 && intensity < 255) {
264-
TIM_TypeDef *tim = led_pwm_config[led - 1].tim;
265-
if (tim != NULL) {
272+
const led_pwm_config_t *pwm_cfg = &led_pwm_config[led - 1];
273+
if (pwm_cfg->tim != NULL) {
266274
// set intensity using PWM pulse width
267275
if (!led_pwm_is_enabled(led)) {
268276
led_pwm_init(led);
269277
}
270-
tim->CCR1 = intensity * (LED_PWM_TIM_PERIOD - 1) / 255;
278+
*LED_PWM_CCR(pwm_cfg) = intensity * (LED_PWM_TIM_PERIOD - 1) / 255;
271279
return;
272280
}
273281
}

0 commit comments

Comments
 (0)