Difference between revisions of "STM32 bit bang PWM"

From Stm32World Wiki
Jump to navigation Jump to search
Line 29: Line 29:
 
// The led_bb_bit points to the bitband address for controlling the PC13
 
// 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);
 
uint8_t *led_bb_bit = (uint8_t*) BITBAND_BIT_ADDR(&LED_GPIO_Port->ODR, 13);
 +
</pre>
 +
 +
A few more global variables keep track of the counter and pwm value:
 +
 +
<pre>
 +
// 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;
 +
</pre>
 +
 +
Now the actual PWM work can be handled in the interrupt callback:
 +
 +
<pre>
 +
// 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;
 +
 +
    }
 +
 +
}
 
</pre>
 
</pre>
  

Revision as of 07:32, 6 May 2024

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

#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):

Bitbang PWM Timer Setting.png

We also need to enable the global timer 10 interrupt:

Bitbang PWM Timer Interrupt Setting.png

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;

    }

}

Result

Miscellaneous Links