T4 , set_arm_clock and micros()?

WMXZ

Well-known member
I get wrong values using micros() after changing CPU speed with set_arm_clock on a T4.
Code:
#if defined(__IMXRT1062__)
extern "C" uint32_t set_arm_clock(uint32_t frequency);
#endif

void setup() {
  // put your setup code here, to run once:
#if defined(__IMXRT1062__)
  set_arm_clock(24000000); // comment here to get full speed
#endif
}

void loop() {
  // put your main code here, to run repeatedly:
 static uint32_t t0;
 if(millis()>(t0+1000))
 {
   t0=millis();
   uint32_t t1=micros();
   delay(50);
   Serial.println(micros()-t1);
 }
}

this code gives me 1050 as printout
when commenting the clock change I get the correct value of 50000
 
I get wrong values using micros() after changing CPU speed with set_arm_clock on a T4.
...
this code gives me 1050 as printout
when commenting the clock change I get the correct value of 50000

@Paul - you'll recognize something here in a flash ... clock change order not leaving millis() clock right?

Interesting - the problem is millis() when the clock drops - if it drops in the RIGHT order the CLOCKS change over - if not millis() is broken:
Code:
 F_CPU=600000000	deg  C=32
	50ms delay:: 50000 us and 50 ms
 F_CPU=240000000	deg  C=33
	50ms delay:: 50000 us and 50 ms
[COLOR="#FF0000"] F_CPU=110000000	deg  C=32
	50ms delay:: 1010 us and 1 ms[/COLOR]
 F_CPU=24000000	deg  C=30
	50ms delay:: 50006 us and 50 ms
 F_CPU=600000000	deg  C=30
	50ms delay:: 50000 us and 50 ms
 F_CPU=129600000	deg  C=34
[B]	50ms delay:: 50001 us and 50 ms
 F_CPU=110000000	deg  C=32
	50ms delay:: 50002 us and 50 ms
[U] F_CPU=24000000	deg  C=31
	50ms delay:: 50006 us and 50 ms[/U][/B]
 F_CPU=600000000	deg  C=30
	50ms delay:: 50000 us and 50 ms
[COLOR="#FF0000"] F_CPU=24000000	deg  C=34
	50ms delay:: 1050 us and 1 ms[/COLOR]
 DONE 
 	 F_CPU=24000000	deg  C=31

Code:
#if defined(__IMXRT1062__)
extern "C" uint32_t set_arm_clock(uint32_t frequency);
#endif

void setup() {
  while ( !Serial);
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  // put your setup code here, to run once:
#if defined(__IMXRT1062__)

  TimeDiff();
  set_arm_clock(240000000); // comment here to get full speed
  TimeDiff();
  set_arm_clock(110000000); // comment here to get full speed
  TimeDiff();
[COLOR="#FF0000"]  set_arm_clock(24000000); // comment here to get full speed[/COLOR]
  TimeDiff();
  set_arm_clock(600000000); // comment here to get full speed
  TimeDiff();
  set_arm_clock(130000000); // comment here to get full speed
  TimeDiff();
  set_arm_clock(110000000); // comment here to get full speed
  TimeDiff();
 [B][U] set_arm_clock(24000000); // comment here to get full speed[/U][/B]
  TimeDiff();
  set_arm_clock(600000000); // comment here to get full speed
  TimeDiff();
[COLOR="#FF0000"]  set_arm_clock(24000000); // comment here to get full speed[/COLOR]
  TimeDiff();
  Serial.printf("\n DONE \n \t F_CPU=%u", F_CPU_ACTUAL );
  Serial.printf( "\tdeg  C=%u\n" , (uint32_t)tempmonGetTemp() );
#endif

}

static uint32_t t0;


void loop() {
  // put your main code here, to run repeatedly:
}

void TimeDiff() {
#if defined(__IMXRT1062__)
  Serial.printf("\n F_CPU=%u", F_CPU_ACTUAL );
  Serial.printf( "\tdeg  C=%u\n" , (uint32_t)tempmonGetTemp() );
#endif
 while (!(millis()>(t0+1000)));
   t0=millis();
   uint32_t t1=micros(), t2=millis();
   delay(50);
   Serial.printf("\t50ms delay:: %u us and %u ms", micros()-t1, millis()-t2);
}
 
Last edited:
the following code
Code:
#if defined(__IMXRT1062__)
extern "C" uint32_t set_arm_clock(uint32_t frequency);
#endif

extern volatile uint32_t systick_cycle_count;

uint32_t m_micros(void)
{
  uint32_t ccdelta, usec, smc, scc;
//  do {
//    __LDREXW(&systick_safe_read);
    smc = systick_millis_count;
    scc = systick_cycle_count;
//  } while ( __STREXW(1, &systick_safe_read));
  ccdelta = ARM_DWT_CYCCNT - scc;
  usec = 1000*smc + (ccdelta/(F_CPU_ACTUAL/1000000));
  return usec;
}

void setup() {
  // put your setup code here, to run once:
#if defined(__IMXRT1062__)
  set_arm_clock(24000000); // comment here to get full speed
#endif
}

void loop() {
  // put your main code here, to run repeatedly:
 static uint32_t t0;
 if(millis()>(t0+1000))
 {
   t0=millis();
   uint32_t t2=millis();
   uint32_t t1=m_micros();
   delay(50);
   Serial.printf("%d %d\n", millis()-t2, m_micros()-t1);
 }
}
gives me
Code:
49 50004
49 50003
1 1048
1 1048
49 50004
1 1048
49 50004
1 1048
49 50003
1 1048
49 50004
1 1047
49 50003
1 1048
1 1048
1 1045
49 50004
1 1048
49 50004
1 1048
1 1048
1 1048
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
49 50004
1 1048
1 1047
1 1048
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
49 50004
1 1048
49 50004
1 1048
1 1047
1 1047
1 1044
1 1047
1 1047
1 1048
1 1048
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
49 50004
1 1048
1 1048
1 1048
1 1047
1 1047
1 1047
1 1047
49 50004
1 1048
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
1 1047
that is, result is frequently correct

but uncommenting the ARM code
Code:
#if defined(__IMXRT1062__)
extern "C" uint32_t set_arm_clock(uint32_t frequency);
#endif

#include "arm_math.h"  // micros() synchronization
extern volatile uint32_t systick_millis_count;
extern volatile uint32_t systick_cycle_count;
extern uint32_t systick_safe_read;   // micros() synchronization

uint32_t m_micros(void)
{
  uint32_t ccdelta, usec, smc, scc;
  do {
    __LDREXW(&systick_safe_read);
    smc = systick_millis_count;
    scc = systick_cycle_count;
  } while ( __STREXW(1, &systick_safe_read));
  ccdelta = ARM_DWT_CYCCNT - scc;
  usec = 1000*smc + (ccdelta/(F_CPU_ACTUAL/1000000));
  return usec;
}

void setup() {
  // put your setup code here, to run once:
#if defined(__IMXRT1062__)
  set_arm_clock(24000000); // comment here to get full speed
#endif
}

void loop() {
  // put your main code here, to run repeatedly:
 static uint32_t t0;
 if(millis()>(t0+1000))
 {
   t0=millis();
   uint32_t t2=millis();
   uint32_t t1=m_micros();
   delay(50);
   Serial.printf("%d %d\n", millis()-t2, m_micros()-t1);
 }
}
gives consistently
Code:
1 1045
1 1047
1 1045
1 1048
1 1048
1 1045
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
1 1048
 
Solved?

doubling the set_arm_clock command seems to work
Code:
#if defined(__IMXRT1062__)
extern "C" uint32_t set_arm_clock(uint32_t frequency);
#endif

void setup() {
  // put your setup code here, to run once:
#if defined(__IMXRT1062__)
  set_arm_clock(24000000); // comment here to get full speed
  set_arm_clock(24000000); // comment here to get full speed
#endif
}

void loop() {
  // put your main code here, to run repeatedly:
 static uint32_t t0;
 if(millis()>(t0+1000))
 {
   t0=millis();
   uint32_t t2=millis();
   uint32_t t1=micros();
   delay(50);
   Serial.printf("%d %d\n", millis()-t2, micros()-t1);
 }
}
produces
Code:
50 50005
50 50005
50 50005
50 50005
50 50005
50 50005
50 50005
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
50 50004
conclusion: are there some wait missing in the set_arm_clock function?
 
Since I was playing I tried various clock settings using just one setArmClock call. It seems to start going off below 200Mhz. At 180Mhz am seeing:
Code:
50 50001
50 50000
50 50000
50 50000
50 50001
50 50001
50 50001
50 50001
50 50001
50 50001
above that its right on. At 150Mhz you start seeing what you are seeing and just gets worse as you lower the clock. At 150Mhz
Code:
3 3007
1 1007
49 50000
1 1007
1 1007
49 50000
1 1007
1 1007
Even if I double up on the set clock calls at 150Mhz it is still off.

Can't remember but 150Mhz sounds familiar for another clock as well Hmm
 
Since I was playing I tried various clock settings using just one setArmClock call. It seems to start going off below 200Mhz. At 180Mhz am seeing:



above that its right on. At 150Mhz you start seeing what you are seeing and just gets worse as you lower the clock. At 150Mhz

Even if I double up on the set clock calls at 150Mhz it is still off.

Can't remember but 150Mhz sounds familiar for another clock as well Hmm

As @mjs513 notes - and I saw in p#2 code - : there is something off in the transitions with set_arm_clock - with orderly transitions some affect on millis() clock is resolved - on some others it is not.

The '__LDREXW' code 'normally' only triggers if the millis_tick happens during the few cycles of the micros() code - i.e. in testing I ran it in tight loops to get EVERY microsecond change - that is multiple calls per us and only once per thousand micros() would the millis_tick happen even then.

The problem is the millis() code even never calling micros() - a 50 ms delay only advances 1 millis() {that is the LEFT number} - which properly tells micros() only 1000 micros advanced in the 50 ms delay.
1 1007
49 50000

Paul understands the clocks and knows of a specific interaction 'I Assume' from notes I've seen in the code when the PLL clock or whatever it was comes and goes during speed transitions that has to change to drive USB Serial or something.

I did clock speed transition testing in Beta as I did micros() … but of course I did uniform steps of … down … up … which triggers what shows here where the one value/setting needing updated is caught.
 
doubling the set_arm_clock command seems to work
Code:
#if defined(__IMXRT1062__)
extern "C" uint32_t set_arm_clock(uint32_t frequency);
#endif

void setup() {
  // put your setup code here, to run once:
#if defined(__IMXRT1062__)
  set_arm_clock(24000000); // comment here to get full speed
  set_arm_clock(24000000); // comment here to get full speed
#endif
}

void loop() {
  // put your main code here, to run repeatedly:
 static uint32_t t0;
 if(millis()>(t0+1000))
 {
   t0=millis();
   uint32_t t2=millis();
   uint32_t t1=micros();
   delay(50);
   Serial.printf("%d %d\n", millis()-t2, micros()-t1);
 }
}
produces
Code:
50 50005
50 50005
50 50005
...
conclusion: are there some wait missing in the set_arm_clock function?

Re-reading this - it points to the problem and the conclusion seems an explanation in the right direction.
 
Paul - TeensyDuino 1.49 fixable? Certain passes through set_arm_clock() with clock speed transition depending on current settings leave the clocking for millis() not properly set.

Post #2 the code in code block #2 does repro on 1.49b1 cores.
 
Back
Top