HardwareTimer fast PWM Interrupt crashing

Post here first, or if you can't find a relevant section!
Post Reply
brenda
Posts: 7
Joined: Thu May 05, 2022 5:36 pm

HardwareTimer fast PWM Interrupt crashing

Post by brenda »

I'm using HardwareTimer to basically do a SPI-like communication, and need it to be at least 1MHz in speed.
MCU is STM32F446, 180MHz.
I've set up a PWM timer with 50% duty cycle, in one half I do SCK down and MOSI setup, in the other SCK up.
The timer operates in bursts of 2*64 bit bursts, with chip select switch in between.

Reason to re-do it with timer is that the previous implementation was just a big function that cycled through the vector and banged the bits with random timing, had to do microDelay() for the chip selects and it took too much time for a synchronous operation.

Problem is, this only works until 6µs cycle. If I go faster than that, something breaks and the MCU stalls.

Init code:

Code: Select all

    HardwareTimer* FireTimer = new HardwareTimer(TIM10);

    FireTimer->setMode(1, TIMER_DISABLED, NC);
    FireTimer->setOverflow(6, MICROSEC_FORMAT);
    FireTimer->setCaptureCompare(1, 3, MICROSEC_COMPARE_FORMAT); // 50%
    FireTimer->attachInterrupt(1, fireCompareCallback);
fireCompareCallback:

Code: Select all

    void fireCompareCallback() {
        HAL_GPIO_WritePin(GPIOE, GPIO_PIN_15, GPIO_PIN_SET); // SCK high
    }
fireUpdateCallback:

Code: Select all

void fireUpdateCallback(HardwareTimer *FireTimer, std::vector<uint8_t> *line, uint8_t *ITi, uint8_t *ITj) {
    uint8_t d = (*line)[*ITi]; // size=16

    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_15, GPIO_PIN_RESET); // SCK low

    d = (d >> (*ITj));
    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, ((d & 1) == 1) ? GPIO_PIN_SET : GPIO_PIN_RESET); // MOSI

    (*ITj)++;

    if(*ITj == 8) {
        *ITj = 0;
        (*ITi)++;
    }

    if(*ITi == 8) {
        HAL_GPIO_WritePin(GPIOE, GPIO_PIN_7, GPIO_PIN_SET); // nSS2 off
        HAL_GPIO_WritePin(GPIOE, GPIO_PIN_8, GPIO_PIN_RESET); // nSS1 on
    }

    if(*ITi == 16) {
        HAL_GPIO_WritePin(GPIOE, GPIO_PIN_8, GPIO_PIN_SET); // nSS1 off
        FireTimer->pause();
    }
}
Timer burst start:

Code: Select all

void firePatternIT(std::vector<uint8_t> line) {
    ITi = 0;
    ITj = 0;

    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_7, GPIO_PIN_RESET); // nSS2 on

    FireTimer->attachInterrupt(std::bind(fireUpdateCallback, FireTimer, &line, &ITi, &ITj));
    FireTimer->resume();
}
Can anyone point me in the right direction, to what is causing the stall, or other way to implement this?
User avatar
Bakisha
Posts: 139
Joined: Fri Dec 20, 2019 6:50 pm
Answers: 5
Contact:

Re: HardwareTimer fast PWM Interrupt crashing

Post by Bakisha »

IMHO, you reached maximum of what interrupt with timer can do. Interrupt latency can be a killer.
You still have few options:
- try to compile with O3 (without or with LTO)
- try precalculated code for

Code: Select all

uint32_t GPIOE->BSSR = uint32_t value[xx]
where value is not just CLK and MOSI bits, but also nSS1 and nSS2 bits
- try DMA to ODR or BSSR register, with timer as source of synchronization (my guess: up to few MHz speed)
- if it is like SPI, then use SPI (if you can use MOSI/CLK pins). Should work up to 45MHz.
dannyf
Posts: 446
Joined: Sat Jul 04, 2020 7:46 pm

Re: HardwareTimer fast PWM Interrupt crashing

Post by dannyf »

1) interrupt overhead on frequent invocations can be expensive.
2) you should be able to do what you want in 20-40 ticks. + 20 or so for the isr overhead. that should be enough - you have over 1K ticks between each invocation.
3) polling might be more efficient here.
4) if you are looking for fast transmission, try using the spi hardware.
Post Reply

Return to “General discussion”