On 04/21/17 00:14, Stuart Longland wrote:
On 21/04/17 02:17, Rodolfo Giometti wrote:
AFAIK the multidrop mode is supported also by Freescale (IMX6 and maybe
IMX7) even if by using directly 9 bits transmission. The SENDA trick
(that is autogically sending the next first byte as an address while the
following ones as data) is Atmel specific. Atmel solution is really
smart (even if limited to 1 byte addresses long) because it allows
developers to send a message without any delay between the address and
the data bytes.
I've seen similar features on the NXP LPC81x series of microcontrollers.
http://www.nxp.com/documents/user_manual/UM10601.pdf page 187 onwards
covers the USART for these chips. The data register is natively 32-bits
wide, so can accommodate the 9th bit easily.
On Atmel AVR, I've also seen it, there the 9th bit is held in a separate
register from what I recall, don't have a datasheet in front of me to
look it up.
Yes, Atmel CPUs can handle multidrop in two manners: the first one is by using
the 9bits transmission while the second is by using the SENDA bit. The latter is
obviously less versatile and less general then the former but it really better
fits into actual Linux TTY subsystem.
The 9-bit mode sounded like a good idea, and I thought of how to
possibly implement it, but then I had to contend with where would I put
the extra bit in an 8-bit byte?
This is exactly the problem I notice in adding multidrop support in Linux trying
to avoid the two calls of the tcsetattr() function which introduce a delay
between the address and data bytes.
Given its use as an address, maybe one option is if the kernel could
have a small table of address bytes/masks that it could watch for on
receive and the ability to set a "preamble" to prepend to packets. Sort
of like subnets in IP; only the mask can be any arrangement of bits.
Supposing we had a userspace program that communicated on RS-485 and
used two bytes for addressing; one being the destination address and the
other being a command.
In that way, the userspace program can tell the kernel:
- Preamble length: 2 bytes
- MSB denotes preamble byte
- Ignore all received packets except those starting with 0x0000 (mask
0xff00) and 0x1200 (mask 0xff00)
- For all future frames, send preamble 0x12ff
IF the kernel driver hears:
[1] 0100 0111 [1] 0001 0110 [0] 0011 0000 …
it'll ignore the frame until it sees another byte with an initial MSB,
because 0x4716 & 0xff00 ≠ 0x1200.
If it hears:
[1] 0001 0010 [1] 0001 0110 [0] 0011 0000 …
we pass the preamble and any subsequent non-preamble bytes to userspace
(minus MSBs). Perhaps we can have an IOCTL call or something that can
tell the userspace before a read how many bytes are part of the preamble.
In the Atmel example above, the driver can use the SENDA feature if the
preamble length is 1 byte.
Food for thought?
IMHO the best solution would be using 9bits transmission (CS9 define):
term.c_cflag &= ~CSIZE;
term.c_cflag |= CS9;
ret = tcsetattr(fd, TCSADRAIN, &term);
...
/* Write data */
n = 0;
buf[n++] = 0x100;
buf[n++] = 0x01c;
buf[n++] = 0x001;
buf[n++] = 0x001;
buf[n++] = 0x000;
buf[n++] = 0x001;
buf[n++] = 0x0de;
buf[n++] = 0x0d4;
ret = writen(fd, buf, 2*n);
...
However doing something like this will require huge modifications into Linux TTY
subsystem. Then my solution tries to keep it simple just still using 8bits
transmission but adding a system call to define how many address bytes we have
into next message:
/* Transmission: enable parity multidrop */
term.c_cflag |= PARENB | CMSPAR | PARMD;
ret = tcsetattr(fd, TCSADRAIN, &term);
...
mdrop.addr_len = 1;
ret = ioctl(fd, TCSSENDA, &mdrop);
...
/* Write data */
n = 0;
buf[n++] = 0x00;
buf[n++] = 0x1c;
buf[n++] = 0x01;
buf[n++] = 0x01;
buf[n++] = 0x00;
buf[n++] = 0x01;
buf[n++] = 0xde;
buf[n++] = 0xd4;
ret = writen(fd, buf, n);
...
[Note that Atmel CPUs support only 1 byte for address length]
Since multidrop is used with RS485 we can think to add all these stuff into
TIOCSRS485 ioctl() as below:
rs485conf.flags |= SER_MULTIDROP_ENABLED;
rs485conf.delay_rts_after_send = 0;
ret = ioctl(fd, TIOCSRS485, &rs485conf);
...
However we still need and ioctl() command to state when new address bytes should
be sent in the data stream...
We can use different solutions but the real problem is avoiding a delay between
the address and data bytes and to do so we must find a way to completely support
9 bits transmission or tricks as the SENDA bit.
Ciao,
Rodolfo
--
HCE Engineering e-mail: giometti@xxxxxxxxxxxxxxxxxxx
GNU/Linux Solutions giometti@xxxxxxxxxxxx
Linux Device Driver giometti@xxxxxxxx
Embedded Systems phone: +39 349 2432127
UNIX programming skype: rodolfo.giometti
Cosino Project - the quick prototyping embedded system - www.cosino.io
Freelance ICT Italia - Consulente ICT Italia - www.consulenti-ict.it
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html