Weird HardwareTimer behavior

Post here all questions related to LibMaple core if you can't find a relevant section!
Post Reply
Eldi4
Posts: 22
Joined: Fri Dec 20, 2019 8:10 am
Answers: 1
Location: Kediri, Indonesia

Weird HardwareTimer behavior

Post by Eldi4 »

Hello there,

I've had problem with HardwareTimer, it wont make me trigger interrupt for more than 500KHz, like it was capped.

Here is my code

Code: Select all

#define G2_LOW() GPIOB->regs->ODR &= ~(1 << 5)
#define G2_HIGH() GPIOB->regs->ODR |= (1 << 5)

unsigned long ms1 = 0;
unsigned long ms2 = 0;
unsigned long ms3 = 0;
unsigned long ms4 = 0;
unsigned long ms5 = 0;
unsigned long ms6 = 0;

bool ledState = 0;


void handler_led(){
  ms1++;
  if(ms1 % 1000 == 0){
    ms5 = micros()-ms6;
    ms6 = micros();
    ms1 = 0;
    ms3++;
  }
  if(ms3 >= 200){
    ms3 = 0;
    ledState = !ledState;
    if(ledState) G2_HIGH(); else G2_LOW();
  }
}

//HardwareTimer timerx(3);

void setup() {
  pinMode(PB5,OUTPUT);
  pinMode(PA8,OUTPUT);
  digitalWrite(PA8,LOW);
  
  Serial.begin(115200);
  ms2 = 5000000;
    Timer2.setMode(TIMER_CH1, TIMER_OUTPUTCOMPARE);   
    Timer2.setPrescaleFactor(18);
    Timer2.setOverflow(4);
    
    Timer2.setCompare(TIMER_CH1, 1);
    Timer2.attachInterrupt(TIMER_CH1, handler_led);
    
}


void loop() {
  Serial.println(ms5);
  delay(500);
}
Theoritically with prescaleFactor of 18 and overflow of 4 the timer will fire each 1uS, but in fact i get 2.5uS confirmed by ms5 that is printing 2500, since ms1 reset each 1000 tick, it gives 2.5uS. i've tried a lot of combination like prescale 72 and overflow 1, prescale 36 and overflow 2, prescaler 18 and overflow 4, but all of them will keep firing at 2.5uS, and weirdly at 2uS when i swapped prescale and overflow value (eg prescale 1 and overflow 72, prescale 2 and overflow 36), My thought it should be the same if we swapped prescaler and overflow, but whatt?????.
Then i thought it was timer clock problem (it was not the same as F_CPU), but when i set prescaleFactor to 2 and overflow to 36000, i get exact correct 1000uS period, same with overflow of 3600 (prescale still 2) i get 100uS period, and overflow of 360 i get 10uS period, but when i set the overflow to 36, i get 2uS again.
And also when i set it fast like prescale 1 and overflow 1 the Serial will stopped working, it will not print anything to Serial monitor, and since i dont have any logic analyzer or oscilloscope to knew exactly what is the interrupt reload frequency is, i dont know exactly what happened on that prescale and overflow value (1), but by looking at led blinking frequency, im pretty sure that it was still 2uS (the led blinking frequency is same as prescale 2 overflow 36).

I use rogerclark core, STM32F103C8T6 china clone (the IC label is TF-A2, but it was indeed C8T6) from some DMD LED Controller (TF-A2 Led Controller), i dont think the ic was the problem, and i upload via Serial.

Did i do something wrong, or the HardwareTimer is buggy?
ag123
Posts: 1655
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: Weird HardwareTimer behavior

Post by ag123 »

my guess is one could check if other interrupts (e.g. usb sof every 1ms and systick every 1ms used for delay(n) ) could be occuring.

one of those tricks i do is place

Code: Select all

asm("wfi");
in loop(), that is nearly the same as delay(1) and have an variable, counter checking the number of "wfi" run per secs (say against rtc). it should be 1khz if only systick is running.
plus usb sof that would be 2khz. then timers probably adds to it.
as interrupts needs to be serviced sequentially, my guess is that it would take time as the cpu switch from isr to isr and the main program and consume time slices
i've also noted that interrupt processing has quite a lot of overheads, if i use the adc 'watchdog' interrupt to catch signal triggering, i get some limits of adc at some 500 ksps or so. but if i remove that watch dog interrupt handling the adc can reach the specified speeds of some 2msps on stm32f103
Eldi4
Posts: 22
Joined: Fri Dec 20, 2019 8:10 am
Answers: 1
Location: Kediri, Indonesia

Re: Weird HardwareTimer behavior

Post by Eldi4 »

So i cleaned code on loop() and placed

Code: Select all

  for(int x = 0; x<1000; x++){
    asm("wfi");
  }
  digitalWrite(PB5,!digitalRead(PB5));
on my loop(), and commented the

Code: Select all

//if(ledState) G2_HIGH(); else G2_LOW();
on handler_led(), what i notice is that, with timer paused, it blink at frequency of (aprroximately what my eyes see) 1Hz, and when i resume the timer, it blink so fast (but my eyes still able to catch the flick), so what is the conclusion?, my board didnt have 32KHz rtc crystal installed, so i checked it using led blink.
ag123
Posts: 1655
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: Weird HardwareTimer behavior

Post by ag123 »

well, it means your timer is generating the interrupts as you expect, so if you expect your timer to say run at 100khz that would be 100k interrupts per sec + 1000 interrupts from systick. so say if you increase the loop count to say 101000 / 2 and split the intervals between led on - led off it would blink at about 1 sec. this isn't really a good way to check that, more of a crude way perhaps.

if you only notice just the timer and systick contributing to the leds frequency change, it also means that probably these are the 2 interrupt sources that are handled. like mention prior, interrupt handling has latency which could perhaps limit how fast that isr can be called. but the timers themselves can run well faster than the isr being handled especially if timer interrupts are disabled. the trouble of course is those interrupts are often used for various purposes including creating waveforms that couldn't be achieved by the timer alone
Last edited by ag123 on Fri Dec 20, 2019 11:59 am, edited 1 time in total.
Eldi4
Posts: 22
Joined: Fri Dec 20, 2019 8:10 am
Answers: 1
Location: Kediri, Indonesia

Re: Weird HardwareTimer behavior

Post by Eldi4 »

Ahh, i got it now, so i set the prescalerFactor to 2 and overflow to 360, and then changes the loop value to 101000, the led blink every 1 second. When i set the overflow to 36, and changes the loop value to 501000, it blink every 2 second (which show 250K "wfi" tick/s), which it should not be, and then i removed :

Code: Select all

//ms5 = micros()-ms6;
    //ms6 = micros();
and the led blink at 1s. soo umm, the interrupt is running at 500KHz (still limited, since prescaler 2 overflow 36 should be 1MHz), did there are no way to increasing that speed because of hardware limitation?, and there is nothing i can do with it? like changing core or accessing timer with HAL?.

My purpose is to use bit banged SPI (because i need 4 spi data out to control led panel), and the clock source is timer, so i can adjust the speed of data transfer, and my maximum targeted speed is at 4Mbps which is 4MHz, since it can only reach 500KHz it was far from my target, so what is other alternative to this?
ag123
Posts: 1655
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: Weird HardwareTimer behavior

Post by ag123 »

one way though is to explore dma
https://www.st.com/content/ccc/resource ... 236305.pdf
chapter 5 Arbitrary waveform generation using timer DMA-burst feature

and this is probably better
AN4666 Parallel synchronous transmission using GPIO and DMA
https://www.st.com/content/ccc/resource ... 169730.pdf

they are kind of 'advanced' features, i'd guess one would need to take time to work them to see how they work
Eldi4
Posts: 22
Joined: Fri Dec 20, 2019 8:10 am
Answers: 1
Location: Kediri, Indonesia

Re: Weird HardwareTimer behavior

Post by Eldi4 »

Thanks a lot for the help, will check it out immediately, for now i'll use non-adjustable speed data shifting using :

Code: Select all

static inline void shiftData8( byte data, bool upperOrLower){
	uint8_t sspi_i;
  // Send 8 bits, with the MSB first.
  for (sspi_i = 0x80; sspi_i != 0x00; sspi_i >>= 1) {
    if (data & sspi_i) {
      if(upperOrLower) R1_HIGH();
	  else R2_HIGH();
    }
    else {
      if(upperOrLower) R1_LOW();
	  else R2_LOW();
    }
	
	SCK_LOW();
	SCK_HIGH();
  }
}
victor_pv
Posts: 9
Joined: Wed Dec 18, 2019 7:33 pm

Re: Weird HardwareTimer behavior

Post by victor_pv »

I haven't tested your code, so this is just a theory, but you if you are trying to fire interrupts at let's say 1Mhz, then the MCU has to be able, in 72 cycles (so 72 instructions), to:
  • Read the interrupt vector
  • Jump to that address
  • That addres most likely is part of the core, not your ISR, so it may do a few calls before calling your ISR
  • Call your ISR
  • Execute your ISR
  • Return back to the core ISR
  • Core ISR to return to whatever code was executing before the timer interrupt fired.

Those are quite a few tasks. I believe in the old forum someone posted how fast the core was servicing some interrupts, can't remember the number but you may want to check the archive of the old forum to see. You may be pushing the limit on how many instructions you need to execute between interrupts.

If you want to simulate SPI with a timers or GPIO, as AG recommended you may want to use DMA so the CPU is free to do other things.
stevestrong
Posts: 502
Joined: Fri Dec 27, 2019 4:53 pm
Answers: 8
Location: Munich, Germany
Contact:

Re: Weird HardwareTimer behavior

Post by stevestrong »

I don't think that the CPU is able to perform faster than 500kHz IRQ frequency.
The 72MHz is a theoretical value, but in practice it takes 0.5µs to enter and leave the ISR.
And reading the code is done with some wait states which is adding some extra execution time if the code needs several jumps.

So I say you are lucky to reach that 500kHz performance, but do not expect to have more.
You could have better chances with F4 series, they have slightly higher clock frequency and, more important, less wait cycles and better CPU architecture (M4 core).
Post Reply

Return to “General discussion”