Unit test Wio Terminal "could not open port" while testing

I am using the Wio Terminal and can build and upload SW using the PlatformIO extension for VSCode. That works fine. But I started with unit tests for that device and cannot get it working.

When I call pio test I get:

[============================  ] 93% (30/32 pages)
[============================= ] 96% (31/32 pages)
[==============================] 100% (32/32 pages)
If you don't see any output for the first 10 secs, please reset board (press reset button)

[Errno 13] could not open port /dev/ttyACM0: [Errno 13] Permission denied: '/dev/ttyACM0'
================================================================================ [FAILED] Took 12.80 seconds ================================================================================

Test           Environment         Status    Duration
-------------  ------------------  --------  ------------
test_embedded  seeed_wio_terminal  FAILED    00:00:12.800
=========================================================================== 1 failed, 0 succeeded in 00:00:12.800 ===========================================================================

I don’t understand the error message could not open port /dev/ttyACM0: [Errno 13] Permission denied: '/dev/ttyACM0' as upload of normal board SW works fine.

My platform.io file looks like:

platform = atmelsam
board = seeed_wio_terminal
framework = arduino
lib_deps = 
	adafruit/Adafruit Zero DMA Library@^1.0.8

The test is:

#include <Sensor/Sensor.h>
#include <unity.h>
#include "rpcWiFi.h"

void TestConvertTemperatureToString(void)
    TEST_ASSERT_EQUAL(32, 32);

void setup()
    // NOTE!!! Wait for >2 secs
    // if board doesn't support software reset via Serial.DTR/RTS


void loop()

I have run the test with an ESP8266 board and it runs fine. So somehow it is related to the Wio Terminal board. I have also checked the rules.d/99-platformio-udev.rules file as described in Redirecting.... It did not contain the PID and VID of the board so I have added that. But the unit test with the Wio Terminal still produces the error described above. Not sure what to do.

On some MCUs (SAMD21 based ones, e.g.) which implement the serial via the MCU’s USB peripheral, I’ve seen code of the style

while(!Serial) {}

which, by C++ operator overload magic, waits for a connection to the serial. You may still want to have a short delay after that. Or maybe you want to do a Serial.begin() before that too?

Another possibility is that some other Linux component, e.g. the modem manager, is accessing or probing the serial port to see if it’s a modem when the MCU re-enumerates the USB connection and provides a new serial. See e.g. Prevent modem manager to capture usb serial devices - Embedded - Linux Tips, as there’s also a udev directive there to tell the modem manager to keep its hands to itself.

@maxgerhardt thanks for the hints but it did not help.

I have changed setup() to

void setup()
    while (!Serial && !Serial.available())


but still the same error. I had already added a line

ATTRS{idVendor}=="2886", ATTRS{idProduct}=="802d", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"

to /etc/udev/rules.d/99-platformio-udev.rules but still I get the error. And I get it immediately after the log

If you don't see any output for the first 10 secs, please reset board (press reset button)

There is no delay between this an the error

[Errno 13] could not open port /dev/ttyACM0: [Errno 13] Permission denied: '/dev/ttyACM0'

I found a work around. When I open the PlatformIO Serial Monitor afterwards I get the log output from my testcase. But still would be nice to avoid that error message.

Okay there may just be timing issues here paired with the re-enumeration of the USB and serial device.
Please do a sudo apt install moreutils (to install the ts command) start a terminal and type

 tail -f /var/log/kern.log | ts "%.T"

After your password entry press enter to have a empty line separator.

In a PlatformIO CLI terminal, execute

pio test | ts "%.T"

to run the test and have timestamps with submillisecond accuracy. Then upload both the dmesg log after the newline and the pio test log here or to pastebin.com.

I use Manjaro based on Arch Linux and cannot find the ts command or /var/log/kern.log.

But I agree with you that it is probably a timing issue. I called

pio test; ls -l /dev/ttyACM0

and got

crw------- 1 root root 166, 0 17. Nov 20:03 /dev/ttyACM0

When I call ls -l /dev/ttyACM0 afterwards I get

crw-rw-rw- 1 root uucp 166, 0 17. Nov 20:03 /dev/ttyACM0

Just a moment. You will get the desired logs.

Ah sorry I assumed a debian based thing like Ubuntu. But moreutils is also in the Arch repo thingy for the ts command.
The main thing I wanted is the dmesg log but in the same timestamp format using ts… Is there dmesg in Arch/Manjaro? On debian it maps to the above file.

Here it is:

➜ pio test | ts "%.T"
20:21:55.277869 Verbose mode can be enabled via `-v, --verbose` option
20:21:55.277974 Collected 1 items
20:21:55.278017 Processing test_embedded in seeed_wio_terminal environment
20:21:55.278035 --------------------------------------------------------------------------------
20:21:55.278417 Building...
20:22:00.141145 Uploading...
20:22:07.893938 Testing...
20:22:07.894086 If you don't see any output for the first 10 secs, please reset board (press reset button)
[Errno 13] could not open port /dev/ttyACM0: [Errno 13] Permission denied: '/dev/ttyACM0'
========================= [FAILED] Took 12.88 seconds =========================
Test           Environment         Status    Duration
-------------  ------------------  --------  ------------
test_embedded  seeed_wio_terminal  FAILED    00:00:12.885
==================== 1 failed, 0 succeeded in 00:00:12.885 ====================


➜ sudo dmesg -W | ts "%.T"
20:22:04.769607 [ 6326.724031] usb 1-2: USB disconnect, device number 39
20:22:05.056316 [ 6327.016836] usb 1-2: new full-speed USB device number 40 using xhci_hcd
20:22:05.196276 [ 6327.159113] usb 1-2: New USB device found, idVendor=2886, idProduct=002d, bcdDevice=42.01
20:22:05.196410 [ 6327.159119] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
20:22:05.196459 [ 6327.159123] usb 1-2: Product: Wio Terminal
20:22:05.196506 [ 6327.159126] usb 1-2: Manufacturer: Seeed Studio
20:22:05.196549 [ 6327.159129] usb 1-2: SerialNumber: 7CEC16765337533438202020FF0F3C36
20:22:05.199597 [ 6327.162935] cdc_acm 1-2:1.0: ttyACM0: USB ACM device
20:22:05.203045 [ 6327.163695] usb-storage 1-2:1.2: USB Mass Storage device detected
20:22:05.203247 [ 6327.164127] scsi host1: usb-storage 1-2:1.2
20:22:05.203386 [ 6327.165835] hid-generic 0003:2886:002D.0010: hiddev0,hidraw0: USB HID v1.00 Device [Seeed Studio Wio Terminal] on usb-0000:00:14.0-2/input3
20:22:06.208091 [ 6328.170569] scsi 1:0:0:0: Direct-Access     Wio Term inal             1.00 PQ: 0 ANSI: 2
20:22:06.208165 [ 6328.171274] sd 1:0:0:0: [sdb] 16000 512-byte logical blocks: (8.19 MB/7.81 MiB)
20:22:06.208187 [ 6328.171533] sd 1:0:0:0: [sdb] Write Protect is off
20:22:06.208207 [ 6328.171535] sd 1:0:0:0: [sdb] Mode Sense: 0f 00 00 00
20:22:06.208225 [ 6328.171716] sd 1:0:0:0: [sdb] No Caching mode page found
20:22:06.208243 [ 6328.171717] sd 1:0:0:0: [sdb] Assuming drive cache: write through
20:22:06.232861 [ 6328.194441]  sdb:
20:22:06.232936 [ 6328.195986] sd 1:0:0:0: [sdb] Attached SCSI removable disk
20:22:07.309510 [ 6329.270450] usb 1-2: USB disconnect, device number 40
20:22:07.309612 [ 6329.270532] cdc_acm 1-2:1.0: failed to set dtr/rts
20:22:07.762969 [ 6329.723471] usb 1-2: new full-speed USB device number 41 using xhci_hcd
20:22:07.909621 [ 6329.870653] usb 1-2: New USB device found, idVendor=2886, idProduct=802d, bcdDevice= 1.00
20:22:07.909731 [ 6329.870657] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
20:22:07.909825 [ 6329.870659] usb 1-2: Product: Seeed Wio Terminal
20:22:07.909903 [ 6329.870661] usb 1-2: Manufacturer: Seeed
20:22:07.909961 [ 6329.870663] usb 1-2: SerialNumber: 7CEC16765337533438202020FF0F3C36
20:22:07.910022 [ 6329.872653] cdc_acm 1-2:1.0: ttyACM0: USB ACM device

Hm yeah this is really interesting. So the upload starts at

And seems like its finished the moment it disconnects from the USB at

then /dev/ttyACM0 enumerates at

…followed by a mysterious USB disconnect. maybe the chip is reset manually some short time after uploading, or this is the bootloader doing something with the USB peripheral

then connects again after ~450 milliseconds

Now the problem is that circa 120 milliseconds after that we want to start testing while this thing is still re-enumerating,

… then the testing fails…

…because /dev/ttyACM0 device fully reenumerates only at

@ivankravets can a fix for that be implemented in the core with e.g. regards to a delay time as test_start_delay so that the core waits a bit before testing? The problem seems very clear to me here.

1 Like

Could you file a feature request and point to this topic? We will do research on our side on how to fix this issue.


Tracked per Add test start delay option · Issue #3742 · platformio/platformio-core · GitHub.

@windsource as workarounds you can do a sudo pio test (ugly…) or pio test --without-testing (see pio test -h for more options), and then explicitly reset the board and open the serial monitor to see the unit test results.

If you want the color output, maybe a procedure like this would work:

  • Upload the test code once using pio test --without-testing
  • Reset the board
  • (the board will re-enumare and be stuck in that delay(5000); for a while
  • Execute pio test --without-building --without-uploading and hopefully PIO will connect to a good serial port without resetting it and just wait for the test results.

Also confirmed workaround: Unit test Wio Terminal "could not open port" while testing - #17 by windsource

By the way, the problem is not only related to test.

When I upload a new SW I suppose that after the upload the Serial Monitor should start. That works for me only sometimes. In those cases when the Serial Monitor does not start after upload I get the logs:

> Executing task: pio device monitor <

--- Available filters and text transformations: colorize, debug, default, direct, hexlify, log2file, nocontrol, printable, send_on_enter, time
--- More details at http://bit.ly/pio-monitor-filters
could not open port '/dev/ttyACM0': [Errno 13] could not open port /dev/ttyACM0: [Errno 13] Permission denied: '/dev/ttyACM0'
The terminal process "pio 'device', 'monitor'" terminated with exit code: 1.

Maybe you can add a delay also in this case.

Does the existing setting

work for you when you already have the serial monitor upen and then do an upload an monitor?

Yes, that works! I wasn’t aware of that setting. Thanks a lot.

I just randomly stumbled upon this topic because someone bumped it: Any way to configure timeout for Upload-Monitor? - #2 by rubillos

A small extra_script executes a time.sleep() in Python code after the upload. That should help, too?

Thanks a lot for that hint! It works. Now I can also run unit tests.

I had to modify the script a little bit to work with python 3:


def after_upload(source, target, env):
    print("Delay while uploading...")
    import time

env.AddPostAction("upload", after_upload)
1 Like

I’m pretty sure I bumped it because I have 4 SAMD21 boards that can’t all be “bricked”.

Uploading to them has gotten progressively more (and intermittently) difficult. Now I’m completely unable to despite my efforts to restore usb/driver/com port problems in windows. I believe that part is resolved now but the upload still hangs on multiple devices.

I came to the conclusion that it might be better to upload the software using an external debugger. I’ve never used one so down that rabbit hole I went. Now I have a JeffProbe (Black Magic Probe clone) connected to the swd ports on my Wio Lite MG126 and UART ports. I believe I have platformio.ini setup correctly but there are all kinds of environments and flags when I read the documentation. Flags within flags within flags.


But I still can’t upload this [expletive] thing


It just hangs here.

It’s like I get stuck in a recursively descending series of issues trying to do work around after workaround to be able to effective start the actual programming again.

Does anyone here know what I’m talking about here or am I posting in the wrong place again?