PIC CDC / UOWN PIC18F4550 problems

PIC CDC / UOWN PIC18F4550 problems

Postby nyholku » Sat Jun 28, 2014 10:24 am

I'm working on a homebrewn USB CDC ACM stack and everything works fine for years,or so I thought.
I'm using the CDC in-direction (device->host) with a terminal emulator on the host (Mac) to
output some debug data from the device to the host.
Everything seems to work fine as long as the host is sucking data from the device but as soon as
I stop the host side terminal emulator my device code gets stuck.
My main loop looks like this:

Code: Select all
while (1) {
    if (!usbcdc_wr_busy()) {

So basically I check if the UIE is busy and if not then I write a single byte.
The function usbcdc_wr_busy is very elementary:

Code: Select all
    char usbcdc_wr_busy() {
        return (ep3_i.STAT & UOWN) != 0;

The usbcdc_putchar() function looks like this:

Code: Select all
void usbcdc_putchar(char c)__wparam
    while (usbcdc_wr_busy())
        /* wait */;
        cdc_tx_buffer[tx_len++] = c;
        if (tx_len >= sizeof(cdc_tx_buffer)) {

So it just waits while UIE is busy (which it can't be because I just checked that
before I call usbcdc_putchar()) and once it is free it sends the
char into the buffer and if the buffer it full it sends it to the host.
And it is in the above "while (usbcdc_wr_busy())" loop that the code
gets stuck if the host is not reading the stuff. But how come is this
possible? Before I call usbcdc_putchar() I check usbcdc_wr_busy()
and only call usbcdc_putchar() if the UIE is not busy ie UOWN == 0.

I understand that once I have buffer full of stuff to send to the host
and the usbcdc_flush() arms the UIE to send it on next host
poll the UOWN bit becomes set and remains set because the host
is not going to read it, but why does my device code get stuck because
it should not enter that wait loop if the UOWN is set?
It almost looks like between the first check and the second check the UOWN
bit becomes set, how can that be?
Or am I just blind enough not to see a trivial error in my rather simple code?
Help greatly appreciated.
For completeness here is the usbcdc_flush() code:

Code: Select all
static unsigned char tx_len = 0;
volatile unsigned char cdc_tx_buffer[16];

void usbcdc_write(unsigned char len)__wparam
    if (len > 0) {
        ep3_i.CNT = len;
        if (ep3_i.STAT & DTS)
            ep3_i.STAT = UOWN | DTSEN;
            ep3_i.STAT = UOWN | DTS | DTSEN;

void usbcdc_flush() {
    tx_len = 0;

br Kusti

The while loop inside the usbcdc_putchar() is there because of course this gets
called from printf() and I can't have the usbcdc_putchar() to fail if the UIE is busy;
instead I want to check if the write is busy once before I call the printf and if
it is busy I continue with the other business in the main loop. Of course I could
check an a character by character bases if the UIE is busy but then I could not use the
standard printf(). BTW checking the UOWN once before each character works
Posts: 1
Joined: Sat Jun 28, 2014 10:16 am
PIC experience: Professional 5+ years with MCHP products

Re: PIC CDC / UOWN PIC18F4550 problems

Postby ric » Sun Jun 29, 2014 6:31 am

Latest test project, an LED matrix display made from one reel of addressable LEDs. here
User avatar
Verified identity
Posts: 412
Joined: Sat May 24, 2014 2:35 pm
Location: Melbourne, Australia
PIC experience: Professional 5+ years with MCHP products

Return to USB

Who is online

Users browsing this forum: No registered users and 1 guest