GCC and AT91SAM7 USB CDC Core Example

Started by Ralph Hempel June 13, 2007
All,

I've hit a bit of a roadblock with the Atmel USB-CDC Core
implementation using GCC 4.1.1

Specifically, everything else I've tested is working fine
except the OUT Endpoint Interrupt Handler.

No matter what I tweak, it loses packets, messes up the
input buffers and generally causes me grief.

I've improved things by going to a strict POLLED implementation
for reading the OUT Endpoint, but my application works this way
anyways so it's not such a big deal right now.

Still, I think that everyone would like to see the CDC example
code from Atmel work correctly, and I've read enough other posts
on other groups to begin to suspect a silicon problem.

One thing I've done is move to the 1.02 CORE example code from the
MSD example and the older 1.01 CDC example on top of the core. This
looks after a few little bugs such as the unconditional clearing
of BK0 and BK1 at the end of every interrupt handler!

I think there's still a race condition in the ping-pong register update
code. It is in a macro that basically ends up expanding to code
that looks something like this:

USP_CSR[ep] &= ~RX_DATA_BKx;

The problem occurs if the other BK bit goes high between the CSR read,
the clear, and the write. Probably the setting and clearing code should
look like this:

CLEARING:

dummy = USP_CSR[ep] | (RX_DATA_BK0 | RX_DATA_BK1);
dummy &= ~(bits_to_clear);
USP_CSR[ep] = dummy;

SETTING:

dummy = USP_CSR[ep] | (RX_DATA_BK0 | RX_DATA_BK1);
dummy |= (bits_to_set);
USP_CSR[ep] = dummy;

That way, the bits get written to 1, which has no effect unless they
are being specifically cleared, and setting other bits does not
inadvertently clear them...

Has anyone had results, good, bad, or otherwise with the
CDC-Core implementation?

Ralph
Hi Ralph,

I've been playing with the BASIC_USB code off and on (IAR). Got it to do
some transfers, but it usually just hangs its self. Yes, I'd LOVE to see a
good clean demo of a CDC USB device.

This demo appears to be written to block waiting for chars from endpoint,
and then again waiting to send back. I want to drop it into my code which
is running a small fixed task list. I have things like SPI that are run off
of a PIT interrupt, and I'd prefer to just poll to get limited chars from
the USB. I'd respond with my chars to the USB in a background task.

Alan KM6VV
>
> All,
>
> I've hit a bit of a roadblock with the Atmel USB-CDC Core
> implementation using GCC 4.1.1
>
> Specifically, everything else I've tested is working fine
> except the OUT Endpoint Interrupt Handler.
>
> No matter what I tweak, it loses packets, messes up the
> input buffers and generally causes me grief.
>
> I've improved things by going to a strict POLLED implementation
> for reading the OUT Endpoint, but my application works this way
> anyways so it's not such a big deal right now.
>
> Still, I think that everyone would like to see the CDC example
> code from Atmel work correctly, and I've read enough other posts
> on other groups to begin to suspect a silicon problem.
>
> One thing I've done is move to the 1.02 CORE example code from the
> MSD example and the older 1.01 CDC example on top of the core. This
> looks after a few little bugs such as the unconditional clearing
> of BK0 and BK1 at the end of every interrupt handler!
>
> I think there's still a race condition in the ping-pong register update
> code. It is in a macro that basically ends up expanding to code
> that looks something like this:
>
> USP_CSR[ep] &= ~RX_DATA_BKx;
>
> The problem occurs if the other BK bit goes high between the CSR read,
> the clear, and the write. Probably the setting and clearing code should
> look like this:
>
> CLEARING:
>
> dummy = USP_CSR[ep] | (RX_DATA_BK0 | RX_DATA_BK1);
> dummy &= ~(bits_to_clear);
> USP_CSR[ep] = dummy;
>
> SETTING:
>
> dummy = USP_CSR[ep] | (RX_DATA_BK0 | RX_DATA_BK1);
> dummy |= (bits_to_set);
> USP_CSR[ep] = dummy;
>
> That way, the bits get written to 1, which has no effect unless they
> are being specifically cleared, and setting other bits does not
> inadvertently clear them...
>
> Has anyone had results, good, bad, or otherwise with the
> CDC-Core implementation?
>
> Ralph
> Yahoo! Groups Links
>
Alan KM6VV wrote:
> Hi Ralph,
>
> I've been playing with the BASIC_USB code off and on (IAR). Got it to do
> some transfers, but it usually just hangs its self. Yes, I'd LOVE to see a
> good clean demo of a CDC USB device.
>
> This demo appears to be written to block waiting for chars from endpoint,
> and then again waiting to send back. I want to drop it into my code which
> is running a small fixed task list. I have things like SPI that are run off
> of a PIT interrupt, and I'd prefer to just poll to get limited chars from
> the USB. I'd respond with my chars to the USB in a background task.

Alan,

The code you're looking at does not sound like the full USB CORE
Framework that I'm talking about.

The Framework is a clever bit of code that provides core functionality
for USB devices, including enumeration, control, bulk and isochronous
transfer.

Then you add your application layer on top, and they provide 3 examples
such as CDC, Mass Storage, and a HID device.

The Framework works quite well, except for the BULK-OUT endpoint
losing data. I can't seem to figure out if the problem is to
do with usbser.sys on Windows sending more data than the endpoint
can accept, or if there is an issue with the receive FIFO or the
interrupt handler.

It's so close to working that it's frustrating to not be able to
get it the last few feet or meters over the goal line :-)

Ralph
Hi Ralph,

Sorry, yes, this is a different demo. I think I know the demo you are
referring to. Much bigger then the CDC limited demo I'm playing with.
About all I need is a simple COMM replacement. It too is using usbser.sys

Please be sure to post your solutions. I'd LOVE to have full framework to
start working from. I have this downloaded:

"AT91 USB Framework - Core 1.01 + CDC 1.0.zip"

for IAR I believe. I'm using this one"

"AT91SAM7S64-BasicUSB-IAR4_11A-1_1.zip"
Sorry I can't be of any help!

Alan KM6VV
>
> The code you're looking at does not sound like the full USB CORE
> Framework that I'm talking about.
>
> The Framework is a clever bit of code that provides core functionality
> for USB devices, including enumeration, control, bulk and isochronous
> transfer.
>
> Then you add your application layer on top, and they provide 3 examples
> such as CDC, Mass Storage, and a HID device.
>
> The Framework works quite well, except for the BULK-OUT endpoint
> losing data. I can't seem to figure out if the problem is to
> do with usbser.sys on Windows sending more data than the endpoint
> can accept, or if there is an issue with the receive FIFO or the
> interrupt handler.
>
> It's so close to working that it's frustrating to not be able to
> get it the last few feet or meters over the goal line :-)
>
> Ralph
Hi Ralph,

> The Framework works quite well, except for the BULK-OUT endpoint
> losing data. I can't seem to figure out if the problem is to
> do with usbser.sys on Windows sending more data than the endpoint
> can accept,

I doubt that very much. I know that usbser.sys doesnt work properly for interrupt
pipes, but it definitely would not send more than the specified EP size from the enum.

> or if there is an issue with the receive FIFO or the
> interrupt handler.

It's not silicon - it does work properly..
I think you will find it's your code somewhere.
If I have time, I'll dig up my own interrupt driven version of CDC I wrote quite some time ago,
a project on CrossWorks for ARM. If I find it I'll send you if you want for testing. I basically
set it up for the SAM7-EK (changed S64 to S256) to work as a "UART bridge".
RXd data from USB is sent out the serial, and Rxd data from the serial is sent out the USB.
To test, I had 2 sessions of Hyperterminal running, one on COM2 and the other COMX (say COM5).
I transferred 2-50 MB files via Z-modem in both directions numerous times, and not _once_
did Z modem ever report a CRC32 error. Admittedly, the serial was only running at 115,200 but data
flow worked perfectly.

I first had similar problems to yours, but found that it was all to do with how you handle :
1. Switching between BK0 and BK1, and when/how.
2. Keeping track of which BK to service in the foreground and when.
3. Timing the disable/enable interrupt (and doing it properly on ARM7 !) for the EP, since
re-enabling the INT when the proper BKx has been serviced but NOT cleared, you will get a new

interrupt, clobbering things with the BK switching sequence. Conversely, if you clear the BKx
too early there is a chance that the Hub will just fill it up again with more data, as the SAM7

will start responding with ACKs instead of NAKs. (I certainly came across this problem to
account for).

I have a feeling you will find your solution will be somewhere around (3) above.
Have a good look at INT & foreground interaction vis-vis BKx processing and _what_ should be
in the foreground and what in the ISR...
HTH
73s & Best Regards,
Kris

________________________________________
From: A... [mailto:A...] On Behalf Of Ralph Hempel
Sent: Thursday, 14 June 2007 1:13 AM
To: A...
Subject: Re: [AT91SAM] GCC and AT91SAM7 USB CDC Core Example

Alan KM6VV wrote:
> Hi Ralph,
>
> I've been playing with the BASIC_USB code off and on (IAR). Got it to do
> some transfers, but it usually just hangs its self. Yes, I'd LOVE to see a
> good clean demo of a CDC USB device.
>
> This demo appears to be written to block waiting for chars from endpoint,
> and then again waiting to send back. I want to drop it into my code which
> is running a small fixed task list. I have things like SPI that are run off
> of a PIT interrupt, and I'd prefer to just poll to get limited chars from
> the USB. I'd respond with my chars to the USB in a background task.

Alan,

The code you're looking at does not sound like the full USB CORE
Framework that I'm talking about.

The Framework is a clever bit of code that provides core functionality
for USB devices, including enumeration, control, bulk and isochronous
transfer.

Then you add your application layer on top, and they provide 3 examples
such as CDC, Mass Storage, and a HID device.

The Framework works quite well, except for the BULK-OUT endpoint
losing data. I can't seem to figure out if the problem is to
do with usbser.sys on Windows sending more data than the endpoint
can accept, or if there is an issue with the receive FIFO or the
interrupt handler.

It's so close to working that it's frustrating to not be able to
get it the last few feet or meters over the goal line :-)

Ralph
Microbit wrote:
> Hi Ralph,
>
>> The Framework works quite well, except for the BULK-OUT endpoint
>> losing data. I can't seem to figure out if the problem is to do
>> with usbser.sys on Windows sending more data than the endpoint can
>> accept,
>
> I doubt that very much. I know that usbser.sys doesnt work properly
> for interrupt pipes, but it definitely would not send more than the
> specified EP size from the enum.

I was hoping you would see this post and answer as I've been following
your discussions on the at91.com site...

>> or if there is an issue with the receive FIFO or the interrupt
>> handler.
>
> It's not silicon - it does work properly.. I think you will find it's
> your code somewhere.

I'm afraid that that's true too. I do occasionally make mistakes :-)

But still, the CORE code does appear to have a bug because even
if I strip out my app completely and just echo out what I get in
from the USB OUT endpoint, the data gets messed up...

> If I have time, I'll dig up my own interrupt driven version of CDC I
> wrote quite some time ago, a project on CrossWorks for ARM. If I find
> it I'll send you if you want for testing. I basically set it up for
> the SAM7-EK (changed S64 to S256) to work as a "UART bridge". RXd
> data from USB is sent out the serial, and Rxd data from the serial is
> sent out the USB. To test, I had 2 sessions of Hyperterminal running,
> one on COM2 and the other COMX (say COM5). I transferred 2-50 MB
> files via Z-modem in both directions numerous times, and not _once_
> did Z modem ever report a CRC32 error. Admittedly, the serial was
> only running at 115,200 but data flow worked perfectly.

I've read about this and was hoping I could get some sample code
from you..

> I first had similar problems to yours, but found that it was all to
> do with how you handle : 1. Switching between BK0 and BK1, and
> when/how. 2. Keeping track of which BK to service in the foreground
> and when. 3. Timing the disable/enable interrupt (and doing it
> properly on ARM7 !) for the EP, since re-enabling the INT when the
> proper BKx has been serviced but NOT cleared, you will get a new
>
> interrupt, clobbering things with the BK switching sequence.

Oooh. This last part looks/sounds interesting...

> Conversely, if you clear the BKx too early there is a chance that the
> Hub will just fill it up again with more data, as the SAM7
> will start responding with ACKs instead of NAKs. (I certainly came
> across this problem to account for).

I agree. And you'd think that the folks at ATMEL would have got
this part of it right in the firmware for the CORE, yes?

> I have a feeling you will find your solution will be somewhere around
> (3) above. Have a good look at INT & foreground interaction vis-vis
> BKx processing and _what_ should be in the foreground and what in the
> ISR...

Cheers, and thanks for the well-thought out reply...

Ralph
Hi Kris,

That could be useful! I'd appreciate a copy. Please send to:

KM6VV /at/ ARRL /.NET/

Or post it in the files!

Do you have an INF (I think that's right) for it also? Sounds like it uses
usbser.sys which should be fine.

Best 73's,

Alan KM6VV
Central coast, CA

>
> It's not silicon - it does work properly..
> I think you will find it's your code somewhere.
> If I have time, I'll dig up my own interrupt driven version of CDC I wrote
> quite some time ago,
> a project on CrossWorks for ARM. If I find it I'll send you if you want
> for testing. I basically
> set it up for the SAM7-EK (changed S64 to S256) to work as a "UART
> bridge".
> RXd data from USB is sent out the serial, and Rxd data from the serial is
> sent out the USB.
> To test, I had 2 sessions of Hyperterminal running, one on COM2 and the
> other COMX (say COM5).
> I transferred 2-50 MB files via Z-modem in both directions numerous times,
> and not _once_
> did Z modem ever report a CRC32 error. Admittedly, the serial was only
> running at 115,200 but data
> flow worked perfectly.
>
> I first had similar problems to yours, but found that it was all to do
> with how you handle :
> 1. Switching between BK0 and BK1, and when/how.
> 2. Keeping track of which BK to service in the foreground and when.
> 3. Timing the disable/enable interrupt (and doing it properly on ARM7 !)
> for the EP, since
> re-enabling the INT when the proper BKx has been serviced but NOT
> cleared, you will get a new
>
> interrupt, clobbering things with the BK switching sequence.
> Conversely, if you clear the BKx
> too early there is a chance that the Hub will just fill it up again
> with more data, as the SAM7
>
> will start responding with ACKs instead of NAKs. (I certainly came
> across this problem to
> account for).
>
> I have a feeling you will find your solution will be somewhere around (3)
> above.
> Have a good look at INT & foreground interaction vis-vis BKx processing
> and _what_ should be
> in the foreground and what in the ISR...
> HTH
> 73s & Best Regards,
> Kris
>
I promise to post the updated CDC in a public place if I
can get it to work with Kris's changes!

Some of you that are having trouble with Alan's shorthand
might benefit from this:

:-)

Cheers, Ralph
When I have a gap, I'll dig it up and post it "as is".
I'm not on the right machine right now, it's at office.
It needs cleaning up a bit - it's by no means a finished clean API doc'd project - but it's sound.
It proves the silicon _and_ usbser.sys work properly wrt. EP OUT et al.
Else we could do what Ralph suggests - I'll send it to him, see if it helps his problem and then
post the possibly revised project.... ?

I posted the INF I used on here a while ago. The main change was that I changed the GUIID so it
comes up as an _actual_ Virtual COM port, instead of a bloody Modem in Device Manager :-)

Best Regards,
Kris

________________________________________
From: A... [mailto:A...] On Behalf Of Alan KM6VV
Sent: Thursday, 14 June 2007 4:19 AM
To: A...
Subject: RE: [AT91SAM] GCC and AT91SAM7 USB CDC Core Example

Hi Kris,

That could be useful! I'd appreciate a copy. Please send to:

KM6VV /at/ ARRL /.NET/

Or post it in the files!

Do you have an INF (I think that's right) for it also? Sounds like it uses
usbser.sys which should be fine.

Best 73's,

Alan KM6VV
Central coast, CA
Microbit wrote:
> When I have a gap, I'll dig it up and post it "as is". I'm not on the
> right machine right now, it's at office. It needs cleaning up a bit -
> it's by no means a finished clean API doc'd project - but it's sound.
> It proves the silicon _and_ usbser.sys work properly wrt. EP OUT et
> al. Else we could do what Ralph suggests - I'll send it to him, see
> if it helps his problem and then post the possibly revised
> project.... ?

I've got the basic Framework ported to GCC 4.1.1 and would be
willing to share the updated portions with the guy at winarm.com
that posts updated projects..

That is, if Kris is OK with that. It would be great if Kris could
either post or send me the code soon because I'm getting so close to
being able to release my project.

I've got decent reliability with polled comms, but wouldn't it
be great to have a fully interrupt driven system working?

In case anyone is interested, here's what I'm working on:



It's a port of the Lua interpreter to the LEGO MINDSTORMS NXT
brick. It's pretty solid now, and when it's got the "good"
framework code, it will be awesome!

BTW, the end result of this is not limited to the NXT, it's a full
Lua interpreter (minus file and OS functions) that you can
run on just about any AT91 device.

My own framework for this is designed for portability to other
CPUs and boards, so if anyone wants to pony up a development
board I'd be happy to port it to that board...especially some
of the newer high-end AT91 devices.

> I posted the INF I used on here a while ago. The main change was that
> I changed the GUIID so it comes up as an _actual_ Virtual COM port,
> instead of a bloody Modem in Device Manager :-)

I have an INF file I'm using too, that has the GUID fixed...

Cheers, Ralph