nRF5 SDK is not maintained anymore
More Info: Consider nRF Connect SDK for new designs

NRF5340 USB SIZE.EPOUT[n] value not stable

Hi All,

I observed strange anomaly on NRF5340 (PCA10095 0.11.0 2020.52.xxxxxxxxx).

Same behavior seen on NRF52840 (PCA10056).

Value of register SIZE.EPOUT[n] does not reflect data that was received in endpoint.

Several consecutive reads from same register yield different values.

It looks like EasyDMA transfer that is in progress on different endpoint  causes problems reading unrelated SIZE.EPOUT[n] register.

Register value is valid before DMA on other endpoint is started then after DMA starts, value of register is usually 0 but sometimes some other random value that does not corresponds to any transfer.

After a while (I suspect that after DMA finishes) SIZE.EPOUT[n] is valid again.

Product specification does not mentions this behavior. I did not find any errata on that.

Do any one knows about such case?

Is there any recommendation on accessing SIZE.EPOUT registers?

Thanks for any help

Jerzy

Parents
  • Hi,

     

    In certain states, a group of registers shall not be accessed, as described here:

    https://infocenter.nordicsemi.com/topic/ps_nrf5340/chapters/usbd/doc/usbd.html?cp=3_0_0_6_38_11

     

    I do not know how your read-routine looks, but please keep this in mind:

    When reading registers directly from the CPU, it is important that you add a wait-state between each read. This is because the peripheral bus runs on a lower clock speed compared to the CPU.

    Pseudo code:

    uint32_t reg = NRF_USBD->SOME_REG;
    // Dummy read of any EVENTS_ register to generate wait-state
    (void)NRF_USBD->EVENTS_STARTED;

     

    Kind regards,

    Håkon

     

  • Hi Håkon, thanks for reply

    Register SIZE.EPOUT is mentioned in USB register access limitations section, but what I observe is that read of this register is in the middle of heavy USB traffic. USB is not disabled, nor suspended, it is transmitting in both direction prior to failure.

    I added dummy read of from EVENTS_STARTED register before read from SIZE.EPOUT and read is still incorrect.

    Code that accessed SIZE.EPOUT register did not try to read any other USBD registers just before read that failed.

    Document you mentioned state that only single EasyDMA can be started at a time at that is enforced in my case but

    I could not find any confirmation that while DMA is running certain registers can't be read.

    Maybe it should be added to USB register access limitation section if it is really the case.

    Jerzy

  • Hi,

     

    Could you share the output that you're getting, and your routine for reading the register?

     

    Kind regards,

    Håkon

  • Hi,

    Code that fails is opensource TinyUSB.

    Line that read invalid value is here

    https://github.com/hathach/tinyusb/blob/f4efb51fe2b7f4fee38c28ff80d03904d0b5b73e/src/portable/nordic/nrf5x/dcd_nrf5x.c#L220


    xact_len = tu_min16((uint16_t) NRF_USBD->SIZE.EPOUT[epnum], xfer->total_len - xfer->actual_len);
    

    While this code have tu_min16 macro that potentially could read register value twice. I tried extracting register read to separate line from tu_min16 and result was the same.

    As visible in code SIZE.EPOUT is first read in function from USBD registers. In case when this read fails, previous access to any register was stating DMA on some other OUT endpoint.

    During investigation process I tried dumping all SIZE.EPOUT registers before DMA is started and just after is starts.

    When reading all register in a loop and storing them in RAM reveled that registers had expected values before DMA was started. Specifically endpoint that had new data had correct value.

    Then DMA for other endpoint was stated.

    Then 8 times I read all SIZE.EPOUT registers again.

    This time read content of the registers were incorrect for one or more loop, then it was correct again.

    I did not verify that this loop start yielding correct values after DMA finished but that is my assumption.

    TinyUSB project is open source testing code is also opensource so I could help with setup if needed.

    br

    Jerzy

Reply
  • Hi,

    Code that fails is opensource TinyUSB.

    Line that read invalid value is here

    https://github.com/hathach/tinyusb/blob/f4efb51fe2b7f4fee38c28ff80d03904d0b5b73e/src/portable/nordic/nrf5x/dcd_nrf5x.c#L220


    xact_len = tu_min16((uint16_t) NRF_USBD->SIZE.EPOUT[epnum], xfer->total_len - xfer->actual_len);
    

    While this code have tu_min16 macro that potentially could read register value twice. I tried extracting register read to separate line from tu_min16 and result was the same.

    As visible in code SIZE.EPOUT is first read in function from USBD registers. In case when this read fails, previous access to any register was stating DMA on some other OUT endpoint.

    During investigation process I tried dumping all SIZE.EPOUT registers before DMA is started and just after is starts.

    When reading all register in a loop and storing them in RAM reveled that registers had expected values before DMA was started. Specifically endpoint that had new data had correct value.

    Then DMA for other endpoint was stated.

    Then 8 times I read all SIZE.EPOUT registers again.

    This time read content of the registers were incorrect for one or more loop, then it was correct again.

    I did not verify that this loop start yielding correct values after DMA finished but that is my assumption.

    TinyUSB project is open source testing code is also opensource so I could help with setup if needed.

    br

    Jerzy

Children
Related