[SOLVED mostly] USB to 3x UART ?

JoeBee
Sat Aug 25, 2018 6:15 am
Hello community.
Any chances that we achieve this function?
https://satoshinm.github.io/blog/171223 … _pill.html
So that we have three virtual Com Ports in Windows that can be use in Arduino.
Do we need to modify the bootloader?

My Goal: Make a 3x Wireless UART Console
Currently I use: Windows->Hub->3xUSB to UART->Blue Pill->Wireless->Blue Pill->3xUART to RS232


stevestrong
Sat Aug 25, 2018 8:18 am
I think the example from the link you provided implements the same USB Tx serial data replicated on 3 USART ports. In one direction, Tx.
What you want is to have 3 different bidirectional comm channels, right?
For that I think you have to write your own application on the PC which multiplexes the 3 serial channels on the same USB CDC channel.
And a respective mux/demux on bp.
I am not aware of any multiple CDC serial COM channel implementation on the same USB port, but I may be wrong.

JoeBee
Sat Aug 25, 2018 9:24 am
Ok, I have to admit that I haven’t understand this article very well.
I’m not very good in all that USB and Windows Driver stuff.
And obviously I can’t program my own windows driver.

stevestrong
Sat Aug 25, 2018 10:41 pm
After a closer look to the link i realised that the bin it is really generating 3 different virtual com ports on the pc!
https://github.com/satoshinm/pill_serial
So i was wrong :?

ag123
Sun Aug 26, 2018 7:31 am
it sounds to me like some kind of usb composite setup, hence it may be possible to do that but with a modified usb-serial code base
since BMP is mentioned, i’d guess one could review the BMP codes to see how that’s implemented

if one is keen on implementing that one may use Apruss’s USB Composite (HID / MIDI / Mass Storage) library
viewtopic.php?f=13&t=2926
as a starting point

the modifications are not likely to keep usb-serial working in its current form hence, that’d most likely need to be done as a fork


arpruss
Wed Aug 29, 2018 6:32 pm
A quick and dirty way is just to make three copies of each of USBComposite.cpp, USBComposite.h, usb_composite_serial.h and usb_composite_serial.c in my USB Composite library, and then rename the globals and classes in two of the three copies so they don’t conflict. E.g., USBComposite.cpp will define the USBCompositeSerial class, while USBComposite2.cpp will define an almost identical USBCompositeSerial2 class.

This will result in some duplicate code, but it would only take about half an hour to do. :-)

The right way to do this is to modify the USB Composite library to allow multiple instances of the same plugin. This would require serious changes to the underlying C code.


JoeBee
Thu Aug 30, 2018 7:32 pm
That’s a good idea. Thank you. I will try this. I have found this lib in my STM32duino folder
But, currently I can’t find an example how to create one USB. I have to admit that I didn’t get it instantly.
Can somebody give me an example for one CompositeSerial ?

JoeBee
Sat Sep 01, 2018 1:18 pm
I have find out how to create one USB/Serial.
But when trying to copy/rename the files I try a whole day but always get “multiple definitions” or “not defined” something.
I give up, because it is always hard for me to get hooked up to somebody’s else code.

JoeBee
Wed Sep 05, 2018 9:01 pm
Can somebody of the Pros can probably help me out and can create those copies?

arpuss wrote that I need to make copies of:
USBComposite.cpp
USBComposite.h
usb_composite_serial.h
usb_composite_serial.c
I’m not sure but do I need to copy USBCompositeSerial.h and USBCompositeSerial.cpp also?


stevestrong
Thu Sep 06, 2018 8:39 am
Imho, the easiest way to get it working would be to use the same environment as the original poster, e.g. libopencm3.

Otherwise only @arpruss would be able to support you with his library.


ag123
Thu Sep 06, 2018 11:44 am
strictly speaking, to meddle with usb one would need to get into the inner workings of the ‘usb descriptors’ and for hid the ‘hid reports’
http://www.usb.org/developers/docs/devclass_docs/
there is quite a lot to digest as usb is a ‘predefined’ standard, in a sense microsoft et.al. implemented a large set of host side ‘drivers’ for device classes conforming to those specs.
but to for a ‘simplification’, one would need to figure out how to return the descriptors when the host issue a ‘get config’, ‘get descriptor’ or ‘get interface’ request and normally that’s for a particular use case (e.g. usb cdc-acm to emulate a ‘modem’)
that would probably need one to become familiar with the usb standard e.g. in the link above

mrburnette
Thu Sep 06, 2018 12:23 pm
[JoeBee – Sat Aug 25, 2018 6:15 am] –
<…>
So that we have three virtual Com Ports in Windows that can be use in Arduino.
Do we need to modify the bootloader?

My Goal: Make a 3x Wireless UART Console
Currently I use: Windows->Hub->3xUSB to UART->Blue Pill->Wireless->Blue Pill->3xUART to RS232

Firstly, the bootloader has nothing to do with the STM32 serial-USB application (sketch); that is to say, the serial-USB is a binary that is appended to the sketch at link time.

Secondly, I am having a difficult time understanding the 1 uC and 3 serial port use case. Pseudo serial streams can easily be done over 1 USB port by using command codes to switch a state machine in software. Of course, one needs PC-based software to steer the streams to awaiting processes.

I admit that enumerating 3 serial ports from one USB connection would be a clever parlor trick, I fail to see true value in such an endeavor. IMHO, the forum has enough trouble with just one serial over USB implementation. This is an entirely different scenario than the previous effort with HID where the library filled in a void. Perhaps one of the USB smarties will implement 3 serials over 1 USB and having such capability will be found to be very useful, but I need to witness the use case(s) before I am sold on the concept.

Ray

Added:
Pseudo serial streams (RO) example: http://www.piclist.com/techref/microchi … 8ch-ba.htm


Rick Kimball
Thu Sep 06, 2018 4:31 pm
[mrburnette – Thu Sep 06, 2018 12:23 pm] –
Secondly, I am having a difficult time understanding the 1 uC and 3 serial port use case. Pseudo serial streams can easily be done over 1 USB port by using command codes to switch a state machine in software. Of course, one needs PC-based software to steer the streams to awaiting processes.

I routinely use more than one USB serial dongle. I need to try out the firmware and see how well it holds up under 115k speed.

The blackmagic probe is the basis for this code from what I can see. The BMP provides 2 comm ports. One virtual serial port for the GDB Remote Server Protocol and one as a general purpose Serial comm device. This allows you to use a single usb connection to support the gdb feature and also connect it up to the serial usart ports.

I see an stm32f103 acting as a usb -> 3 virtual comm ports a really useful feature. You could plug this into a raspberry pi and provide 3 usart ports and only use one usb port. Pretty useful i think.


Rick Kimball
Thu Sep 06, 2018 4:52 pm
Seems pretty decent :) .. Thanks stoshinm!

You can see the libopencm3 library produces some small code. This entire thing is less than an empty arduino sketch:
$ arm-none-eabi-size pill_serial.elf
text data bss dec hex filename
8452 32 940 9424 24d0 pill_serial.elf


stevestrong
Thu Sep 06, 2018 5:25 pm
+10 :D

JoeBee
Thu Sep 06, 2018 6:12 pm
My usecase: I’m a network guy and I want to mange some/three devices over a serial wireless console.
On the PC I use Putty connected to three Com port as terminal emulation.
Now I want to transfer these 3*9600 serial over NRF24l01 to a second STM that act as a receiver.
Currently I have done this as a prototype with arduino (with NRF Lib somewhere here in the forum already described) and 3 usb to Serial converter. If i could eliminate the need of these 3 converters would be really nice.

The problem. I have only used Arduino for all this stm32 stuff. I have to admit that I’m currently not able to compile the Source that I posted at the beginning. And I also have no idea how I could add the NRF Stuff to the opening post software and if there are some libs available or if I need to implement NRF stuff from scratch.
That’s why I ask here. Currently I’m somehow bound to Arduino.


mrburnette
Thu Sep 06, 2018 9:12 pm
I stand amaze.
If Rick says it is useful, it surely must be. As my daughter would say, “… I do not roll that way…” but heck, it looks cool.

Ray


Rick Kimball
Thu Sep 06, 2018 10:43 pm
Earlier, I had found a blue pill i could use to test this stuff. However, it didn’t have any pins on it. So all I did was fix the R10 1k5 resistor when I showed the working /dev/ttyACMx. Since then I’ve found some more pins and soldered them on and did some testing.

In my testing I’ve found an oddity with USART1 receive. It doesn’t seem to be working properly. USART2 and USART3 work fine. At first I thought it might be a peripheral clock problem which it wasn’t. I did some more tests and connected an FTDI dongle to PA9/PA10 to help isolate the problem.
While the serial_pill sends out data on the USART1 TX/PA9 fine with the correct baud rate, It doesn’t receive properly on the PA10 pin. I get a garbled character. I need to do some more digging.

One other thing, is you can easily overflow the the USART ports. I tested with various speeds but in all cases if you type this in your terminal

12345678901234567890123456789012345678901234567890123456789012345678901234567890
12345678901234567890123456789012345678901234567890123456789012345678901234567890
12345678901234567890123456789012345678901234567890123456789012345678901234567890
12345678901234567890123456789012345678901234567890123456789012345678901234567890

then copy and paste that into the terminal window, it will only get about 130 characters before it just ignores the rest of your paste.

Seems like the code would benefit from using an USART ISR for the transmit. The receive already does it work with an ISR handler.

So I at least got 2 good virtual comm ports out of it, USART2 and USART3

Of course this is all on linux, maybe someone could try on windows or mac os/x


Rick Kimball
Fri Sep 07, 2018 4:03 am
So I should have just gone to the issues section on the github page. https://github.com/satoshinm/pill_serial/issues/1

I tried some modifications. I found that by changing the order of the usart1 usbd_ep_setup() setup calls and putting them before the usart2 set, I can make PA9/PA10 work. That breaks whatever set is the last ones. I’m guessing he is using too many usb endpoints.

So you get 2.5 uart ports. instead of 3. Still this code might be useful if you are using 3 ports but one of your serial port usages is output only. :)


JoeBee
Sun Sep 09, 2018 5:54 am
This was also mentioned in the readme from arpruss.
https://github.com/arpruss/USBComposite_stm32f1

Beginning with “Memory Limitations” and also the “Endpoint Limitation” which adds up to 9 with 3 Serial.
So two Serial seems to be the maximum, but still quite nice.

Can somebody give me a path, how I can setup a simple development environment under Windows to compile these example?


JoeBee
Sun Sep 09, 2018 4:30 pm
For German Speaking audience. https://www.mikrocontroller.net/article … _mit_STM32
Nice step by step guide to programming the USB.

GnuReligion
Sat Sep 22, 2018 7:31 pm
[Rick Kimball – Fri Sep 07, 2018 4:03 am] –
So I should have just gone to the issues section on the github page. https://github.com/satoshinm/pill_serial/issues/1

I tried some modifications. I found that by changing the order of the usart1 usbd_ep_setup() setup calls and putting them before the usart2 set, I can make PA9/PA10 work. That breaks whatever set is the last ones. I’m guessing he is using too many usb endpoints.

So you get 2.5 uart ports. instead of 3. Still this code might be useful if you are using 3 ports but one of your serial port usages is output only. :)

Rick, I see your comment in the issue section of pill_serial on GitHub. I had the same issue for the last-declared ACM.
Following your lead, actually read stuff, like here: https://github.com/arpruss/USBComposite_stm32f1
There are 320 bytes of hardware buffer memory available after endpoint 0 is taken into account. The following are the default buffer memory needs of the current components:
USB Serial: 144 bytes

Yup, only room for two, but further down, you can see some optimism.
However, USB Serial, USB HID and USB MIDI allow you to decrease buffer sizes (and allow for more complex composite devices) by calling:

MIDI.setRXPacketSize(size);
MIDI.setTXPacketSize(size);

So can we manipulate the packet size? I tried editing pill_serial/src/cdcacm.h, and shrinking it:
#define CDCACM_PACKET_SIZE 8
//#define CDCACM_PACKET_SIZE 64
The old size was 64 … and just tried 8 to see. Now the three ACM’s hopefully take less than the 320 bytes of hardware buffer space.

What do you know? /dev/ttyACM2, or the last-declared, primary UART port on PA9/PA10 now sends and receives without garbage!

Will solder up the other two ports tonight to see how this hack adversely affects speed and things.

JoeBee, if this works out, and we cannot get satoshinm to fix it, I will fork off a revision of pill_serial and put out a “.bin” for you.


Rick Kimball
Sun Sep 23, 2018 5:03 pm
[GnuReligion – Sat Sep 22, 2018 7:31 pm] –
#define CDCACM_PACKET_SIZE 8
//#define CDCACM_PACKET_SIZE 64

I just tried this with 32 and it seems to work in cursory testing. Good find!


Image


GnuReligion
Sun Sep 23, 2018 7:52 pm
Thanks. Was quite pleased with it all, until trying your mini stress test, of just pasting a few hundred characters into Minicom.
It seems to repeat characters sometimes, and drop them others. Sometimes a delayed echo. Bleah.

Tried a number of things last night …

  • Increasing the frequency of the interrupts.
    Decreasing the frequency of the interrupts.
    Correcting a coding problem with the UART FIFO buffer.
    Increasing the size of the FIFO buffer (128).

Nothing had an affect.

I suspect the serial timer interrupts (three of them) and USB handling interrupts are clobbering each other.
Also, suspect a blocking serial transmit function may overrun the time slice allotted to the timer interrupt. (shrug)
The FIFO buffers are not protected with semaphores, and not using a class for this structure.
The whole thing seems crudely implemented, and minimally documented.

Perhaps I should start from scratch … there must be a stm32duino example that implements just one CDC serial, that is bulletproof?


Rick Kimball
Sun Sep 23, 2018 8:10 pm
[GnuReligion – Sun Sep 23, 2018 7:52 pm] –
Perhaps I should start from scratch … there must be a stm32duino example that implements just one CDC serial, that is bulletproof?

Last time I tried an stm32duino native usb uart stuff, it failed my paste test. * been a while > 1 year


GnuReligion
Mon Sep 24, 2018 7:43 am
Found a solution to the “Paste Test” problem. The interrupt that reads from USB was hanging on a full TX buffer … inside an interrupt (cringe).

In usbuart.c, usart_send_blocking() is blithely called, without checking to see if the buffer is full.
Did some reading on http://libopencm3.org/docs and found usart_get_flag(uint32_t usart, uint32_t flag).
One of the flags indicates when the TX buffer is empty. I put an “if” block here in the interrupt handler, and *poof*, the paste test works.

static void usbuart_usb_out_cb(int USBUSART, usbd_device *dev, uint8_t ep, int CDCACM_UART_ENDPOINT)
{
(void)ep;
char buf[CDCACM_PACKET_SIZE];

if ( usart_get_flag(USBUSART, USART_SR_TXE) )
{
int len = usbd_ep_read_packet(dev, CDCACM_UART_ENDPOINT, buf, CDCACM_PACKET_SIZE);

gpio_set(LED_PORT_UART, LED_UART);
for(int i = 0; i < len; i++)
usart_send_blocking(USBUSART, buf[i]);
gpio_clear(LED_PORT_UART, LED_UART);

} // if TX buffer is empty
}


Rick Kimball
Mon Sep 24, 2018 3:29 pm
[GnuReligion – Mon Sep 24, 2018 7:43 am] –
Found a solution to the “Paste Test” problem. The interrupt that reads from USB was hanging on a full TX buffer … inside an interrupt (cringe).

That didn’t seem to fix the issue for me.

[GnuReligion – Mon Sep 24, 2018 7:43 am] –

However, when I try a zmodem transfer, just between these linked ports, it fails. Nak, timeout. Weird, text is different than binary.

Maybe change the buffer to unsigned character?:

static void usbuart_usb_out_cb(int USBUSART, usbd_device *dev,
int CDCACM_UART_ENDPOINT)
{
uint8_t buf[CDCACM_PACKET_SIZE];
...


Rick Kimball
Mon Sep 24, 2018 3:49 pm
Even though my putty paste test doesn’t seem to work this python script works fine sending 23 lines of text

#!/usr/bin/env python

############################### txUSB.py ###############################

import serial;
import time;

# 64 bytes per row
txData = b'12345678901234567890123456789012345678901234567890123456789012345678901234567890'\
;

def main():
try:
serialPort = serial.Serial("/dev/ttyUSB0",\
115200,
serial.EIGHTBITS,\
serial.PARITY_NONE,
serial.STOPBITS_ONE);
except:
print("Couldn't open serial port");
exit();

text = txData;

byteSent = 0;

# First time slice
t1 = time.time()

for i in range(23):
send = serialPort.write(text);

# Second time slice
t2 = time.time()
print (t2 -t1);

if __name__ == '__main__':
main()


GnuReligion
Fri Sep 28, 2018 8:51 am
Well, Rick, I saw your bug report over at github. It appears the pill_serial maintainer is not too keen on maintaining the code, or perfecting it.

Was able to use your python script to over-flood one of the ACM’s. A tiny pause, time.sleep(0.01), after each line straightens it right out.

I am still unable to use two ACMs at once with a null modem link between them at full Zmodem transfer speed.

What may be going on is that preemptive USB IRQs are not giving the timer interrupts enough time to service the USARTS, when being slammed with requests.

Well, it is interesting that any single ACM works, and the line settings work … but it could be this single core hardware is just not robust enough to support multiple devices. (shug) Just do not know.


Rick Kimball
Fri Nov 02, 2018 3:48 pm
I used the 32 byte size modification to get all 3 serial ports working. I’ve attached the .bin binary in a zip file here so you can load it on a bluepill. Just unzip the file below and use stm32flash to upload the .bin file to a bluepill. When I plug this into my raspberry pi, I get 3 serial ports for the price of 1 USB port.

/dev/ttyACM0 is PA2/PA3 (TX/RX)
/dev/ttyACM1 is PB10/PB11 (TX/RX)
/dev/ttyACM2 is PA9/PA10 (TX/RX)

On windows/mac osx I have no clue about the com or /dev names. You will have to figure that out.

have fun!

pill_serial.bin.zip:

pill_serial.bin.zip
(5.82 KiB) Downloaded 26 times

Leave a Reply

Your email address will not be published. Required fields are marked *