SPIM

Hi everyone,

I am trying to use SPIM for an external DAC. The DAC does not require MISO, only SCK, MOSI, and CS.

I configured SPIM like this:

#define SPI_DAC NRF_SPIM2
SPI_DAC->ENABLE = SPIM_ENABLE_ENABLE_Enabled;
SPI_DAC->FREQUENCY = SPIM_FREQUENCY_FREQUENCY_M8 << SPIM_FREQUENCY_FREQUENCY_Pos;
SPI_DAC->PSEL.CSN = NRF_SPIM_PIN_NOT_CONNECTED;
SPI_DAC->PSEL.SCK = NRF_GPIO_PIN_MAP(0, 29);
SPI_DAC->PSEL.MOSI = NRF_GPIO_PIN_MAP(1, 10);
SPI_DAC->PSEL.MISO = NRF_SPIM_PIN_NOT_CONNECTED;

SPI_DAC->TXD.LIST = 0;
SPI_DAC->RXD.LIST = 0;

SPI_DAC->TXD.PTR = (uint32_t)&dac_tx_buf;
SPI_DAC->TXD.MAXCNT = 2;

SPI_DAC->RXD.PTR = (uint32_t)&dac_rx_dummy;
SPI_DAC->RXD.MAXCNT = 2;

SPI_DAC->CONFIG =
    (SPIM_CONFIG_ORDER_MsbFirst << SPIM_CONFIG_ORDER_Pos) |
    (SPIM_CONFIG_CPOL_ActiveHigh << SPIM_CONFIG_CPOL_Pos) |
    (SPIM_CONFIG_CPHA_Leading << SPIM_CONFIG_CPHA_Pos); // Mode 0

Then I try to start the transfer like this:

SPI_DAC->EVENTS_END = 0;
SPI_DAC->TASKS_START = 1;

while (!SPI_DAC->EVENTS_END) {
    LOG_DBG("in while");
    k_sleep(K_SECONDS(5));
}

SPI_DAC->EVENTS_END = 0;

The problem is that the code stays forever in this while loop, meaning EVENTS_END is never set.

I checked the signals with a logic analyzer. The CS pin goes low, but SCLK and MOSI do not toggle. They just stay in their idle states.

Does anyone know what could prevent SPIM from actually starting the transfer in this case?

Parents
  • I recommend using an oscilloscope.

    The SPIM units have the quirk that they require to "see" level changes on the SCK pin and will stop (and not produce end event) otherwise.

    Its very easy to overlook a pin being used elsewhere in the DTS or being forwarded to the net core.

  • Im using logic analyzer. I saw that i disabled by accident a spim, after fixing that i now see SCLK MOSI generating, but still have problem with CS. If i do this SPI_DAC->PSEL.CSN = CSPIN; does than SPIM controls CS, with task start will he put pin low and after transfer put it high ?

  • Hello,

    You need to configure CSN pin as output in the GPIO peripheral with intial value high before enabling SPIM. source:SPIM — Serial peripheral interface master with EasyDMA

    The key points here is to configure GPIO before SPIM is enabled and to set PSEL registers while SPIM is disabled. So , your approach is correct now.

    For example something like below code (based on your code in first thread)

    // 1. Make sure SPIM is disabled first
    SPI_DAC->ENABLE = SPIM_ENABLE_ENABLE_Disabled;
    
    // 2. Configure GPIO pins BEFORE enabling SPIM
    // SCK - output, initial value same as CPOL (0 for Mode 0)
    nrf_gpio_pin_clear(NRF_GPIO_PIN_MAP(0, 29));
    nrf_gpio_cfg_output(NRF_GPIO_PIN_MAP(0, 29));
    
    // MOSI - output, initial value 0
    nrf_gpio_pin_clear(NRF_GPIO_PIN_MAP(1, 10));
    nrf_gpio_cfg_output(NRF_GPIO_PIN_MAP(1, 10));
    
    // CSN - output, initial value 1 (deasserted/high)
    nrf_gpio_pin_set(CSPIN);
    nrf_gpio_cfg_output(CSPIN);
    
    // 3. Configure PSEL registers while SPIM is still disabled
    SPI_DAC->PSEL.SCK  = NRF_GPIO_PIN_MAP(0, 29);
    SPI_DAC->PSEL.MOSI = NRF_GPIO_PIN_MAP(1, 10);
    SPI_DAC->PSEL.MISO = NRF_SPIM_PIN_NOT_CONNECTED;
    SPI_DAC->PSEL.CSN  = CSPIN;  // SPIM will now control CS automatically
    
    // 4. Configure frequency and SPI mode
    SPI_DAC->FREQUENCY = SPIM_FREQUENCY_FREQUENCY_M8 << SPIM_FREQUENCY_FREQUENCY_Pos;
    SPI_DAC->CONFIG =
        (SPIM_CONFIG_ORDER_MsbFirst  << SPIM_CONFIG_ORDER_Pos) |
        (SPIM_CONFIG_CPOL_ActiveHigh << SPIM_CONFIG_CPOL_Pos)  |
        (SPIM_CONFIG_CPHA_Leading    << SPIM_CONFIG_CPHA_Pos);  // Mode 0
    
    // 5. Set up DMA buffers
    SPI_DAC->TXD.LIST   = 0;
    SPI_DAC->RXD.LIST   = 0;
    SPI_DAC->TXD.PTR    = (uint32_t)&dac_tx_buf;
    SPI_DAC->TXD.MAXCNT = 2;
    SPI_DAC->RXD.PTR    = 0;
    SPI_DAC->RXD.MAXCNT = 0;  // No RX needed for DAC
    
    // 6. Enable SPIM
    SPI_DAC->ENABLE = SPIM_ENABLE_ENABLE_Enabled;
    
    // 7. Start transfer - SPIM will automatically:
    //    - Pull CSN low
    //    - Clock out data on MOSI
    //    - Pull CSN high when done
    SPI_DAC->EVENTS_END = 0;
    SPI_DAC->TASKS_START = 1;
    
    while (!SPI_DAC->EVENTS_END) { /* wait */ }
    SPI_DAC->EVENTS_END = 0;

Reply
  • Hello,

    You need to configure CSN pin as output in the GPIO peripheral with intial value high before enabling SPIM. source:SPIM — Serial peripheral interface master with EasyDMA

    The key points here is to configure GPIO before SPIM is enabled and to set PSEL registers while SPIM is disabled. So , your approach is correct now.

    For example something like below code (based on your code in first thread)

    // 1. Make sure SPIM is disabled first
    SPI_DAC->ENABLE = SPIM_ENABLE_ENABLE_Disabled;
    
    // 2. Configure GPIO pins BEFORE enabling SPIM
    // SCK - output, initial value same as CPOL (0 for Mode 0)
    nrf_gpio_pin_clear(NRF_GPIO_PIN_MAP(0, 29));
    nrf_gpio_cfg_output(NRF_GPIO_PIN_MAP(0, 29));
    
    // MOSI - output, initial value 0
    nrf_gpio_pin_clear(NRF_GPIO_PIN_MAP(1, 10));
    nrf_gpio_cfg_output(NRF_GPIO_PIN_MAP(1, 10));
    
    // CSN - output, initial value 1 (deasserted/high)
    nrf_gpio_pin_set(CSPIN);
    nrf_gpio_cfg_output(CSPIN);
    
    // 3. Configure PSEL registers while SPIM is still disabled
    SPI_DAC->PSEL.SCK  = NRF_GPIO_PIN_MAP(0, 29);
    SPI_DAC->PSEL.MOSI = NRF_GPIO_PIN_MAP(1, 10);
    SPI_DAC->PSEL.MISO = NRF_SPIM_PIN_NOT_CONNECTED;
    SPI_DAC->PSEL.CSN  = CSPIN;  // SPIM will now control CS automatically
    
    // 4. Configure frequency and SPI mode
    SPI_DAC->FREQUENCY = SPIM_FREQUENCY_FREQUENCY_M8 << SPIM_FREQUENCY_FREQUENCY_Pos;
    SPI_DAC->CONFIG =
        (SPIM_CONFIG_ORDER_MsbFirst  << SPIM_CONFIG_ORDER_Pos) |
        (SPIM_CONFIG_CPOL_ActiveHigh << SPIM_CONFIG_CPOL_Pos)  |
        (SPIM_CONFIG_CPHA_Leading    << SPIM_CONFIG_CPHA_Pos);  // Mode 0
    
    // 5. Set up DMA buffers
    SPI_DAC->TXD.LIST   = 0;
    SPI_DAC->RXD.LIST   = 0;
    SPI_DAC->TXD.PTR    = (uint32_t)&dac_tx_buf;
    SPI_DAC->TXD.MAXCNT = 2;
    SPI_DAC->RXD.PTR    = 0;
    SPI_DAC->RXD.MAXCNT = 0;  // No RX needed for DAC
    
    // 6. Enable SPIM
    SPI_DAC->ENABLE = SPIM_ENABLE_ENABLE_Enabled;
    
    // 7. Start transfer - SPIM will automatically:
    //    - Pull CSN low
    //    - Clock out data on MOSI
    //    - Pull CSN high when done
    SPI_DAC->EVENTS_END = 0;
    SPI_DAC->TASKS_START = 1;
    
    while (!SPI_DAC->EVENTS_END) { /* wait */ }
    SPI_DAC->EVENTS_END = 0;

Children
No Data
Related