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 spi asynchronus api transfer with asymmetric buffers error

Hi,

Zephyr 3.0 , nrf5340  ncs 1.9.1 

i can successfully sent data with

this function ; 
int adxl362ext_get_fifo_data(const struct device *dev,uint8_t *read_buf, uint16_t count,struct k_poll_signal *signal_)
{
	const struct adxl362ext_config *cfg = dev->config;
	int err;
	uint8_t access[1] = { ADXL362EXT_READ_FIFO};
	const struct spi_buf buf[2] = {
		{
			.buf = access,
			.len = 1
		},
		{
			.buf = read_buf,
			.len = count
		}
	};
	struct spi_buf_set tx = {
		.buffers = buf,
		.count = 1
	};

	const struct spi_buf_set rx = {
		.buffers = buf,
		.count = 2
	};
	err = spi_transceive_dt(&cfg->bus,&tx, &rx);
	//err = spi_transceive_async_dt(&cfg->bus,&tx, &rx,signal_);
	return err;
}
So it sends 2 transactions without changing cs state.
1byte tx+rx  , and remaining rx bytes at the second transaction.. all works as expected.
but if i try async transceive function with these the same buffers / buffersets , i got kpoll event signal result as  -5 error ...
update: i could get 0 (success) but again it only sends the first buffers in the buffer set . 
if count is 1 in the buffer set , it works, but if count is 2 only the first parts fires. 
this is the debugger watch after the first chunk transferred. so this is the second chunk and it says 0 for rx and tx buffers.
if i use synchronous spi these chunks points the initial buffer address...
static inline int spi_transceive_async_dt(const struct spi_dt_spec *spec,
				    const struct spi_buf_set *tx_bufs,
				    const struct spi_buf_set *rx_bufs,struct k_poll_signal *signal_)
{
	return spi_transceive_async(spec->bus, &spec->config, tx_bufs, rx_bufs,signal_);
}
i tested with symmetric buffers, and it worked! 
one more finding , may be this helps to find out the issue ; 
void spi_context_update_rx(struct spi_context *ctx, uint8_t dfs, uint32_t len)
{
#ifdef CONFIG_SPI_SLAVE
	if (spi_context_is_slave(ctx)) {
		ctx->recv_frames += len;
	}

#endif /* CONFIG_SPI_SLAVE */

	if (!ctx->rx_len) {
		return;
	}
if(len>100){
volatile int oo;
oo=0;
}
	if (len > ctx->rx_len) {
		LOG_ERR("Update exceeds current buffer");
		return;
	}

	ctx->rx_len -= len;
	if (!ctx->rx_len) {
		/* Current buffer is done. Get the next one to be processed. */
		++ctx->current_rx;
		--ctx->rx_count;
		ctx->rx_buf = (uint8_t *)
			spi_context_get_next_buf(&ctx->current_rx,
						 &ctx->rx_count,
						 &ctx->rx_len, dfs);
	} else if (ctx->rx_buf) {
		ctx->rx_buf += dfs * len;
	}

	LOG_DBG("rx buf/len %p/%zu", ctx->rx_buf, ctx->rx_len);
}
i have added this code to make a breakpoint for debugger in spi_context_update_rx(struct spi_context *ctx, uint8_t dfs, uint32_t len) function( as you can see above. line 13)
if(len>100){
volatile int oo;
oo=0;
}
I set my second buffer length as 256
	uint8_t access[1] = { ADXL362EXT_READ_FIFO};
	const struct spi_buf buf[2] = {
		{
			.buf = access,
			.len = 1
		},
		{
			.buf = read_buf,
			.len = 256
		}
	};
	struct spi_buf_set tx = {
		.buffers = buf,
		.count = 1
	};

	const struct spi_buf_set rx = {
		.buffers = buf,
		.count = 2
	};
	#if(CONFIG_SPI_ASYNC)
	err = spi_transceive_async_dt(&cfg->bus,&tx, &rx,signal_);
	#else
If i transfer these buffers with this function ;
spi_transceive_async_dt(&cfg->bus,&tx, &rx,signal_);
debugger will never stop at  len>100 condition;
if i transfer the same buffer with 
err = spi_transceive_dt(&cfg->bus,&tx, &rx);
debugger stops at break point and , i can see len is 256...
So i check the documentation i couldn't find any information about this issue.
How can we use asymmetric buffer/sets with asynchronous spi api ?
Thanks.
Parents
  • Hi Mehmet

    I don't seem to have any issues with this on my side. I can use the spi_transceive_async functions whether or not I have the same number of TX and RX buffers. 

    Please find my main.c file attached:

    /*
     * Copyright (c) 2016 Intel Corporation
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr.h>
    #include <device.h>
    #include <devicetree.h>
    #include <drivers/gpio.h>
    #include <drivers/spi.h>
    
    /* 1000 msec = 1 sec */
    #define SLEEP_TIME_MS   1000
    
    /* The devicetree node identifier for the "led0" alias. */
    #define LED0_NODE DT_ALIAS(led0)
    
    #if DT_NODE_HAS_STATUS(LED0_NODE, okay)
    #define LED0	DT_GPIO_LABEL(LED0_NODE, gpios)
    #define PIN	DT_GPIO_PIN(LED0_NODE, gpios)
    #define FLAGS	DT_GPIO_FLAGS(LED0_NODE, gpios)
    #else
    /* A build error here means your board isn't set up to blink an LED. */
    #error "Unsupported board: led0 devicetree alias is not defined"
    #define LED0	""
    #define PIN	0
    #define FLAGS	0
    #endif
    
    #define PIN1 DT_GPIO_PIN(DT_ALIAS(led1), gpios)
    
    static const struct spi_config spi_cfg = {
    	.operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB |
    		     SPI_MODE_CPOL | SPI_MODE_CPHA,
    	.frequency = 4000000,
    	.slave = 0,
    };
    
    const struct device * spi_dev;
    
    static void spi_init(void)
    {
    	const char* const spiName = "SPI_2";
    	spi_dev = device_get_binding(spiName);
    
    	if (spi_dev == NULL) {
    		printk("Could not get %s device\n", spiName);
    		return;
    	}
    }
    
    const struct device *dev;
    
    static struct k_poll_signal async_sig = K_POLL_SIGNAL_INITIALIZER(async_sig);
    static struct k_poll_event  async_evt =
    	K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
    				 K_POLL_MODE_NOTIFY_ONLY,
    				 &async_sig);
    
    void spi_test_send(void)
    {
    	int err;
    	static uint8_t tx_buffer1[4] = {1,2,3,4};
    	static uint8_t tx_buffer2[3] = {2,3,4};
    	static uint8_t rx_buffer[2];
    	static uint8_t rx_buffer2[4];
    
    	const struct spi_buf tx_buf[2] = {{
    		.buf = tx_buffer1,
    		.len = sizeof(tx_buffer1)}, {
    		.buf = tx_buffer2, 
    		.len = sizeof(tx_buffer2)}
    	};
    	const struct spi_buf_set tx = {
    		.buffers = tx_buf,
    		.count = 1
    	};
    
    	struct spi_buf rx_buf[2] = {{
    		.buf = rx_buffer,
    		.len = sizeof(rx_buffer)},{
    		.buf = rx_buffer2,
    		.len = sizeof(rx_buffer2)}
    	};
    	const struct spi_buf_set rx = {
    		.buffers = rx_buf,
    		.count = 2
    	};
    	
    	//err = spi_transceive(spi_dev, &spi_cfg, &tx, &rx);
    	err = spi_transceive_async(spi_dev, &spi_cfg, &tx, &rx, &async_sig);
    
    	if (err) {
    		printk("SPI error: %d\n", err);
    		return;
    	}
    	// Waiting for event to occur
    	err = k_poll(&async_evt, 1, K_MSEC(100));
    	if (err) {
    		printk("Failed waiting for SPI async event\n");
    	} else {
    		printk("SPI complete!\n");
    		printk("TX sent: %x-%x-%x-%x\n", tx_buffer1[0], tx_buffer1[1], tx_buffer1[2], tx_buffer1[3]);
    		printk("RX recv: %x-%x\n", rx_buffer[0], rx_buffer[1]);
    		printk("RX2 recv: %x-%x\n", rx_buffer2[0], rx_buffer2[1]);
    		tx_buffer1[0]++;
    		tx_buffer1[1]++;
    		tx_buffer1[2]++;
    	}
    }
    
    void main(void)
    {
    	bool led_is_on = true;
    	int ret;
    
    	printk("SPI async test\n");
    
    	dev = device_get_binding(LED0);
    	if (dev == NULL) {
    		return;
    	}
    
    	ret = gpio_pin_configure(dev, PIN, GPIO_OUTPUT_ACTIVE | FLAGS);
    	if (ret < 0) {
    		return;
    	}
    
    	ret = gpio_pin_configure(dev, PIN1, GPIO_OUTPUT_ACTIVE | FLAGS);
    	if (ret < 0) {
    		return;
    	}
    
    	spi_init();
    
    	while (1) {
    		gpio_pin_set(dev, PIN, (int)led_is_on);
    		led_is_on = !led_is_on;
    		spi_test_send();
    		k_msleep(SLEEP_TIME_MS);
    	}
    }
    

    Are you sure you are setting up the poll signal and event correctly?

    How are you polling the signal after starting the SPI transaction?

    Best regards
    Torbjørn

Reply
  • Hi Mehmet

    I don't seem to have any issues with this on my side. I can use the spi_transceive_async functions whether or not I have the same number of TX and RX buffers. 

    Please find my main.c file attached:

    /*
     * Copyright (c) 2016 Intel Corporation
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr.h>
    #include <device.h>
    #include <devicetree.h>
    #include <drivers/gpio.h>
    #include <drivers/spi.h>
    
    /* 1000 msec = 1 sec */
    #define SLEEP_TIME_MS   1000
    
    /* The devicetree node identifier for the "led0" alias. */
    #define LED0_NODE DT_ALIAS(led0)
    
    #if DT_NODE_HAS_STATUS(LED0_NODE, okay)
    #define LED0	DT_GPIO_LABEL(LED0_NODE, gpios)
    #define PIN	DT_GPIO_PIN(LED0_NODE, gpios)
    #define FLAGS	DT_GPIO_FLAGS(LED0_NODE, gpios)
    #else
    /* A build error here means your board isn't set up to blink an LED. */
    #error "Unsupported board: led0 devicetree alias is not defined"
    #define LED0	""
    #define PIN	0
    #define FLAGS	0
    #endif
    
    #define PIN1 DT_GPIO_PIN(DT_ALIAS(led1), gpios)
    
    static const struct spi_config spi_cfg = {
    	.operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB |
    		     SPI_MODE_CPOL | SPI_MODE_CPHA,
    	.frequency = 4000000,
    	.slave = 0,
    };
    
    const struct device * spi_dev;
    
    static void spi_init(void)
    {
    	const char* const spiName = "SPI_2";
    	spi_dev = device_get_binding(spiName);
    
    	if (spi_dev == NULL) {
    		printk("Could not get %s device\n", spiName);
    		return;
    	}
    }
    
    const struct device *dev;
    
    static struct k_poll_signal async_sig = K_POLL_SIGNAL_INITIALIZER(async_sig);
    static struct k_poll_event  async_evt =
    	K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
    				 K_POLL_MODE_NOTIFY_ONLY,
    				 &async_sig);
    
    void spi_test_send(void)
    {
    	int err;
    	static uint8_t tx_buffer1[4] = {1,2,3,4};
    	static uint8_t tx_buffer2[3] = {2,3,4};
    	static uint8_t rx_buffer[2];
    	static uint8_t rx_buffer2[4];
    
    	const struct spi_buf tx_buf[2] = {{
    		.buf = tx_buffer1,
    		.len = sizeof(tx_buffer1)}, {
    		.buf = tx_buffer2, 
    		.len = sizeof(tx_buffer2)}
    	};
    	const struct spi_buf_set tx = {
    		.buffers = tx_buf,
    		.count = 1
    	};
    
    	struct spi_buf rx_buf[2] = {{
    		.buf = rx_buffer,
    		.len = sizeof(rx_buffer)},{
    		.buf = rx_buffer2,
    		.len = sizeof(rx_buffer2)}
    	};
    	const struct spi_buf_set rx = {
    		.buffers = rx_buf,
    		.count = 2
    	};
    	
    	//err = spi_transceive(spi_dev, &spi_cfg, &tx, &rx);
    	err = spi_transceive_async(spi_dev, &spi_cfg, &tx, &rx, &async_sig);
    
    	if (err) {
    		printk("SPI error: %d\n", err);
    		return;
    	}
    	// Waiting for event to occur
    	err = k_poll(&async_evt, 1, K_MSEC(100));
    	if (err) {
    		printk("Failed waiting for SPI async event\n");
    	} else {
    		printk("SPI complete!\n");
    		printk("TX sent: %x-%x-%x-%x\n", tx_buffer1[0], tx_buffer1[1], tx_buffer1[2], tx_buffer1[3]);
    		printk("RX recv: %x-%x\n", rx_buffer[0], rx_buffer[1]);
    		printk("RX2 recv: %x-%x\n", rx_buffer2[0], rx_buffer2[1]);
    		tx_buffer1[0]++;
    		tx_buffer1[1]++;
    		tx_buffer1[2]++;
    	}
    }
    
    void main(void)
    {
    	bool led_is_on = true;
    	int ret;
    
    	printk("SPI async test\n");
    
    	dev = device_get_binding(LED0);
    	if (dev == NULL) {
    		return;
    	}
    
    	ret = gpio_pin_configure(dev, PIN, GPIO_OUTPUT_ACTIVE | FLAGS);
    	if (ret < 0) {
    		return;
    	}
    
    	ret = gpio_pin_configure(dev, PIN1, GPIO_OUTPUT_ACTIVE | FLAGS);
    	if (ret < 0) {
    		return;
    	}
    
    	spi_init();
    
    	while (1) {
    		gpio_pin_set(dev, PIN, (int)led_is_on);
    		led_is_on = !led_is_on;
    		spi_test_send();
    		k_msleep(SLEEP_TIME_MS);
    	}
    }
    

    Are you sure you are setting up the poll signal and event correctly?

    How are you polling the signal after starting the SPI transaction?

    Best regards
    Torbjørn

Children
Related