Teensy 3 startup procedure

Status
Not open for further replies.

Matthew

Member
Hello,

I'm missing something and I would like to clear it out. Let's start with code (I'm using Arduino IDE 1.8.10 and Teensyduino 1.48 and Teensy 3.6 in this example) - toogling the pin 13 (PC5):

Code:
#include <Arduino.h>

void setup()
{
    pinMode(13, OUTPUT);
}

void loop()
{
    GPIOC_PTOR |= (uint32_t)(1 << 5);  // make use of pin toggle output register (PTOR)
}

void yield(){}

It works just fine, I get ~4.73MHz (almost) square wave.

Now I have something like that (setting up pin 13 using registers):

Code:
#include <Arduino.h>

void setup()
{
    pinMode(11, OUTPUT);              // ! setting pin 11 not 13
    PORTC_PCR5 = (uint32_t)(1 << 8);  // set as GPIO mode
    GPIOC_PDDR |= (uint32_t)(1 << 5); // set as Output
}

void loop()
{
    GPIOC_PTOR |= (uint32_t)(1 << 5); // make use of pin toggle output register (PTOR)
}

void yield(){}

And same as before I get ~4.73MHz (almost) square wave.

In all above examples the program size is: 8784 bytes (~0.84%) and global variables take 3048 bytes (~1.16%).


But if i do something like that - remove pinMode() and only use the registers:
Code:
#include <Arduino.h>

void setup()
{
//    pinMode(11, OUTPUT);              // ! setting pin 11 not 13
    PORTC_PCR5 = (uint32_t)(1 << 8);  // set as GPIO mode
    GPIOC_PDDR |= (uint32_t)(1 << 5); // set as Output
}

void loop()
{
    GPIOC_PTOR |= (uint32_t)(1 << 5); // make use of pin toggle output register (PTOR)
}

void yield(){}

The program size is now: 2440 bytes (~0.23%) and global variables take 1092 bytes (~0.41%). Which is great, but unfortunately the program is not working now. I guess that startup initialization (.startup section ?) is missing when no core's function is used.

I would be very grateful for pointing me out what is the issue and how to make it right and maybe explain with details why .startup section (if it is the issue) is not invoked in such case.I also appreciate the quick explanation of low-level initialization stuff connected with it.
 
Something strange is going on here, and it's related to the blank yield() function.

For example, this runs and produces a 30 MHz waveform, but fails if the yield function is uncommented.

Code:
void setup()
{
    PORTC_PCR5 = PORT_PCR_MUX(1);
    GPIOC_PDDR |= (uint32_t)(1 << 5); // set as Output
}

void loop()
{
   while (1) {
     GPIOC_PTOR = (uint32_t)(1 << 5); // make use of pin toggle output register (PTOR)
   }
}

//void yield() {}

I'm looking into the details now.....
 
Indeed, with core yield() (not overrided in main) it works ok.

With implemented yield(), at least one core functions must be invoked, for example:

Code:
#include <Arduino.h>

void setup()
{
    PORTC_PCR5 = PORT_PCR_MUX(1);
    GPIOC_PDDR |= (uint32_t)(1 << 5); // set as Output
}

void loop()
{
   while (1) {
     GPIOC_PTOR = (uint32_t)(1 << 5); // make use of pin toggle output register (PTOR)
   }
}

void yield(void)
{
    millis();
}

And then it works. I just guess that something looks to be optimized out, but how? The amount of code with and without any core function is about 3x different in size.
 
Yes, indeed something is optimized away. In fact, after inspecting the code the compiler is generating, *everything* is being completely optimized away. Well, everything except some small chunks of code from the compiler and C lib. Not just the startup code & USB stack are missing from the final binary, but your code too!

Turns out we've never had the linker script explicitly require the vector table. So if you don't access at least 1 thing from the core lib, as pretty much always happens for normal programs, then the compiler builds a binary without even the vector table needed for the ARM core to start running. The result is an immediate fault when it tries to fetch the very first instruction.

I've committed a fix.

https://github.com/PaulStoffregen/cores/commit/5e3ce5a4cab5c1f3c41d2f744e4c1850789faeaf

I'm running your original program now and I can confirm it is producing ~4.7 MHz on pin 13.
 
Yes, indeed something is optimized away. In fact, after inspecting the code the compiler is generating, *everything* is being completely optimized away. Well, everything except some small chunks of code from the compiler and C lib. Not just the startup code & USB stack are missing from the final binary, but your code too!

Turns out we've never had the linker script explicitly require the vector table. So if you don't access at least 1 thing from the core lib, as pretty much always happens for normal programs, then the compiler builds a binary without even the vector table needed for the ARM core to start running. The result is an immediate fault when it tries to fetch the very first instruction.

I've committed a fix.

After pulling the changes, it works! Thank you very much!

At least i could find "bugs" to make Teensy better.
 
Status
Not open for further replies.
Back
Top