Teensy4 datalogger problems

Hello,
I am attempting to build a datalogger using a Teensy4 board. This has to log data every 15 seconds. The data acquisition process only takes a few milliseconds, and the datalogger is intended to be battery powered (3x AA) with an ideal battery life of a few years. I am currently attempting to use powerdown with RTC alarm to lower current consumption to ~150uA in between measurements. The built in NOR flash is used together with LittleFS to log data, and the MTP library is used to download logged data to a PC.
This works... most of the time. However, occasionally the Teensy4 will get stuck in bootloader mode after the shutdown. Once entered, there is no exit from the bootloader, so the datalogger is unusable. This problem usually occurs within a few minutes. I have tried adding an external 1k resistor from the program pin to 3v3, as I wondered if there was an EMI issue, but this did not solve the problem. Adding a 300ms delay in startup might have cured the problem, but I have seen it occur once or twice with the delay (delay seemed to reduce regularity of the issue by a substantial amount).
The shutdown/wakeup code is included below
Code:
void rtc_setAlarm(uint32_t alarmSeconds, uint32_t prio = 13) {
	uint32_t tmp = SNVS_LPCR; //save control register
	/* disable SRTC alarm interrupt */
	rtc_stopAlarm();
	SNVS_LPTAR = alarmSeconds;
	while (SNVS_LPTAR != alarmSeconds);
	//attachInterruptVector(IRQ_SNVS_IRQ, rtc_isr);
	//NVIC_SET_PRIORITY(IRQ_SNVS_IRQ, prio * 16); // 8 is normal priority
	//NVIC_DISABLE_IRQ(IRQ_SNVS_IRQ);
	//NVIC_ENABLE_IRQ(IRQ_SNVS_IRQ);
	SNVS_LPCR = tmp | SNVS_LPCR_LPTA_EN_MASK; // restore control register and set alarm
	while (!(SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK));
}

uint32_t rtc_getAlarm() {
	return SNVS_LPTAR;
}

void doShutdown(void) {
	SNVS_LPCR |= (1 << 6) ; // turn off power
}

void setWakeupCallandSleep(uint32_t nsec) {
	uint32_t to = now();
	rtc_setAlarm(to + nsec, 4);
	doShutdown();
	while (1) asm("wfi");
}
note that a 300ms delay is not an acceptable solution as it increases power consumption excessively.
 
So far, I have no issue with the following test program
Code:
#define SNVS_LPCR_LPTA_EN_MASK          (0x2U)

void hibernate(uint32_t nsec)
{
    uint32_t tmp = SNVS_LPCR; // save control register

    SNVS_LPSR |= 1;

    // disable alarm
    SNVS_LPCR &= ~SNVS_LPCR_LPTA_EN_MASK;
    while (SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK);

    __disable_irq();

    //get Time:
    uint32_t lsb, msb;
    do {
      msb = SNVS_LPSRTCMR;
      lsb = SNVS_LPSRTCLR;
    } while ( (SNVS_LPSRTCLR != lsb) | (SNVS_LPSRTCMR != msb) );
    uint32_t secs = (msb << 17) | (lsb >> 15);

    //set alarm
    secs += nsec;
    SNVS_LPTAR = secs;
    while (SNVS_LPTAR != secs);

    // restore control register and set alarm
    SNVS_LPCR = tmp | SNVS_LPCR_LPTA_EN_MASK; 
    while (!(SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK));

    __enable_irq();
  
    SNVS_LPCR |= (1 << 6); // turn off power
    while (1) asm("wfi");  
}

void setup() {
  // put your setup code here, to run once:

  pinMode(13,OUTPUT);
  digitalWriteFast(13,HIGH);
}

void loop() {
  // put your main code here, to run repeatedly:
  if(millis()>1000) {digitalWriteFast(13,LOW); hibernate(15);}
}

It is running on T4.1 connected to PC.
Suggest to run this program on PC connected T4.x and again on your standalone system.

Having a wire connected to program pin can indeed create problems. Happened here also.
 
Interesting, thanks for this.
Maybe the issue is some sort of EMI or power issue. I have made some extensive modifications to the Teensy4 : I lifted the gate pin on the reverse polarity protection P-FET and connected it to VUSB. Also there is a diode and ferrite bead from VUSB bypassing the P-FET. These modifications allow the Teensy to swap from battery to USB power when USB is connected.
I have connected a diode from pin14 to the power on/off pin, to allow the on/off button to be used as a mode control button without shorting VBAT to VCC through the ESD protection diodes when the Teensy is sleeping. After further reading I think there is a library that should allow this functionality to be achieved without the diode.
Maybe some of these modifications are causing issues.
I will try the simplified RTC alarm function you quoted before looking at the various parts of the circuit with a scope (multimeter suggests its all working correctly, but there could be transients somewhere)
 
I'm running a modified version of the code WMXZ posted. So far its been running ok for over an hour.
I didn't realise that the bootloader IC on Teensy4 is effectively a JTAG adaptor that is permanently connected. I think it enables breakpoints in various fault handlers, and then enters bootloader mode.
I've a good idea what the problem could be: after reading sensor values, they are linearised using cubic spline interpolation. The cubic spline is stored in NVRAM, but there are flaws in my code which could cause uninitialised memory to be used. It may be that a hardfault occurred jut before my rtcalarm/wake function - inside the cubic spline library.
Code:
#define SNVS_LPCR_LPTA_EN_MASK          (0x2U)

void startup_middle_hook(void) {
  // force millis() to be 300 to skip startup delays
  systick_millis_count = 300;
}

void hibernate(uint32_t nsec)
{
    uint32_t tmp = SNVS_LPCR; // save control register

    SNVS_LPSR |= 1;

    // disable alarm
    SNVS_LPCR &= ~SNVS_LPCR_LPTA_EN_MASK;
    while (SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK);

    __disable_irq();

    //get Time:
    uint32_t lsb, msb;
    do {
      msb = SNVS_LPSRTCMR;
      lsb = SNVS_LPSRTCLR;
    } while ( (SNVS_LPSRTCLR != lsb) | (SNVS_LPSRTCMR != msb) );
    uint32_t secs = (msb << 17) | (lsb >> 15);

    //set alarm
    secs += nsec;
    SNVS_LPTAR = secs;
    while (SNVS_LPTAR != secs);

    // restore control register and set alarm
    SNVS_LPCR = tmp | SNVS_LPCR_LPTA_EN_MASK; 
    while (!(SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK));

    __enable_irq();
  
    SNVS_LPCR |= (1 << 6); // turn off power
    while (1) asm("wfi");  
}

void setup() {
  // put your setup code here, to run once:

  pinMode(13,OUTPUT);
  digitalWriteFast(13,HIGH);
}

void loop() {
  // put your main code here, to run repeatedly:
  if(millis()>350) {digitalWriteFast(13,LOW); hibernate(15);}
}
 
If you are getting a hard fault, you might try adding support for CrashReport.

When I run into crashes, I end up adding in some stuff like:

Code:
void setup() {
    while (!Seial && millis() < 3000) ; // wait up to 3 seconds for Serial to startup up.  Sometimes I put in longer
    if (CrashReport) Serial.print(CrashReport);
...
Sometimes If I get into an endless crash, I will change the simple if/print above to an if() {print...) and wait for keyboard input to continue

If I don't wish to use Serial object, you can use any object that is derived from Print. For example, I have in the past have created a quick and dirty class that is derived from
Print, which simply writes everything out to a memory buffer, which you can then save in any which way. In my case I was working with MTP and there is issue that I can not output anything to Serial, until MTP completes its setup. So before that I write everything out to memory and when Serial is finally available, I dump it then to Serial. But could just as easily write to SD or Flash memory or...
 
It looks like the issue is now fixed, but I'm left with some user unfriendly behaviour: the datalogger cannot recognise when the USB is connected, and has to wait for a RTC alarm before it can connect.
Is there any way to wake on USB? I could connect a capacitor and N-FET from VUSB to on/off to emulate a button press when USB is first plugged in, but a software solution would be nicer.
 
Yes, when put into hibernate state all MCU but RTC is shut down. This includes USB and as I discovered during this test it "disables" the bootloader. In other words if in hibernate state, pressing program button does not initiate the bootloader process.

(@ Paul: can you confirm this?)

Only ways to download new program was to
- keep bootloader pin pressed/down while waiting for RTC event, red light will flash once, after release of program button reprogramming will start
- keep bootloader pin pressed/down while power cycle

Caveat: I did this without RTC battery, so power cycle disabled also RTC, not sure what happens if RTC battery is connected.
 
I guess I could set a wakeup every 10s or so, then use NVRAM to track time until the true wakeup (when sensor is read).
Might be simpler to dead bug a 2N7000 onto the on/off pins, then connect gate to VUSB via 1uF cap and ~1MOhm resistor tho.
 
Project update: with 2N7000 fet it can wake on USB connection.
However, when I tried to impliment a brownout detection, I noticed something weird on the Teensy: the 3.0V USB output is actually hovering around 2.22 to 2.25V. The brownout bit is continually set on the 3.0V regulator.
I'm struggling to work out whats going on here, - no obvious damage to the board, and datasheet indicates that >0.175V below brownout threshold should cause reset of the whole processor, so that should occur at 2.65V output.
Does anybody have any ideas?
 
So far, I have no issue with the following test program
Code:
#define SNVS_LPCR_LPTA_EN_MASK          (0x2U)

void hibernate(uint32_t nsec)
{
    uint32_t tmp = SNVS_LPCR; // save control register

    SNVS_LPSR |= 1;

    // disable alarm
    SNVS_LPCR &= ~SNVS_LPCR_LPTA_EN_MASK;
    while (SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK);

    __disable_irq();

    //get Time:
    uint32_t lsb, msb;
    do {
      msb = SNVS_LPSRTCMR;
      lsb = SNVS_LPSRTCLR;
    } while ( (SNVS_LPSRTCLR != lsb) | (SNVS_LPSRTCMR != msb) );
    uint32_t secs = (msb << 17) | (lsb >> 15);

    //set alarm
    secs += nsec;
    SNVS_LPTAR = secs;
    while (SNVS_LPTAR != secs);

    // restore control register and set alarm
    SNVS_LPCR = tmp | SNVS_LPCR_LPTA_EN_MASK;
    while (!(SNVS_LPCR & SNVS_LPCR_LPTA_EN_MASK));

    __enable_irq();
 
    SNVS_LPCR |= (1 << 6); // turn off power
    while (1) asm("wfi");
}

void setup() {
  // put your setup code here, to run once:

  pinMode(13,OUTPUT);
  digitalWriteFast(13,HIGH);
}

void loop() {
  // put your main code here, to run repeatedly:
  if(millis()>1000) {digitalWriteFast(13,LOW); hibernate(15);}
}

It is running on T4.1 connected to PC.
Suggest to run this program on PC connected T4.x and again on your standalone system.

Having a wire connected to program pin can indeed create problems. Happened here also.
Sorry for reactivating this old thread, BUT tried the program again on a T4.1, but Teensy does not hibernate anymore (A2.3.2, TD1.59 ) Teensy shuts down and restarts immediately (no 15s hibernation)

Edit: It turned out to be a bad RTC battery connection. With another system program works as expected.
 
Last edited:
Back
Top