6 Replies Latest reply on Nov 1, 2019 11:53 AM by LePo_1062026

    PSoC5LP : USBUART component detects port close

    MaMi_1205306

      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,

        • 1. Re: PSoC5LP : USBUART component detects port close
          BoTa_264741

          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

          1 of 1 people found this helpful
          • 2. Re: PSoC5LP : USBUART component detects port close
            MaMi_1205306

            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,

            • 3. Re: PSoC5LP : USBUART component detects port close
              LePo_1062026

              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

              1 of 1 people found this helpful
              • 4. Re: PSoC5LP : USBUART component detects port close
                LePo_1062026

                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

                • 6. Re: PSoC5LP : USBUART component detects port close
                  LePo_1062026

                  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