wspiReceive called twice, no cleared NDTR register Topic is solved

Report here problems in any of ChibiOS components. This forum is NOT for support.
error414
Posts: 12
Joined: Fri Jan 22, 2021 12:11 am
Has thanked: 3 times

wspiReceive called twice, no cleared NDTR register  Topic is solved

Postby error414 » Sun Feb 28, 2021 7:04 pm

Hi Giovanni,

I play with WSPI and I noticed weird issue. If I call twice wspiReceive(), then NDRT register for DMA is not cleared.

Simple code for test:

Code: Select all


#include "ch.h"
#include "hal.h"

int main(void) {
   halInit();
   chSysInit();
   wspiStart(&WSPID1, &config);

   /* NCSS */
   palSetPadMode(GPIOB, 6, PAL_MODE_ALTERNATE(10) | PAL_STM32_OSPEED_HIGHEST);

   /* SCK */
   palSetPadMode(GPIOF, 10, PAL_MODE_ALTERNATE(9) | PAL_STM32_OSPEED_HIGHEST);

   /* IO0 */
   palSetPadMode(GPIOF, 8, PAL_MODE_ALTERNATE(10) | PAL_STM32_OSPEED_HIGHEST);

   /* IO1 */
   palSetPadMode(GPIOF, 9, PAL_MODE_ALTERNATE(10) | PAL_STM32_OSPEED_HIGHEST);
   
   wspi_command_t mode;

   static uint8_t buffer1[512];
   static uint8_t buffer2[512];
   static uint8_t buffer3[512];

   mode.cmd   = 0x9f;
   mode.cfg   = (WSPI_CFG_CMD_MODE_ONE_LINE       | \
                 WSPI_CFG_ADDR_MODE_NONE          | \
                 WSPI_CFG_ALT_MODE_NONE           | \
                 WSPI_CFG_DATA_MODE_ONE_LINE       | \
                 WSPI_CFG_CMD_SIZE_8              | \
                 WSPI_CFG_ADDR_SIZE_24);
   mode.addr  = 0U;
   mode.alt   = 0U;
   mode.dummy = 0U;

   wspiReceive(&WSPID1, &mode, 3, buffer1);
   
   
   //ends in infinity while wspi_lld_serve_interrupt   "while (dmaStreamGetTransactionSize(wspip->dma) > 0U)"
   wspiReceive(&WSPID1, &mode, 3, buffer2);
   
   
   
   wspiReceive(&WSPID1, &mode, 3, buffer3);

while (true) {
   chThdSleepMilliseconds(1000);
}   


Second calling of " wspiReceive(&WSPID1, &mode, 3, buffer2);" ends in infinity "while" because NDTR is not cleared, I checked communication in QSPI pin and all what should be send, were send.

Infinity while:

Code: Select all

static void wspi_lld_serve_interrupt(WSPIDriver *wspip) {

  /* Portable WSPI ISR code defined in the high level driver, note, it is
     a macro.*/
  _wspi_isr_code(wspip);

  /* Stop everything, we need to give DMA enough time to complete the ongoing
     operation. Race condition hidden here.*/
  while (dmaStreamGetTransactionSize(wspip->dma) > 0U)  <-------------------------
    ;

  /* Handling of errata: Extra data written in the FIFO at the end of a
     read transfer.*/
  if (wspip->state == WSPI_RECEIVE) {
    while ((wspip->qspi->SR & QUADSPI_SR_BUSY) != 0U) {
      (void) wspip->qspi->DR;
    }
  }
}




Does not metter whether memory is connected or not, in both case same behavior. If memory is connected then firts calling "wspiReceive" fills buffer1 with propper data, so communication with memory works, at least for first "wspiReceive" calling.

My mcuconf.h
https://pastebin.com/GXneeyy7
/*
* WSPI driver system settings.
*/
#define STM32_WSPI_USE_QUADSPI1 TRUE
#define STM32_WSPI_QUADSPI1_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) // stream (2, 7) = the same issue
#define STM32_WSPI_QUADSPI1_PRESCALER_VALUE 255


* Latest CHibiOs from github
* STM32F767Zi nucleo 144

User avatar
Giovanni
Site Admin
Posts: 14444
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1074 times
Been thanked: 921 times
Contact:

Re: wspiReceive called twice, no cleared NDTR register

Postby Giovanni » Sun Feb 28, 2021 7:24 pm

Hi,

Moving in bug reports, I will give it a try probably tomorrow.

Giovanni

error414
Posts: 12
Joined: Fri Jan 22, 2021 12:11 am
Has thanked: 3 times

Re: wspiReceive called twice, no cleared NDTR register

Postby error414 » Tue Mar 02, 2021 12:16 pm

Small progress.

It started to work when I added "dmaStreamClearInterrupt(wspip->dma);". I'm not sure whether it's right solution, but it works

Code: Select all

--- a/ChibiOS/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.c   (revision 2bf5987875f11e02acc4f20eda412fabe7f6dafc)
+++ b/ChibiOS/os/hal/ports/STM32/LLD/QUADSPIv1/hal_wspi_lld.c   (date 1614683492813)
@@ -299,6 +299,7 @@
 void wspi_lld_receive(WSPIDriver *wspip, const wspi_command_t *cmdp,
                       size_t n, uint8_t *rxbuf) {
 
+  dmaStreamClearInterrupt(wspip->dma);
   dmaStreamSetMemory0(wspip->dma, rxbuf);
   dmaStreamSetTransactionSize(wspip->dma, n);
   dmaStreamSetMode(wspip->dma, wspip->dmamode | STM32_DMA_CR_DIR_P2M);


User avatar
Giovanni
Site Admin
Posts: 14444
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1074 times
Been thanked: 921 times
Contact:

Re: wspiReceive called twice, no cleared NDTR register

Postby Giovanni » Tue Mar 02, 2021 1:10 pm

Thanks, to be verified if it is an effect of the problem or the cause.

Giovanni

User avatar
FXCoder
Posts: 384
Joined: Sun Jun 12, 2016 4:10 am
Location: Sydney, Australia
Has thanked: 180 times
Been thanked: 130 times

Re: wspiReceive called twice, no cleared NDTR register

Postby FXCoder » Tue Mar 02, 2021 11:00 pm

Hi Giovanni,
I was doing some work with QSPI last year which had to be shelved due to other priorities.
Getting back on to that project soon though.

I did make some minor changes to QUADSPIv1 which were not extensively tested and there is likely more to be done...
--
Bob

Code: Select all

Index: hal_wspi_lld.c
===================================================================
--- hal_wspi_lld.c   (revision 14056)
+++ hal_wspi_lld.c   (working copy)
@@ -68,7 +68,6 @@
  */
 static void wspi_lld_serve_dma_interrupt(WSPIDriver *wspip, uint32_t flags) {
 
-  (void)wspip;
   (void)flags;
 
   /* DMA errors handling.*/
@@ -77,6 +76,7 @@
     STM32_WSPI_DMA_ERROR_HOOK(wspip);
   }
 #endif
+  dmaStreamClearInterrupt(wspip->dma);
 }
 
 /**
@@ -86,10 +86,6 @@
  */
 static void wspi_lld_serve_interrupt(WSPIDriver *wspip) {
 
-  /* Portable WSPI ISR code defined in the high level driver, note, it is
-     a macro.*/
-  _wspi_isr_code(wspip);
-
   /* Stop everything, we need to give DMA enough time to complete the ongoing
      operation. Race condition hidden here.*/
   while (dmaStreamGetTransactionSize(wspip->dma) > 0U)
@@ -102,6 +98,10 @@
       (void) wspip->qspi->DR;
     }
   }
+
+  /* Portable WSPI ISR code defined in the high level driver, note, it is
+     a macro.*/
+  _wspi_isr_code(wspip);
 }
 
 /*===========================================================================*/


error414
Posts: 12
Joined: Fri Jan 22, 2021 12:11 am
Has thanked: 3 times

Re: wspiReceive called twice, no cleared NDTR register

Postby error414 » Thu Mar 04, 2021 12:15 pm

Thank you very much for comment FXCoder. Unfortunately the patch does't work me because "wspi_lld_serve_dma_interrupt" is not never called. Flags for enable DMA interupt are set to 0x0; There are enabled only flags for DMA error interrupts.

I can post all values from registers if needed.

User avatar
FXCoder
Posts: 384
Joined: Sun Jun 12, 2016 4:10 am
Location: Sydney, Australia
Has thanked: 180 times
Been thanked: 130 times

Re: wspiReceive called twice, no cleared NDTR register

Postby FXCoder » Fri Mar 05, 2021 12:47 am

Hi,
Interesting that neither TCIE or HTIE are enabled yet there would seem to be a lingering ISR or other status blocking the next operation.
Inspecting the DMA ISR after the first receive could give a clue.
--
Bob

User avatar
Giovanni
Site Admin
Posts: 14444
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1074 times
Been thanked: 921 times
Contact:

Re: wspiReceive called twice, no cleared NDTR register

Postby Giovanni » Fri Mar 05, 2021 8:17 am

FXCoder wrote:Hi,
Interesting that neither TCIE or HTIE are enabled yet there would seem to be a lingering ISR or other status blocking the next operation.
Inspecting the DMA ISR after the first receive could give a clue.


This is exactly what I want to do as soon I have some time for this, the 1st operation leaves the DMA and/or QSPI in an unfinished state probably. It is possible this is specific to the command format used, I have not seen problems using the existing flash infrastructure.

Giovanni

error414
Posts: 12
Joined: Fri Jan 22, 2021 12:11 am
Has thanked: 3 times

Re: wspiReceive called twice, no cleared NDTR register

Postby error414 » Fri Mar 05, 2021 3:27 pm

I'm so sorry for screenshots, it's not possible to copy whole register list :(

Screenshots are captured after first call "wspiReceive(&WSPID1, &mode, 3, buffer1);"

(two screenshots for DMA2, one for QSPI)

BTW: I use DMA2 Channel2
#define STM32_WSPI_QUADSPI1_DMA_STREAM STM32_DMA_STREAM_ID(2, 2)
Attachments
qspi.png
dma2_2.png
dma2.png

User avatar
Giovanni
Site Admin
Posts: 14444
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1074 times
Been thanked: 921 times
Contact:

Re: wspiReceive called twice, no cleared NDTR register

Postby Giovanni » Sun Mar 07, 2021 9:10 am

Hi,

I have been able to reproduce the problem. The root cause is that the DMA interrupt is not enabled so the DMA ISR is not invoked in the DMA driver, flags are cleared there.

This is the fix I committed on trunk, apparently it works, could you confirm? I will back-port this to stable branches after confirmation.

Code: Select all

static void wspi_lld_serve_interrupt(WSPIDriver *wspip) {

  /* Portable WSPI ISR code defined in the high level driver, note, it is
     a macro.*/
  _wspi_isr_code(wspip);

  /* Stop everything, we need to give DMA enough time to complete the ongoing
     operation. Race condition hidden here.*/
  while (dmaStreamGetTransactionSize(wspip->dma) > 0U)
    ;

  /* Clearing DMA interrupts here because the DMA ISR is not called on
     transfer complete.*/
  dmaStreamClearInterrupt(wspip->dma);

  /* Handling of errata: Extra data written in the FIFO at the end of a
     read transfer.*/
  if (wspip->state == WSPI_RECEIVE) {
    while ((wspip->qspi->SR & QUADSPI_SR_BUSY) != 0U) {
      (void) wspip->qspi->DR;
    }
  }
}


Traced as bug #1147.

Giovanni


Return to “Bug Reports”

Who is online

Users browsing this forum: No registered users and 5 guests