I’m trying to write an interrupt-driven transmit buffer for AVR hardware USARTS, using the TX complete interrupt to load and send the next buffered character, but I’ve hit a big snag: how to trigger the first transmission.
I can’t just send out a garbage byte (it will mess up the protocol of the device I’m sending data to), and manually transmitting the first byte of the buffer is proving ugly and cumbersome. What I really want is a way to just set the TX complete flag without sending a byte, or even a way to jump to the interrupt vector, but have the interrupt function return back to wherever in my code the jump was made from. Anyone have any ideas or suggestions?
In the meantime I’ll keep trying it the ugly way.
Are you using C or assembly? Assuming it’s C, my vote is for the ugly way, but is there a reason you can’t make the body of the ISR consist entirely of a call to an inline function, and call the exact same function from your code to start the transmission? Maybe I don’t understand exactly what ugliness you want to avoid.
Yeah, that’s sort of what I’m doing now. It’s close to working, but a little buggy.
The problem is that I’m sending a three-part packet, with pauses in between the parts to wait for a response character from the receiving device. At the end of the part I disable the TX complete interrupt from within its ISR function, and the RX interrupt ISR function re-enables it when the proper response character comes through.
The part I consider ugly is having global variables representing which part of the packet we’re at passed back and forth between the two interrupt functions. Its not working quite right at the moment, and I’m probably going to reuse this code a lot in the future. I thought it would be more elegant if the RX interrupt could recognize the response character, enable the TX complete interrupt, and kick start it by just setting the flag. Then I would only need to worry about the packet state inside the TX complete ISR function (and have only one function to edit in the future).
Another option I’m going to try this morning is to just leave the TX complete flag floating and unanswered for the periods of time between packets and parts of packets while the interrupt is disabled. I just have to make sure to send one byte (garbage or otherwise) way in the beginning to start everything off.
-Adam (who avoids assembler at ALL COSTS)
Hah! I have learned two things:
In addition to the TX complete interrupt, there is a general Data Register Empty interrupt, which occurs any time there is no byte being transmitted. I guess you’d have to be careful to disable that one when you were done sending your packet, or it would just constantly interrupt things. I ended up using the TX complete interrupt and making sure to kick it off by sending out useless bytes way at the beginning of the program.
Buffering on the AVR side wasn’t my problem anyway. It turns out the datalogger board I was trying to interface is damaged/defective. It requires hardware flow-control, but its RTS pin was never changing state. It’s really hard to track down a bug in software that is actually occurring in hardware. Oh well.
Well, we decided to go with the UDRE register empty interrupt for the serial functions that we just added to the Pololu AVR Library. It’s definitely important to remember to disable that interrupt at the end of transmission, and after that it seems to work just fine. You can download the library and take a look at the code if you want to see how we did it. Did you get your application working in the end?
Cool. I just saw your announcement and I’ll definitely check it out. I ended up just swapping out hardware for my project, an interrupt driven dual quadrature decoder and data logger.
I was originally trying to use a Parallax USB memory stick data logger, which is basically just a breakout board for an FTDI chip called the Vinculum (“to bind” from Latin, but I suspect a project engineer was just trying to sneak in a Star Trek reference). It’s really cool to be able to read/write a USB memory stick with just a UART interface, but there is a lot of overhead between the UART and the flash memory (and not much buffering on their end apparently).
I need to write 270 bytes per second, not terribly much, and to stay out of interrupt functions most of the time. The Vinculum would mostly accept data at whatever baud rate with no trouble, but occasionally (every minute or so) it would pause the flow, sometimes for as long as 0.3 seconds, and sometimes in quick succession. I built huge interrupt-driven buffers to account for this, but somehow I was still missing state changes of the CTS pin.
I’m sure it could have been done properly, but I needed something that would work immediately, so instead I switched it out for an old SparkFun Logomatic 1.0, which does its own buffering, guarantees write times to an SD card, and doesn’t even bother with hardware flow control. It’s a little more cumbersome in that you can’t close and open new files with commands from your microcontroller (until I tap into the stop/reset pins that is), but it worked immediately and reliably.
P.S. I’ve got one of the new (easily firmware hackable) Logomatic 2.0 boards in the mail, exciting!