Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 5 of 5

Thread: Teensy 3 startup procedure

  1. #1
    Junior Member
    Join Date
    Oct 2018
    Location
    Poland, Cracov
    Posts
    19

    Teensy 3 startup procedure

    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.

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,760
    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.....

  3. #3
    Junior Member
    Join Date
    Oct 2018
    Location
    Poland, Cracov
    Posts
    19
    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.

  4. #4
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,760
    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/co...4c1850789faeaf

    I'm running your original program now and I can confirm it is producing ~4.7 MHz on pin 13.

  5. #5
    Junior Member
    Join Date
    Oct 2018
    Location
    Poland, Cracov
    Posts
    19
    Quote Originally Posted by PaulStoffregen View Post
    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.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •