STM32 bit bang PWM
On many of the cheaper STM32 Development Boards there is a LED attached to PC13. This is perfectly ok if you want to switch it on or off, but PC13 is not attached to any of the timer channels, so it will not be possible to control the brightness using PWM.
Fortunately, while not ideal, it is possible to bitbang the PWM in a manner which doesn't require too much computation. Contrary to PWM using a Timer channel, it does require some computation in the MCU.
Bit-banding
Bit-banding is a feature
#define BITBAND_BIT_ADDR(src_byte_addr, bit) (((((uint32_t)(src_byte_addr) & 0x000fffff) << 5) | ((uint32_t)(src_byte_addr) & 0xfff00000) | 0x02000000) + (((uint32_t)(bit)) << 2))
Code
Timer Settings
Firstly configure some timer (we use TIM10 here):
We also need to enable the global timer 10 interrupt:
Implementation
We use bitbanding to address the bit used for GPIO:
// The led_bb_bit points to the bitband address for controlling the PC13 uint8_t *led_bb_bit = (uint8_t*) BITBAND_BIT_ADDR(&LED_GPIO_Port->ODR, 13);
A few more global variables keep track of the counter and pwm value:
// Variables to run the pwm. led_pwm_cnt goes from 0-255 and then roll back over to 0. // led_pwm_val determines the ratio between on and off status of the LED. uint32_t led_pwm_cnt; uint8_t led_pwm_val = 0x00;
Now the actual PWM work can be handled in the interrupt callback:
// Callback which runs the PWM void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == LED_PWM_TIM) { // Increase the counter - it will roll over automatically every 256 bit ++led_pwm_cnt; // Switch LED on off or on depending on value of led_pwm_cnt. *led_bb_bit = (uint8_t) led_pwm_cnt >= led_pwm_val ? 1 : 0; } }