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

Drive SS(CS) in SPI manually with easyDMA

Hello I am using nRF52832, sdk v14.1, pca10040.

With regard to SPI, I am using the spi master in nrf_drv_spi.c to handle multi-byte spi transactions. I am able to do this successfully and the driver sets the SS pin low during the transaction and then back high after it has completed.

After I complete these multi-byte transactions, I want to enable easyDMA so that spi read transactions subsequently occur without CPU involvement. The start of the transaction will be initiated by a hi-to-low transition on a GPIO pin called /DRDY. I have setup GPIOTE in "in_event" mode and PPI to automatically start the spi transaction by calling nrf_drv_spi_xfer() with NRF_DRV_SPI_FLAG_HOLD_XFER and NRF_DRV_SPI_FLAG_REPEATED_XFER flags to setup the spi transfer but hold the actual transfer until triggered by PPI and since its a continuous stream of data also use the other flag.

I have setup the easyDMA as follows:

//easy DMA stuff
#define BUFFER_SIZE 3

typedef struct ArrayList
{
    uint8_t buffer[BUFFER_SIZE];
} ArrayList_type;

ArrayList_type afeStreamArrayList[4];
ArrayList_type bufTx[4];

NRF_SPIM0->RXD.MAXCNT = sizeof(afeStreamArrayList);
NRF_SPIM0->RXD.PTR = (int32_t) &afeStreamArrayList;
NRF_SPIM0->RXD.LIST = SPIM_RXD_LIST_LIST_ArrayList;

NRF_SPIM0->TXD.MAXCNT = sizeof(bufTx);
NRF_SPIM0->TXD.PTR = (int32_t) bufTx;
NRF_SPIM0->TXD.LIST = SPIM_RXD_LIST_LIST_Disabled;

nrf_drv_spi_xfer_desc_t xfer_desc;
//xfer_desc.p_tx_buffer = &bufTx;
//xfer_desc.p_rx_buffer = &afeStreamArrayList;
xfer_desc.tx_length   = sizeof(bufTx);
xfer_desc.rx_length   = sizeof(afeStreamArrayList);

nrf_drv_spi_xfer(&spi, &xfer_desc,
             NRF_DRV_SPI_FLAG_HOLD_XFER
            |NRF_DRV_SPI_FLAG_REPEATED_XFER
            );

question1: Is easyDMA setup the correct way? I have a total of 12 bytes(96 bits) I need to clock out during the spi transaction so I would like to organize into 3-32byte buffers (pointers) I can later access.

question 2: I am reading these 96 bits from a device external to the nRF52832. I would like to read these 96 bits and write directly to RAM via easyDMA to the array called "afeStreamArrayList". Then from some other point in the code (like main()), I would read from that array and perform some calculations on the data, so I have my buffers setup correctly?

question 3: argument 2 in nrf_drv_spi_xfer() is the transfer descriptor, which is commented out as you can see, all I did was declare the variable, do I need to configure the transfer descriptor any further or does my easyDMA setup take care of that?

question 4: With the code above, I am able to see the 96 clocks being issued by the SPI driver when the hi-to-low transition occurs on /DRDY consistently but no data is being clocked out because SS is not being driven when in easyDMA mode, it is permanently high. So..I want to manually drive SS but when I try to issue a command like:

//permanently hold CS low
nrf_gpio_cfg_output(ADS129x_SPI_CS_PIN);
nrf_gpio_pin_clear(ADS129x_SPI_CS_PIN);

nothing happens with the pin, it stays high. It seems it is locked by SPI driver and I cannot drive SS manually. How do I modify the spi configuration so that I am able to drive this pin directly? Do I use a fork to the original spi start event that also drives SS low and another fork to the original end event that takes it back high?

thank you for reading

  • Hi,

    Q1: Did you mean 3 * 32 bits? If you have a look at the EasyDMA list documentation of SPIM peripheral, you can see that you have setup 4 * 24 bits in your buffer. If you want 3 * 32 bits, you should swap 3 and 4 in your arrays.

    Q2: If the SPIM peripheral is setup to receive the data, the data will be stored in the array in RAM. As long as you wait until the transfer is completed before reading the array, this should be fine. Make sure you don't start a new SPI transfer before you have changed the buffer pointer, or are done processing the buffer.

    Q3: Here you are mixing accessing the registers directly with functions from the driver. If the driver is setup to not use EasyDMA, calling the nrf_drv_spi_xfer() function will setup the transfer using the legacy SPI peripheral. You should either setup the SPI master driver to use EasyDMA, or you need to configure the entire SPIM peripheral using the registers.

    Q4: The SS pin should not be "locked" by the driver, the driver use the same nrf_gpio_pin_set()/nrf_gpio_pin_clear() pins to set and clear the SS pin as you are using. Are you sure that you are checking the correct pin? Have you tried with a different GPIO for the SS pin?

    Best regards,

    Jørgen

  • I am facing the same problem as in Q4 of this post. When I use (set and clear) the P0.6 pin 6 as a GPIO on my nrf52382 based custom PCB, it works fine. The LOW value is in millivolts and HIGH is 3.3V as should be. But as soon as I write the SPI code and configure P6 as spi_config.ss pin, I have problems setting it LOW... the value of P6 gets to 0.7 V which is a floating value but does not get LOW properly. Is this something with the SPI master example?? 

    I am using SDK 15.2, Keil uVision 5.0. 

Related