| Author |
Message |
|
|
Posted: Nov 22, 2011 - 07:01 AM |
|

Joined: Mar 17, 2005
Posts: 1307
Location: Stockholm, Sweden
|
|
Hi,
I have a custom board with a UC3A3128 on and a firmware based on the USB Device CDC Example.
Code:
usb_write_ep_txpacket(TX_EP, (char*) array, numberOfBytesInAUSBFrame, NULL);
I use this command to load a message into the USB interface. When the variable numberOfBytesInAUSBFrame = 512, the message gets sent automatically and it all works fine. But when numberOfBytesInAUSBFrame < 512, it sometimes screws up. I think it is because the buffer is not sent in time, so it is still there when I want to send the next message and then it starts to pad the messages.
So what I want to do is to perform a command after the loading of the message into USB interface, that sais that the buffer is ready to send. How do I do this? I tried "Usb_send_in(TX_EP);" and "Usb_raise_sof();". But what is the correct way? |
|
|
| |
|
|
|
|
|
Posted: Nov 22, 2011 - 09:22 AM |
|

Joined: May 24, 2011
Posts: 253
Location: Berlin
|
|
Hi Agwanil,
I'm not so familiar with USB device, only USB host.
But maybe it's worth to have a look at the V2 USB device stack in:
<asf>/common/services/usb/class/cdc/device
There seems to exist a callback functionality for your issue:
udi_cdc.c -> udi_cdc_data_sent() "Callback called after data transfer on USB line"
You may not be happy to hear something like "use another software stack". I don't know how Atmel deals with outdated software, but the V1 stack might not be supported in future anyway.
-sb |
|
|
| |
|
|
|
|
|
Posted: Nov 22, 2011 - 09:33 AM |
|

Joined: Aug 25, 2011
Posts: 392
Location: Europe
|
|
| I think you need to "ack" (acknowledge) the IN endpoint when not sending a full 512 packet. The ASF has the macro Usb_ack_in_ready(ep) macro for that. Usually you’ll end up using it together with the send macro, so there’s a combined macro called Usb_ack_in_ready_send(ep) that you can use instead of just Usb_send_in(ep). Maybe that solves your problem. Have a look at one of the USB example projects. It should be used in there. |
|
|
| |
|
|
|
|
|
Posted: Nov 22, 2011 - 10:23 AM |
|

Joined: Mar 17, 2005
Posts: 1307
Location: Stockholm, Sweden
|
|
Thanks for your assistance. I tried the "Usb_ack_in_ready_send(ep)" but it does not help. If I have too short time between data transfers (still at least 2ms) everything hangs. Both on computer side and on uC side. I would expect beening able to send microframes 8(?) times/µs.
There is going to be quite a lot of work getting V2 of the USB stack. There seems to be a lot of changes. Ill look a little into it, but I have written quite a lot of code into the old example. |
|
|
| |
|
|
|
|
|
Posted: Nov 22, 2011 - 10:30 AM |
|

Joined: Aug 25, 2011
Posts: 392
Location: Europe
|
|
| Sorry, I slightly misunderstood your initial question. You were asking how to tell whether the endpoint is ready: Use the Is_usb_in_ready(ep) macro for that, possibly by just polling it. It probably only works properly if you use the Usb_ack_in_ready_send(ep) macro afterwards. Usb_raise_sof() has nothing to do with it, so better don’t touch it. |
|
|
| |
|
|
|
|
|
Posted: Nov 22, 2011 - 08:45 PM |
|

Joined: Mar 28, 2010
Posts: 127
Location: Palmerston North, New Zealand
|
|
Hi Agwanll,
Had the same problem, I use the following code
Code:
uiIndex = 0;
unwrittenBytes = 0;
Usb_reset_endpoint_fifo_access(TX_EP);
do {
unwrittenBytes = usb_write_ep_txpacket(TX_EP, &(ucUSBTxBuffer[uiIndex]), (usUSBTxDataCount - uiIndex), NULL);
uiIndex = uiIndex + (usUSBTxDataCount - (unwrittenBytes + uiIndex));
Usb_ack_in_ready_send(TX_EP);
uiTimeout = 100000;
while(!Is_usb_in_ready(TX_EP)) {
uiTimeout--;
if(uiTimeout == 0) {
break;
}
}
} while (unwrittenBytes != 0);
Points to note, until the Is_usb_in_ready(TX_EP) returns true (Hardware indicating that the last transaction completed) I busy wait with a timeout. This is very similar to the send code in the framework (for the host CDC task).
Also the transactions only send 64 bytes at a time, hence when sending a buffer that is larger, I needed to manage the amount of data already sent from the buffer and the location to send.
Its not pretty but it works.
Regards.
(EDIT:) This is for the older framework 1.7... |
|
|
| |
|
|
|
|
|
Posted: Nov 23, 2011 - 08:08 AM |
|

Joined: Mar 17, 2005
Posts: 1307
Location: Stockholm, Sweden
|
|
Thanks daffniles, just handling un-sent data fixed my byte dropping problem. Just why did I not try that earlier?? I thought I never got un-transfered bytes, but apperantly the computer does not read fast enough to keep up. (strange?)
So no dropped data now, but still computer software hang when data is sent too fast. Connecting and disconnecting the PC program (Realterm) to the port jiggles the bytes loose, and after a few times, everything runs again. And I know that when the computer does not read the bytes, the device stops and waits for the PC to read, so that works.
Also running remote desktop onto the computer who has the connection to the device makes it fail a lot more. Closing all programs possible, makes if fail less often. Stupid computer not beeing able to handle one single USB endpoint at close to speed limit. 18-22 Mbit/s is my transfer rate. |
|
|
| |
|
|
|
|
|
Posted: Nov 23, 2011 - 09:18 AM |
|

Joined: Aug 25, 2011
Posts: 392
Location: Europe
|
|
The problem you described is something I observed with Realterm as well, so I don’t think it’s your computer. Keep in mind that Realterm was probably designed for real serial connections, chugging along at 115200 bytes/s at best. Usually it displays all data on screen and that’s not really fast. If you throw 18-22 Mbit/s at it, the screen redrawing just takes to long and Realterm starts choking. If you want to store the data on your PC, use that option that just captures incoming data and writes it into a file. Then everything should work fine without hanging or stalling. Otherwise just write a simple Program yourself to shovel the data from the virtual serial port to somewhere else (or install Cygwin and just use dd ). |
|
|
| |
|
|
|
|
|
Posted: Nov 24, 2011 - 07:46 AM |
|

Joined: Mar 17, 2005
Posts: 1307
Location: Stockholm, Sweden
|
|
Is there a known bug in the driver for atmels CDC VPC? Talking about the 1.7 framework version.
I send a request to my uC to give me about 9 megs of data. After a few megs, the transfer stops. But I can get it to send another 16384 bytes if I send a byte to the uC again. I get the exakt amount for every transfer I do until the full 9 megs has been transfered. Then the uC starts to respond as ursually to bytes sent to it.
It feels like someone sitting in the middle of my uC and my PC program stops the transfer and fills its buffer until it is poked upon with a message from the other side. |
|
|
| |
|
|
|
|
|
Posted: Nov 24, 2011 - 09:22 AM |
|

Joined: Aug 25, 2011
Posts: 392
Location: Europe
|
|
I’m using the ASF 1.7 and I experienced similar problems during initial development, but it was always an error on my part, not calling the right functions at the right time or not setting the correct flags. It works perfectly now and I can send arbitrary amounts of data from and to the MCU without ever losing data. I’m using the UDDMA instead of accessing the USBB SRAM directly, though.
You description is rather vague, so my only guess would be that you’re not ACK’ing the data at some point, either because the order of function calls is incorrect or because you’re missing an event somewhere. Maybe you swapped the endpoint numbers for RX and TX somewhere, ACK’ing the wrong endpoint and it works once you send something in the opposite direction.
If you’re still using Realterm to display your data on screen, I’d blame that, though. |
|
|
| |
|
|
|
|
|
Posted: Nov 24, 2011 - 09:50 AM |
|

Joined: Mar 17, 2005
Posts: 1307
Location: Stockholm, Sweden
|
|
| My send routine does not do much.
Code:
// USB free and should I send and am I in send state?
if (uart_usb_tx_ready() && isToSendData() && (state == STATE_SEND)) {
// Are there unsent bytes since last try? Send it.
if (nonWrittenBytes > 0) {
nonWrittenBytes = usb_write_ep_txpacket(TX_EP, (char*) array, nonWrittenBytes, NULL);
}
// Else send new bytes if not enough bytes already sent
else if (counter++ < numberOfBytesInAPacket) {
nonWrittenBytes = usb_write_ep_txpacket(TX_EP, (char*) array, numberOfBytesInAUSBFrame, NULL);
}
// if enough bytes has been sent for this packet, reset counter and change state
else {
counter = 0;
state = STATE_SAMPLE;
// if enougt packets has been sent, reset counter and state
if (counter2 >= numberOfDatasPackets) {
counter2 = 0;
endReadFrame();
}
}
}
I do set both number of bytes to send every USB frame, USB-frames/packet and number of packets to send. Between each packet I have a sample time.
Sampling state switches some GPIO:s and has a
Code:
cpu_delay_us( sampleTime , 12000000 );
in it. If I remove the delay, all bytes are sent trough. But then my sampling time is not settable. I don´t understand how this delay does anything but makes the USB transfers happen less often. |
|
|
| |
|
|
|
|
|
Posted: Nov 24, 2011 - 10:08 AM |
|

Joined: Aug 25, 2011
Posts: 392
Location: Europe
|
|
Where do you tell the USBB to actually send the data? I don’t see a Usb_ack_in_ready_send(ep) or Usb_send_in(ep) anywhere. Also do you call Usb_reset_endpoint_fifo_access(ep) before the first write into an empty endpoint?
Sending a packet should happen like this:
- Call Usb_reset_endpoint_fifo_access(ep)
- Call usb_write_ep_txpacket(...) as many times as necessary until the endpoint is full
- Call Usb_ack_in_ready_send(ep)
- Repeat cycle for next block
Maybe have a look at the notes in the description of the usb_write_ep_txpacket(...) function. |
|
|
| |
|
|
|
|
|
Posted: Nov 24, 2011 - 10:27 AM |
|

Joined: Mar 17, 2005
Posts: 1307
Location: Stockholm, Sweden
|
|
| I have this routine to send the data:
Code:
if (!Is_usb_write_enabled(TX_EP)) { // If Endpoint full -> flush
Usb_ack_in_ready_send(TX_EP);
}
In the end of the sampling routine I call "Usb_reset_endpoint_fifo_access(TX_EP);" and then go over to the loading of data into buffer I showed above. As you can see in the prior code I posted, the sample routine is called between each packet. The packet can be multiple 512 bytes thou, is that ok? |
|
|
| |
|
|
|
|
|
Posted: Nov 24, 2011 - 10:37 AM |
|

Joined: Aug 25, 2011
Posts: 392
Location: Europe
|
|
I think you need to call Usb_reset_endpoint_fifo_access(TX_EP); after every Usb_ack_in_ready_send(TX_EP);
I didn’t catch whether you’re doing that every time or just once per 16k block.
The size of your data block isn’t restricted to multiples of 512 bytes. It can be anything, as long as you properly call Usb_ack_in_ready_send(TX_EP); at the end. |
|
|
| |
|
|
|
|
|
Posted: Nov 24, 2011 - 11:27 AM |
|

Joined: Mar 17, 2005
Posts: 1307
Location: Stockholm, Sweden
|
|
| I'm doing it once every 1 to 200 batches of 1-512 bytes each. Number of batches and number of bytes in a batch is settable. |
|
|
| |
|
|
|
|
|
Posted: Nov 24, 2011 - 12:29 PM |
|

Joined: Mar 17, 2005
Posts: 1307
Location: Stockholm, Sweden
|
|
| Another thing that makes the transfer not hang is if I remove the "Usb_ack_in_ready_send(TX_EP);", and use this to flush the data out, but have 10 ms timer for it:
Code:
if (sof_cnt >= NB_MS_BEFORE_FLUSH) { //Flush buffer in Timeout
sof_cnt = 0;
uart_usb_flush();
}
|
|
|
| |
|
|
|
|
|
Posted: Nov 24, 2011 - 01:37 PM |
|

Joined: Mar 17, 2005
Posts: 1307
Location: Stockholm, Sweden
|
|
I don't really get how this should be done correct.
Lets say I want to sample 10 times for 5 ms and each sample to be 300 bytes.
I am guessing like this:
Code:
Start sampling
Stop sampling
Usb_reset_endpoint_fifo_access(TX_EP);
usb_write_ep_txpacket(TX_EP, (char*) array, 300, NULL);
Usb_ack_in_ready_send(TX_EP);
Can I do it like that?
And how much data can I transfer between each reset of endpoint and ack-in-ready-send?
Lets say I want to sample 10 times for 5 ms and each sample to be 100k bytes instead. Do I do reset of endpoint and ack-in-ready-send for every 512 butes or for every 16k bytes? Or do I use a command to get if the buffer is full and then do it? |
|
|
| |
|
|
|
|
|
Posted: Nov 24, 2011 - 02:11 PM |
|

Joined: Aug 25, 2011
Posts: 392
Location: Europe
|
|
Between endpoint FIFO reset and ack-in-ready-send you can put data into the endpoint until it is full. How much the endpoint takes depends on how you configured it and whether you use FullSpeed or HiSpeed USB. It’s best to just use Is_usb_write_enabled.
Maybe try it like this:
Code:
start_sampling();
stop_sampling();
Usb_reset_endpoint_fifo_access(TX_EP);
while (Is_usb_write_enabled(TX_EP)) {
unwritten = usb_write_ep_txpacket(TX_EP, things, amount, NULL);
// handle unwritten data here
}
Usb_ack_in_ready_send(TX_EP);
If I understood the ASF correctly, it should work like that.
So you actually don’t call the endpoint FIFO reset and ack-in-ready-send for every 512 bytes, every 16k or another fixed size. You call them once for every block of data that fits into the endpoint, as determined by Is_usb_write_enabled(TX_EP). |
|
|
| |
|
|
|
|
|
Posted: Nov 24, 2011 - 03:42 PM |
|

Joined: Mar 17, 2005
Posts: 1307
Location: Stockholm, Sweden
|
|
So is there a reason to not call reset-endpoint-fifo-access every time just after the usb-ack-in-ready? It feels like it should be some time in between there or another kind of contition.
Is it so that I cannot call the reset-command until I get usb-write-enabled? |
|
|
| |
|
|
|
|
|
Posted: Nov 24, 2011 - 04:34 PM |
|

Joined: Aug 25, 2011
Posts: 392
Location: Europe
|
|
Calling the reset-command before writing is better style because you might not know in which state the endpoint FIFO was left after the last access. Also the endpoint is busy until Is_usb_write_enabled() returns true, so the program behaves more similar to the hardware if you call reset only after the endpoint is writeable again.
You could probably mix it around however you want, but that will make your program harder to understand and harder to debug. |
|
|
| |
|
|
|
|
|