This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

USB peripheral enable

Hi,

We have recently moved from using the nRF52840 PDK to a custom PCB.  The custom PCB uses nRF52840 Q1AABB, while the PDK has Q1AAAA.

On the custom PCB, the code is getting stuck in nrf_drv_usbd_enable().  USB power has been detected at this point, and the power handler has called into this function to enabled the USB peripheral.  The code gets stuck in the while loop after nrf_usbd_enable().

This does not happen on the PDK board.

Any ideas on why the USBD module is not generating a ready event after setting the enable bit?

Thanks,

Jacob

Parents
  • Hi Jacob,

    I understand you have addressed PAN 171. But please allow me to address PAN 171 in this email as well.

    There are 3 versions of the nRF52840 and the related DKs have different errata. To complicate things a bit more there are two DK versions with Rev A devices on them. So knowing what DK version, SDK, and silicon revision being used is extremely important.  If this message does not address your issue, please provide all of this information. 

    Below are patches addressing some of the errata found in the revision B and C silicon. A couple of these patches will be included in SDK15. The use of SKD15 and the related softdevice will be required to use the Nordic QID.

    The three functions below are updated USB functions: nrf_drv_usbd_enable, nrf_drv_usbd_wakeup_req, and nrf_drv_usbd_suspend.  These functions from SDK15 will identify the IC and apply the appropriate software changes to resolve various USB errata.

     SDK 14.2 does not support the function calls to nrf_drv_usbd_errata_xxxx.  For my use, I removed the parentheses of the function calls and used the following conditional compilation.

     #define DK_0_11_0 1

    // DK 0.11.0 is the newest nrf52840-PDK with Rev B silicon.

     #ifdef  DK_0_11_0

    #define nrf_drv_usbd_errata_166 1

    #define nrf_drv_usbd_errata_171 1

    #define nrf_drv_usbd_errata_187 1

    #else

    #define nrf_drv_usbd_errata_166 1

    #define nrf_drv_usbd_errata_171 0

    #define nrf_drv_usbd_errata_187 0

    #endif

     

    This was a quick and easy solution. I am sure you can crate a more elegant way of accomplishing this.

     With the release of SDK15, we are shifting to a unified and public driver support paradigm. Therefore, some of the #defines have changed from NRF_DRV_xxxx to NRFX_DRV_xxxx. Removing the X will allow the patch to compile with SDK14.2. This also allow SDK14.2 to be used with Rev C devices.

    Going forward NRFX drivers will be maintained on github. This repository is currently the work in progress for drivers to be released in SDK15. If there any issues with the SDK14 drivers, please review the updates on github first.

     The DK with production/rev C devices and SDK15 are both scheduled to be released 3/23 or shortly thereafter.

    Please let me know how this works out for you.

    Cheers,

    Jeff

     


    bool nrf_drv_usbd_suspend(void)
    {
    bool suspended = false;

    CRITICAL_REGION_ENTER();
    if (m_bus_suspend)
    {
    usbd_ep_abort_all();

    if (!(nrf_usbd_eventcause_get() & NRF_USBD_EVENTCAUSE_RESUME_MASK))
    {
    nrf_usbd_lowpower_enable();
    if (nrf_usbd_eventcause_get() & NRF_USBD_EVENTCAUSE_RESUME_MASK)
    {
    nrf_usbd_lowpower_disable();
    }
    else
    {
    suspended = true;

    if (nrf_drv_usbd_errata_171())
    {
    if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000)
    {
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    *((volatile uint32_t *)(0x4006EC14)) = 0x00000000;
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    }
    else
    {
    *((volatile uint32_t *)(0x4006EC14)) = 0x00000000;
    }
    }
    }
    }
    }
    CRITICAL_REGION_EXIT();

    return suspended;
    }

    bool nrf_drv_usbd_wakeup_req(void)
    {
    bool started = false;

    CRITICAL_REGION_ENTER();
    if (m_bus_suspend && nrf_usbd_lowpower_check())
    {
    nrf_usbd_lowpower_disable();
    started = true;

    if (nrf_drv_usbd_errata_171())
    {
    if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000)
    {
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0;
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    }
    else
    {
    *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0;
    }

    }
    }
    CRITICAL_REGION_EXIT();

    return started;
    }

    void nrf_drv_usbd_enable(void)
    {
    ASSERT(m_drv_state == NRFX_DRV_STATE_INITIALIZED);

    /* Prepare for READY event receiving */
    nrf_usbd_eventcause_clear(NRF_USBD_EVENTCAUSE_READY_MASK);

    if (nrf_drv_usbd_errata_187())
    {
    CRITICAL_REGION_ENTER();
    if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000)
    {
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    *((volatile uint32_t *)(0x4006ED14)) = 0x00000003;
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    }
    else
    {
    *((volatile uint32_t *)(0x4006ED14)) = 0x00000003;
    }
    CRITICAL_REGION_EXIT();
    }

    if (nrf_drv_usbd_errata_171())
    {
    CRITICAL_REGION_ENTER();
    if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000)
    {
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0;
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    }
    else
    {
    *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0;
    }
    CRITICAL_REGION_EXIT();
    }

    /* Enable the peripheral */
    nrf_usbd_enable();
    /* Waiting for peripheral to enable, this should take a few us */
    while (0 == (NRF_USBD_EVENTCAUSE_READY_MASK & nrf_usbd_eventcause_get()))
    {
    /* Empty loop */
    }
    nrf_usbd_eventcause_clear(NRF_USBD_EVENTCAUSE_READY_MASK);

    if (nrf_drv_usbd_errata_171())
    {
    CRITICAL_REGION_ENTER();
    if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000)
    {
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    *((volatile uint32_t *)(0x4006EC14)) = 0x00000000;
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    }
    else
    {
    *((volatile uint32_t *)(0x4006EC14)) = 0x00000000;
    }

    CRITICAL_REGION_EXIT();
    }

    if (nrf_drv_usbd_errata_187())
    {
    CRITICAL_REGION_ENTER();
    if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000)
    {
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    *((volatile uint32_t *)(0x4006ED14)) = 0x00000000;
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    }
    else
    {
    *((volatile uint32_t *)(0x4006ED14)) = 0x00000000;
    }
    CRITICAL_REGION_EXIT();
    }

    if (nrf_drv_usbd_errata_166())
    {
    *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7E3;
    *((volatile uint32_t *)(NRF_USBD_BASE + 0x804)) = 0x40;
    __ISB();
    __DSB();
    }

    nrf_usbd_isosplit_set(NRF_USBD_ISOSPLIT_Half);

    m_ep_ready = (((1U << NRF_USBD_EPIN_CNT) - 1U) << USBD_EPIN_BITPOS_0);
    m_ep_dma_waiting = 0;
    m_dma_pending = 0;
    m_last_setup_dir = NRF_DRV_USBD_EPOUT0;

    m_drv_state = NRFX_DRV_STATE_POWERED_ON;
    }

     

Reply
  • Hi Jacob,

    I understand you have addressed PAN 171. But please allow me to address PAN 171 in this email as well.

    There are 3 versions of the nRF52840 and the related DKs have different errata. To complicate things a bit more there are two DK versions with Rev A devices on them. So knowing what DK version, SDK, and silicon revision being used is extremely important.  If this message does not address your issue, please provide all of this information. 

    Below are patches addressing some of the errata found in the revision B and C silicon. A couple of these patches will be included in SDK15. The use of SKD15 and the related softdevice will be required to use the Nordic QID.

    The three functions below are updated USB functions: nrf_drv_usbd_enable, nrf_drv_usbd_wakeup_req, and nrf_drv_usbd_suspend.  These functions from SDK15 will identify the IC and apply the appropriate software changes to resolve various USB errata.

     SDK 14.2 does not support the function calls to nrf_drv_usbd_errata_xxxx.  For my use, I removed the parentheses of the function calls and used the following conditional compilation.

     #define DK_0_11_0 1

    // DK 0.11.0 is the newest nrf52840-PDK with Rev B silicon.

     #ifdef  DK_0_11_0

    #define nrf_drv_usbd_errata_166 1

    #define nrf_drv_usbd_errata_171 1

    #define nrf_drv_usbd_errata_187 1

    #else

    #define nrf_drv_usbd_errata_166 1

    #define nrf_drv_usbd_errata_171 0

    #define nrf_drv_usbd_errata_187 0

    #endif

     

    This was a quick and easy solution. I am sure you can crate a more elegant way of accomplishing this.

     With the release of SDK15, we are shifting to a unified and public driver support paradigm. Therefore, some of the #defines have changed from NRF_DRV_xxxx to NRFX_DRV_xxxx. Removing the X will allow the patch to compile with SDK14.2. This also allow SDK14.2 to be used with Rev C devices.

    Going forward NRFX drivers will be maintained on github. This repository is currently the work in progress for drivers to be released in SDK15. If there any issues with the SDK14 drivers, please review the updates on github first.

     The DK with production/rev C devices and SDK15 are both scheduled to be released 3/23 or shortly thereafter.

    Please let me know how this works out for you.

    Cheers,

    Jeff

     


    bool nrf_drv_usbd_suspend(void)
    {
    bool suspended = false;

    CRITICAL_REGION_ENTER();
    if (m_bus_suspend)
    {
    usbd_ep_abort_all();

    if (!(nrf_usbd_eventcause_get() & NRF_USBD_EVENTCAUSE_RESUME_MASK))
    {
    nrf_usbd_lowpower_enable();
    if (nrf_usbd_eventcause_get() & NRF_USBD_EVENTCAUSE_RESUME_MASK)
    {
    nrf_usbd_lowpower_disable();
    }
    else
    {
    suspended = true;

    if (nrf_drv_usbd_errata_171())
    {
    if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000)
    {
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    *((volatile uint32_t *)(0x4006EC14)) = 0x00000000;
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    }
    else
    {
    *((volatile uint32_t *)(0x4006EC14)) = 0x00000000;
    }
    }
    }
    }
    }
    CRITICAL_REGION_EXIT();

    return suspended;
    }

    bool nrf_drv_usbd_wakeup_req(void)
    {
    bool started = false;

    CRITICAL_REGION_ENTER();
    if (m_bus_suspend && nrf_usbd_lowpower_check())
    {
    nrf_usbd_lowpower_disable();
    started = true;

    if (nrf_drv_usbd_errata_171())
    {
    if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000)
    {
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0;
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    }
    else
    {
    *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0;
    }

    }
    }
    CRITICAL_REGION_EXIT();

    return started;
    }

    void nrf_drv_usbd_enable(void)
    {
    ASSERT(m_drv_state == NRFX_DRV_STATE_INITIALIZED);

    /* Prepare for READY event receiving */
    nrf_usbd_eventcause_clear(NRF_USBD_EVENTCAUSE_READY_MASK);

    if (nrf_drv_usbd_errata_187())
    {
    CRITICAL_REGION_ENTER();
    if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000)
    {
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    *((volatile uint32_t *)(0x4006ED14)) = 0x00000003;
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    }
    else
    {
    *((volatile uint32_t *)(0x4006ED14)) = 0x00000003;
    }
    CRITICAL_REGION_EXIT();
    }

    if (nrf_drv_usbd_errata_171())
    {
    CRITICAL_REGION_ENTER();
    if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000)
    {
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0;
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    }
    else
    {
    *((volatile uint32_t *)(0x4006EC14)) = 0x000000C0;
    }
    CRITICAL_REGION_EXIT();
    }

    /* Enable the peripheral */
    nrf_usbd_enable();
    /* Waiting for peripheral to enable, this should take a few us */
    while (0 == (NRF_USBD_EVENTCAUSE_READY_MASK & nrf_usbd_eventcause_get()))
    {
    /* Empty loop */
    }
    nrf_usbd_eventcause_clear(NRF_USBD_EVENTCAUSE_READY_MASK);

    if (nrf_drv_usbd_errata_171())
    {
    CRITICAL_REGION_ENTER();
    if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000)
    {
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    *((volatile uint32_t *)(0x4006EC14)) = 0x00000000;
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    }
    else
    {
    *((volatile uint32_t *)(0x4006EC14)) = 0x00000000;
    }

    CRITICAL_REGION_EXIT();
    }

    if (nrf_drv_usbd_errata_187())
    {
    CRITICAL_REGION_ENTER();
    if (*((volatile uint32_t *)(0x4006EC00)) == 0x00000000)
    {
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    *((volatile uint32_t *)(0x4006ED14)) = 0x00000000;
    *((volatile uint32_t *)(0x4006EC00)) = 0x00009375;
    }
    else
    {
    *((volatile uint32_t *)(0x4006ED14)) = 0x00000000;
    }
    CRITICAL_REGION_EXIT();
    }

    if (nrf_drv_usbd_errata_166())
    {
    *((volatile uint32_t *)(NRF_USBD_BASE + 0x800)) = 0x7E3;
    *((volatile uint32_t *)(NRF_USBD_BASE + 0x804)) = 0x40;
    __ISB();
    __DSB();
    }

    nrf_usbd_isosplit_set(NRF_USBD_ISOSPLIT_Half);

    m_ep_ready = (((1U << NRF_USBD_EPIN_CNT) - 1U) << USBD_EPIN_BITPOS_0);
    m_ep_dma_waiting = 0;
    m_dma_pending = 0;
    m_last_setup_dir = NRF_DRV_USBD_EPOUT0;

    m_drv_state = NRFX_DRV_STATE_POWERED_ON;
    }

     

Children
No Data
Related