XPLAIN Bridge Firmware Update
Today I wasted a good portion of my day running around my University trying to get the forms I need for my Norwegian Visa application for my internship at Atmel in November. Ever seen the Hitchhiker’s Guide to the Galaxy movie, the scene where they try to free Trillian by filling out all the bureaucratic forms, and are forced to line up several times, each time with a different form? Today was like that, but worse, since half the staff are away on leave during the mid-year break, and the remaining staff are on lunch break. After all my trouble, I’ve now got to go back next week and pick up my $25 form letter stating that yes, I am indeed a student at Latrobe. Bah.
Now, back to the good stuff. I believe that every programmer has an Achilles Heel, that one algorithm that everyone else seems to have no trouble with, but for that person it causes endless frustration and misery. For me, that algorithm is the implementation of a software U(S)ART. I’ve now written and re-written different implementations several times, and although they eventually work, my bidirectional software UARTs always seem to miss the occasional character.
A software UART is supposed to be a simple affair – after all, with the most common 8-bit, no parity, one stop bit setting that many devices use, each frame is just the raw bytes framed by a low start and a high stop bit. This translates to some fairly simple code, which is usually run in a timer ISR to ensure that the timing of each bit is constant, to prevent reception errors at either end.
A unidirectional UART is possibly the easiest algorithm to get working, with the exception perhaps of a software SPI port. It’s when the requirements are for a bidirectional software UART that things get hairy, since now you’ve got to work out how to prevent the bit transmission and reception ISRs from tripping each other up and delaying the other long enough to corrupt the transfer. This is needed in my XPLAIN Bridge firmware for Atmel’s XPLAIN board, when the bridge operates as a USB to Serial converter. Since the AVR’s hardware UART is instead used as the PDI programmer transport to the XMEGA chip on the board, the serial channel is instead implemented in software on the USB AVR side.
It’s not just me that’s had trouble with this algorithm however; recognizing that it’s not as simple as it appears I originally outsources the software UART code on AVRFreaks, and ended up with an ASM and a C implementation from two kind members there. Both of these worked, but things got wonky when both ends of the link tried to send at the same time, as the transmission and reception code blocked each other.
After some complaints about my less-than-perfect UART code, I took yet another crack at it last night, trying to fix up the implementation so that lost characters would be the exception, rather than the rule. This has led to my new implementation of the software UART, which uses two timers and an external interrupt pin. This new implementation uses one timer for bit transmissions – each bit period, either the next bit to send is transmitted, or the next byte to send is loaded into a temporary buffer so that it can be shifted out. The reception code relies on an external interrupt pin to sense the start bit, which then starts the bit reception timer to shift in the incoming bits.
Additionally, I found that the Windows CDC driver does not like mostly-empty incoming packets, even though it is quite happy to issue them to attached devices – I found my Windows 7 machine locking up when I barraged it with a constant stream of single-byte packets (one for each incoming character). This also lead to the reception buffer being overflown due to the host not processing the packets fast enough, which corrupted the incoming data stream occasionally. To combat this, the bridge code has a third timer which flushes the current reception buffer contents to the host in a single packet rapidly (30 flushes a second) to aggregate multiple bytes into a single USB IN packet.
Tests on the latest code show this new code to be far, far more reliable that the old, although large streams in both directions can still cause some issues. I’d like some more testers on this before the next official release to get a wider opinion on the new code’s performance – I’ve started uploading pre-built versions of the project to the XPLAIN Bridge project page for convenience.
Hi Dean,
thank you for your very useful implementation of the PDI programmer.
If I may make a suggestion relating the serial port problem:
Wouldn’t it be the best to implement only one timer interrupt for the sending and receiving routine? I don’t know, if there is sufficient computing power available on the ATXmega for a fast interrupt service routine with lets say 10us repetition rate.
If there is, than you can implement a state machine in this interrupt routine which handles both: the receiving and transmitting task. This would avoid the problem of disturbing to interrupts each other.
Best regarts,
chris
Chris,
The latest builds all but solve the issue – the probability of the two ISRs delaying one-another for a long enough time to cause issues should be very low. Keeping the two separate ISRs allows for the bridge code to continue a transmission that is in progress even while a byte is being received or vice-versa – a state machine approach would either dump the incoming byte, or abort the outgoing byte. The dual ISRs allow for the possibility of both incoming and outgoing bytes to be transferred correctly — if not, one or the other will win out over the other and nothing will be lost over the state machine approach anyway.
The latest version will not start a new transmission while a byte is being received, which should also add to the reliability of the system.
– Dean
Hi Dean,
for my experiments I downloaded your code on July 17th. I startet this memory test programm
http://www.mikrocontroller.net/attachment/82592/XPlainRamTest.zip
Your new version works much better than the older version. But there are still errors in transmission. I would say, one byte of a 100 is wrong.
Best regards,
chris
Chris,
That’s a lot better than it was – is that 1% error in reception only, transmission only, or both directions? Tightening up the ISRs might be able to reduce that even more, however note that no bidirectional software UART will ever be perfect.
– Dean
Because I mainly use the direction from the XPLAIN to Hyperterminal, my observations are only valid for the XPLAIN sending direcion.
– chris