Presetting micros() start value.

I have some library code that uses a LoRa module to transmit FSKRTTY. The program shifts the frequency of the LoRa module thats generating a carrier between high and low frequencies and uses micros() to time the shifts so that the bit time (baud rate) is correct. The code works just fine, the data sent can be decoded with an SDR and FLDIGI, and it does carry on working across the rollover.

However, there appears to be a timing glitch as the rollover happens and the FSKRTTY sentence then has a decode error, its CRC checked on receipt.

So I want to test what is actually happening and see the bit timings as the overflow occurs. Its a pain to have to wait 71 minutes for the rollover to occur, and I have missed it a couple of times.

I believe the micros() timer is timer0_overflow_count and whilst I seem to have found its initialisation in wiring.c;

volatile unsigned long timer0_overflow_count = 0;

I dont seem to be able to change its start value.

Any ideas, apart from just keep waiting ?

Use macros to replace "micros" with your own "offsetMicros"

Very reluctant to stray too far away from standard stuff.

I dont need a solution as such, the decode error would only occur on average once in 600 sentence decodes and since this is designed for receptoion at 100s of km, there is likley to be a much higher decode error rate than that. So if I cannot troubleshoot the potential decode problem I would accepts the 1:600 error rate.

Running the code on an 8Mhz Pro Mini.

After reading many times about how to avoid rollover problems with millis(), I’d like to see the code that uses micros() and has a problem rolling over.

I am assuming that you have use the recommended techniques for obviating rollover problems and it is some other kinda low level thing. Which, again, I would like to appreciate.

I guesss that’s longhand for post you code. ;-]

a7

Well here is the code;

void SX127XLT::transmitFSKRTTY(uint8_t chartosend, uint16_t baudPerioduS, int8_t pin)
{
  //This overloaded version of transmitFSKRTTY() defaults to 1 start bit, 7 data bits, no parity and 2 stop bits.

#ifdef SX127XDEBUG1
  Serial.println(F("transmitFSKRTTY() "));
#endif

  uint8_t numbits;
  uint32_t startuS;
  
  //startbit
  
  startuS = micros();
  setRfFrequencyDirect(_freqregH, _freqregM, _freqregL); //set carrier frequency  (low)

  if (pin >= 0)
  {
    digitalWrite(pin, LOW);
  }

  while (((uint32_t) (micros() - startuS) < baudPerioduS)); 

  for (numbits = 1;  numbits <= 7; numbits++)           //send bits, LSB first
  {
    startuS = micros();
    if ((chartosend & 0x01) != 0)                       //test for bit set, a 1
    {
      if (pin >= 0)
      {
        digitalWrite(pin, HIGH);
      }
      setRfFrequencyDirect(_ShiftfreqregH, _ShiftfreqregM, _ShiftfreqregL); //set carrier frequency for a 1
    }
    else
    {
      if (pin >= 0)
      {
        digitalWrite(pin, LOW);
      }
      setRfFrequencyDirect(_freqregH, _freqregM, _freqregL);                //set carrier frequency for a 0
    }
    chartosend = (chartosend >> 1);           //get the next bit
    while (((uint32_t) (micros() - startuS) < baudPerioduS));
  }

  //stop bits

  startuS = micros();

  if (pin >= 0)
  {
    digitalWrite(pin, HIGH);
  }

  setRfFrequencyDirect(_ShiftfreqregH, _ShiftfreqregM, _ShiftfreqregL);     //set carrier frequency

  while ((uint32_t) (micros() - startuS) < (baudPerioduS * 2));

}

The code works, there is no lockup if its running at the time of the rollover.

However after waiting another 71 minutes, there was a rollover in the middle of the sentence transmit, 130 characters, I definetly heard a pause in the RTTY, but the decode was OK, so it seems likley that the pause was in the period where it matters little, the start and stop bits.

'Fixing' the code is not really the objective of my question. And it would take several days of testing, because of the 71 minute waits, to prove a fix.

What I really want to know, is how exactly you can set up the Arduino environement so that the rollover is going to occur in say, 60 seconds.

Assuming ATmega, use a 16 bit timer as a basis your own micros() function. Then you can do anything you want. With a prescaler of 8 you could have 0.5 usec resolution, for example.

I appreciate your frustration and understand what you are looking to do.

I have seen a technique for jamming values into the register(s) used for millis(), this in the context of a tutorial to demonstrate rollover problems and how to deal with them w/o waiting 49 days or whatever it is exactly.

I cannot find that again (yet). Shouldn’t a similar idea work for micros()? In which case it would need to be known the register(s) micros() uses, which may be what and all you are asking. Examination of the code for micros(), which I haven’t found (yet) either should determine whether the same trick could be employed.

It is very annoying to prove or flunk code which must show its correctness when real long times is involved. Not here perhaps but in some cases a simple change can make things run a bit faster or use a ore-planned ability to skip ahead by hours and minutes. Like you are trying to do.

a7

alto777:
I have seen a technique for jamming values into the register(s) used for millis(), this in the context of a tutorial to demonstrate rollover problems and how to deal with them w/o waiting 49 days or whatever it is exactly.

Me too, and such a process to check some code that used millis() to wait a period for a GPS fix, waiting xx days to check it was working through overflow was not practical, so I set millis() to expire in 60 seconds and ran several tests, all OK.

I tried the same technique for micros() and it did not work.

I am at liberty to alter any of the code in the Arduino core, I have my machine setup so that the IDE is a portable one, all code and libraries in one folder, backups of the entire environment are easy.

Have you tried change the Timer 0 prescaler from 64 to 1? 71 minutes to rollover should scale accordingly

srnet:
I dont seem to be able to change its start value.

What does that mean. Did you change the initialization in wiring.c? Something like:

volatile unsigned long timer0_overflow_count = 2090000UL;

That should overflow micros() in less than 15 seconds (on 8 MHz AVR).

Does your installation have several versions of wiring.c? Maybe you changed the wrong one?

gfvalvo:
Does your installation have several versions of wiring.c? Maybe you changed the wrong one?

Yes it does have several, I tried them all, although I set it to a HEX value, not UL.

Should that change;

volatile unsigned long timer0_overflow_count = 2090000UL;

Have worked, if so I will try again .............

I use this to generate microsecond delays using timer2 from the Atmega328P. This is using the internal 8MHz clock so if you are running 16MHz, you have to multiply the usec value by two, which will limit the delay to 127 microseconds instead of 255

void delay2_us(uint8_t usec)
{
	// use CTC mode
	TCCR2A = 1<<WGM21 | 0<<WGM20;
	TCCR2B = 0<<WGM22;

	// set TOP value
	OCR2A = usec;

	// clear counter
	TCNT2 = 0;

	// start timer2, 1MHz clock, DIV8
	TCCR2B = 0<<WGM22 | 0<<CS22 | 1<<CS21 | 0<<CS20;

	// wait for OCF2A flag
	while((TIFR2 & 1<<OCF2A) == 0);

	// clear flag
	TIFR2 = 1<<OCF2A;

	// stop timer2
	TCCR2B = 0<<WGM22 | 0<<CS22 | 0<<CS21 | 0<<CS20;

	return;
}

if 16MHz Arduino (the max delay would be 127)

OCR2A = 2 * usec;

There is no overflow to deal with since you start and stop the timer at will. As long as you don't use anything above 0xFF since timer2 is an 8 bit timer

Don't have a Pro Mini, tried this on an Uno (16 MHz). Set wiring.c:

volatile unsigned long timer0_overflow_count = 4180000UL;

Cause micros() overflow in ~14 seconds.

#include "Arduino.h"

uint32_t oldMicros;

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("Starting");
  oldMicros = micros();
}

void loop() {
  uint32_t currentMicros = micros();
  if (currentMicros < oldMicros) {
    Serial.println("Micros Overflow");
  }
  oldMicros = currentMicros;
}

IIf I understand, subsequent cycles will still take 71 minutes. How/where/when (!) could one sorta goose timer0_overflow_count to elide say 70 minuets?

Note when it passes 1000 and set it to 41800000UL?

It may not be necessary for this case here, just asking.

It looks like timer0_overflow_count runs free.

a7

alto777:
Note when it passes 1000 and set it to 41800000UL?

You'd have to further modify wiring.c to do that. And, your application code would need to handle the massive discontinuity in returned micros() value it would cause.

gfvalvo:
Don't have a Pro Mini, tried this on an Uno (16 MHz). Set wiring.c:

volatile unsigned long timer0_overflow_count = 4180000UL;

Just setting that line did the trick, before I was also trying to set the value from the sketch as well, that did not work.

I was then able to run the RTTY sentence transmit so that the rollover occured in the middle, confirmed with printouts of micros() before and after the send.

Decode was reliable across the rollover. Without being able to preset the micros() value what would have taken several days took a few minutes.

Thanks for the help.