nRF5 SDK is not maintained anymore
More Info: Consider nRF Connect SDK for new designs
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Zephyr nrf5340 cpu app SPI1 burst read missing byte

Hi,

I am trying to burst read FIFO of ADXL362 with zephyr adxl362 sample. 1 byte tx (read fifo command) and n byte rx ( reading the fifo data);

Zephyr is the last version 3.0 , ncs is 1.9.1   , mcu is nrf5340 app s

i write this function to set a spi transaction is like this ; 

adxl362.c

#define ADXL362_READ_FIFO          0x0D
int adxl362ext_get_fifo_data(const struct device *dev,uint8_t *read_buf, uint8_t count)
{
	const struct adxl362ext_config *cfg = dev->config;
	uint8_t access[1] = { ADXL362_READ_FIFO};
volatile int i=1,m=9;
	const struct spi_buf txbuf =
	{
			.buf = access,
			.len = 1
	};

	const struct spi_buf_set tx = {
		.buffers = &txbuf,
		.count = 1
	};	

	const struct spi_buf rxbuf =	{
			.buf = read_buf,
			.len = count
	};

	const struct spi_buf_set rx = {
		.buffers = &rxbuf,
		.count = 1
	};

	return spi_transceive_dt(&cfg->bus, &tx, &rx);
}

i call it from the standard function comes with the adxl362 sample ; 

adxl362_trigger.c

uint8_t Acc_Data[400];

static void adxl362_thread_cb(const struct device *dev)
{
	struct adxl362_data *drv_data = dev->data;
	uint8_t status_buf;

	/* Clears activity and inactivity interrupt */
	if (adxl362_get_status(dev, &status_buf)) {
		LOG_ERR("Unable to get status.");
		return;
	}

	k_mutex_lock(&drv_data->trigger_mutex, K_FOREVER);
	if (drv_data->th_handler != NULL) {
		if (ADXL362_STATUS_CHECK_INACT(status_buf) ||
		    ADXL362_STATUS_CHECK_ACTIVITY(status_buf)) {
			drv_data->th_handler(dev, &drv_data->th_trigger);
		}
	}

	if (drv_data->drdy_handler != NULL &&
	    ADXL362_STATUS_CHECK_DATA_READY(status_buf)) {
		drv_data->drdy_handler(dev, &drv_data->drdy_trigger);
	}

	
	adxl362ext_get_fifo_data(dev,(uint8_t *)&Acc_Data,7);

	k_mutex_unlock(&drv_data->trigger_mutex);
}

Result is like this ; 
Debug:

I can also verify by logic analyzer 1 byte is missing from the original count. 

If i set it to 1 , i can not see any spi clocks for rx buffer.

If i set it to 6 , i can see that spi will be clocked out for 5 bytes.

I couldn't locate the code makes it from 7 to 6, or 6 to 5  or n  to n-1 .

Thanks

Parents Reply
  • Are you able to provide some simple project I may run on an nRF5340-DK that I can run to replicate this? I assume the adxl362 is not needed to show the problem. 

    Just to avoid any confusion , I assume you understand that the amount register will be set to the length of rxbuf or txbuf, whichever is longest, and not an addition of the two. This because the two buffers run in paralell and not after eachother.

    Kenneth

Children
  • This because the two buffers run in paralell and not after eachother.

    i will create small project but , i think you have already clarified it.

    this 

    spi_transceive(spec->bus, &spec->config, tx_bufs, rx_bufs);
      , i work with nrf52 and sdk15-17 before but it seems zephyr drivers are implemented slightly different than old ones. 

    Previous projects with SES, i was using this one ( not with zephyr ) and if i remember correctly , it was sending tx then getting the rx to the buffer....It was not writing to the rx buffers during the tx time. 

     	nrf_drv_spi_xfer (nrf_drv_spi_t const *const p_instance, nrf_drv_spi_xfer_desc_t const *p_xfer_desc, uint32_t flags)
     	
     	
     with 

      NRFX_SPI_XFER_TRX

    But as you said  zephyr driver runs tx rx in parallel. (maybe even before the zephyr, those nrf spi drivers were running the buffer in parallel, i am not sure ). but i was getting only rx data in rx buffer.

    Now i tested zephyr driver ,yes it overwrites the 1st rx buffer when sending the tx bytes, then overwrites to 2nd  rx buffer....and i guess if i provide only one rx buffer during the tx&rx transaction it recalculates rx count and filling rx maxcnt counter accordingly... So it divides only one rx buffer for two parts automatically...As i remember previous non zephyr drivers were not behaving like this.

    If this is true, i was wondering about  huge gap between tx and rx transactions for zephyr nrf spi driver, so it means cpu switching those buffer arrays between &tx and &rx transactions.... as i remember it was not like that before  for sdk14-15 at least . so zephyr using something like "transaction manager" style driver i guess...

  • I found the driver code  and i can say they put extra buffer switch things into spi driver , so zephyr driver is not just  like nrfx_spim_xfer( , actually it still uses nrfx_spim_xfer but there is much more such as ; 

    it looks like "transaction manager" stye driver.

     

    static inline void *spi_context_get_next_buf(const struct spi_buf **current,
    					     size_t *count,
    					     size_t *buf_len,
    					     uint8_t dfs)
    {
    	/* This loop skips zero-length buffers in the set, if any. */
    	while (*count) {
    		if (((*current)->len / dfs) != 0) {
    			*buf_len = (*current)->len / dfs;
    			return (*current)->buf;
    		}
    		++(*current);
    		--(*count);
    	}
    
    	*buf_len = 0;
    	return NULL;
    }
     

    		++(*current);
    		--(*count);

    static void event_handler(const nrfx_spim_evt_t *p_event, void *p_context)
    {
    	struct spi_nrfx_data *dev_data = p_context;
    
    	if (p_event->type == NRFX_SPIM_EVENT_DONE) {
    #ifdef CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58
    		anomaly_58_workaround_clear(dev_data);
    #endif
    		spi_context_update_tx(&dev_data->ctx, 1, dev_data->chunk_len);
    		spi_context_update_rx(&dev_data->ctx, 1, dev_data->chunk_len);
    
    		transfer_next_chunk(dev_data->dev);
    	}
    }

  • I think you understand what is occuring now, so I don't think there is anything I can add, but just to clarify a bit on how it works:

    In SPI there is a clock signal that synchronously output/input the MOSI (from tx_buf)/MISO(to rx_buf) signals, this is done in parallel by hardware. It should always have been this, though it might have been small changes whether the entire transaction was handled in one transfer and/or on byte level depending on the software/hardware implementation. Depending on the driver/library it might have been that the above described low level buffering was masked out on higher abstraction layers (e.g. that you didn't observe that the low level hardware buffer was +1 byte).

    Best regards,
    Kenneth

Related