How to create a tunnel between two half-duplex serial ports? - embedded

I am working on an embedded project which includes two half duplex UARTS, and one full duplex UART.
UART1 is connected to Device A. UART2 is connected to Device B, and UART3 is connected to the PC. UART1 and UART2 are half-duplex, thus RX/TX modes have to be configured properly.
When a signal on UART1 is triggered, UART2 fetches some data from Device B. That data is put into a buffer, and then transmitted back to UART1, AND UART3. Device A consumes the data, and sends more items on UART1, which then has to be passed to UART2 for Device B to respond.
I was thinking about an efficient state machine that can handle the switching modes between TX/RX mode, and so far my UART code is interrupt driven. What would be some ways to tackle the flow of this program?

I don't think you will need a state machine for this case. Why not just hook up all interrupts accordingly and just forward anything received from one devivce to the other(s)?
You may want to include a TX (ring-)buffer to accomodate for different speeds of each UART and then just have a RX-ISR write the data received to the appropriate TX buffer(s), from where it will then be consumed by the other UARTs' UDRE-ISRs.

Related

STM32f103 HAL USB - UART bridge

I have a third party device that is UART programmable.
I need to create a USB - UART bridge with a functional password (programming only after entering the correct password)
generated the code using the latest version of STM32CubeMX for Atollic TrueSTUDIO for STM32 9.3.0 ...
I transfer data between USB and UART through a buffer (one for usb-uart, and another one for uart-usb)
when I try to transfer several characters everything is OK, but when I try to transfer a large data packet, problems start due to the fact that the USB speed is much higher than the UART ...
there are two questions:
1.How do I tell USB that I need to stop transferring data and wait until the UART (buffer) is busy
2.How on the side of the microcontroller to get the baud rate set on the PC (set when the terminal is connected to the virtual COM port)
USB provides flow control. That's what you need to implement. A general introduction can be found here:
https://medium.com/#manuel.bl/usb-for-microcontrollers-part-4-handling-large-amounts-of-data-f577565c4c7d
Basically, the setup for the USB-to-UART direction should be:
Indicate that the code is ready to receive a USB packet
Receive a USB packet
Indicate that you are no longer ready to receive a USB packet
Transmit the data via UART
Start over
Step 0: Initial setup
Call USBD_CDC_SetRxBuffer to set the buffer for receiving the USB data. Unless you use several buffers to achieve higher throughput, a single call at the start of the program is sufficient.
Step 1: Ready to receive data
Call USBD_CDC_ReceivePacket. Other than what the name implies, this function indicates that the app is ready to receive data. It immediately returns before the data has actually been received.
Step 2: Receive a USB packet
You don't need to do anything here. It will happen automatically. Once it's complete, CDC_Itf_Receive will be called.
Step 3: Indicate that you are no longer ready to receive a USB packet
Nothing to do here. This happens automatically whenever a packet has been received (and double buffering is not enabled).
Step 4: Transmit the data via UART
I guess you know how to do this. It's up to you whether you want to do it in a blocking fashion or using DMA.
Since a callback is involved, you cannot put this code into the main loop. It might be possible to put all code into CDC_Itf_Receive if blocking UART is used. It would appear in the order 2, 3, 4, 1. Additionally, initialization is needed (0 and 1).
In the UART-to-USB direction, you would need to implement flow control on the UART. The USB flow control is managed by the host. Even though USB is much faster than UART, flow control is relevant as the application on the host can process data as slow as it likes to.
Regarding question 2: I'm not sure I understand it... The microcontroller cannot set the baud rate on the host. Either the host can specify a baud rate (transmitted over USB and applied to UART), or if the UART has a fixed baud rate, you can ignore baud rate (any baud rate set on the host side will work as it does not apply to USB).

Does the operation of the CAN peripheral in STM32 wait for the execution of the ISR routine code?

I'm developing a stack layer on microcontroller STM32L433 that uses the CAN protocol; a fundamental part of the stack is the authentication of the devices.
During authentication it can occur that two (or more) devices start to send a CAN message (authentication message) with the same identifier and different payload (true random value). In this case every device should be able to detect if this message was sent first from another device.
I have studied this case and three situations can occur:
the devices start to send message at the same time; in this case only one device is able to sent the message because all others devices detect one error and then abort the transmission.
only one device is able to send the message and occupy the bus before all others devices load the transmission MAILBOX of the CAN peripheral, or before the CAN peripheral of the others devices set the message that is going to be sent in the SCHEDULED state.
In this case, the devices that have not been able to send the message will receive the reception interrupt; within the ISR routine of reception I'm able to abort the transmission.
only one device are able to send the message and occupy the bus and all others CAN peripherals of others devices have message in SCHEDULED state and are waiting that bus become idle.
In this case the devices that have not been able to send the message will receive the reception interrupt. Also in this situation I thought to stop the transmission within the ISR routine of reception (like situation 2) ), but I'm not sure that this is guaranteed for all messages because if the CAN peripheral sets the message that is going to be sent in the TRANSMIT state before the code inside ISR is executed, the operation of abort will have no effect.
My question is (related to the situation 3): Is the message in the transmission MAILBOX in the SCHEDULED state set in the TRANSMISSION state after that the code in the receiving ISR routine is executed or is this thing not guaranteed?
To answer on your third case first, no it is not guaranteed that your message is not on the bus, while receiving. Because interrupts might have some latency too, and within this time, the mailbox might be able to go ahead with transmission.
Your "authentication" also sounds a bit troublesome, since nobody from outside could also actually decide which ECU was actually the one that won the arbitration and actually sent that specific message.
We have ECUs in vehicles which decide at runtime, according to certain methods, where they are mounted by pin and some CAN reception, but only in listen mode. TX is actually disabled in the stack. After that, detection has completed, we switch configurations and restart the communications stack and further initialize the software going up.
But these "setups" are usually defined beforehand, e.g. due to master/slave (vehicle/private bus communication), or maybe some connector pins connected to GND / OPEN / UBAT, or maybe some bus message which tells on which bus it is on.
That seems to be more reliable than your method.

MBED Serial dropping data

I use MBED (online IDE & libraries) for my application with host board NUCLEO-411RE and 4D Systems touch display connected by full duplex serial communication.
I am able to send data successfully from host to display without errors. However when sending data from display back to host I am losing data.
Reducing baud to 9600 does not solve the problem.
The host processor remains in a super loop with the first action to check if LCD sends serial data ( lcd4d.readable() ).
Host then receives one character at a time ( lcd4D.getc() ), echos it to the PC via usb ( pc.printf(&recChar) ) and does some further processing.
I am also monitoring the physical host receive pin on a separate terminal session. Using this I am certain that the LCD sends data correctly, however this data is not received and echoed correctly by the host processor (echo to PC is only used for debugging purposes).
Refer to super loop code snippet:
do {
if ( lcd4D.readable() ) {
recChar = lcd4D.getc();
pc.printf(&recChar);
lcd4D_intr_Rx();
}
Also refer to attached screen print showing terminal left PC echo (data loss) and terminal right hardware pin monitor (confirming data sent correctly).
Implementing SerialRX interrupt also does not help the situation with data loss still occurring.
Thanks for any suggestions; I am out of ideas.
I have solved the problem.
The issue was that the host processor needed to respond fast enough to the serial data received. I basically implemented a fast serial receive buffer and ensured that received characters are buffered immediately upon interrupt.

Accurately measuring Time for an event ( relay contact closure) using GPS PPS

I have a relay contact closure event that needs to be timestamped accurately ( 1 msec) with a GPS and the PPS output... I am not sure how to feed the relay contact output to a microcontroller and then synchronize the microcontroller clock to the GPS ...plus how to get the UTC afterall?
Can you please help me.
thanks
If your microcontroller has at least two interrupts based on hardware pins, you could connect the relay to one of the interrupt-generating pins, and the PPS to the other interrupt-generating pin.
You will need to connect the NMEA (or other proprietary protocol of your GPS) to the corresponding port in your microcontroller. Some common buses are UART or SIP.
Then, every time that you get a PPS interrupt, you enable a global flag that can be used in the main loop to reset a counter. This counter will tell you how far apart from the PPS the relay switched (if it happens within that second). If you know the base frequency of your counter, you can convert the counter into fractions of seconds. Note that if both edges of the relay state change have to be detected, you will need an interrupt source capable to interrupt on both edges (or use two interrupts)
Then, if the Relay interrupt goes off, you can get the value of the counter upon interrupt, and save it in storage, send it to host, etc. (Note, it would be best to save the value in RAM, lift a flag of "value present", and leave the sending/storing to the main loop, then turning off the flag).
Finally, when you receive a complete NMEA message (this could be being parsed in your main loop by a state machine for instance), you can send this information to the host or storage along with the counter that you saved to time your relay state change. Note please that the NMEA message will be generated and decoded with a certain delay from the PPS, so you will need to compensate for that.

XBee Arduino API Remote At Command Response

I'm in trouble with programming my Arduino. I've two XBee Series 2 Modules and an Arduino UNO. I use the XBee-API library from: http://code.google.com/p/xbee-api/.
I generate three RemoteATRequest Packets (0x17) to control a Digital Pin of the Remote Sleepy Node and send it out of a SoftwareSerial to the XBee Coordinator which is plugged via a Sparkfun XBee Arduino Shield (https://www.sparkfun.com/products/10854) to the Arduino UNO. The Communication works fine. Every Request Packet is sending out to the Remote. And for every Request Packet a Remote Packet is received. I checked this with a Serial Monitor and a RS232<-> TTL Converter. But in my Arduino Software it seems to be that only one Remote Packet is received. Curious is the point that when I send the Request Packets in the time the Remote is sleeping than I read three Response if it is awake and takes the Requests from the Coordinator.
Does anyone try the same or hase the same problems? I've tried so much until know another Baudrate, delays befor sending out. Nothing works.
My recollection of ZigBee and/or 802.15.4 is that the parent node for a sleepy end device will only hold/queue a single frame for when the sleepy device wakes up. And note that in ZigBee it's only guaranteed to queue it for 7.5 seconds. You may need to modify your code to send a single Remote AT Request at a time, and wait for the response before sending another.
This page has a good description about how the MAC layer works:
Once the frame is assembled, there are actually two ways to send it.
If its going to another router or an end device whose receiver is
always on, the frame will be sent directly via the radio. Otherwise,
if the destination is a sleepy end device, the frame will need to be
sent as an indirect transfer. The frame will go to the indirect queue
until the destination device wakes up and polls the parent. Once the
poll comes in, the frame will get sent to the destination.
It would be great if the XBee module supported a frame type that contains multiple AT commands, but as far as I can tell, that isn't an option.