Bug in SPI in DMA mode code (3.5.285)

Page 361 of the RSL10_hardware_reference manual says:

CAUTION: When the DMA interface is used to control transfers that use
an interface or peripheral, all accesses to that interface or
peripheral’s data registers using the peripheral bus clears the DMA
request signals. If a DMA request signal is cleared due to an ARM
Cortex-M3 processor access, the underlying DMA transfer becomes corrupted.

and yet the code does exactly that. The symptom was that the SPI in DMA mode was working correctly a few thousand times and then is was stopping after the first 16 bytes were sent. I’ve changed the order of the instructions placing the dma->Start last and that cured the problem.

In SPI_RSLxx.c @ line 1541

     dma->ConfigureAddr( spi->info->default_cfg.tx_dma_ch, &buffTCfg );

     /* Start the tx dma channel */
-    dma->Start( spi->info->default_cfg.tx_dma_ch );
-
     /* !!!WORKAROUND!!! set the RW transfer before setting the dma control to properly send first byte */
     spi->reg->CTRL0 &= ~SPI0_CTRL0_SPI0_CONTROLLER_Pos;
-    spi->reg->CTRL1 |= ( SPI0_START | transferType );
+    // spi->reg->CTRL1 |= (SPI0_START | transferType);
     spi->reg->CTRL0 |= SPI0_CONTROLLER_DMA;
+    dma->Start( spi->info->default_cfg.tx_dma_ch );
   }
   else
   {

another issue is when you configure the SPI as “master ss unused” (mode 0x10). Then the code will reconfigure your ssel pin anyways.

In SPI_RSLxx.c @ line 1005 I’ve changed:

         /* Prepare offset for configuration */
         uint32_t      offset = 0;
+        bool          ssel_config = true;

         /* Check if spi1 was selected */
         if( spi->reg == SPI1 )
         {
+#if( RTE_SPI1_MODE_DEFAULT == 0x10 )
+          ssel_config = false;
+#endif
           /* Change offset to spi1 */
           offset = SPI1_OFFSET;
        }
         else
         {
+#if( RTE_SPI0_MODE_DEFAULT == 0x10 )
+          ssel_config = false;
+#endif
           /* Reset SPI0 register */
           gpio->ResetAltFuncRegister( GPIO_FUNC_REG_SPI0 );
         }
         gpioLocCfg.io_mode = GPIO_MODE_SPI0_CLK_OUT + offset;
         gpio->ConfigurePad( spi->info->default_cfg.sclk_pin, &gpioLocCfg );

-        /* Configure ssel pin */
-        gpioLocCfg.io_mode = GPIO_MODE_SPI0_CS_OUT + offset;
-        gpio->ConfigurePad( spi->info->default_cfg.ssel_pin, &gpioLocCfg );
+        if( ssel_config )
+        {
+          /* Configure ssel pin */
+          gpioLocCfg.io_mode = GPIO_MODE_SPI0_CS_OUT + offset;
+          gpio->ConfigurePad( spi->info->default_cfg.ssel_pin, &gpioLocCfg );
+        }

         /* Configure miso pin */
         gpioLocCfg.io_mode = GPIO_MODE_SPI0_SERI_IN + offset;
             case ARM_SPI_SS_MASTER_UNUSED:
             {
-              /* Unconfigure SSEL Pin */
-              gpioLocCfg.io_mode = GPIO_MODE_DISABLED;
-              gpio->ConfigurePad( spi->info->default_cfg.ssel_pin,
-                  &gpioLocCfg );
+              if( ssel_config )
+              {
+                /* Unconfigure SSEL Pin */
+                gpioLocCfg.io_mode = GPIO_MODE_DISABLED;
+                gpio->ConfigurePad( spi->info->default_cfg.ssel_pin,
+                    &gpioLocCfg );
+              }
               mode |= ARM_SPI_SS_MASTER_UNUSED;
               break;
             }
2 Likes

Thank you for reporting this issue and sharing the fixes with the user community!

Your suggested fixes are welcomed and we will add this to our items to be addressed in future releases.

2 Likes

Further information regarding the apparent conflict with the Hardware Reference Manual:

The cautionary note included in the hardware reference warns against accessing the peripheral’s data registers using the peripheral bus, as use of these registers will clear data ready signals to the DMA peripheral that will corrupt transfers.

At the start of a DMA-controlled transfer using SPI in master mode (if the interface was previously idle) this note does not apply as the data ready signals are known to be already cleared and will remain so until the transfer has been started by manual intervention. The SPI interface will only signal that it is ready for more TX data once a data word has been transferred to the interface’s internal registers to be shifted out over the interface, so the first data ready signal needed by the DMA peripheral is triggered by queuing the first word to be transferred over SPI manually after which the DMA transfer manages the remainder of the transfer.

So another way to address the issue is to ensure that the SPI interface is idle before initiating another transfer.

Hello Emil,

Thank you again for taking the time to report these issues. You may be pleased to know your recommend fix for the unconfigured SSEL pin has made its way into the newest release, version 3.6.465.

We have also added some additional comments to the dma tx only config section, explaining why this use case contradicts the warning in the hardware reference manual. I am still interested in what caused the problem in your setup, that made you need to change the order of things. If you would like to tell me more about the device you are communicating with and your hardware setup, I would be happy to investigate it further. Otherwise, thankyou again for reaching out to us!

1 Like