USB serial port garbage when the device resets - c

When I reset a USB device that is connected via USB serial it starts printing garbage.
If I close out the serial monitor (using Arduino's serial console but should not matter) and reopen, clean text starts printing. Judging by the rate of transmission, the garbage is clearly caused by my device doing normal serial printing -- that is, it is not random garbage.
This is a homebrew USB serial device so the problem could very well be in there. In fact, I can very easily change the code in USB serial device, but cannot do the same for the serial terminal program :-), so would prefer if the solution was there.
No, this is not an incorrect baud or parity setting so please don't suggest it! :-)
Thanks for any help/ideas!

Is it printing garbage even when nothing is being (intentionally) transmitted? If so, there is a hardware problem. Either it resets into a "break" state, or it is jabbering.
If it happens only when data is written through it, then, when the device resets, what serial settings does it default to? Almost certainly this is caused by a speed/data bits/stop bits problem.

Related

Why does read not terminate for my USB device?

I have an USB-device connected with my RaspberryPi 3 B+ (Raspbian Buster Lite 2019-07-10). I also write an small program to read data from the USB Device. The device has an custom, CDC conform firmware, so the device is detected correctly by the OS and and tty is attached.
But when I call 'read' for the device, the syscall never terminates. The odd thing is, when I access the device with MiniCom, CuteCom or even H-Term, it works correct.
I already tried the answers from the following questions:
Reading and writing to serial port in C on Linux
How to open, read, and write from serial port in C?
C program to read data from USB device connected to the system
None of them worked.
I also tried to flush the tty with tcflush and tcdrain.
int dev = open("/dev/ttyACM0", O_RWDR | O_NOCTTY);
// I tried to adapt the device parameters with termios, see above
uint8_t req[] = {0x21, 0x42, 0x00, 0x12}; // the actual request
write(dev, req, 4);
uint8_t resp[12];
read(dev, resp, 8); // does not terminate
I expect a result, 12 bytes long, but read just blocks. If I try the O_NONBLOCK/O_NDELAY option, read terminates with the EAGAIN error.
Of course I checked the result values from every syscall and library function, they all returned/terminated as expected. And as I mentioned above, when connected with a terminal program the device works how it should, so it can't be the firmware.
Also I traced with strace what minicom and cutecom did, but they also did nothing more than open, write and read and of course I tried everything with sudo, so the rights are not the problem.
Seems like the device has never taken the request, so its never processing and getting blocked. so, something prob in the way the request is written. Did you try setting the speed of the port/interface?
I found the Answer myself: the ICANON bit in the termios struct, c_lflag field musst be cleared and the VMIN field in the c_cc array should be set to 1.
Further explanations are found here:
https://www.gnu.org/software/libc/manual/html_node/Local-Modes.html#Local-Modes
https://www.gnu.org/software/libc/manual/html_node/Mode-Data-Types.html
(be carefull, some parts of this documentary are a little bit outdated, for example the CCTS_OFLOW Flag does not exist on Raspbian-Buster)

Forcing raw serial mode in C - linux

Not sure how to word the title, but what I'm trying to do is test my micro controller with my Linux PC to ensure data is correct. After hours of searching, I found out that the stty command can change how data is managed through the serial port and it turned out that by default if xon or xoff characters are received from the port, they don't get displayed. At first I thought my computer was too slow that I was losing characters at 57.6Kbps but that wasn't the case.
Back in the day when I was playing with the serial mouse in QuickBasic for DOS, I could use this command to start the serial port:
OPEN "com1:1200,n,7,1,op0" for binary as #1
So what I want to do now is create something simple in C that would allow me to open up the serial port in the rawest mode possible. I want it so that whatever data I give to it is sent to it unmodified. I also want to receive data unmodified. so if the controller decides to send a character the PC would recognize as a special control code, I still want to see the character, not have the PC go funny just because a character matches a control code.
One idea I thought of is to create a fork to the stty program and use nearly every (50+?) parameters added to the program making the requirement of program stack space a bit high.
Another idea I thought of is to do direct I/O with the port address itself (using inb and outb) but I'm not sure if the kernel would run those commands through anything else before the data reaches the port, but I'd rather use that as a last option in case I ever replace my computer and the serial port value changes (or becomes a serial port made through USB to serial converter hardware).
so rather than inb and outb and those variants (like inw), and without executing stty with specifying 50+ parameters in my program, is there a function in C I can use (without requiring a special library not included with a standard linux distribution) to force the serial port device as a raw device so I can do any I/O on it without the kernel modifying or dropping data?

RS232 Serial Pin Read in C in Linux

Ist there any possibility to read values from the pins of the COM Port? Any solution in C under Linux is appreciated!
Yes, see for instance this guide.
You use the ioctl() function, to read the various control pins. Data is, of course, best read through the normal read() handling, you don't want to be polling asynchronuous serial data.
I don't think your assumption (expressed in a comment) that the driver must check the pin-states to handle data is correct, normally a serial port is "backed" by an UART and that typically handles the RX/TX pins in hardware.
Am pretty sure , you can't read/write pins of UART.
Even at the hardware level , you have to read/write an entire byte.There is no bit access or read/write pin access.
The Byte is read/written in the Receive/Transmit UART buffer .
In either ways you can't just access the buffer directly , on your behalf the linux driver will do the job. You just have to make use of the driver in your application , to work with the UART , the linux driver for UART provides , standard API's like open(),read(),write(),ioctl() through which you interact the UART device.
If you want to work with drivers , and new to this field , the best place to start will be
this book.
The exact answer to this question depends on the precise hardware in question. I know of a piece of code where I worked, based on receiving the letter 'a' as the indication of bitrate, and it would poll the RX pin to detect the transitions between 0 and 1 to detect the "width" of the bits, and it would then calculate the correct clock-rate for the serial port and configure the serial port to match the bitrate of the other end.
A "PC" type hardware solution will not be able to read the RX/TX pins. In other hardware, it may be possible to do so. Many embedded systems allow various pins to be configured as inputs, outputs or "have a function" (in our case, RX, TX, CTS, RTS, etc) - so for example, you could configure the RX pin to be a input, and thus read the state of it. Of course, the normal serial port drivers will probably set these pins to "have a function" [or expect the boot code running before the kernel is started to have configure it this way]. So you would have to reconfigure the pins in some kernel code of your own, most likely. Beware that this may cause unexpected side-effects with the driver for the actual serial port - it may "get upset" when it tries to do things to the serial port and it's "not working as expected" because it's been "misconfigured".
You can almost certainly read (and/or write) the state of the control pins, such as CTS, RTS via IOCTL calls.

Init a serial communication with c library open() causes TX to send one bit on RPi

I'm trying to set up a serial communication between the RPI and an FPGA. However, there is an issue when using the standard C library open() to init the serial interface: I'm using a scope to monitor what is sent and received via the RX and TX lines. A call to open causes the TX line of the RPI to go low for the length of one bit. I do not see this behavior with other computers/linux PCs. The point is, the FPGA assumes a valid transmission, since he thinks it's a start bit, but it's not.
I checked with minicom installed on the RPI. Same thing. Starting minicom causes the TX line sending one bit. Once minicom has started, the communication runs as expected and all bytes have the correct frame size. Is there any way to suppress the TX line going low upon the open call to init the serial communication? Is this an expected behavior?
This is a super far-fetched hunch, but this code seems a bit suspicious, from the pl011_startup() function in the PL011 serial port driver:
/*
* Provoke TX FIFO interrupt into asserting.
*/
It seems as if it's twiddling the TX line when starting up the port, which would explain the pulse you're seeing. More investigation would surely be needed before concluding this is what happens, of course.
So, I guess my "answer" boils down to: that sounds weird, perhaps it's something with the driver?
Of course, one way of working around this is to apply some care in the FPGA end, assuming you have more control over it. "Proper" framing would take care of this, and make it clear that the spurious send can be discarded.
UPDATE: I meant that if "proper" messages were to be always framed by some sequence of bytes, the FPGA might be able to discard invalid ("unframed") data anyway, and thus become immune to the random pulse. For instance, messages could be defined to always start with SOH (start of header) or SOT (start of text) symbols (bytes with the values 0x01 and 0x02, respectively).

Write value to parallel port register

I'm trying to write to my lpt register with the function outb(0x378,val);
well.. I tried to debug with the call int ret=inb(0x378); I always get the ret=255 no matter what value I insert with outb before.
*I'm writing on the kernel mode since my program is a driver, therefore I didn't use ioperm() etc.
thank you in advance.
You have the parameters of outb function wrong, correct order is :
outb(value, port)
so you have to change your code to do:
outb(val, 0x378)
For more details please read Linux I/O Programming Howto .
Do you know for a fact that you have a parallel port installed at that address?
Get yourself a small low-current LED. Stick the long end in one of pin 2 (LSB) to pin 9 (MSB) and the short end in pin 25 (ground).
Try writing various values and see if you can get the LED to change by the bit value of what you write.
This should work (unless as previously mentioned you've gotten it programmed in an input mode) Being able to read back the port value is less certain, depending on the type of parallel port and implementation details (for example, you probably couldn't with the buffer chip that implemented it in the original PC)
Also note that most USB "printer" adapters don't give you bitwise register access. Something hanging off of the PCI or PCMCIA, etc may also have problems with direct register access at the legacy port address. There are nice USB parallel interface chips such as the FT245 and successors which you can use if you don't have a "true" parallel port hanging off the chipset available.
Have you set the direction register? If it is set as input then you will read what is on the port.
inb(0x378) is not required to return what was written; at least I've seen chips to behave so. Well, since you, at some point, have called outb, you know what's on anyway.

Resources