December 13, 2020

USB - sending packets

Now that I am receiving packets, I am looking into sending replies.

It seems to work a lot like receiving. There is a fifo and you write bytes to it. There is also a FIFO empty interrupt.

I am wondering though about the best way to manage this. Suppose I have 4 bytes I want to send. Why wait for a Tx empty interrupt to shove them into the fifo? Isn't it the purpose of a FIFO to allow you to be shoving data in one end while the USB engine is pulling data out of the other? How can you determine if there is space in the FIFO? Do you have to check first, or can you try to push something and have it rejected. I don't think the latter is possible.

The simple option is to just stick the bytes into some kind of queue that I manage and then when I get a Tx empty interrupt, copy that into the FIFO. Or part of it. Or since I know how big the fifo is and I know I am starting with an empty fifo, never shove more in than the fifo size. All this will least to a "bursty" sort of transmitting though, so it is worth investigating if there are ways to test fifo capacity at any given moment.

My FIFO layout looks like this:

#define RX_FIFO_SIZE    128
#define TX0_FIFO_SIZE   64
#define TX1_FIFO_SIZE   128
#define TX2_FIFO_SIZE   0
#define TX3_FIFO_SIZE   0
So I am only using endpoints 0 and 1. All receiving is done on FIFO 0 (so each packet must be checked to see what endpoint it is destined for). I have two Tx FIFO's. One for endpoint 0 and control messages, and a bigger one for endpoint 1 and my application.

Indeed when I scour the datasheet, I find that the "status" register for each of the four IN endpoints is what I want. It holds a count of the number of words of FIFO space available. So I ought to be able to just check this and write info directly into the FIFO. Note that the writes must be quantized by 4 bytes, since we write words. I wonder if there is a way to have an interrupt when the FIFO reaches half empty or some such.

The fact that I was itching for registers with this information and that there is one, makes me feel good about how I am thinking.

There is a half empty status/interrupt! The bit to control this is in the AHBCFG register (of all places) and it seems to be all or nothing for the entire USB peripheral. You can choose to have all Tx empty interrupts trigger on either half empty or all the way empty. All a question of your strategy when writing your driver.


Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org