mirror of
https://github.com/UzixLS/picocom.git
synced 2025-07-19 07:21:18 +03:00
added --lower-rts
and --lower-dtr
command line options
see also https://github.com/npat-efault/picocom/pull/47
This commit is contained in:
81
lowerrts.md
Normal file
81
lowerrts.md
Normal file
@ -0,0 +1,81 @@
|
||||
Using uart handshake lines to control microcontroller reset signals in bare metal development
|
||||
=============================================================================================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
In bare metal software development, it's common practice to misuse uart handshake lines for e.g. controlling the reset signal of the target microcontroller.
|
||||
We're often using e.g. RTS to drive the microcontrollers reset input pin and e.g. DTR to switch between bootloader and normal operation mode.
|
||||
|
||||
For example, if the microcontrollers reset input uses negative logic (low = reset, high = running), just connect the RTS ttl level to the microcontrollers reset input pin.
|
||||
|
||||
Problem at open("port")
|
||||
-----------------------
|
||||
In both linux and osx, we observe, that the RTS handshake line will be driven active (positive voltage on RS232 signal level = logic low on ttl level implicitely within the `open()` call,
|
||||
even when the uart port is used without hardware handshake.
|
||||
|
||||
This behaviour could not be avoided until patching the linux kernel driver (see also http://stackoverflow.com/a/21753723/2880699).
|
||||
|
||||
Working around from user space Api
|
||||
----------------------------------
|
||||
|
||||
All we can do in our terminal software is, to reset the RTS signal back to ttl high level after the `open()` call.
|
||||
But even when we do this quiet fast directly after the `open()` call, the RTS signal changes for a short time which might be enough to perform a reset of the microcontroller.
|
||||
|
||||
With my picocom patch (`--lower-rts` command line option), I'd measured about 50µs-70µs on my linux machine and 250µs-450µs on my old Macbook Pro with running OSX (tested with Ftdi FT2232H).
|
||||
But note, that there is no guarantee for this times; because our PC is no realtime system, the OS might preempt our terminal application between toe `open()` and `ioctl()` calls.
|
||||
|
||||
If this possibly microcontroller reset is disliked, we should work around against it by adding a bit more hardware between RTS and the microcontrollers reset input pin.
|
||||
Sometimes a simple low pass filter (resistor and capacitor) do this job.
|
||||
|
||||
Using python3
|
||||
-------------
|
||||
Python's serial communication example tool `python3 -m serial.tools.miniterm` provides a command line option `--rts 0` which also lowers the RTS handline line after opening the port.
|
||||
On the same linux machine mentioned above, I measured a peak about duration of about 150µs-170µs.
|
||||
|
||||
When using something like `python3 -c "import serial; ser = serial.Serial('/dev/ttyUSB0'); ser.setRTS(False); ... "`, I measured a peak about duration of about 180µs-260µs.
|
||||
|
||||
Deeper analysis
|
||||
---------------
|
||||
Analyzed using:
|
||||
- Macbook Pro
|
||||
- Ft2232H based Usb serial adapter
|
||||
- Kubuntu 16.04 64 bit
|
||||
- picocom 2.3a, patched with `--lower-rts` command line option
|
||||
|
||||
CRTSCTS=0x80000000. This bit is set in tty->termios->c_cflag when the uart is used with Rts/Cts handshake.
|
||||
When calling open() / ftdi_open(), I'd observed that this flag seems to be undefined. I found it either set or unset, depending on if the last session was with or without hardware handshake.
|
||||
So user space api open() calls the following functions of the `ftdi_sio` kernel driver module:
|
||||
ftdi_open(c_cflag=000008BD) // note that CRTSCTS flag is undefined here
|
||||
ftdi_set_termios(c_cflag=000008BD) // called implicitely by ftdi_open
|
||||
ftdi_dtr_rts(on=1, c_cflag=000008BD) // called regardless if using hardware handshake or not
|
||||
update_mctrl(set=0006, clear=0000) // CRTSCTS flag is still undefined here
|
||||
|
||||
Hacking the ftdi_sio kernel driver module
|
||||
-----------------------------------------
|
||||
|
||||
see also http://stackoverflow.com/a/40811405/2880699
|
||||
|
||||
static void ftdi_dtr_rts(struct usb_serial_port *port, int on) {
|
||||
...
|
||||
/* drop RTS and DTR */
|
||||
if (on)
|
||||
set_mctrl(port, TIOCM_DTR /*| TIOCM_RTS*/); // <<-- HERE
|
||||
else
|
||||
clear_mctrl(port, TIOCM_DTR /*| TIOCM_RTS*/); // <<-- and maybe even HERE
|
||||
}
|
||||
|
||||
Steps to perform on e.g. Kubuntu 16.04:
|
||||
$ sudo apt-get install build-essential ;# etc.
|
||||
$ apt-get source linux-image-$(uname -r) ;# of course, neets to have deb-src in /etc/apt/sources.list activated
|
||||
-> this creates a ~/linux-4.4.0 with about 760 MiB source code including linux-4.4.0/drivers/usb/serial/ftdi_sio.c
|
||||
$ cd ~/linux-4.4.0
|
||||
$ chmod +x debian/scripts/misc/splitconfig.pl
|
||||
$ chmod +x debian/scripts/config-check
|
||||
$ debian/rules genconfigs
|
||||
$ cp CONFIGS/amd64-config.flavour.generic .config
|
||||
and then after each change in drivers/usb/serial/ftdi_sio.c:
|
||||
$ make -C /lib/modules/$(uname -r)/build M=${PWD} drivers/usb/serial/ftdi_sio.ko
|
||||
$ sudo rmmod ftdi_sio.ko
|
||||
$ sudo insmod drivers/usb/serial/ftdi_sio.ko
|
||||
ergo:
|
||||
$ make -C /lib/modules/$(uname -r)/build M=${PWD} drivers/usb/serial/ftdi_sio.ko && sudo rmmod ftdi_sio.ko && sudo insmod drivers/usb/serial/ftdi_sio.ko
|
15
picocom.1.md
15
picocom.1.md
@ -270,7 +270,20 @@ Picocom accepts the following command-line options.
|
||||
be replaced before being echoed-back to the terminal, if
|
||||
local-echo is enabled). See
|
||||
**[INPUT, OUTPUT, AND ECHO MAPPING]**. (Defaul: **delbs,crcrlf**)
|
||||
|
||||
|
||||
**--lower-rts**
|
||||
|
||||
: Lower the RTS control signal after opening the serial port (by
|
||||
default RTS is raised after open implicitely by the OS). Only
|
||||
supported when flow-control mode is not set to RTS/CTS, ignored
|
||||
otherwise. Only supported in Linux.
|
||||
|
||||
**--lower-dtr**
|
||||
|
||||
: Lower the DTR control signal after opening the serial port (by
|
||||
default DTR is raised after open implicitely by the OS).
|
||||
Only supported in Linux.
|
||||
|
||||
**--help** | **-h**
|
||||
|
||||
: Print a short help message describing the command-line
|
||||
|
28
picocom.c
28
picocom.c
@ -190,6 +190,8 @@ struct {
|
||||
int imap;
|
||||
int omap;
|
||||
int emap;
|
||||
int lower_rts;
|
||||
int lower_dtr;
|
||||
} opts = {
|
||||
.port = "",
|
||||
.baud = 9600,
|
||||
@ -208,7 +210,9 @@ struct {
|
||||
.receive_cmd = "rz -vv -E",
|
||||
.imap = M_I_DFL,
|
||||
.omap = M_O_DFL,
|
||||
.emap = M_E_DFL
|
||||
.emap = M_E_DFL,
|
||||
.lower_rts = 0,
|
||||
.lower_dtr = 0
|
||||
};
|
||||
|
||||
int sig_exit = 0;
|
||||
@ -1290,6 +1294,8 @@ show_usage(char *name)
|
||||
printf(" --imap <map> (input mappings)\n");
|
||||
printf(" --omap <map> (output mappings)\n");
|
||||
printf(" --emap <map> (local-echo mappings)\n");
|
||||
printf(" --lower-rts\n");
|
||||
printf(" --lower-dtr\n");
|
||||
printf(" --<h>elp\n");
|
||||
printf("<map> is a comma-separated list of one or more of:\n");
|
||||
printf(" crlf : map CR --> LF\n");
|
||||
@ -1331,6 +1337,8 @@ parse_args(int argc, char *argv[])
|
||||
{"parity", required_argument, 0, 'y'},
|
||||
{"databits", required_argument, 0, 'd'},
|
||||
{"stopbits", required_argument, 0, 'p'},
|
||||
{"lower-rts", no_argument, 0, 'R'},
|
||||
{"lower-dtr", no_argument, 0, 'D'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
@ -1469,6 +1477,12 @@ parse_args(int argc, char *argv[])
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'R':
|
||||
opts.lower_rts = 1;
|
||||
break;
|
||||
case 'D':
|
||||
opts.lower_dtr = 1;
|
||||
break;
|
||||
case 'h':
|
||||
show_usage(argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
@ -1569,6 +1583,18 @@ main(int argc, char *argv[])
|
||||
if ( r < 0 )
|
||||
fatal("failed to add device %s: %s",
|
||||
opts.port, term_strerror(term_errno, errno));
|
||||
|
||||
if ( opts.lower_rts ) {
|
||||
r = term_lower_rts(tty_fd);
|
||||
if ( r < 0 )
|
||||
fatal("failed to lower RTS of device %s: %s", opts.port, term_strerror(term_errno, errno));
|
||||
}
|
||||
if ( opts.lower_dtr ) {
|
||||
r = term_lower_dtr(tty_fd);
|
||||
if ( r < 0 )
|
||||
fatal("failed to lower DTR of device %s: %s", opts.port, term_strerror(term_errno, errno));
|
||||
}
|
||||
|
||||
r = term_apply(tty_fd, 0);
|
||||
if ( r < 0 )
|
||||
fatal("failed to config device %s: %s",
|
||||
|
Reference in New Issue
Block a user