PSoC5LP : USBUART component detects port close

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
MiNe_85951
Level 7
Level 7
Distributor - TED (Japan)
50 likes received 500 replies posted 50 solutions authored

Hi,

We use USBUART component of PSoC5LP.

The character string is transmitted from PSoCtLP to PC using USBUART component.

If the PC closes the port while PSoC5LP is sending a character string, the operation of PSoC5LP stops.

After sending the character string with USBSoC of PSoC5LP,
Waiting for transmission preparation completion with USBUART_CDCIsReady () API.
However, when the port is disconnected, it does not wait for completion.

while (USBUART_CDCIsReady () == 0);

In other words, because it waits in the above description, it becomes an infinite loop.

In order to get out of this infinite loop state,

It is necessary for PSoC5LP to detect that the port is closed. However, no suitable API is found.

Is there a way to know on USBUART of PSoC5LP side that the PC has closed the port?

Please let us know if there is a way to determine port closed status.

Regards,

0 Likes
1 Solution
lock attach
Attachments are accessible only for community members.

To all following this post,

I believe I have addressed the USB unplugged lock-up post.  In working on it, I also found a similar problem where the same lockup occurs eventually when the host port is not open.  This has been addressed in the attached project with the new UART_USB.c module.

In summary, the recommended use of:

while(USBUART_CDCIsReady() == 0) {}  // This is where the lockup can occur when the USB is unplugged or the host port is not open.

I replaced it with the following function that makes use of the SysTick counter that escapes while(USBUART_CDCIsReady() == 0) loop if up looping two milliseconds.

_Bool usb_active = USBUART_TRUE;

/*--------------------------------------------------------------------------------*/

//_Bool USBUART_IsTxReady(_Bool allow_blocking)

// This prevents a lockup condition if the USB is unplugged or if the host-side has a closed port.

// The SysTick Timer must be enabled to detect that the USB is unplugged or the host port is not open.

//

// This can be used as a blocking test function or a non-blocking implementation.  Non-blocking is useful for RTOSes

//

// Returns:

//            TRUE = port ready to accept new data.

//            FALSE = port unplugged or failed.  Do not send new data.

//---------------------------------------------------------

_Bool USBUART_IsTxReady(_Bool allow_blocking)

{

_Bool ret = USBUART_TRUE;

 

    if(allow_blocking == USBUART_TRUE)

    {    // blocking implementation

    int8 subsystick_wrap_cnt = 0;

    int32_t subsystick_reload = (int32_t)CySysTickGetReload();    // SysTick Reload value

    int32_t subsystick_cnt = (int32_t)CySysTickGetValue();    // SysTick Timestamp when we entered this function

 

        CySysTickStart();        // Start the SysTick interval @ 1ms.  This allows USBUART_IsTxReady() to use the SysTick count for determining if the host is not responding.

        while(USBUART_CDCIsReady() == 0)

        { // Tx Port is not ready.

            if(usb_active == USBUART_FALSE) {ret = USBUART_FALSE; break;}    // break out of while() because we detected the USB port is not active.

            else

            {    // check the SysTick counter timestamp exceeds up to 2 times the SysTick Reload value (approx. 2ms)

            int32_t subsystick_cnt_diff = subsystick_cnt - (int32)CySysTickGetValue();    // get the difference between the current and prev timestamps

                if(subsystick_cnt_diff < 0) { subsystick_wrap_cnt++; }    // if current subsystick value > prev value increment wrap cnt

                if(( (subsystick_wrap_cnt*subsystick_reload) + (subsystick_cnt_diff)) > (subsystick_reload*2))

                {

                    ret = USBUART_FALSE;    // Exceeded SysTick 1ms

                    break;                    // break out of while() because we detected the USB port is not active.

                }

                subsystick_cnt = (int32_t)CySysTickGetValue();                            // store new current value

            }

        }

        usb_active = ret;

    }

    else ret = (USBUART_CDCIsReady() ? USBUART_TRUE : USBUART_FALSE);        // non-blocking

    return ret;

}

With this fix, I can now unplug the USB cable (PSoC not powered by this USB port) or close the host port and the application will continue to run.

Len

Len
"Engineering is an Art. The Art of Compromise."

View solution in original post

0 Likes
6 Replies
odissey1
Level 9
Level 9
First comment on KBA 1000 replies posted 750 replies posted

One possible way to check that Com port is open is to use an expiration counter, see e.g.

Re: PSOC5  USB UART buffer when no program is reading the data

/odissey1

MiNe_85951
Level 7
Level 7
Distributor - TED (Japan)
50 likes received 500 replies posted 50 solutions authored

Odissey1-san,

We will refer to the URL you provice us.
Alternatively, we will consider how to exit an infinite loop using a timer interrupt.

Regards,

0 Likes

MaMi,

A few of ways to use a timer I think of at the top of my head:

  • Using a dedicated timer, you can set into one-shot mode.  Before you enter the loop,  enable the timer and trigger it.  If can either setup an ISR to signal to the loop that the timer expired or poll the TC status.  If the timer expires, exit the loop.
  • There is a SysTick counter available to the system if you want to use it.  I've used it many times and it doesn't use any extra PSoC resources.  If you use it, store the systick count before you enter the loop.   This is your entry timestamp.  In the loop, compare the current systick to your entry timestamp + your timer expiration time.  If the current systick is greater, then exit the loop.
  • You can also use a loop counter.  You would increment the count in the loop and compare the count to a terminal count.  The issue with this method is the counter count rate varies depending on your BUS_CLK.

Len

Len
"Engineering is an Art. The Art of Compromise."
lock attach
Attachments are accessible only for community members.
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

MaMi,

I might have a low-CPU overhead solution for the USB unplug condition that causes a while() loop lockup.

In general, substitute the following lines of code:

while (USBUART_CDCIsReady () == 0);

with:

/*--------------------------------------------------------------------------------*/

// This prevents a lockup condition if the USB is unplugged.

//

// Returns:

//            TRUE = port ready to accept new data.

//            FALSE = port unplugged or failed.  Do not send new data.

_Bool USBUART_IsReady(void)

{

    while(USBUART_CDCIsReady() == 0)

    {

        if(USBUART_CheckActivity() == 0) return USBUART_FALSE;    // if bus activity not detected (unplugged or fault),  return FALSE

    }

    return USBUART_TRUE;

}

So the use of the following function call to PutString() waits for the USB port to finish any previous data output and prevents a lockup in the while() loop if the USB is unplugged.  Note:  if the USB is unplugged, the outgoing data is not queued but thrown-away just like a real UART port would do.

void UART_PutString(char8 string[])

{

    if(USBUART_IsReady() == USBUART_TRUE) USBUART_PutString(string);

}

I've attached a UART to USBUART conversion program.  It allows the user to develop using the standard simplier UART port.  Once the UART comm is solid and working, you add the USBUART component, UART_USB.c and UART_USB.h files and disable the UART component.  The functions in the UART_USB.h/.c substitute UART calls to an equivalent USBUART calls so that it minimizes changes to your working UART API calls. Note: Not all UART API calls are supported at this time.  If needed, many more substitutes can be created.

When creating this UART to USBUART conversion, I tried to use ISRs as much as possible to eliminate some of the polling that eats up CPU time.

Let me share some of the things I've learned.  Here is a list of the ISRs supported by the USBUART component.

  • SOF => Heartbeat @ 1ms.  This interrupt is available only if enabled.
  • EP0 => USB configuration comm.  Occurs when the port is opened or closed at the host.  Used in place of USBUART_GetConfiguration()
  • EP1 => unknown at this time.
  • EP2 => Occurs when data to the host is sent
  • EP3 => Occurs when data from the host is available
  • DP => unknown at this time.
  • ARB => unknown at this time.
  • BUS_RESET => Occurs with the USB device is enabled (or plugged in)

If someone has better or more information about this topic, please reply.

Len

UPDATE 10.24.2019 !!!

The USBUART_CheckActivity() does appear to detect that the USB is unplugged.  However, the way I used it in my UART_USB code, it causes problems with back-to-back Tx operations with the USB plugged in.    I just found this out when I used it on an old program.

I will look at a better solution.  Thanks for your patience.

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
lock attach
Attachments are accessible only for community members.

To all following this post,

I believe I have addressed the USB unplugged lock-up post.  In working on it, I also found a similar problem where the same lockup occurs eventually when the host port is not open.  This has been addressed in the attached project with the new UART_USB.c module.

In summary, the recommended use of:

while(USBUART_CDCIsReady() == 0) {}  // This is where the lockup can occur when the USB is unplugged or the host port is not open.

I replaced it with the following function that makes use of the SysTick counter that escapes while(USBUART_CDCIsReady() == 0) loop if up looping two milliseconds.

_Bool usb_active = USBUART_TRUE;

/*--------------------------------------------------------------------------------*/

//_Bool USBUART_IsTxReady(_Bool allow_blocking)

// This prevents a lockup condition if the USB is unplugged or if the host-side has a closed port.

// The SysTick Timer must be enabled to detect that the USB is unplugged or the host port is not open.

//

// This can be used as a blocking test function or a non-blocking implementation.  Non-blocking is useful for RTOSes

//

// Returns:

//            TRUE = port ready to accept new data.

//            FALSE = port unplugged or failed.  Do not send new data.

//---------------------------------------------------------

_Bool USBUART_IsTxReady(_Bool allow_blocking)

{

_Bool ret = USBUART_TRUE;

 

    if(allow_blocking == USBUART_TRUE)

    {    // blocking implementation

    int8 subsystick_wrap_cnt = 0;

    int32_t subsystick_reload = (int32_t)CySysTickGetReload();    // SysTick Reload value

    int32_t subsystick_cnt = (int32_t)CySysTickGetValue();    // SysTick Timestamp when we entered this function

 

        CySysTickStart();        // Start the SysTick interval @ 1ms.  This allows USBUART_IsTxReady() to use the SysTick count for determining if the host is not responding.

        while(USBUART_CDCIsReady() == 0)

        { // Tx Port is not ready.

            if(usb_active == USBUART_FALSE) {ret = USBUART_FALSE; break;}    // break out of while() because we detected the USB port is not active.

            else

            {    // check the SysTick counter timestamp exceeds up to 2 times the SysTick Reload value (approx. 2ms)

            int32_t subsystick_cnt_diff = subsystick_cnt - (int32)CySysTickGetValue();    // get the difference between the current and prev timestamps

                if(subsystick_cnt_diff < 0) { subsystick_wrap_cnt++; }    // if current subsystick value > prev value increment wrap cnt

                if(( (subsystick_wrap_cnt*subsystick_reload) + (subsystick_cnt_diff)) > (subsystick_reload*2))

                {

                    ret = USBUART_FALSE;    // Exceeded SysTick 1ms

                    break;                    // break out of while() because we detected the USB port is not active.

                }

                subsystick_cnt = (int32_t)CySysTickGetValue();                            // store new current value

            }

        }

        usb_active = ret;

    }

    else ret = (USBUART_CDCIsReady() ? USBUART_TRUE : USBUART_FALSE);        // non-blocking

    return ret;

}

With this fix, I can now unplug the USB cable (PSoC not powered by this USB port) or close the host port and the application will continue to run.

Len

Len
"Engineering is an Art. The Art of Compromise."
0 Likes