Teensy 3.5 at 2MHz / VLPR

tni

Well-known member
Has anyone been able to use Teensy 3.5 at the 2MHz setting (which enables Very Low Power Run mode)?

I'm having frequent crashes. E.g., the code below often hangs at "SD.begin(chipSelect)". If it doesn't, it will hang at some point later. Things work fine, if I disable VLPR (still running at 2MHz). The same code works on Teensy 3.6 in VLPR mode.

Code:
#include <array>
#include <SD.h>

const char* log_file_name = "log.bin";

void blink() {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(200);
    digitalWrite(LED_BUILTIN, LOW);
}

void setup() {
    //SMC_PMCTRL &= ~SMC_PMCTRL_RUNM(0b11); // disable VLPR
    elapsedMillis timer;
    elapsedMillis timer_sd_write;

    pinMode(LED_BUILTIN, OUTPUT);

    Serial1.begin(115200);
    delay(1000);
    
    Serial1.println("Init SD card");

    const auto chipSelect = BUILTIN_SDCARD;
    if (!SD.begin(chipSelect)) {
        Serial1.println("SD init failed.");
        return;
    }
    Serial1.println("SD init done.");

    size_t written_bytes = 0;
    SD.remove(log_file_name);
    File file = SD.open(log_file_name, FILE_WRITE);

    if (!file) {
        Serial1.println("Error opening log file.");
        return;
    }
    
    size_t non_flushed_writes = 0;
    size_t flush_cnt = 0;
    uint32_t write_cnt = 0;
    
    while(true) {
        if(timer >= 5000) {
            timer -= 5000;
            blink();
        }
        if(timer_sd_write >= 10000) {
            timer_sd_write -= 10000;
            uint32_t start_time = millis();
            static std::array<uint8_t, 16*1024> buffer = {};
            file.write(buffer.data(), buffer.size());
            written_bytes += buffer.size();
            uint32_t end_time = millis();
            uint32_t elapsed = end_time - start_time;
            Serial1.print(write_cnt); Serial1.print(": ");
            Serial1.print("  fsize: "); Serial1.print(written_bytes);
            Serial1.print("  write time: ");
            Serial1.println(elapsed);
            non_flushed_writes++;
            write_cnt++;

            if(non_flushed_writes >= 20) {
                non_flushed_writes = 0;
                file.flush();
                end_time = millis();
                elapsed = end_time - start_time;
                Serial1.print("Flush time: "); Serial1.print(elapsed);
                Serial1.print("  Flush count: "); Serial1.println(flush_cnt);
                flush_cnt++;
            }
        }
        asm volatile ("dsb");
        asm volatile ("wfi");
    }
}

void loop() { blink(); delay(500); }
 
Last edited:
Looks like the value is '1' either way - but this is confusing: pinMode(LED_BUILTIN, HIGH); >>pinMode(LED_BUILTIN, OUTPUT);

The prints are to Serial1 - so with NO_USB ( which I think the build enforces? ) I assume that is seen to work?

SDIO function at 2 MHz would be cool - Assuming you are getting some stuff there showing it does work - but doing 'wfi' without always flushing first could cause grief. Does it do better if you comment out the :: asm("wfi"); ?

Not sure about the rules on SD card and holding power high to the chip to be ready? Closing the file might let the data flush and drop the 'ready' power on the SD? Could see that on current usage perhaps.
 
Looks like the value is '1' either way - but this is confusing: pinMode(LED_BUILTIN, HIGH); >>pinMode(LED_BUILTIN, OUTPUT);
That's a typo, but it's the same anyway.
core_pins.h:
#define OUTPUT 1
#define HIGH 1

The prints are to Serial1 - so with NO_USB ( which I think the build enforces? ) I assume that is seen to work?
Yes, USB is disabled.
SDIO function at 2 MHz would be cool - Assuming you are getting some stuff there showing it does work
It does work at 2MHz without VLPS (and T3.6 both VLPS on and off).
Does it do better if you comment out the :: asm("wfi"); ?
No.
Not sure about the rules on SD card and holding power high to the chip to be ready? Closing the file might let the data flush and drop the 'ready' power on the SD? Could see that on current usage perhaps.
That's why I'm using SD and not SdFat. The card sleeps perfectly fine. It goes to sleep immediately after each write, no need to flush or close the file. SdFat uses open multi-sector writes that keep the card awake.

Power consumption is 17.5mA with SdFat-beta, 1.1mA with SD.
 
Last edited:
That's why I'm using SD and not SdFat. The card sleeps perfectly fine. It goes to sleep immediately after each write, no need to flush or close the file. SdFat uses open multi-sector writes that keep the card awake.
I found the magic incantation to get SdFat to close the write (it issues SD CMD12 to terminate the multi-block transfer that is open): "SD.card()->syncBlocks();". With this code, the card goes to sleep just like with SD.

Code:
#include <array>
#include <SdFat.h>

const char* log_file_name = "log.bin";

SdFatSdioEX SD;

void blink() {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(200);
    digitalWrite(LED_BUILTIN, LOW);
}

void setup() {
    //SMC_PMCTRL &= ~SMC_PMCTRL_RUNM(0b11); // disable VLPR
    elapsedMillis timer;
    elapsedMillis timer_sd_write;

    pinMode(LED_BUILTIN, OUTPUT);

    Serial1.begin(115200);
    delay(1000);
    
    Serial1.println("Init SD card");

    if (!SD.begin()) {
        Serial1.println("SD init failed.");
        return;
    }
    Serial1.println("SD init done.");

    size_t written_bytes = 0;
    SD.remove(log_file_name);
    File file = SD.open(log_file_name, FILE_WRITE);

    if (!file) {
        Serial1.println("Error opening log file.");
        return;
    }
    
    size_t non_flushed_writes = 0;
    size_t flush_cnt = 0;
    uint32_t write_cnt = 0;
    
    while(true) {
        if(timer > 5000) {
            timer -= 5000;
            blink();
        }
        if(timer_sd_write > 10000) {
            timer_sd_write -= 10000;
            uint32_t start_time = millis();
            static std::array<uint8_t, 16*1024> buffer = {};
            file.write(buffer.data(), buffer.size());
            SD.card()->syncBlocks();
            written_bytes += buffer.size();
            uint32_t end_time = millis();
            uint32_t elapsed = end_time - start_time;
            Serial1.print(write_cnt); Serial1.print(": ");
            Serial1.print("  fsize: "); Serial1.print(written_bytes);
            Serial1.print("  write time: ");
            Serial1.println(elapsed);
            non_flushed_writes++;
            write_cnt++;

            if(non_flushed_writes >= 20) {
                non_flushed_writes = 0;
                file.flush();
                end_time = millis();
                elapsed = end_time - start_time;
                Serial1.print("Flush time: "); Serial1.print(elapsed);
                Serial1.print("  Flush count: "); Serial1.println(flush_cnt);
                flush_cnt++;
            }
        }
        while(Serial1.available()) Serial1.read();
        asm volatile ("dsb");
        asm volatile ("wfi");
    }
}

void loop() { blink(); delay(500); }
 
Last edited:
Back
Top