platformio / platform-teensy

Teensy: development platform for PlatformIO
https://registry.platformio.org/platforms/platformio/teensy
Apache License 2.0
88 stars 48 forks source link

can't compile/upload for two teensies simultaneously #78

Open defenestrated opened 2 years ago

defenestrated commented 2 years ago

Description of problem

When uploading to two teensy boards, either a 4.1 & 3.6 or two 3.6's, platformio can't compile / upload for the correct boards, even when explicit upload_ports are set. See https://community.platformio.org/t/one-project-two-boards-two-codebases-with-src-filter/23586/6 for a more thorough explanation.

Sketches build apparently successfully and can be uploaded via TyCommander no problem.

Steps to Reproduce

  1. create two files, primary.cpp and secondary.cpp
  2. set up platformio.ini as below
  3. run platformio-upload

Actual Results

Expected Results

PlatformIO builds each env correctly and uploads to the appropriate board. Teensy CLI should be able to figure out which board is which if they're different versions at least.

If problems with PlatformIO Build System:

The content of platformio.ini:

[env:one]
platform = teensy
board = teensy36
framework = arduino
upload_protocol = teensy-cli
upload_port = /dev/cu.usbmodem102538701 ; the 3.6 is on this port
src_filter = +<*> -<.git/> -<.svn/> -<example/> -<examples/> -<test/> -<tests/> -<secondary.cpp*>

[env:two]
platform = teensy
board = teensy41
framework = arduino
upload_protocol = teensy-cli
upload_port = /dev/cu.usbmodem89957801 ; the 4.1 is on this port
src_filter = +<*> -<.git/> -<.svn/> -<example/> -<examples/> -<test/> -<tests/> -<primary.cpp*>

Source file to reproduce issue:

// primary.cpp
int led = LED_BUILTIN;

void setup() {
  pinMode(led, OUTPUT);
  Serial.begin(9600);
  while(!Serial && millis() < 4000);
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  Serial.println("hi i'm primary");
}

void loop() {
  digitalWrite(led, HIGH);
  delay(100);
  digitalWrite(led, LOW);
  delay(200);
}
// secondary.cpp
int led = LED_BUILTIN;

void setup() {
  pinMode(led, OUTPUT);
  Serial.begin(9600);
  while(!Serial && millis() < 4000);
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  Serial.println("hi i'm secondary");
}

void loop() {
  digitalWrite(led, HIGH);
  delay(1000);
  digitalWrite(led, LOW);
  delay(2000);
}
ivankravets commented 2 years ago

See

PaulStoffregen commented 2 years ago

@ivankravets - Maybe PlatformIO is detecting only serial ports for "upload_port" mentioned here?

Teensy's upload process (teensy_post_compile) does not use serial port names. It uses USB location names. For example, on MacOS the name is "usb:#########" where the number encoded the physical USB controller and chain of hubs/ports to reach the actual USB device.

image

The "teensy_ports" program is meant to be run to give a list of all the Teensy devices connected and their port location name.

If you don't do this and just run the upload process without a proper location name, it will attempt to upload to the first device it can find, since you didn't tell it a proper location.

We use location names rather than serial port names because Teensy is capable of many protocols which are not USB serial, like Keyboard, Mouse, Joystick, Audio, RawHID, etc. In those other modes, there is no serial port name at all. The USB location name is the reliable way to specify exactly which USB board to access, regardless of which protocol it is currently implementing.

valeros commented 2 years ago

Hi @PaulStoffregen ! Could you please elaborate on how to use these tools together? I tried the teensy_ports app but it seems it runs in an infinite loop waiting for boards. Is there any way to control it via timeout or something?

Even if we manage to retrieve the list of connected boards and their port locations, how to pass this data to the Teensy GUI uploader (or Teensy CLI loader )? Is there any documentation on this matter?

PaulStoffregen commented 2 years ago

Run with -L if you want to just see a list and quit. Otherwise it will continue running indefinitely and print info as ports appear and vanish.

valeros commented 2 years ago

Thanks @PaulStoffregen , could you please also shed some light on the upload process and how it should be implemented to distinguish two simultaneously connected boards? Let's imagine we managed to get USB locations, how to pass this data to the Teensy GUI uploader (or Teensy CLI loader )?

PaulStoffregen commented 2 years ago

The basic idea is you give the location info you got from "teensy_ports" to "teensy_post_compile".

The teensy_post_compile program will first tell Teensy Loader to open the file and go into Auto mode. Auto mode means Teensy Loader will automatically reprogram and reboot the next Teensy it finds. Then once Teensy Loader is ready, teensy_post_compile finds the Teensy you specified and sends it a message requesting reboot into bootloader mode. If the USB communication is not successful, which can indeed fail if Teensy has interrupts disable or is stuck in sleep mode or has disabled its USB port, then after several seconds a message is printed asking the user to manually press the pushbutton. But the normal flow is Teensy still runs whatever code was previously programmed, so it can hear the request teensy_post_compile sends, and as soon as your PC detect the device, Teensy Loader see it and does the upload because it was set to Auto mode.

valeros commented 2 years ago

@PaulStoffregen

The basic idea is you give the location info you got from "teensy_ports" to "teensy_post_compile".

Am I missing something or the teensy_post_compile tool doesn't accept any arguments regarding USB locations?

teensy_post_compile.exe --help

teensy_post_compile - inform the Teensy Loader of freshly compiled code

Usage:
   teensy_post_compile -file=<file> -path=<path> -tools=<toolspath>

       <file> - The code to program (without .hex) to your Teensy board
       <path> - The directory where <file.hex> is located
       <toolspath> - The directory where the Teensy Loader is located
PaulStoffregen commented 2 years ago

The usage info was not updated as more options were added. Sadly, this stuff just isn't documented well. Best source for info right now is to run Arduino with "verbose info during compilation" turned on from File > Preferences. Then you can see the actual command line usage.

PaulStoffregen commented 2 years ago

I will update the usage info for version 1.56. Here is the updated info.

teensy_post_compile - inform the Teensy Loader of freshly compiled code

Usage:
   teensy_post_compile [-v] -file=<file> -path=<path> [-tools=<toolspath>]
                       [-board=<board>] [-port=<port>] [-portlabel=<name>]
                       [-reboot]

      -file=<file>        Code to program (without .hex) to your Teensy board
      -path=<path>        Directory where <file.hex> is located
      -tools=<toolspath>  Directory where Teensy Loader is located
      -board=<board>      Board expected to be found
      -port=<port>        USB location (from teensy_ports)
      -portlabel=<name>   User visiable name for port
      -reboot             Send request to go into bootloader mode
      -v                  Show verbose info
valeros commented 2 years ago

Many thanks for the updates! I also checked the output of teensy_ports -L and it seems there is no info about USB locations, only some generic specs:

Port_#0002.Hub_#0008 COM44 (Teensy 3.2) Serial

If I run it in continuous mode I can see the address field:

{
  "address": "usb:0/140000/0/6/2",
  "online": true,
  "label": "COM44 (Teensy 3.2) Serial",
  "vid": "16C0",
  "pid": "0483",
  "iserial": "167924",
  "boardName": "Teensy 3.2",
  "protocol": "Teensy"
}

Any hints?

PaulStoffregen commented 2 years ago

You might also think about running teensy_secure to create the EHEX file for people who have an encryption key.

Good news is this does have documentation. Scroll to the end for "Integration with Non-Arduino Development Tools".

https://www.pjrc.com/teensy/td_code_security.html

The short version: just run "teensy_secure encrypthex [key.pem]" after running objdump to create the HEX file. It will create a EHEX file, using the HEX file.

Teensy Loader will automatically use the EHEX file if you opened the HEX file and hardware is found which supports use of encryption.

PaulStoffregen commented 2 years ago

Oh no, looks like teensy_ports -L is indeed broken on Windows. I will fix -L in the next version, but at least for now, the JSON output for Arduino is the only way. :(

PaulStoffregen commented 2 years ago

Here is a Windows build of teensy_ports with the -L bug fixed.

https://www.pjrc.com/tmp/teensy_ports.exe

Also updated usage info.