Interfacing with MAX11198 dual simultaneous ADC over SPI

Hi,

I am trying to interface with the MAX11198 simultaneous dual ADC over SPI. The ADC has two channels and I am able to read values from one channel at a time using the nRF52832 DK as a SPI master. The ADC has one CLK pin, one CNVST pin (conversion start, acts as chip select) and 2 DOUT pins. I have set the conversion rate to 100kHz using a timer and PPI to toggle the CNVST at this rate. I am reading 2000 samples from the ADC then stoppping sampling to do some processing of the data. To do the repeated SPI master read I use:

ret_code_t ret_0 = nrf_drv_spi_xfer(&spi0, &xfer_0, NRF_DRV_SPI_FLAG_HOLD_XFER | NRF_DRV_SPI_FLAG_REPEATED_XFER ); 

To read from both DOUT pins at once I am trying to use a SPI slave instance with its CLK and CS pins physically tied to CLK and CNVST of the SPI master instance. However, I cannot figure out how to set up repeated slave SPI reads like can be done with nrf_drv_spi_xfer() function and the NRF_DRV_SPI_FLAG_REPEATED_XFER flag.

I'm open to any suggestions on better ways to accomplish this or if anyone has used this part before with a Nordic MCU.

Here are relevant functions from my project:

void spi_event_handler(nrf_drv_spi_evt_t const * p_event,
                       void *                    p_context)
{
    if(count0==ADC_QUE_SIZE)
    {
      spi_sampling_event_disable();
      spi_xfer_done = true;
    }
    else
    {
      adc0[count0++] = ((uint16_t)(m_rx_buf_0[0]<<8) | m_rx_buf_0[1]);
    }
}

void spis_event_handler(nrf_drv_spis_event_t event)
{
    if(event.evt_type == NRF_DRV_SPIS_XFER_DONE)
    {
        adc1[count1++] = ((uint16_t)(m_rx_buf_1[0]<<8) | m_rx_buf_1[1]);
      
        memset(m_rx_buf_1, 0, m_length);

        nrf_drv_spis_buffers_set(&spis, m_tx_buf, m_length, m_rx_buf_1, m_length);
    }
}

void spi_config(void)
{
    // Instance 0 config
    nrf_drv_spi_config_t spi_config_0 = NRF_DRV_SPI_DEFAULT_CONFIG;

    spi_config_0.mode      = NRF_DRV_SPI_MODE_1;
    spi_config_0.frequency = NRF_DRV_SPI_FREQ_8M;
    spi_config_0.ss_pin    = NRF_DRV_SPI_PIN_NOT_USED;
    spi_config_0.miso_pin  = SPI_MISO_PIN;
    spi_config_0.mosi_pin  = NRF_DRV_SPI_PIN_NOT_USED;
    spi_config_0.sck_pin   = SPI_SCK_PIN;

    APP_ERROR_CHECK(nrf_drv_spi_init(&spi0, &spi_config_0, spi_event_handler, NULL)); 
      
    memset(m_rx_buf_0, 0, m_length);

    nrf_drv_spi_xfer_desc_t xfer_0 = NRF_DRV_SPI_XFER_TRX(m_tx_buf, m_length, m_rx_buf_0, m_length);

    ret_code_t ret_0 = nrf_drv_spi_xfer(&spi0, &xfer_0, NRF_DRV_SPI_FLAG_HOLD_XFER | NRF_DRV_SPI_FLAG_REPEATED_XFER ); 

  
    // Instance 1 config    
    nrf_drv_spis_config_t spis_config = NRF_DRV_SPIS_DEFAULT_CONFIG;
   
    spis_config.mode      = NRF_DRV_SPI_MODE_1;
    spis_config.csn_pin   = APP_SPIS_CS_PIN;
    spis_config.miso_pin  = NRFX_SPIS_PIN_NOT_USED;
    spis_config.mosi_pin  = APP_SPIS_MOSI_PIN;
    spis_config.sck_pin   = APP_SPIS_SCK_PIN;
    
    APP_ERROR_CHECK(nrf_drv_spis_init(&spis, &spis_config, spis_event_handler));
      
    memset(m_rx_buf_1, 0, m_length);

    nrf_drv_spis_buffers_set(&spis, m_tx_buf_1, m_length, m_rx_buf_1, m_length);
}

void spi_sampling_event_init(void)
{
    ret_code_t err_code;
    
    nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(true);  // Initialize high
    
    err_code = nrf_drv_gpiote_out_init(GPIO_OUTPUT_PIN_NUMBER, &config); //CNVST
    
    // 159 = 100kHz
    nrf_drv_timer_extended_compare(&timer, NRF_TIMER_CC_CHANNEL0, 159, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);

    uint32_t gpiote_task_addr = nrf_drv_gpiote_out_task_addr_get(GPIO_OUTPUT_PIN_NUMBER); 

    uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&timer,NRF_TIMER_CC_CHANNEL0);
    
    uint32_t spi_start_task_addr   = nrf_drv_spi_start_task_get(&spi0);
    uint32_t spi_end_evt_addr = nrf_drv_spi_end_event_get(&spi0);

    err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_1);
    err_code = nrf_drv_ppi_channel_assign(ppi_channel_1, timer_compare_event_addr, gpiote_task_addr);
    err_code = nrf_drv_ppi_channel_fork_assign(ppi_channel_1, spi_start_task_addr);																				 																		 

    err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_2);
    err_code = nrf_drv_ppi_channel_assign(ppi_channel_2, spi_end_evt_addr, gpiote_task_addr);
}

void spi_sampling_event_enable(void)
{
    ret_code_t err_code;
    nrf_drv_gpiote_out_task_enable(GPIO_OUTPUT_PIN_NUMBER);
    err_code = nrf_drv_ppi_channel_enable(ppi_channel_1);
    err_code = nrf_drv_ppi_channel_enable(ppi_channel_2);
    nrf_drv_timer_enable(&timer);
}

void spi_sampling_event_disable(void)
{
    ret_code_t err_code;
    nrf_drv_gpiote_out_task_disable(GPIO_OUTPUT_PIN_NUMBER);
    err_code = nrf_drv_ppi_channel_disable(ppi_channel_1);
    err_code = nrf_drv_ppi_channel_disable(ppi_channel_2);
    nrf_drv_timer_disable(&timer);
}

I am developing on the nRF52832 dev kit with Segger Embedded Studio v6.30 using SDK v17.1.0.

Thanks,

Daragh

Related