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+
4449typedef 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+
110118typedef 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
261269void 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