Pascal
Pascal

Reputation: 2214

STM32L011D3 IR led

I built a small board with a STM32L011D3 and an LED. I want to use the LED at 38kHz with a duty cycle of 50%. Now I connected the LED to the wrong pin on the mcu so I can not use the timer as a PWM generator directly. So I was trying to generate the PWM signal manually in the main loop. I thought this would work since I am actually not doing anything else on the mcu.

I configured my clock like the image shows below: clock configuration

The timer TIM2 I configured like the image shows below: timer configuration

So this means I should have 4MHz / 4 / 26 = 38.461kHz

The main loop currently looks like this: main loop

With this setup I get something around 37us on / 37us off. The timings are not very stable.

Could it be, that my instructions to enable/disable the led are too long to be executed all 25us, to get a stable pwm output?

Upvotes: 0

Views: 226

Answers (1)

Clifford
Clifford

Reputation: 93446

You are wasting time reading the output - you set it, so you already know what it is:

for(;;)
{
    int out = (timer2Value >= 13) ? GPIO_PIN_SET : GPIO_PIN_RESET ;
    HAL_GPIO_WritePin( GPIOA, GPIO_PIN_7, out ) ;
}

If the timing does not then change, then the problem is more likely that your clock is not running at the frequency you think it is.

A more deterministic solution (short of correcting the hardware design), is to set the timer to generate an interrupt at 38000-1 intervals, and toggle the output in the interrupt handler:

void TIM2_IRQHandler()
{
    static int out = 0 ;
    out = out ? 0 : 1 ;
    HAL_GPIO_WritePin( GPIOA, GPIO_PIN_7, out ) ;
}

Or even just:

void TIM2_IRQHandler()
{
    HAL_GPIO_TogglePin( GPIOA, GPIO_PIN_7 ) ;
}

If you really want the fastest possible output switching, then you might determine the bitband address of the pin and and toggle that directly:

Given:

__IO uint32_t* getBitBandAddress( volatile const void* address, int bit )
{
    __IO uint32_t* bit_address = 0;
    uint32_t addr = reinterpret_cast<uint32_t>(address);

    // This bit maniplation makes the function valid for RAM
    // and Peripheral bitband regions
    uint32_t word_band_base = addr & 0xf0000000;
    uint32_t bit_band_base = word_band_base | 0x02000000;
    uint32_t offset = addr - word_band_base;

    // Calculate bit band address
    bit_address = reinterpret_cast<__IO uint32_t*>(bit_band_base + (offset * 32u) + (static_cast<uint32_t>(bit) * 4u));

    return bit_address ;
}

Then:

__IO uint32_t* gpioA7 = getBitBandAddress( &GPIOA->ODR, 7 ) ;
for(;;)
{
    *gpioA7 = (timer2Value >= 13) ;
}

Similarly in an interrupt:

void TIM2_IRQHandler()
{
    static __IO uint32_t* gpioA7 = getBitBandAddress( &GPIOA->ODR, 7 ) ;

    *gpioA7 = !*gpioA7 ;
}

Though you might choose to initialise gpioA7 externally in the interrupt case.

Upvotes: 2

Related Questions