SPI Communication Issue: Zephyr Driver Works, nrfx Driver Returns 0xFF

I'm having an issue with SPI communication. The problem is quite simple: if I use the Zephyr driver, everything works fine, but if I use the nrfx driver, it doesn't.
The function I call to read a register, Spi_Write_And_Read, using the Zephyr driver is:

&spi2 {
	compatible = "nordic,nrf-spim";
	status = "okay";
	pinctrl-0 = <&spi2_default>;
	pinctrl-1 = <&spi2_sleep>;
	pinctrl-names = "default", "sleep";
	cs-gpios = <&gpio0 24 GPIO_ACTIVE_LOW>;
	
	ad7779: ad7779@0 {
		compatible = "adi,ad7779";
		// compatible = "spi-device";
        reg = <0>;
        spi-max-frequency = <8000000>;
    };
};


static struct spi_dt_spec ad779SpiSpec = SPI_DT_SPEC_GET( DT_NODELABEL( ad7779 ), SPI_WORD_SET( 8 ) | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA, 0 );

spi_is_ready_dt( &ad779SpiSpec );

static int Spi_Write_And_Read( uint8_t *data, uint16_t len )
{
	const struct spi_buf spiTxBuff = { .buf = data, .len = len };
    const struct spi_buf spiRxBuff = { .buf = data, .len = len };
    const struct spi_buf_set tx = { .buffers = &spiTxBuff, .count = 1 };
    const struct spi_buf_set rx = { .buffers = &spiRxBuff, .count = 1 };

    return spi_transceive_dt( &ad779SpiSpec, &tx, &rx );
}

where *data is a pointer to a 2-byte buffer, with the first byte set to the value of the register I want to read, OR'ed with 0x80. This function works well and returns the buffer with the register value in the second byte.
However, if I modify the function to use:

&spi2 {
	compatible = "nordic,nrf-spim";
	status = "okay";
	pinctrl-0 = <&spi2_default>;
	pinctrl-1 = <&spi2_sleep>;
	pinctrl-names = "default", "sleep";
	cs-gpios = <&gpio0 24 GPIO_ACTIVE_LOW>;
	
	ad7779: ad7779@0 {
		compatible = "adi,ad7779";
		// compatible = "spi-device";
        reg = <0>;
        spi-max-frequency = <8000000>;
    };
};


static const nrfx_spim_t ad779SpiInstance = NRFX_SPIM_INSTANCE( 2 );
static nrfx_spim_config_t spiConfig = NRFX_SPIM_DEFAULT_CONFIG( AD7779_SCK_PIN, AD7779_MOSI_PIN, AD7779_MISO_PIN, AD7779_CS_PIN );

nrfx_spim_init( &ad779SpiInstance, &spiConfig, NULL, NULL );

static int Spi_Write_And_Read( uint8_t *data, uint16_t len )
{
    nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TRX( data, len, data, len );    
    nrfx_err_t err_code = nrfx_spim_xfer( &ad779SpiInstance, &xfer_desc, 0 );
    return ( err_code == NRFX_SUCCESS ) ? 0 : -1;
}

I only read 0xFF.
I checked with an oscilloscope and the SCK, MOSI, and MISO signals are identical in both cases. I'm starting to think it's a configuration issue, but I believe I've tried everything.
Do you have any suggestions?

Parents Reply Children
  • I wouldn't bet my life on it, but I checked both cases with the oscilloscope and the signals seem to be the same, including the timing. The MISO line carries the same signal. I tried configuring a pull-up/pull-down resistor in the MISO setup of the nrfx driver. I'm starting to think it might be an issue with how the buffers are handled—maybe they're somehow being reset when using nrfx.


  • Hi,

     

    Could you try to split the buffers, ie. uint8_t * data_tx and data_rx, and see if this helps?

     

    Kind regards,

    Håkon

  • I have this function that I use to read the registers of my AD7779 (Analog Devices driver):

    int32_t ad7779_spi_int_reg_read(ad7779_dev *dev,
    				uint8_t reg_addr,
    				uint8_t *reg_data)
    {
    	uint8_t buf[3];
    	uint8_t buf_size = 2;
    	uint8_t crc;
    	int32_t ret;
    
    	buf[0] = 0x80 | (reg_addr & 0x7F);
    	buf[1] = 0x00;
    	buf[2] = 0x00;
    	if (dev->spi_crc_en == AD7779_ENABLE)
    		buf_size = 3;
    	ret = dev->spi_transmit(buf, buf_size);
    	// ret = dev->spi_read(buf[0], &buf[1], buf_size - 1);
    
    	*reg_data = buf[1];
    	if (dev->spi_crc_en == AD7779_ENABLE) {
    		buf[0] = 0x80 | (reg_addr & 0x7F);
    		crc = ad7779_compute_crc8(&buf[0], 2);
    		if (crc != buf[2]) {
    			// LOG_WRN("%s: CRC Error.\n", __func__);
    			ret = -1;
    		}
    	}
    
    	return ret;
    }

    The dev->spi_transmit function is my Spi_Write_And_Read. When I use this configuration:

    static struct spi_dt_spec ad779SpiSpec = SPI_DT_SPEC_GET( DT_NODELABEL( ad7779 ), SPI_WORD_SET( 8 ) | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA, 0 );
    
    err = spi_is_ready_dt( &ad779SpiSpec );
    
    if ( !err )
    {
        LOG_WRN( "SPI Eeg Sensor is not ready, err: %d", err );
        Error_Managing_Signal( SYSTEM_ERROR_INIT_EEG, __FILE__, __LINE__ );
        return SYSTEM_ERROR;
    }
    
    static int Spi_Write_And_Read( uint8_t *data, uint16_t len )
    {
    	const struct spi_buf txBuff = { .buf = data, .len = len };
        const struct spi_buf rxBuff = { .buf = data, .len = len };
        const struct spi_buf_set tx = { .buffers = &txBuff, .count = 1 };
        const struct spi_buf_set rx = { .buffers = &rxBuff, .count = 1 };
    
        return spi_transceive_dt( &ad779SpiSpec, &tx, &rx );
    }

    everything works.

    But if I use this alternative setup:

    static const nrfx_spim_t ad779SpiInstance = NRFX_SPIM_INSTANCE( 2 );
    static nrfx_spim_config_t spiConfig = NRFX_SPIM_DEFAULT_CONFIG( AD7779_SCK_PIN, AD7779_MOSI_PIN, AD7779_MISO_PIN, AD7779_CS_PIN );
    
    spiConfig.frequency = NRFX_MHZ_TO_HZ( 8 );
    spiConfig.mode = NRF_SPIM_MODE_3;
    spiConfig.bit_order = NRF_SPIM_BIT_ORDER_MSB_FIRST;
    
    if ( nrfx_spim_init( &ad779SpiInstance, &spiConfig, NULL, NULL ) != NRFX_SUCCESS )
    {
        Error_Managing_Signal( SYSTEM_ERROR_INIT_EEG, __FILE__, __LINE__ );
        return SYSTEM_ERROR;
    }
    
    static int Spi_Write_And_Read( uint8_t *data, uint16_t len )
    {
    	nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TRX( data, len, data, len );    
        nrfx_err_t err_code = nrfx_spim_xfer( &ad779SpiInstance, &xfer_desc, 0 );
        return ( err_code == NRFX_SUCCESS ) ? 0 : -1;
    }

    it no longer works, and ad7779_spi_int_reg_read returns 0xFF in reg_data.

    If I instead implement the function like this:

    static int Spi_Write_And_Read( uint8_t *data, uint16_t len )
    {
    	uint8_t dataTx[ len ];
        uint8_t dataRx[ len ];
        memcpy( dataTx, data, len );
        memset( dataRx, 0, len );
    
        LOG_WRN( "dataTx 0x%X 0x%X", dataTx[ 0 ], dataTx[ 1 ] );
        LOG_WRN( "dataRx 0x%X 0x%X", dataRx[ 0 ], dataRx[ 1 ] );
        nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TRX( dataTx, len, dataRx, len );    
        nrfx_err_t err_code = nrfx_spim_xfer( &ad779SpiInstance, &xfer_desc, 0 );
        LOG_WRN( "dataTx 0x%X 0x%X", dataTx[ 0 ], dataTx[ 1 ] );
        LOG_WRN( "dataRx 0x%X 0x%X", dataRx[ 0 ], dataRx[ 1 ] );
        return ( err_code == NRFX_SUCCESS ) ? 0 : -1;
    }

    I get the following output:

    00> [00:00:02.695,739] <wrn> adc: dataTx 0x91 0x0
    00> [00:00:02.695,739] <wrn> adc: dataRx 0x0 0x0
    00> [00:00:02.695,770] <wrn> adc: dataTx 0x91 0x0
    00> [00:00:02.695,800] <wrn> adc: dataRx 0xFF 0xFF

    Do you have any advice on what else I could try?

  • Hi,

     

    It is unclear to me what is the expected result.

    Q1: Could you share what value you expect to read?

     

    Q2: Could you also share a scope plot of the communication?

    As it is the MISO pin that is, as far as I understand, not reading correct, it would be interesting to see if the sensor shifts out correctly.

     

    Q3: What is the physical pin out that you use? Please share what AD7779_MISO_PIN is and what your pinctrl entries for spi2 are.

     

    Kind regards,

    Håkon

Related