Page 1 of 1

HardwareTimer fast PWM Interrupt crashing

Posted: Thu Apr 27, 2023 10:41 am
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?

Re: HardwareTimer fast PWM Interrupt crashing

Posted: Thu Apr 27, 2023 7:38 pm
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.

Re: HardwareTimer fast PWM Interrupt crashing

Posted: Sun Apr 30, 2023 4:29 pm
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.