earlephilhower / arduino-pico

Raspberry Pi Pico Arduino core, for all RP2040 and RP2350 boards
GNU Lesser General Public License v2.1
2.03k stars 422 forks source link

while(!Serial) returns TRUE while the serial state machine is not ready quite yet. #1563

Closed lindoran closed 1 year ago

lindoran commented 1 year ago

was trying this example program which uses !Serial to determine if the USB port is connected. However, when run it cuts off the top half of the output. (this is using the Pico SDK USB stack and a plain old Pi Pico dev board.)

 /*
  ASCII table

  Prints out byte values in all possible formats:
  - as raw binary values
  - as ASCII-encoded decimal, hex, octal, and binary values

  For more on ASCII, see http://www.asciitable.com and http://en.wikipedia.org/wiki/ASCII

  The circuit: No external hardware needed.

  created 2006
  by Nicholas Zambetti 
  modified 9 Apr 2012
  by Tom Igoe

  This example code is in the public domain.

  https://www.arduino.cc/en/Tutorial/BuiltInExamples/ASCIITable
*/

void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin (115200);
  while (!Serial) {
    ;  // wait for serial port to connect. Needed for native USB port only
  }

  // prints title with ending line break
  Serial.println("ASCII Table ~ Character Map");
}

// first visible ASCIIcharacter '!' is number 33:
int thisByte = 33;
// you can also write ASCII characters in single quotes.
// for example, '!' is the same as 33, so you could also use this:
// int thisByte = '!';

void loop() {
  // prints value unaltered, i.e. the raw binary version of the byte.
  // The Serial Monitor interprets all bytes as ASCII, so 33, the first number,
  // will show up as '!'
  Serial.write(thisByte);

  Serial.print(", dec: ");
  // prints value as string as an ASCII-encoded decimal (base 10).
  // Decimal is the default format for Serial.print() and Serial.println(),
  // so no modifier is needed:
  Serial.print(thisByte);
  // But you can declare the modifier for decimal if you want to.
  // this also works if you uncomment it:

  // Serial.print(thisByte, DEC);

  Serial.print(", hex: ");
  // prints value as string in hexadecimal (base 16):
  Serial.print(thisByte, HEX);

  Serial.print(", oct: ");
  // prints value as string in octal (base 8);
  Serial.print(thisByte, OCT);

  Serial.print(", bin: ");
  // prints value as string in binary (base 2) also prints ending line break:
  Serial.println(thisByte, BIN);

  // if printed last visible character '~' or 126, stop:
  if (thisByte == 126) {  // you could also use if (thisByte == '~') {
    // This loop loops forever and does nothing
    while (true) {
      continue;
    }
  }
  // go on to the next character
  thisByte++;
}

I did notice we CAN make it work by introducing a 1.5s delay to make sure the serial port is really ready to go. by amending to :

 
 //Initialize serial and wait for port to open:
  Serial.begin (115200);
  delay(1500);
  while (!Serial) {
      // wait for serial port to connect. Needed for native USB port only
  }

This issue is the same for Serial.write as well. I did find if you change this to wait for characters in the RX buffer by using Serial.available(), it works correctly. however then you have to press a key ... and I am fairly sure the human delay and the de-bounce delay in the keyboard works out to around 1.5s. so then were splitting hairs.

earlephilhower commented 1 year ago

That's a combination of OS and serial monitor and unfortunately there's nothing I know of that can be done on the Pico end. The operator bool just returns the USB connectivity state directly: https://github.com/earlephilhower/arduino-pico/blob/9e89dda9005545fc09298e8fe32cacfb9d4af922/cores/rp2040/SerialUSB.cpp#L171

As far as the Pico knows, the USB endpoint has been set and is ready. Whether the OS and monitor can re-open the special /dev/ttyACMx or COMx: file before things start being sent (and they are discarded by the OS if the special file is not opened) is a game of chance. :(

lindoran commented 1 year ago

fair enough :) at least that's an answer that makes sense. Its funny on an Arduino Mega (uses the same /dev/ttyACMx file) you don't see the issue but a 8 bit avr running at 16 mhz. prob has a hard enough time getting serial active in 1.5s let alone running through all the machine code for Serial.begin. I can work around it with the delay... just makes the reset window that much longer on the project.

earlephilhower commented 1 year ago

On the AVRs it's a separate chip that connects to USB, not the AVR itself (at least on Uno etc.) So, there is always a /dev/ttyXXX or COMx port. Here, the Pico itself needs to run code so when you upload the port goes away.

lindoran commented 1 year ago

Ok, but in this case the issue happens if you plug the device in and the file is present, then when you launch your terminal issue still happens. So to clarify the device is present and ready in the system but there is still an issue.

On Sun, Jun 25, 2023, 4:52 PM Earle F. Philhower, III < @.***> wrote:

On the AVRs it's a separate chip that connects to USB, not the AVR itself (at least on Uno etc.) So, there is always a /dev/ttyXXX or COMx port. Here, the Pico itself needs to run code so when you upload the port goes away.

— Reply to this email directly, view it on GitHub https://github.com/earlephilhower/arduino-pico/issues/1563#issuecomment-1606274090, or unsubscribe https://github.com/notifications/unsubscribe-auth/AQIK5ZAEJ3DCQ5PZQU7VC4TXNCXJBANCNFSM6AAAAAAZTLGUG4 . You are receiving this because you authored the thread.Message ID: @.***>