Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
AgwanII
PostPosted: Nov 22, 2011 - 07:01 AM
Posting Freak


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?
 
 View user's profile Send private message  
Reply with quote Back to top
sambrown
PostPosted: Nov 22, 2011 - 09:22 AM
Hangaround


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
 
 View user's profile Send private message  
Reply with quote Back to top
catweax
PostPosted: Nov 22, 2011 - 09:33 AM
Hangaround


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.
 
 View user's profile Send private message  
Reply with quote Back to top
AgwanII
PostPosted: Nov 22, 2011 - 10:23 AM
Posting Freak


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.
 
 View user's profile Send private message  
Reply with quote Back to top
catweax
PostPosted: Nov 22, 2011 - 10:30 AM
Hangaround


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.
 
 View user's profile Send private message  
Reply with quote Back to top
daffniles
PostPosted: Nov 22, 2011 - 08:45 PM
Hangaround


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...
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
AgwanII
PostPosted: Nov 23, 2011 - 08:08 AM
Posting Freak


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.
 
 View user's profile Send private message  
Reply with quote Back to top
catweax
PostPosted: Nov 23, 2011 - 09:18 AM
Hangaround


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 Razz).
 
 View user's profile Send private message  
Reply with quote Back to top
AgwanII
PostPosted: Nov 24, 2011 - 07:46 AM
Posting Freak


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.
 
 View user's profile Send private message  
Reply with quote Back to top
catweax
PostPosted: Nov 24, 2011 - 09:22 AM
Hangaround


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.
 
 View user's profile Send private message  
Reply with quote Back to top
AgwanII
PostPosted: Nov 24, 2011 - 09:50 AM
Posting Freak


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.
 
 View user's profile Send private message  
Reply with quote Back to top
catweax
PostPosted: Nov 24, 2011 - 10:08 AM
Hangaround


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.
 
 View user's profile Send private message  
Reply with quote Back to top
AgwanII
PostPosted: Nov 24, 2011 - 10:27 AM
Posting Freak


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?
 
 View user's profile Send private message  
Reply with quote Back to top
catweax
PostPosted: Nov 24, 2011 - 10:37 AM
Hangaround


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.
 
 View user's profile Send private message  
Reply with quote Back to top
AgwanII
PostPosted: Nov 24, 2011 - 11:27 AM
Posting Freak


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.
 
 View user's profile Send private message  
Reply with quote Back to top
AgwanII
PostPosted: Nov 24, 2011 - 12:29 PM
Posting Freak


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();
   }
 
 View user's profile Send private message  
Reply with quote Back to top
AgwanII
PostPosted: Nov 24, 2011 - 01:37 PM
Posting Freak


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?
 
 View user's profile Send private message  
Reply with quote Back to top
catweax
PostPosted: Nov 24, 2011 - 02:11 PM
Hangaround


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).
 
 View user's profile Send private message  
Reply with quote Back to top
AgwanII
PostPosted: Nov 24, 2011 - 03:42 PM
Posting Freak


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?
 
 View user's profile Send private message  
Reply with quote Back to top
catweax
PostPosted: Nov 24, 2011 - 04:34 PM
Hangaround


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.
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits