PSOC5LP and USB

I received a comment that the USB port on the CY8CKit-059 is causing a timeout. This is from a Thesis. I looked at the student’s code, and it is slightly different from my implementation, so I suspect something is missing. I borrowed the code from the automatically generated API and fixed some issues with it, and released my changes GPL, with a proviso that previous licenses are not overridden.

I have not change previously posted code for USB. One of the readers of the blog who had issues traced their problems back to a bad board. There is a FreeRTOS on github under wmaxfield which is specific to the 059 board and good to use for a testbed.

During my work with the PSOC and USB, I was forced to document some of my issues for drivers within a file so I could easily recreate the environment on any new machines without having to do rediscovery. I hid it from myself in a file named Configuration.h. Nowhere close to USBSerial.c. Go figure.

Here is the text of Instructions to Myself (ITM) for the driver for a USB PSOC5 incarnation for windows 7 and Windows 10:

//--------------------------------------------------------------------------
// The PSOC CY8CKit-059 is an (up to) 80mzh processor with built in USB.
// It also has a USB finger stub which can be broken off. 
//--Finger STUB:
//  *IF YOU KEEP IT ATTACHED* you can communicate over the finger stub with an
//  additional serial port.  With that port, you can use the UART on it with 
//  TeraTerm or Putty, or a Linux or Mac machine (using "screen" or some 
//other app).  It must be in Kitprog mode. CMSIS-DAP won't work for kitprog, 
//but will for kitprog2 updated to kitprog3.
//  Under Windows, the signed driver for the stub will automatically install
//  when it is plugged in.  In Linux or Mac, it will show up in 
//     /dev/tty (ls /dev/tty.*)
//--MICRO-USB: 
//-----
//  Macintosh 
//  The USB UART (micro-USB) connector on the CY8C-Kit059 is under 
//          /dev/tty.usbmodemxxxxx
//  or      /dev/cu.usbmodemxxxxx as a tty device.  
//-----    
//  Linux:
//  The USB UART (micro-USB) connector on the CY8C-Kit059 is usually under 
//      /dev/ttyACM0. 
//  It can be under ttyACM1, ttyACM2,...ttyACM9.
//  To make world usable under Linux, then
//  create the following file as root: /etc/udev/rules.d/50-local.rules
//  using "sudo nano" to write the file,
//  with the following 2 lines
//
//   KERNEL=="ttyUSB[0-9]*",MODE="0666"
//   KERNEL=="ttyACM[0-9]*",MODE="0666"
//
//  this will make the plugin of the /dev/ttyACMx world usable without
//  running as root. Easiest is to reboot the linux machine to make this 
//  work.
//  You can restart the udev services rather than reboot.    
//-----
// Windows
//  The USB UART (micro-USB) driver is automatically created by PSOC Creator, 
//  and can be installed
//  under Windows 7 (unsigned driver) or under Windows 10 (signed).  See
//  the following information:  
//  https://socmaker.com/?p=168 for a discussion of Windows 7 Driver,
//--    
//  or
//     Windows 10 driver info: (cypress page)
//      https://community.cypress.com/message/57726#57726
//      (infineon page:)
//      https://community.cypress.com/t5/PSoC-5-3-1-MCU/PSoC5LP-USBUART-signed-driver/m-p/129820#57726
//    
//   The knowledge base article is here: (cypress page)
//     ( https://community.cypress.com/docs/DOC-10894 )
//      (infineon page)
//      https://community.cypress.com/t5/Knowledge-Base-Articles/Binding-a-USB-Serial-Device-to-a-Microsoft-CDC-Driver-KBA91366/ta-p/250126
//--
//  or
//
//    Windows 7 driver info:
//  After programming the PSoC, plug in the USBUART using a USB cable. 
//  You can interrupt the install, but that takes as long as waiting for the 
//  installer to give up talking to Windows Update Server.  Select the local 
//  file location option, and browse to the driver file in the PSOC directory 
//  in your project. It will be at:  
//     PROJECTNAME.cysdn\Generated_Source\PSOC5, 
//  assuming your project is named “PROJECTNAME.” Install that unsigned 
//  driver. 
//  You may have to Google allowing unsigned drivers for Windows 7. 
//  It should be functional after that. 
//    If not, try rebooting your VM if running under Mac or Linux or 
//    reboot your Windows machine if running natively.

Here is the FreeRTOS style code for using the USB port. Notice the “lineChanged” section to detect plug/unplugs:

/*
  * SOCino 3d printer firmware, FreeRTOS version
 *
 * Copyright 2020, Wade Maxfield
 * Written by Wade Maxfield
 *
 * Commercial license Available.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
    This license does not override previous licenses

    THIS TASK MONITORS AND KEEPS THE USB SERIAL PORT IN OPERATION, THROUGH
     PLUGS AND UNPLUGS.  IT ALSO PROVIDES USB SERIAL PORT UTILITY ROUTINES
    
 */
#include "main.h"
#include "Debug/TerminalDebug.h"
#include "Messages/MessageRouter.h"

#define USBFS_DEVICE (0)  // not sure why needed, is probably in future Cypress plans

#define USBSerialSTACK_SIZE		configMINIMAL_STACK_SIZE
const TickType_t xDelay = pdMS_TO_TICKS(1);
const TickType_t mDelay = pdMS_TO_TICKS(5000) ;

// these variables are modified at runtime to allow input from
// UART or from USB Serial.
// If this is to be standalone you MUST setup the Q here.
QueueHandle_t *USBMessageQPtr; // in the USB receive task 

SerialMessage *USBSerialRxBuffer[NUMBER_OF_MSG_BUFFERS+1];

int16_t currentBuffer;
    
/* The task that is created three times. */
static portTASK_FUNCTION_PROTO( vUSBSerialTask, pvParameters );
SemaphoreHandle_t USBMutex;
static int16_t qError;


/*-----------------------------------------------------------*/
// allow multiple task access through semaphores.
// Blocks until sends or a failure occurs.
// Fails silently
/*-----------------------------------------------------------*/
void USBport_putString( char *msg)
{
    int16 hold=0;
    if(0 == USBUART_GetConfiguration()) 
        return;
    // the following has to be checked more than once,
    // since at ~80mhz bus clock the USB can report
    // no activity between calls.
    // if 20 milliseconds have passed, the USB is 
    // probably unplugged.
    while (0==USBUART_CheckActivity()){
        if (++hold>20){
            xSemaphoreGive(USBMutex);
            return;
        }
        vTaskDelay(xDelay);// wait 1 millisecond
    }
    hold=0;  
  
    xSemaphoreTake(USBMutex,portMAX_DELAY);
    while(0 == USBUART_CDCIsReady()){
        // if an error in the uart, skip.
        if (++hold>10){
            xSemaphoreGive(USBMutex);
            return;
        }
        vTaskDelay(xDelay);
    }

    if (USBUART_CDCIsReady())
        USBUART_PutString(msg);
        
    xSemaphoreGive(USBMutex);
}

/*-----------------------------------------------------------*/
// create the task and the serialization semaphore
/*-----------------------------------------------------------*/
void vStartUSBSerialTask( UBaseType_t uxPriority )
{
    
    /*Setup the mutex to control port access*/
    USBMutex = xSemaphoreCreateMutex();
	/* Spawn the task. */
	xTaskCreate( vUSBSerialTask, "USBSerial", USBSerialSTACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) &TaskMonitorArray[USB_SERIAL_TASK].taskHandle);

}
/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/
static portTASK_FUNCTION( vUSBSerialTask, pvParameters )
{
    uint16_t rxCount;
    uint16_t myTaskMsgBufferNumber=0;
    TaskMonitor_t *TaskMonitorPtr = &TaskMonitorArray[USB_SERIAL_TASK];
    static uint16_t firstTime=pdFALSE;
    
   	/* The parameters are not used. */
	( void ) pvParameters;
    
    int index;
    
    for (index=0; index < NUMBER_OF_MSG_BUFFERS; index++) {
        if (!USBSerialRxBuffer[index]) // did someone else handle?
            USBSerialRxBuffer[index]=(SerialMessage *) pvPortMalloc( sizeof(SerialMessage));   
    }

    DebugPrintString("USBSerial Task Started..." CRLF);
    // allow queues to be set up, etc.
    vTaskDelay(pdMS_TO_TICKS(50));
        
// This code provides a message router between uart and usb if needed
//    HandleMessageRoutingSetup();// sets up USBMessageQPtr


  //!!!!!!! WARNING  !!!!!!!!!!!!
  // set up the Queue pointer properly here if you do not have
  // an external message router.  In original code, this was
  // already done in HandleMessageRoutingSetup();
  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    /* Start the USB_UART */
    /* Start USBFS operation with 5-V operation. */
    // This, in theory, should be in HardwareInit.c
    USBUART_Start(USBFS_DEVICE, USBUART_5V_OPERATION);
    firstTime = pdFALSE;
   
    
	for(;;)
	{
        TaskMonitorPtr->runCounter++;
        
        /* Host can send double SET_INTERFACE request. */
        if (0u != USBUART_IsConfigurationChanged())
        {
            /* Initialize IN endpoints when device is configured. */
            if (0u != USBUART_GetConfiguration())
            {
                /* Enumeration is done, enable OUT endpoint to receive data 
                 * from host. */
                USBUART_CDC_Init();
            }
        }
        
        if(0 != USBUART_GetConfiguration()){  
            if (USBUART_IsLineChanged())
                firstTime = pdTRUE;
            
            if (firstTime){
                // every time a connect or change of baud, etc. occurs
                // print the signon string
                firstTime = pdFALSE;
                USBport_putString(START_STRING CRLF);
            }
            /* Check for input data from host. */
            if (0u != USBUART_DataIsReady()){
                SerialMessage *ptr = USBSerialRxBuffer[myTaskMsgBufferNumber];
                /* Read received data and re-enable OUT endpoint. */
                rxCount = USBUART_GetAll(ptr->msg);
                // now post these bytes to the Debug Terminal Task
                ptr->ucMessageID = myTaskMsgBufferNumber++;
                ptr->size=rxCount;
                ptr->msg[rxCount]=0;// terminate string just in case
                
                
                // if Message queue not assigned, don't use
                if (USBMessageQPtr){// see MessageRouter.c
                    //------------------------------------------------------
                    // message will either post to GCodeCommandReceiverMessageQ (in GCodeHandlerTask.c)
                    // or TerminalSerialMessageQ (in TerminalDebug.c)
                    // General Message Flow:
                    // GCodeCommandReceiverMessageQ->GCodeHoldOffMessageQ->gMotorCommandQueue
                    //------------------------------------------------------
                    if( QSend( *USBMessageQPtr,&ptr, pdMS_TO_TICKS(50),TaskMonitorPtr ) != pdPASS )
                		{
                			qError ++;
                            //try one more time
                            QSend( *USBMessageQPtr,&ptr, pdMS_TO_TICKS(50),TaskMonitorPtr);
                		}
                    if (myTaskMsgBufferNumber >= NUMBER_OF_MSG_BUFFERS)
                        myTaskMsgBufferNumber=0; // reset the ring
                }
                /* Get and process inputs here */
                //vTaskDelay(mDelay);
            } else {
                // let someone else run, wait 50 milliseconds
                vTaskDelay(pdMS_TO_TICKS(50));
            }

        } else {
            // let someone else run, wait 50 milliseconds to see if event occurs
            vTaskDelay(pdMS_TO_TICKS(50));
        }


    } /*lint !e715 !e818 !e830 Function definition must be standard for task creation. */

}

// end of file

Fini

Enjoy!

Add a Comment

Your email address will not be published. Required fields are marked *