Raspberry Pi Pico USB Serial (CDC) not appearing on macOS

Dear all,

I am currently working on Chapter 8 of my Raspberry Pi Pico Ada tutorial, which demonstrates USB serial communication using the CDC ACM profile. This approach should eliminate the need for an external debug probe or USB-to-RS232 adaptor.

Unfortunately, I am unable to get USB serial working on macOS. Neither my own implementation nor Jeremy Grosser’s well-known usb_echo example produces a visible serial device:

  • No /dev/tty.* device appears
  • system_profiler SPUSBDataType shows no new USB device from the Pico

Links:

The code builds and flashes without error, and the Pico appears to be running. The issue seems specific to macOS USB enumeration.

Has anyone successfully used USB CDC serial with Ada (or even C/C++) on a Pico under macOS? Any known macOS-specific configuration, driver, or picotool / uf2 flashing quirks I should be aware of?

Thank you in advance for any assistance.

Best regards,
Martin Krischik

Are you using a single configuration or a composite configuration (multiple USB functions) ?

Single. Only USB_Serial. As does Jeremy’s example. However his examples are sometimes out of date. In the WS2812 sample code the RP.PIO.Enable call is missing. It is quite possible that a call in missing here as well.

Martin

See e.g. Fix lsusb requests · Pull Request #11 · Fabien-Chouteau/usb_embedded
I have some working code for USB serial including “standard” Pico reboot to bootloader.

I can compare it to your code later, maybe I can spot the problem.

Since you don’t use interrupts, you have to call Poll at regular intervals.

Reminds me of the fact, that I wanted to submit a PR with improved documentation…

Never returns from Poll. That’s interesting.

I added Poll in a separate task on CPU 2 and everything runs but the USB device still doesn’t appear in the system_profiler SPUSBDataType list. Not sure if wireshark helps if the device isn’t even seen by the OS.

That USB_Stack.Poll; never works makes me wonder about @JeremyGrosser example. How is that supposed to work.

There is also a usb_echo_interrupt example. Maybe I try that one next

The is a get for CDC_Line_Coding but no set. So you can never set the baut rate. That’s limiting.

Wireshark is low level tool, it listen for packages on USB bus, even if host/device can’t understand them.

Hello,

Thank you very much for your suggestions — they have already helped significantly.

Progress update: macOS now correctly detects the Pico. Both the Debug Probe and my Ada application appear in system_profiler SPUSBDataType:

>Debug-Search-Devices.command 
Debug Probe (CMSIS-DAP):

            Debug Probe (CMSIS-DAP):

              Product ID: 0x000c
              Vendor ID: 0x2e8a
              Version: 2.30
              Serial Number: E664A836A3096D37
              Speed: Up to 12 Mb/s
              Manufacturer: Raspberry Pi
              Location ID: 0x14420000 / 34
              Current Available (mA): 500
              Current Required (mA): 100
              Extra Operating Current (mA): 0

Ada Device:

            Sketch_08_1_Serial_Print (Ada):

              Product ID: 0x000c
              Vendor ID: 0x2e8a
              Version: 1.21
              Serial Number: 4F72A1C3D9B8E7F1
              Speed: Up to 12 Mb/s
              Manufacturer: Raspberry Pi Pico
              Location ID: 0x14410000 / 10
              Current Available (mA): 500
              Current Required (mA): 100
              Extra Operating Current (mA): 0

I have also moved USB_Stack.Poll into a proper interrupt handler as recommended.

CoolTerm can now connect to the virtual serial port, but unfortunately no data is being received from the Pico. The program builds and runs without error but nothing appears in in CoolTerm.

The repository has been updated with the latest version.

Has anyone experienced a similar issue where the CDC device enumerates correctly and a terminal can connect, but no data is transferred? Any suggestions on what to check next (buffer handling, interrupt priorities, TinyUSB configuration, etc.) would be greatly appreciated.

Best regards, Martin

The pico example used to work. I think I remember check the last usb_embedded version with them.

Wireshark can be a good resource, but you have to get familiar with the USB protocol to understand what’s going on.

These are settings that you receive from the USB host and you should apply to the hardware UART when in a USB to serial adaptor situation. Here you are not mapping to a hardware UART so there settings have no meaning.

I checked the source code and had a closer look at Len and decided that it would be a good idea to check the returned Len. And indeed that showed some interesting behaviour:

+ Sketch_08_1_Serial_Print.Main
> Initialising Main
+ USB_Task
> Coding.Bitrate   =>  115200
> Coding.Data_Bits =>  8
> Coding.Stop_Bit  =>  0
> Coding.Parity    =>  0
- USB_Task
> Data written     =>  43
> Starting main loop
> Writing to USB Serial
> Data written     =>  11
> Writing to USB Serial
> Data written     =>  11
> Writing to USB Serial
> Data written     =>  11
> Writing to USB Serial
> Data written     =>  11
> Writing to USB Serial
> Data written     =>  0
> Writing to USB Serial
> Data written     =>  0
> Writing to USB Serial
> Data written     =>  0
> Writing to USB Serial
> Data written     =>  0
> Writing to USB Serial
> Data written     =>  0

That looks like the output buffer is just filled up and never send. I’ll take it that wireshark won’t help here.

Once just once it worked and data output was shown in CoolTerm but I was never able to repeat it.

Last not least I noted that there is some kind of logging in usb_embedded but I don’t understand how that is supposed to work as the data is just written list which can’t be accessed.

If the data was accessible I could write them UART_IO.

Do you have a second Pico that you can use as a debugger?

I remember that I once had similar issues when I didn’t wait until the terminal program has connected before sending any data.

I have Raspberry Debug Probe and I use it for debugging. It’s also connected to UART0 which works for serial I/O — that’s where the log comes from.

But for the next part of the tutorial I need to get USB serial up and running.

What I also didn’t to work is Ada.Text_IO which should, AFAIK, output via the debug port. But instead it just crashes.

A Debug Probe is money well spend. I also have a Pico 2 but Pico 2 and Ada isn’t quite there yet. There is an blog post on how to setup:

Ada.Text_IO on all my runtimes use semihosting, which requires an attached debugger to be able to read their output (see the runtime documentation here).

Unfortunately, on Armv6-M targets like the RP2040, if you try to use semihosting without a debugger attached then semihosting calls will trigger a HardFault. This doesn’t happen on other architectures like Armv7-M, since they allow the CPU to be configured to ignore semihosting calls if no debugger is attached.

I’d like to make Ada.Text_IO configurable to implement some other choices, but I haven’t gotten around to that yet.

But I have a debugger attached and it still crashes:

I also had another successfull run:

Raspberry Pi Pico initialization completed!
 4307908927
 4308952227
 4309995457
 4311038676
 4312082070
 4313125803
 4314169541
 4315213283
 4316257020

What I noted here that I had a breakpoint after Initialise. Without the breakpoint it didn’t work. That idicates timing as well.

Sorry, I forgot to mention that you also need to enable semihosting in your debug probe (it’s usually disabled by default).

I don’t know what the command is for your debug setup, but with my J-Link I run the command monitor semihosting enable from GDB to enable it.

For OpenOCD I think it’s monitor arm semihosting enable.

Before you do any I/O on USB_Serial (also for write!) you need to check USB_Serial.List_Ctrl_State.DTE_Is_Present. Otherwise the buffer will fill up since the host does not fetch the data and Poll eventually does not return.

Update: A delay 1.0 between init and first write does the trick. delay 0.5 was not enough. I suspect some timing problem.