This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

LP-AM243: USB_TESTMODE

Part Number: LP-AM243


Tool/software:

I am running the cdc_echo_freertos_am243x-evm_r5fss0-0_freertos_ti-arm-clang project on LP-AM243.

How can I check the USB TESTMODE (TEST_J, TEST_K, TEST_PACKET, SE0_NAK)?

best regards,

  • Hi Motofumi,

    To test the application, Connect the J10 on AM243x LP to the USB host(Windows/Linux). The two enumerated COM ports can be displayed using the Device Manager on Windows .

    Please refer EXAMPLES_USB_CDC_ECHO for details.

    Regards,

    Tushar

  • Hi Tushar,

    Thank you for your reply.

    I was able to communicate with COM Port on a Windows PC.

    However, what I am trying to do is output the waveforms for the USB compliance test. (TEST_J, TEST_K, TEST_PACKET, SE0_NAK)

    Is there a way to do that available?

    best regards,

  • Hi Motofumi,

    You can check the handleFeatureRecDevTest API for the above use case.

    This API can be found at ${MCU+SDK}/source/usb/cdn/core_driver/device/src/cusbd.c file.

    Regards,

    Tushar

  • Hi Tushar,

    Thank you for your reply.

    I have tried to call the API when CDC receive a specific string.

    Writing to the USBR_CMD register appears to be taking place, but there is no change in the D+ D- signal.

    Is there a sample that would confirm the correct usage of the API?

    best regards,

  • Hi Motofumi,

    but there is no change in the D+ D- signal.

    Can you please tell how are you probing this signals?

    Is there a sample that would confirm the correct usage of the API?

    There is no sample code in the SDK or drivers to confirm it's usage.

    Regards,

    Tushar

  • Hi Tushar,

    Can you please tell how are you probing this signals?

    I measured those signals with an oscilloscope.

    I have also confirmed that CDC continues to function after writing to the USBR_CMD register. (Even when SE0_NAK is written)

    There is no sample code in the SDK or drivers to confirm it's usage.

    Okay, am I correct in assuming that no other operations are required other than calling handleFeatureRecDevTest?

    best regards,

    Motofumi

  • Hi Motofumi,

    Okay, am I correct in assuming that no other operations are required other than calling handleFeatureRecDevTest?

    Yes, this is the function which needs to be called when the USB device is in test mode.

    Regards,

    Tushar

  • Hi Tushar,

    I have also confirmed that CDC continues to function after writing to the USBR_CMD register. (Even when SE0_NAK is written)

    I don't see any change in the chip behavior just by calling the handleFeatureRecDevTest API, is there really no need for any other operations?

  • Hi Motofumi,

    I don't see any change in the chip behavior just by calling the handleFeatureRecDevTest API, is there really no need for any other operations

    How are you calling this function?

    What value have you written to the USBR_CMD register?

    Can you share dummy code snippet of handleFeatureRecDevTest call with passed values?

    Regards,

    Tushar

  • Hi Tushar,

    These are the dummy codes I added.

    cdc_echo_freertos_am243x-evm_r5fss0-0_freertos_ti-arm-clang/cdc_echo_freertos.c
    Line 156-175

            {
                extern void dcd_testmodeCheck(int test_selector);
                switch (buf[i])
                {
                case 'a':
                    dcd_testmodeCheck(1);
                    break;
                case 'b':
                    dcd_testmodeCheck(2);
                    break;
                case 'c':
                    dcd_testmodeCheck(3);
                    break;
                case 'd':
                    dcd_testmodeCheck(4);
                    break;
                default:
                    break;
                }
            }

    cdc_echo_freertos_am243x-evm_r5fss0-0_freertos_ti-arm-clang\usb\tinyusb\portable\am64x_am243x\dcd.c
    Line 523-532

    void dcd_testmodeCheck(int test_selector)
    {
        extern void testmodeCheck(CUSBD_PrivateData* pD, int test_Selector);
        testmodeCheck(usb_handle.pD, test_selector);
    }

    cdc_echo_freertos_am243x-evm_r5fss0-0_freertos_ti-arm-clang/usb/cdn/core_driver/device/src/cusbd.c
    Line 2466-2471

    void testmodeCheck(CUSBD_PrivateData * dev, int test_selector)
    {
        CH9_UsbSetup setup;
        setup.wIndex = (test_selector & 0xFF) << 8;
        handleFeatureRecDevTest(dev, &setup);
    }

    best regards,

    Motofumi

    /*
     *  Copyright (C) 2021-2023 Texas Instruments Incorporated
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    /* Adapted by TI for running on its platform and SDK */
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    
    #include <usb/cdn/include/usb_init.h>
    #include "tusb.h"
    
    #include "FreeRTOS.h"
    #include "TaskP.h"
    
    #include "ti_drivers_config.h"
    #include "ti_drivers_open_close.h"
    #include "ti_board_open_close.h"
    
    #ifdef TINYUSB_INTEGRATION
    
    #define DSR_TASK_PRI  (TaskP_PRIORITY_HIGHEST-2)
    #define DSR_TASK_SIZE (1024U)
    uint8_t gDsrTaskStack[DSR_TASK_SIZE] __attribute__((aligned(32)));
    TaskP_Object gDsrTaskObj;
    TaskP_Params gDsrTaskParams;
    
    #endif /* TINYUSB_INTEGRATION */
    
    
    #define TUD_TASK_PRI  (TaskP_PRIORITY_HIGHEST-3)
    #define TUD_TASK_SIZE (1024U)
    uint8_t gTudTaskStack[TUD_TASK_SIZE] __attribute__((aligned(32)));
    TaskP_Object gTudTaskObj;
    TaskP_Params gTudTaskParams;
    
    
    #define CDC_TASK_PRI  (TaskP_PRIORITY_HIGHEST-4)
    #define CDC_TASK_SIZE (1024U)
    uint8_t gCdcTaskStack[CDC_TASK_SIZE] __attribute__((aligned(32)));
    TaskP_Object gCdcTaskObj;
    TaskP_Params gCdcTaskParams;
    
    #ifdef TINYUSB_INTEGRATION
    void dsr_task_loop(void *args);
    #endif /* TINYUSB_INTEGRATION */
    
    void tud_task_loop(void *args);
    void cdc_task_loop(void *args);
    
    int cdc_echo_main(void)
    {
        int32_t status;
    
        Drivers_open();
        Board_driversOpen();
    
    #ifdef TINYUSB_INTEGRATION
    
        /* Cadence DSR task is to handle the USB device events */
        TaskP_Params_init(&gDsrTaskParams);
        gDsrTaskParams.name = "dsr_task";                /**< Pointer to task name */
        gDsrTaskParams.stackSize = DSR_TASK_SIZE;        /**< Size of stack in units of bytes */
        gDsrTaskParams.stack = gDsrTaskStack;            /**< Pointer to stack memory, MUST be aligned based on CPU architecture, typically atleast 32b on 32b systems */
        gDsrTaskParams.priority = DSR_TASK_PRI;          /**< Task priority, MUST be between \ref TaskP_PRIORITY_LOWEST and TaskP_PRIORITY_HIGHEST */
        gDsrTaskParams.args = NULL;                      /**< User arguments that are passed back as parater to task main */
        gDsrTaskParams.taskMain = dsr_task_loop;         /**< Entry point function to the task */
        /* create the task */
        status = TaskP_construct(&gDsrTaskObj, &gDsrTaskParams);
        DebugP_assert(status == SystemP_SUCCESS);
    #endif
    	
    	/* Enable debug for cdn module */ 
    	DbgMsgEnableModule(USBSSP_DBG_CUSBD);
    	DbgMsgEnableModule(USBSSP_DBG_CUSBD_ISR);
    	DbgMsgSetLvl(100); 
    	
        /* TUD task is to handle the USB device events */
        TaskP_Params_init(&gTudTaskParams);
        gTudTaskParams.name = "tud_task";                /**< Pointer to task name */
        gTudTaskParams.stackSize = TUD_TASK_SIZE;        /**< Size of stack in units of bytes */
        gTudTaskParams.stack = gTudTaskStack;            /**< Pointer to stack memory, MUST be aligned based on CPU architecture, typically atleast 32b on 32b systems */
        gTudTaskParams.priority = TUD_TASK_PRI;          /**< Task priority, MUST be between \ref TaskP_PRIORITY_LOWEST and TaskP_PRIORITY_HIGHEST */
        gTudTaskParams.args = NULL;                      /**< User arguments that are passed back as parater to task main */
        gTudTaskParams.taskMain = tud_task_loop;         /**< Entry point function to the task */
        /* create the task */
        status = TaskP_construct(&gTudTaskObj, &gTudTaskParams);
        DebugP_assert(status == SystemP_SUCCESS);
    
        /* CDC task is to handle the CDC class events */
        TaskP_Params_init(&gCdcTaskParams);
        gCdcTaskParams.name = "cdc_task";                /**< Pointer to task name */
        gCdcTaskParams.stackSize = CDC_TASK_SIZE;        /**< Size of stack in units of bytes */
        gCdcTaskParams.stack = gCdcTaskStack;            /**< Pointer to stack memory, MUST be aligned based on CPU architecture, typically atleast 32b on 32b systems */
        gCdcTaskParams.priority = CDC_TASK_PRI;          /**< Task priority, MUST be between \ref TaskP_PRIORITY_LOWEST and TaskP_PRIORITY_HIGHEST */
        gCdcTaskParams.args = NULL;                      /**< User arguments that are passed back as parater to task main */
        gCdcTaskParams.taskMain = cdc_task_loop;         /**< Entry point function to the task */
        /* create the task */
        status = TaskP_construct(&gCdcTaskObj, &gCdcTaskParams);
        DebugP_assert(status == SystemP_SUCCESS);
    
        return 0;
    }
    
    /* echo to either Serial0 or Serial1
       with Serial0 as all lower case, Serial1 as all upper case
     */
    static void echo_serial_port(uint8_t itf, uint8_t buf[], uint32_t count)
    {
        for(uint32_t i=0; i<count; i++)
        {
            if (itf == 0)
            {
                /* echo back 1st port as lower case */
                if (isupper(buf[i])) buf[i] += 'a' - 'A';
            }
            else
            {
                /* echo back additional ports as upper case */
                if (islower(buf[i])) buf[i] -= 'a' - 'A';
            }
    
            tud_cdc_n_write_char(itf, buf[i]);
    
            if ( buf[i] == '\r' ) tud_cdc_n_write_char(itf, '\n');
            {
                extern void dcd_testmodeCheck(int test_selector);
                switch (buf[i])
                {
                case 'a':
                    dcd_testmodeCheck(1);
                    break;
                case 'b':
                    dcd_testmodeCheck(2);
                    break;
                case 'c':
                    dcd_testmodeCheck(3);
                    break;
                case 'd':
                    dcd_testmodeCheck(4);
                    break;
                default:
                    break;
                }
            }
        }
        tud_cdc_n_write_flush(itf);
    }
    
    static void cdc_task(void)
    {
        uint8_t itf;
    
        for (itf = 0; itf < CFG_TUD_CDC; itf++)
        {
            /* connected() check for DTR bit
               Most but not all terminal client set this when making connection
             */
            /* if ( tud_cdc_n_connected(itf) ) */
            {
                if ( tud_cdc_n_available(itf) )
                {
    
                    uint8_t buf[64];
    
                    uint32_t count = tud_cdc_n_read(itf, buf, sizeof(buf));
    
                    /* echo back to both serial ports */
                    echo_serial_port(0, buf, count);
                    echo_serial_port(1, buf, count);
                }
            }
        }
    }
    void dsr_task_loop(void *args)
    {
        while (1)
        {
    	    cusbd_dsr();
        }
    }
    void tud_task_loop(void *args)
    {
        while (1)
        {
            tud_task();
        }
    }
    
    void cdc_task_loop(void *args)
    {
        while (1)
        {
            cdc_task();
        }
    }
    
    /*
     * The MIT License (MIT)
     *
     * Copyright (c) 2018, hathach (tinyusb.org)
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy
     * of this software and associated documentation files (the "Software"), to deal
     * in the Software without restriction, including without limitation the rights
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the Software is
     * furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice shall be included in
     * all copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     * THE SOFTWARE.
     *
     * This file is part of the TinyUSB stack.
     */
    /*
     *  Copyright (C) 2021 Texas Instruments Incorporated
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    /* Adapted by TI for running on its platform and SDK */
    
    #include "tusb_option.h"
    #include <stdarg.h> 
    
    #include "usb_wrapper.h"
    #include "device/dcd.h"
    #include <kernel/dpl/DebugP.h> 
    #include <kernel/nortos/dpl/common/printf.h>
    
    void outEpXferCmplCb(CUSBD_Ep *ep, CUSBD_Req * req);
    
    /*
    --------------------------------------------------------------------+
     MACRO TYPEDEF CONSTANT ENUM DECLARATION
    --------------------------------------------------------------------+
    */
    CUSBD_Ep* getEpFromAddr(CUSBD_Dev *dev, uint8_t epaddr)
    {
      LIST_ListHead *list; /* used in for_each loop */
    
      /* find the right EP matching the epaddr */
      /* for EP0, dev->ep0 is bi-directional */
      if ((dev->ep0->address&0x0F) == (epaddr&0x0F))
        return dev->ep0;
    
      /* for other EPs */
      for (list = dev->epList.next; list != &dev->epList; list = list->next) {
          CUSBD_Ep *ep = (CUSBD_Ep *) list;
          if (ep->address == epaddr) {
              return ep;
          }
      }
    
      return NULL;
    }
    
    CUSBD_Dev* getDevFromAddr(usb_handle_t *pD, uint8_t devaddr)
    {
      return NULL;
    }
    
    /*------------------------------------------------------------------*/
    /* Device API
     *------------------------------------------------------------------*/
    
    /* Initialize controller to device mode */
    void dcd_init (uint8_t rhport)
    {
      TU_LOG2("[dcd_init]\n");
    
      usbDeviceInit(NULL); /* USB SS initialization */
    
      return;
    }
    
    /* Enable device interrupt */
    void dcd_int_enable (uint8_t rhport)
    {
      /* Enable USB interrupt */
      HwiP_enableInt(usb_handle.hwiParamsUsb.intNum);
    
      (void) rhport;
    }
    
    /* Disable device interrupt */
    void dcd_int_disable (uint8_t rhport)
    {
      /* Disable USB interrupt */
      HwiP_disableInt(usb_handle.hwiParamsUsb.intNum);
    
      (void) rhport;
    }
    
    /* Receive Set Address request, mcu port must also include status IN response */
    void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
    {
      CUSBD_PrivateData * dev;
      CH9_UsbState state;
    
      dev = usb_handle.pD;
      state = dev->device.state;
    
      TU_LOG2("[dcd_set_address] dev_addr=%d\n", dev_addr);
    
      /* check if device address is within correct range */
      if (dev_addr > 0x007FU) {
          TU_LOG2("Invalid device address %d\n", dev_addr);
          return;
      }
    
      /* check if device is in correct state */
      if (state == CH9_USB_STATE_CONFIGURED) {
          TU_LOG2("Trying to set address when configured %c\n", ' ');
      return;
      }
    
      /* set device address in controller */
      CPS_UncachedWrite32(&dev->reg->USBR_CMD, ((dev_addr << 1) | 0x00000001U));
    
      if (dev_addr > 0U) {
          dev->device.state = CH9_USB_STATE_ADDRESS;
      } else {
          dev->device.state = CH9_USB_STATE_DEFAULT;
      }
    
      /* Response with zlp status */
      dcd_edpt_xfer(rhport, 0x80, NULL, 0);
    
      return;
    }
    
    /* Wake up host */
    void dcd_remote_wakeup (uint8_t rhport)
    {
      TU_LOG2("[dcd_remote_wakeup]\n");
      (void) rhport;
    }
    
    /* Connect by enabling internal pull-up resistor on D+/D- */
    void dcd_connect(uint8_t rhport)
    {
      TU_LOG2("[dcd_connect]\n");
      usb_handle.drv->start(usb_handle.pD);
    }
    
    /* Disconnect by disabling internal pull-up resistor on D+/D- */
    void dcd_disconnect(uint8_t rhport)
    {
      (void) rhport;
      TU_LOG2("[dcd_disconnect]\n");
      usb_handle.drv->stop(usb_handle.pD);
    }
    
    /*
    --------------------------------------------------------------------+
     Endpoint API
    --------------------------------------------------------------------+
    */
    /* Configure endpoint's registers according to descriptor */
    bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
    {
      CUSBD_Dev * dev;
      CUSBD_Ep * ep;
      int32_t res = 0;
    
      TU_LOG2("[dcd_edpt_open] ep_addr=%d\n", ep_desc->bEndpointAddress);
    
      /* get device handle dev */
      usb_handle.drv->getDevInstance(usb_handle.pD, &dev);
    
      /* Get EP according to ep_addr */
      ep = (CUSBD_Ep *) getEpFromAddr(dev, ep_desc->bEndpointAddress);
    
      if (ep!= NULL)
      {
        /* enable this EP accroding to the EP descriptor */
        res = ep->ops->epEnable(usb_handle.pD, ep, (uint8_t *) ep_desc);
        if (res!=0)
        {
          TU_LOG2("[dcd_edpt_open] epEnable error(%d) ep_addr=%d\n", res, ep_desc->bEndpointAddress);
          return false;
        } else
        {
          TU_LOG2("[dcd_edpt_open] epEnable EP%02X sucessfully\n", ep_desc->bEndpointAddress);
        }
    
        (void) rhport;
    
        return true;
      } else
      {
        TU_LOG2("[dcd_edpt_open] EP open error|||\n");
        return false;
      }
    
      return true;
    }
    
    void dcd_edpt_close_all (uint8_t rhport)
    {
      (void) rhport;
      /* TODO implement dcd_edpt_close_all() */
    }
    
    void ctrlInCmplCb(CUSBD_Ep *ep, CUSBD_Req * req)
    {
      if (req->status != 0)
      {
        TU_LOG2("[ctrlInCmplCb][WARNING] status(%d) != 0 !!!!\n", (int)(req->status));
        return;
      } else
      {
        TU_LOG2("[ctrlInCmplCb] Transfer complete on ep:%02X, %d(%d) bytes\n", ep->address, req->actual, req->length);
        /* inform the tud_task the transfer is completed */
        dcd_event_t event = { .rhport = 0, .event_id = DCD_EVENT_XFER_COMPLETE };
        event.xfer_complete.ep_addr = ep->address;
        event.xfer_complete.len     = req->actual;
        event.xfer_complete.result  = req->status;
        dcd_event_handler(&event, true);
    
        return;
      }
    }
    
    void inEpXferCmplCb(CUSBD_Ep *ep, CUSBD_Req * req) {
    
        TU_LOG2("[inEpXferCmplCb] EP:%02X req(0x%08X) buf(0x%08X) status(%d) length(%d) actual(%d)\n",
                ep->address, (uintptr_t) req, (uintptr_t)req->buf, req->status, req->length, req->actual);
    
        /* inform the tud_task the transfer is completed */
        dcd_event_t event = { .rhport = 0, .event_id = DCD_EVENT_XFER_COMPLETE };
        event.xfer_complete.ep_addr = ep->address;
        event.xfer_complete.len     = req->actual;
        event.xfer_complete.result  = req->status;
        dcd_event_handler(&event, true);
    }
    
    void outEp0XferCmplCb(CUSBD_Ep *ep, CUSBD_Req * req) {
    
        TU_LOG2("[outEp0XferCmplCb] EP:%02X req(0x%08X) buf(0x%08X) status(%d) length(%d) actual(%d)\n",
                ep->address, (uintptr_t) req, (uintptr_t)req->buf, req->status, req->length, req->actual);
    
        /* copy the received data from completed request buffer to TinyUSB buffer */
        memcpy(req->buf, (uint8_t *)req->dma, req->actual);
        TU_LOG2("[outEp0XferCmplCb] memcpy: from (0x%08X) to (0x%08X) redIdx(%d) (%d)bytes \n",
            (uintptr_t)req->dma, (uintptr_t)req->buf, 0x80, req->actual);
    
        /* inform the tud_task the transfer is completed */
        dcd_event_t event = { .rhport = 0, .event_id = DCD_EVENT_XFER_COMPLETE };
        event.xfer_complete.ep_addr = (ep->address)&0x0F;
        event.xfer_complete.len     = req->actual;
        event.xfer_complete.result  = req->status;
        dcd_event_handler(&event, true);
    }
    
    void outEpXferCmplCb(CUSBD_Ep *ep, CUSBD_Req * req) {
    
        int reqIdx = usbGetDataXferRequestIndexOut(req);
    
        TU_LOG2("[outEpXferCmplCb] EP:%02X req(0x%08X) buf(0x%08X) reqIdx(%d) status(%d) length(%d) actual(%d)\n",
                ep->address, (uintptr_t) req, (uintptr_t)req->buf, reqIdx, req->status, req->length, req->actual);
        if (reqIdx == -1) {
            TU_LOG2("[outEpXferCmplCb] Illegal reqIdx(%d)\n", reqIdx);
            return;
        } else {
            /* copy the received data from completed request buffer to TinyUSB expected data buffer */
            memcpy(req->buf, (uint8_t *)req->dma, req->actual);
            TU_LOG2("[outEpXferCmplCb] memcpy: from (0x%08X) to (0x%08X) redIdx(%d) (%d)bytes \n",
                (uintptr_t)req->buf, (uintptr_t)req->dma, reqIdx, req->actual);
    
            /* inform the tud_task the transfer is completed */
            dcd_event_t event = { .rhport = 0, .event_id = DCD_EVENT_XFER_COMPLETE };
            event.xfer_complete.ep_addr = ep->address;
            event.xfer_complete.len     = req->actual;
            event.xfer_complete.result  = req->status;
            dcd_event_handler(&event, true);
        }
    
        return;
    }
    
    /* Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack */
    bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
    {
      CUSBD_Dev * dev;
      CUSBD_Ep * ep;
      int32_t reqIdx = 0;
      int32_t res = 0;
    
      usb_handle.drv->getDevInstance(usb_handle.pD, &dev);
      /* Get EP according to ep_addr */
      ep = (CUSBD_Ep *) getEpFromAddr(dev, ep_addr);
      if (ep == NULL)
        return false;
    
      TU_LOG2("[dcd_edpt_xfer] ep:%02X (%08X)\n", ep_addr, (uint32_t)ep);
    
      /* if it is EP0 OUT */
      if (ep_addr==0)
      {
        /* if it is ZLP then then return */
        if (total_bytes==0)
        {
            /* inform the tud_task the transfer is completed */
            dcd_event_t event = { .rhport = 0, .event_id = DCD_EVENT_XFER_COMPLETE };
            event.xfer_complete.ep_addr = 0;
            event.xfer_complete.len     = 0;
            event.xfer_complete.result  = 0;
            dcd_event_handler(&event, true);
        } else
        {
          /* EP0 OUT data stage */
          /* clear the request */
          memset(&ep0DataXferRequest, 0, sizeof(CUSBD_Req));
          ep0DataXferRequest.length = total_bytes;
          /* save the TinyUSB buffer pointer in the request */
          ep0DataXferRequest.buf = buffer;
          ep0DataXferRequest.dma =  (uintptr_t)buffEp0;
          ep0DataXferRequest.complete = outEp0XferCmplCb;
    	  ep0DataXferRequest.deferStatusStage = 1;
          usb_handle.pD->ep0NextState = CH9_EP0_DATA_PHASE;
          usb_handle.pD->ep0DataDirFlag = 0;
          TU_LOG2("[dcd_edpt_xfer] request for ep:%02X, %d bytes, CompCb=%08X\n", ep_addr,
                  ep0DataXferRequest.length, (uint32_t)ep0DataXferRequest.complete);
          /* put the ep0 OUT request into the queue */
          res = ep->ops->reqQueue(usb_handle.pD, ep, &ep0DataXferRequest);
          if (res!=0)
          {
            TU_LOG2("[dcd_edpt_xfer] error(%x) when queue request for ep:%02X, %d bytes, CompCb=%08X\n", res, ep_addr,
                    ep0DataXferRequest.length, (uint32_t)ep0DataXferRequest.complete);
          } else
          {
            TU_LOG2("[dcd_edpt_xfer] queued request for ep:%02X, %d bytes, CompCb=%08X\n", ep_addr,
                    ep0DataXferRequest.length, (uint32_t)ep0DataXferRequest.complete);
          }
        }
        return true;
      }
    
      /* for EP0 IN */
      if ((ep_addr&0x0F)==0)
      {
        /* fill in the EP0 request */
        ep0Req.length = total_bytes;
        /* copy data to ep0Buff */
        memcpy(ep0Buff, buffer, total_bytes);
        ep0Req.buf = ep0Buff;
        ep0Req.dma = (uintptr_t)(ep0Req.buf);
        ep0Req.complete = &ctrlInCmplCb;
    
        /* Add the request to the EP request queue */
        if (ep0Req.length>0)
          usb_handle.pD->ep0NextState = CH9_EP0_DATA_PHASE;
        else
          usb_handle.pD->ep0NextState = CH9_EP0_STATUS_PHASE;
        if ((ep_addr&0xF0)>0)
          usb_handle.pD->ep0DataDirFlag = 1;
        else
          usb_handle.pD->ep0DataDirFlag = 0;
    
        TU_LOG2("[dcd_edpt_xfer] request for ep:%02X, %d bytes, CompCb=%08X\n", ep_addr, ep0Req.length, (uint32_t)ep0Req.complete);
        res = ep->ops->reqQueue(usb_handle.pD, ep, &ep0Req);
        if (res!=0)
        {
          TU_LOG2("[dcd_edpt_xfer] error(%x) when queue request for ep:%02X, %d bytes, CompCb=%08X\n", res, ep_addr,
                ep0DataXferRequest.length, (uint32_t)ep0DataXferRequest.complete);
        } else
        {
          TU_LOG2("[dcd_edpt_xfer] queued request for ep:%02X, %d bytes, CompCb=%08X\n", ep_addr,
                ep0DataXferRequest.length, (uint32_t)ep0DataXferRequest.complete);
        }
    
      } else
      {
        /* for EP IN request */
        if ((ep_addr&0xF0)>0)
        {
          /* use dataXferBufferIn for EP IN */
          reqIdx = (ep->address&0x0F) - 1;
          if ((reqIdx<0)||(reqIdx>=DATA_XFER_BUFFER_COUNT))
          {
            TU_LOG2("[dcd_edpt_xfer] Error: incorrect EP address(%02X)\n", ep_addr);
            return false;
          }
    
          /* use DataXferRequestIn[reqIdx] for EP IN */
          memset(&DataXferRequestsIn[reqIdx], 0, sizeof(CUSBD_Req));
          DataXferRequestsIn[reqIdx].length = total_bytes;
          /* copy data to dataXferBufferIn[reqIdx] */
          memcpy(dataXferBufferIn[reqIdx], buffer, total_bytes);
          DataXferRequestsIn[reqIdx].buf = dataXferBufferIn[reqIdx];
          DataXferRequestsIn[reqIdx].dma = (uintptr_t)(dataXferBufferIn[reqIdx]);
          DataXferRequestsIn[reqIdx].complete = inEpXferCmplCb;
    
          /* Add the request to the EP IN request queue */
          TU_LOG2("[dcd_edpt_xfer] request(%d) for ep:%02X, %d bytes\n", reqIdx, ep_addr, total_bytes);
          res = ep->ops->reqQueue(usb_handle.pD, ep, &DataXferRequestsIn[reqIdx]);
          if (res!=0)
          {
            TU_LOG2("[dcd_edpt_xfer] error(%x) when queue request for ep:%02X, %d bytes, CompCb=%08X\n", res, ep_addr,
                    DataXferRequestsIn[reqIdx].length, (uint32_t)DataXferRequestsIn[reqIdx].complete);
          } else
          {
            TU_LOG2("[dcd_edpt_xfer] queued request for ep:%02X, %d bytes, CompCb=%08X\n", ep_addr,
                    DataXferRequestsIn[reqIdx].length, (uint32_t)DataXferRequestsIn[reqIdx].complete);
          }
        } else
        {
          /* for EP Out request */
          reqIdx = (ep->address&0x0F) - 1;
          if ((reqIdx<0)||(reqIdx>=DATA_XFER_BUFFER_COUNT))
          {
            TU_LOG2("[dcd_edpt_xfer] Error: incorrect EP address(%02X)\n", ep_addr);
            return false;
          }
    
          TU_LOG2("[dcd_edpt_xfer] waiting request(%d) for ep:%02X, %d bytes to buffer=%08X\n", reqIdx, ep_addr,
                  total_bytes, (uint32_t)buffer);
    
          /* use DataXferRequestOut[reqIdx] for EP Out */
          memset(&DataXferRequestsOut[reqIdx], 0, sizeof(CUSBD_Req));
    
          /* save the TinyUSB buffer pointer in the request */
          DataXferRequestsOut[reqIdx].buf = buffer;
          DataXferRequestsOut[reqIdx].dma = (uintptr_t)(dataXferBufferOut[reqIdx]);
          DataXferRequestsOut[reqIdx].complete = outEpXferCmplCb;
          DataXferRequestsOut[reqIdx].length = total_bytes;
          res = ep->ops->reqQueue(usb_handle.pD, ep, &DataXferRequestsOut[reqIdx]);
          if (res!=0)
          {
            TU_LOG2("[dcd_edpt_xfer] error(%x) when queue request for ep:%02X, %d bytes, CompCb=%08X\n", res, ep_addr,
                    total_bytes, (uint32_t)DataXferRequestsOut[reqIdx].complete);
          } else
          {
            TU_LOG2("[dcd_edpt_xfer] queue request for ep:%02X, %d bytes, CompCb=%08X\n", ep_addr,
                    total_bytes, (uint32_t)DataXferRequestsOut[reqIdx].complete);
          }
        }
      }
    
      (void) rhport;
      return true;
    }
    
    /* Stall endpoint */
    void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
    {
      CUSBD_Dev * dev;
      CUSBD_Ep * ep;
    
      (void) rhport;
    
      TU_LOG2("[dcd_edpt_stall] ep_addr=%d\n", ep_addr);
    
      usb_handle.drv->getDevInstance(usb_handle.pD, &dev);
      /* Get EP according to ep_addr */
      ep = (CUSBD_Ep *) getEpFromAddr(dev, ep_addr);
      usb_handle.drv->epSetHalt(usb_handle.pD, ep, 1);
    }
    
    /* clear stall, data toggle is also reset to DATA0 */
    void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
    {
      CUSBD_Dev * dev;
      CUSBD_Ep * ep;
    
      (void) rhport;
    
      TU_LOG2("[dcd_edpt_clear_stall] ep_addr=%d\n", ep_addr);
    
      usb_handle.drv->getDevInstance(usb_handle.pD, &dev);
      /* Get EP according to ep_addr */
      ep = (CUSBD_Ep *) getEpFromAddr(dev, ep_addr);
      usb_handle.drv->epSetHalt(usb_handle.pD, ep, 0);
    }
    
    #ifdef CFG_TUSB_DEBUG 
    
    int CFG_TUSB_DEBUG_PRINTF(const char *format, ...)
    {
    	va_list va; 
    	va_start(va,format); 
    	printf_("[TUSB MSG]");
    	vprintf_(format,va);
    	va_end(va);
    	return 0 ; 
    }
    #endif 
    
    void dcd_testmodeCheck(int test_selector)
    {
        extern void testmodeCheck(CUSBD_PrivateData* pD, int test_Selector);
        testmodeCheck(usb_handle.pD, test_selector);
    }
    
    cusbd.c

  • Hello Motofumi,

    Thanks for sharing the above details. Please allow some time to review and revert back.

    Regards,

    Tushar

  • Hi Motofumi,

    The above code looks okay. 

    Please try once after setting the USB_CMD.STMODE[9] bit value to 1 before calling the handleFeatureRecDevTest API. Please let us know the results.

    Regards,

    Tushar

  • Hi Tushar,

    Thanks for the review.

    I tried the following two patterns and saw no change in either.

    ① Write STMODE and TMODE_SEL in order

    void testmodeCheck(CUSBD_PrivateData * dev, int test_selector)
    {
        CH9_UsbSetup setup;
        setup.wIndex = (test_selector & 0xFF) << 8;
        CPS_UncachedWrite32(&dev->reg->USBR_CMD, 1U << 9);
        handleFeatureRecDevTest(dev, &setup);
    }

    ②Write STMODE and TMODE_SEL at the same time

    static uint32_t handleFeatureRecDevTest(CUSBD_PrivateData * dev, const CH9_UsbSetup *ctrl) {
    
        uint32_t wIndex = ctrl->wIndex;
        uint32_t ret = CDN_EOK;
    
        if ((wIndex & 0xffU) != 0U) {
            ret = CDN_EINVAL;
        }
    
        if (ret == CDN_EOK) {
            uint8_t test_selector = (uint8_t) ((ctrl->wIndex >> 8) & 0x00FFU);
            uint32_t regSelec = 1U << 9;
            switch (test_selector) {
    
            /* TEST J */
            case CH9_TEST_J:
                SET_USB_CMD_TMODE_SEL(&regSelec, USBRV_TM_TEST_J);
                break;
    
            /*test K*/
            case CH9_TEST_K:
                SET_USB_CMD_TMODE_SEL(&regSelec, USBRV_TM_TEST_K);
                break;
    
            /*test se0_NAK*/
            case CH9_TEST_SE0_NAK:
                SET_USB_CMD_TMODE_SEL(&regSelec, USBRV_TM_SE0_NAK);
                break;
    
            /* packet test */
            case CH9_TEST_PACKET:
                SET_USB_CMD_TMODE_SEL(&regSelec, USBRV_TM_TEST_PACKET);
                break;
    
            case CH9_TEST_FORCE_EN:
                break;
    
            default:;
                break;
            }
            CPS_UncachedWrite32(&dev->reg->USBR_CMD, regSelec);
        }
        return ret;
    }

    best regards,

    Motofumi

  • Hi Motofumi,

    I tried the following two patterns and saw no change in either.

    Can you please also try setting the below values and check once?

    bmRequestType = CH9_USB_REQ_RECIPIENT_DEVICE
    wValue = CH9_USB_FS_TEST_MODE
    bRequest = CH9_USB_REQ_SET_FEATURE
    

    Regards,

    Tushar

  • Hi Tushar,

    Is the following implementation correct?
    I rechecked with this and did not see any change.

    void testmodeCheck(CUSBD_PrivateData * dev, int test_selector)
    {
        CH9_UsbSetup setup;
        setup.wIndex = (test_selector & 0xFF) << 8;
        setup.bmRequestType = CH9_USB_REQ_RECIPIENT_DEVICE;
        setup.wValue = CH9_USB_FS_TEST_MODE;
        setup.bRequest = CH9_USB_REQ_SET_FEATURE;
        CPS_UncachedWrite32(&dev->reg->USBR_CMD, 1U << 9);
        handleFeatureRecDevTest(dev, &setup);
    }

    best regards,

    Motofumi

  • Hi Tushar,

    I have solved the problem.

    The modifications are as follows.

    1. Call setConfigStateAddressed API upon receipt of Set Configuration. (Not called in the sample because TINYUSB_INTEGRATION is enabled.)

    2. Write STMODE and TMODE_SEL at the same time.

    Thank you for all your support!

    best regards,

    Motofumi

  • Hi Motofumi,

    Thanks for the above update. Glad to hear that you are able to resolve the issue.

    Can you please tell from which API are you calling this setConfigStateAddressed function?

    Is your code now looks like below snippet?

    void testmodeCheck(CUSBD_PrivateData * dev, int test_selector)
    {
        CH9_UsbSetup setup;
        setup.wIndex = (test_selector & 0xFF) << 8;
        setup.bmRequestType = CH9_USB_REQ_RECIPIENT_DEVICE;
        setup.wValue = CH9_USB_FS_TEST_MODE;
        setup.bRequest = CH9_USB_REQ_SET_FEATURE;
        CPS_UncachedWrite32(&dev->reg->USBR_CMD, 1U << 9);
        setConfigStateAddressed(dev, setup, test_selector);
        handleFeatureRecDevTest(dev, &setup);
    }

    Regards,

    Tushar

  • Hi Tushar,

    Here is my code.

    1. I have stopped using CDC data as a trigger. (to call setConfigStateAddressed at the timing of receiving Set configuration)

    2. Added processing to detect CH9_USB_REQ_SET_CONFIGURATION in the handleEp0IrqSetup function to call setConfigStateAddressed and testmodeCheck.

        if (ctrl.bRequest == CH9_USB_REQ_SET_CONFIGURATION)
        {
            setConfigStateAddressed(dev, &ctrl, ctrl.wValue & 0xFF);
            testmodeCheck(dev, 1);
        }

    3. To write TMODE_SEL and STMODE simultaneously, the implementation around the test mode is as follows

    static uint32_t handleFeatureRecDevTest(CUSBD_PrivateData * dev, const CH9_UsbSetup *ctrl) {
    
        uint32_t wIndex = ctrl->wIndex;
        uint32_t ret = CDN_EOK;
    
        if ((wIndex & 0xffU) != 0U) {
            ret = CDN_EINVAL;
        }
    
        if (ret == CDN_EOK) {
            uint8_t test_selector = (uint8_t) ((ctrl->wIndex >> 8) & 0x00FFU);
            uint32_t regSelec = 1U << 9;
            switch (test_selector) {
    
            /* TEST J */
            case CH9_TEST_J:
                SET_USB_CMD_TMODE_SEL(&regSelec, USBRV_TM_TEST_J);
                break;
    
            /*test K*/
            case CH9_TEST_K:
                SET_USB_CMD_TMODE_SEL(&regSelec, USBRV_TM_TEST_K);
                break;
    
            /*test se0_NAK*/
            case CH9_TEST_SE0_NAK:
                SET_USB_CMD_TMODE_SEL(&regSelec, USBRV_TM_SE0_NAK);
                break;
    
            /* packet test */
            case CH9_TEST_PACKET:
                SET_USB_CMD_TMODE_SEL(&regSelec, USBRV_TM_TEST_PACKET);
                break;
    
            case CH9_TEST_FORCE_EN:
                break;
    
            default:;
                break;
            }
            CPS_UncachedWrite32(&dev->reg->USBR_CMD, regSelec);
        }
        return ret;
    }
    
    void testmodeCheck(CUSBD_PrivateData * dev, int test_selector)
    {
        CH9_UsbSetup setup;
        setup.wIndex = (test_selector & 0xFF) << 8;
        setup.bmRequestType = CH9_USB_REQ_RECIPIENT_DEVICE;
        setup.wValue = CH9_USB_FS_TEST_MODE;
        setup.bRequest = CH9_USB_REQ_SET_FEATURE;
    
        handleFeatureRecDevTest(dev, &setup);
    }

    best regards,

    Motofumi

    1222.cusbd.c

  • Hi Motofumi,

    Thanks for providing the above details. Really appreciated.

    Best Regards,

    Tushar