sam-ba can only sometimes switch /dev/ttyACM0 to binary mode on my desktop. Always works on my work laptop

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I write firmware to a SAMA5D2 based card with sam-ba using a custom QML script (just a wrapper for applet.write). On my work machine (a Debian VM on a Macbook Pro) this works 100% of the time. I boot the card into romboot, run the script with sam-ba -x ... and it writes the whole image. However, the exact same software only works on my home machine some of the time, maybe one success for every five attempts. (I'm running Manjaro on an AMD B450 chipset). When it fails sam-ba gives the error

 

Opening serial port 'ttyACM0'
Error: Could not switch monitor on port 'ttyACM0' to binary mode
Connection closed.

On my home machine the serial port always presents as

$ stty -F /dev/ttyACM0
speed 9600 baud; line = 0;
-brkint -imaxbel

 

Where the work machine it's

$ stty -F /dev/ttyACM0
speed 921600 baud; line = 0;
min = 0; time = 0;
-brkint -icrnl -imaxbel
-opost
-isig -icanon -iexten -echo

I'm unsure how to go about debugging this. Is this a Linux config issue where my serial port isn't being set up correctly?

Last Edited: Fri. Jul 17, 2020 - 02:31 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey there,

 

I have the same issue although on different machines.

My linux intel machine was able to successfully enumerate samba device for over a year and suddenly started having the same issue you are reporting :(

 

Did you have any luck debugging this?

 

Charlee

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dberliner wrote:

sam-ba can only sometimes switch /dev/ttyACM0 to binary mode on my desktop. Always works on my work laptop

This title indicates a misinterpretation of the error message "Could not switch monitor on port 'ttyACM0' to binary mode". 

The "monitor" in the error message refers to the SAM-BA Monitor, i.e. the ROM code that is expected to be executing on the target board.  

This SAM-BA Monitor program can receive command parameters and data in either text or binary mode.  The "switch" (in the error message) refers to the mode of the SAM-BA Monitor, and does not indicate any issue with the serial port.

The error message simply indicates that the target board has not properly responded to the command sent by the SAM-BA utility (executing on the PC). 

 

This error message does report that the port in use is /dev/ttyACM0, and does not indicate any status regarding that port.

This error message is rarely caused by any (termios) (mis)configuration of the serial terminal on the PC host. 

Hence occurrence of this error message should not correlate with any PC host nor location, e.g. desktop at home versus laptop at work.

 

The likeliest cause of this error message is that the target board is simply not executing the SAM-BA Monitor program. 

Refer to the SoC datasheet for the requirements of the ROM boot program to "fail" so that the SAM-BA Monitor can execute, as well as the BSC register settings which can inhibit execution of the SAM-BA Monitor.

 

The simplest method to verify that the SAM-BA Monitor is executing through the USB gadget connector is to start a terminal-emulator program (on the PC), such as minicom

Reset (and inhibit any on-board NVM devices on) the target board. 

Expect to see "RomBOOT" displayed on the screen. 

Send the version command V# and expect an appropriate response and prompt from the SAM-BA Monitor (assuming it's actually executing). 

Exit the terminal-emulator program (on the PC), and then expect the SAM-BA utility to execute without any "switch ... to binary mode" issue.

 

 

dberliner wrote:

I'm unsure how to go about debugging this.

Charlee wrote:

Did you have any luck debugging this?

 

There are two easy ways to investigate this:

 

1. Inspect the SAM-BA utility source code (that's included with most versions of the 3.x executable). 

Search for the text of the error message, and find out the reason why it's printed.

 

OR

 

2. Assuming that you're using a Linux host, use the strace command with the offending SAM-BA utility command. 

Find the open syscall for "/dev/ttyACM0" to obtain the value of the file descriptor. 

Find the write syscall to stderr for that particular error message. 

Between these two lines, find the last I/O syscall with the serial terminal's file descriptor. 

That syscall should be a write() (followed by an iteration of poll and clock_gettime to implement a timed wait for a response). 

Lookup that output string in the SAM-BA Monitor command list in the SoC datasheet.

 

 

 

 

 

 

Last Edited: Fri. Feb 25, 2022 - 02:01 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey there,

 

Thanks for you reply.

 

You say that it cannot be the PC. However, I have the issue with 3 different sam-ba devices. Furthermore, when I plug in the same device into my other windows machine I am successfully able to let sam-ba read the unique id of the device, whereas if I do the same command on my linux device (that used to be able to flash this device with no problems) I get the error "Error: Cannot open invalid port 'ttyACM0'". I even tried to run windows on this very same machine, and there I DO manage to read the unique ID.

On linux I have tried sending V# over minicom (running minicom -D /dev/ttyACM0 and typing V#), but it stays silent.

 

Then I tried  your strace tip, and to be honest looking at system calls is new for me (but it seems very useful!). I compared one for a device that cannot convert the port to binary mode with one that is successful.
They look mostly the same, until the point where they try to access the port. It seems like my device times out on polling on reaction after the second write to the port:
 

openat(AT_FDCWD, "/dev/ttyACM0", O_RDWR|O_NOCTTY|O_NONBLOCK|O_CLOEXEC) = 6
fcntl(6, F_SETFD, FD_CLOEXEC)           = 0
ioctl(6, TIOCEXCL)                      = 0
ioctl(6, TCGETS, {B9600 opost isig icanon echo ...}) = 0
ioctl(6, TCGETS, {B9600 opost isig icanon echo ...}) = 0
ioctl(6, SNDCTL_TMR_START or TCSETS, {B9600 -opost -isig -icanon -echo ...}) = 0
ioctl(6, TCGETS, {B9600 -opost -isig -icanon -echo ...}) = 0
ioctl(6, TCGETS2, {B9600 -opost -isig -icanon -echo ...}) = 0
ioctl(6, TIOCGSERIAL, 0x7ffd2d3b98f0)   = 0
ioctl(6, TCGETS, {B9600 -opost -isig -icanon -echo ...}) = 0
ioctl(6, TCGETS, {B9600 -opost -isig -icanon -echo ...}) = 0
ioctl(6, SNDCTL_TMR_START or TCSETS, {B921600 -opost -isig -icanon -echo ...}) = 0
ioctl(6, TCGETS, {B921600 -opost -isig -icanon -echo ...}) = 0
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
ppoll([{fd=6, events=POLLIN|POLLOUT}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 1 ([{fd=6, revents=POLLOUT}], left {tv_sec=0, tv_nsec=9996850})
write(6, "#", 1)                        = 1
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN|POLLOUT}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 1 ([{fd=6, revents=POLLOUT}], left {tv_sec=0, tv_nsec=9993192})
write(6, "N#", 2)                       = 2
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
write(2, "Error: Could not switch monitor "..., 65) = 65

The successful write looks as follows:

 

openat(AT_FDCWD, "/dev/ttyACM2", O_RDWR|O_NOCTTY|O_NONBLOCK|O_CLOEXEC) = 6
fcntl(6, F_SETFD, FD_CLOEXEC)           = 0
ioctl(6, TIOCEXCL)                      = 0
ioctl(6, TCGETS, {B9600 opost isig icanon echo ...}) = 0
ioctl(6, TCGETS, {B9600 opost isig icanon echo ...}) = 0
ioctl(6, SNDCTL_TMR_START or TCSETS, {B9600 -opost -isig -icanon -echo ...}) = 0
ioctl(6, TCGETS, {B9600 -opost -isig -icanon -echo ...}) = 0
ioctl(6, TCGETS2, {B9600 -opost -isig -icanon -echo ...}) = 0
ioctl(6, TIOCGSERIAL, 0x7ffc1fc88350)   = 0
ioctl(6, TCGETS, {B9600 -opost -isig -icanon -echo ...}) = 0
ioctl(6, TCGETS, {B9600 -opost -isig -icanon -echo ...}) = 0
ioctl(6, SNDCTL_TMR_START or TCSETS, {B921600 -opost -isig -icanon -echo ...}) = 0
ioctl(6, TCGETS, {B921600 -opost -isig -icanon -echo ...}) = 0
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
write(3, "\1\0\0\0\0\0\0\0", 8)         = 8
ppoll([{fd=6, events=POLLIN|POLLOUT}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 1 ([{fd=6, revents=POLLOUT}], left {tv_sec=0, tv_nsec=9998659})
write(6, "#", 1)                        = 1
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 0 (Timeout)
ppoll([{fd=6, events=POLLIN|POLLOUT}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 1 ([{fd=6, revents=POLLOUT}], left {tv_sec=0, tv_nsec=9996581})
write(6, "N#", 2)                       = 2
ppoll([{fd=6, events=POLLIN}], 1, {tv_sec=0, tv_nsec=10000000}, NULL, 8) = 1 ([{fd=6, revents=POLLIN}], left {tv_sec=0, tv_nsec=9997436})
read(6, "\n\r", 512)                    = 2
write(2, "Connection opened.\n", 19)    = 19

 

With my limited knowledge this still points towards an issue with the board, but how does that explain that if I plug in the same board, without changing anything, into a windows machine I have here, I can successfully do the "readuniqueid" call?
I would compare with a local linux machine with the same board, but I don't have access to that at the moment.

 

Kind regards, Charlee

 

P.S. Sorry for the late reply, I gave up on this for a while but would still like to solve it.

 

 

 

Charlee

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In fact, using a linux live USB on PC-device combination that otherwise presents problems seems to resolve the issue. Isn't that curious!

Another interesting fact: After I have done a successful access from a non-problematic PC, the problematic one can usually also successfully access the device once.

 

So to summarize:
Machine1 + Device 1, 2 or 3 --> "Could not switch port ttyACM0" to binary mode."

Machine2 + Device 4 --> No problems

Windows on Machine3 + Device1, 2 or 3 --> No problems
Machine1 through live USB + Device1, 2 or 3 --> No problems

 

Any further tips for debugging this? The strace tips were very useful! I haven't found the sourcecode..

 

Kind regards, Charlee

Charlee

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Charlee wrote:

You say that it cannot be the PC.

You're misquoting me.  I was not that unequivocal.

 

 

Charlee wrote:

However, I have the issue with 3 different sam-ba devices. Furthermore, when I plug in the same device into my other windows machine I am successfully able to let sam-ba read the unique id of the device, whereas if I do the same command on my linux device (that used to be able to flash this device with no problems) I get the error "Error: Cannot open invalid port 'ttyACM0'".

Hold on.  That's a completely different error message, and an indication of a different problem. 

In all likelihood, for that specific error message, you're simply using the incorrect device node.  The target board is not connecting at /dev/ttyACM0

Either inspect the /dev/ directory (e.g. 'ls /dev/ttyACM*') or check the system log (e.g. 'dmesg | tail') for the last cdc_acm message.

 

 

Charlee wrote:

On linux I have tried sending V# over minicom (running minicom -D /dev/ttyACM0 and typing V#), but it stays silent.

As I already stated, that means that minicom has connected to the target board, but the target board is probably not executing the SAM-BA Monitor program.

As a sanity check, have you tried this version command on PCs that do successfully execute the SAM-BA utility?

 

 

Charlee wrote:

With my limited knowledge this still points towards an issue with the board, but how does that explain that if I plug in the same board, without changing anything, into a windows machine I have here, I can successfully do the "readuniqueid" call?

What is this "readuniqueid" call?

 

What do you mean by "without changing anything"?  Aren't you resetting the board to establish a new CDC-ACM connection?

 

Suggest you check the PC's syslog after a board reset for messages similar to:

[26086.897031] usb 2-1: new high-speed USB device number 9 using ehci-pci
[26087.053604] usb 2-1: New USB device found, idVendor=03eb, idProduct=6124, bcdDevice= 1.10
[26087.053611] usb 2-1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[26087.054424] cdc_acm 2-1:1.0: ttyACM0: USB ACM device

 

 

Charlee wrote:

I haven't found the sourcecode..

https://github.com/atmelcorp/sam...

 

Regards

 

Last Edited: Thu. Mar 17, 2022 - 05:11 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey there,

 

Thanks so much for replying again. Even after my messy mesasge.

 

Sorry I wrote the reply over several hours while doing debugging and the final result appears to have become somewhat messy. Let me clarify.

 

The first error message I described "Error: Cannot open invalid port 'ttyACM0'" was indeed when I was not plugging in the device at all.. I updated parts of my message after finding that out but must have missed this one. The rest of the message in terms of comparison of machines + devices is still valid.

 

I also did not manage to decribe what call I was doing. I was just comparing whether I could communicate with the device with the following call 

sam-ba_3.5/sam-ba -p serial:ttyACM0 -d sama5d2 -a readuniqueid:tmp.uid

just because it was quick and easy, it does communication with the module without needing anything. And it is the first call we do in our code when flashing the device.

Then finally, I see no issues in the syslog.
 

[ 2496.776062] usb 1-7.4: new high-speed USB device number 15 using xhci_hcd
[ 2496.924667] usb 1-7.4: New USB device found, idVendor=03eb, idProduct=6124, bcdDevice= 1.10
[ 2496.924682] usb 1-7.4: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[ 2496.928759] cdc_acm 1-7.4:1.0: ttyACM0: USB ACM device
charlee@lenovo:~/iq$ ls /dev/ttyACM*
/dev/ttyACM0
charlee@lenovo:~/iq$ tools/sam-ba_3.5/sam-ba -p serial:ttyACM0 -d sama5d2 -a readuniqueid:uid.tmp
Opening serial port 'ttyACM0'
Error: Could not switch monitor on port 'ttyACM0' to binary mode
Connection closed.

 

Right now I am at the point that I feel like the only thing I can do is reinstall linux..

 

In terms of kernel versions, I did try a one of the lower kernel versions that was still listed in my "advanced boot options" for ubuntu, and no difference. Also, the kernel version used by the problematic PC and the linux live USB are both 5.13

Kind regards, Charlee

Charlee

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Charlee wrote:

Then finally, I see no issues in the syslog.

 

[ 2496.776062] usb 1-7.4: new high-speed USB device number 15 using xhci_hcd
[ 2496.924667] usb 1-7.4: New USB device found, idVendor=03eb, idProduct=6124, bcdDevice= 1.10
[ 2496.924682] usb 1-7.4: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[ 2496.928759] cdc_acm 1-7.4:1.0: ttyACM0: USB ACM device
charlee@lenovo:~/iq$ ls /dev/ttyACM*
/dev/ttyACM0
charlee@lenovo:~/iq$ tools/sam-ba_3.5/sam-ba -p serial:ttyACM0 -d sama5d2 -a readuniqueid:uid.tmp
Opening serial port 'ttyACM0'
Error: Could not switch monitor on port 'ttyACM0' to binary mode
Connection closed.

After getting such an error, you need to reset the target board while ensuring that all NVM are deselected or disabled.  

Then check the syslog again,  and retry the SAM-BA command or try the V# test.

 

For a better perspective of what the target board is doing, execute a terminal emulator program (on the PC) connected

to the serial console of the target board. 

Then you can confirm the board reset with the display of "RomBOOT" on the console.  If the board proceeds to boot from a NVM, then you didn't deselect or disable that NVM.

This console connection can also be used to display the SAM-BA trace messages.

 

Regards