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

Testing variations of int num_events & k_timeout_t timeout arguments in k_poll API for "spi_transceive_async"

Hello,

Let me just briefly state that I have referred to required documentation and also executed spi_transceive_async() test, at zephyr\tests\drivers\spi\spi_loopback.
So request to kindly not suggest going back to documentation or trying sample program.

My question is I want to test  variations of int num_events & k_timeout_t timeout arguments in k_poll API for "spi_transceive_async".

As in what happens if i vary num_events  & what happens  if i vary timeout ...?

And how can I get this variation to reflect on "spi_transceive_async"..?

I need to know how to vary and test the sample code at zephyr\tests\drivers\spi\spi_loopback:
As In,

#if (CONFIG_SPI_ASYNC)
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);
static K_SEM_DEFINE(caller, 0, 1);
K_THREAD_STACK_DEFINE(spi_async_stack, STACK_SIZE);
static int result = 1;

static void spi_async_call_cb(struct k_poll_event *async_evt,
			      struct k_sem *caller_sem,
			      void *unused)
{
	int ret;

	LOG_DBG("Polling...");

	while (1) {
		ret = k_poll(async_evt, 10, K_MSEC(2000)); /***** varied here ******/
		zassert_false(ret, "one or more events are not ready");

		result = async_evt->signal->result;
		k_sem_give(caller_sem);

		/* Reinitializing for next call */
		async_evt->signal->signaled = 0U;
		async_evt->state = K_POLL_STATE_NOT_READY;
	}
}

static int spi_async_call(const struct device *dev,
			  struct spi_config *spi_conf)
{
	const struct spi_buf tx_bufs[] = {
		{
			.buf = buffer_tx,
			.len = BUF_SIZE,
		},
	};
	const struct spi_buf rx_bufs[] = {
		{
			.buf = buffer_rx,
			.len = BUF_SIZE,
		},
	};
	const struct spi_buf_set tx = {
		.buffers = tx_bufs,
		.count = ARRAY_SIZE(tx_bufs)
	};
	const struct spi_buf_set rx = {
		.buffers = rx_bufs,
		.count = ARRAY_SIZE(rx_bufs)
	};
	int ret;

	LOG_INF("Start async call");

	ret = spi_transceive_async(dev, spi_conf, &tx, &rx, &async_sig);
	if (ret == -ENOTSUP) {
		LOG_DBG("Not supported");
		return 0;
	}

	if (ret) {
		LOG_ERR("Code %d", ret);
		zassert_false(ret, "SPI transceive failed");
		return -1;
	}

	k_sem_take(&caller, K_FOREVER);

	if (result)  {
		LOG_ERR("Call code %d", ret);
		zassert_false(result, "SPI transceive failed");
		return -1;
	}

	LOG_INF("Passed");

	return 0;
}
#endif

Thanking you in anticipation,

Parents
  • Test the following code:

    spi_loopback_async.zip

    I don't have an nRF52833 DK, so I tested it on an nRF52840 DK. You need to add an overlay file nrf52833dk_nrf52833.overlay and modify SPI_DRV_NAME in main.c.

    If the program runs as expected, you should get the following output:

    *** Booting Zephyr OS build v2.7.99-ncs1-rc2  ***
    Polling...
    SPI test on buffers TX/RX 0x20000280/0x20000d70
    Start async call
    Polling...
    Sent: '0123456789abcdef' |||  Received: '0123456789abcdef'
    SPI test on buffers TX/RX 0x20000280/0x20000d70
    Start async call
    Polling...
    Sent: '0123456789abcdef' |||  Received: '0123456789abcdef'
    SPI test on buffers TX/RX 0x20000280/0x20000d70
    Start async call
    Polling...
    Sent: '0123456789abcdef' |||  Received: '0123456789abcdef'
    

Reply
  • Test the following code:

    spi_loopback_async.zip

    I don't have an nRF52833 DK, so I tested it on an nRF52840 DK. You need to add an overlay file nrf52833dk_nrf52833.overlay and modify SPI_DRV_NAME in main.c.

    If the program runs as expected, you should get the following output:

    *** Booting Zephyr OS build v2.7.99-ncs1-rc2  ***
    Polling...
    SPI test on buffers TX/RX 0x20000280/0x20000d70
    Start async call
    Polling...
    Sent: '0123456789abcdef' |||  Received: '0123456789abcdef'
    SPI test on buffers TX/RX 0x20000280/0x20000d70
    Start async call
    Polling...
    Sent: '0123456789abcdef' |||  Received: '0123456789abcdef'
    SPI test on buffers TX/RX 0x20000280/0x20000d70
    Start async call
    Polling...
    Sent: '0123456789abcdef' |||  Received: '0123456789abcdef'
    

Children
  • Hello ,

    Thank you for the suggestion, with minor timeout tweaks in the code you helped me with, I was able to get polling happen more than once.

    /*
     * Copyright (c) 2017 Intel Corporation.
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    //#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
    //#include <logging/log.h>
    //LOG_MODULE_REGISTER(main);
    
    #include <zephyr.h>
    #include <sys/printk.h>
    #include <string.h>
    #include <stdio.h>
    //#include <ztest.h>
    
    #include <drivers/spi.h>
    
    #define SPI_DRV_NAME	"SPI_0"
    #define SPI_SLAVE	0
    #define FAST_FREQ	16000000
    
    #define CS_CTRL_GPIO_DRV_NAME "GPIO_0"
    struct spi_cs_control spi_cs = {
    	.gpio_pin = 28,
    	.gpio_dt_flags = GPIO_ACTIVE_LOW,
    	.delay = 0,
    };
    #define SPI_CS (&spi_cs)
    
    
    /* to run this test, connect MOSI pin to the MISO of the SPI */
    
    #define STACK_SIZE 512
    #define BUF_SIZE 17
    #define BUF2_SIZE 36
    
    
    /* this src memory shall be in RAM to support using as a DMA source pointer.*/
    uint8_t buffer_tx[] = "0123456789abcdef\0";
    uint8_t buffer_rx[BUF_SIZE] = {0};
    
    
    struct spi_config spi_cfg_fast = {
    	.frequency = FAST_FREQ,
    #if CONFIG_SPI_LOOPBACK_MODE_LOOP
    	.operation = SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_LOOP |
    #else
    	.operation = SPI_OP_MODE_MASTER | SPI_MODE_CPOL |
    #endif
    	SPI_MODE_CPHA | SPI_WORD_SET(8) | SPI_LINES_SINGLE,
    	.slave = SPI_SLAVE,
    	.cs = SPI_CS,
    };
    
    static int cs_ctrl_gpio_config(void)
    {
    	spi_cs.gpio_dev = device_get_binding(CS_CTRL_GPIO_DRV_NAME);
    	if (!spi_cs.gpio_dev) {
    		printk("Cannot find %s!\n", CS_CTRL_GPIO_DRV_NAME);
    		//zassert_not_null(spi_cs.gpio_dev, "Invalid gpio device");
    	}
    
    	return 0;
    }
    
    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);
    static K_SEM_DEFINE(caller, 0, 1);
    K_THREAD_STACK_DEFINE(spi_async_stack, STACK_SIZE);
    static int result = 1;
    
    static void spi_async_call_cb(struct k_poll_event *async_evt,
    			      struct k_sem *caller_sem,
    			      void *unused)
    {
    	int ret;
    
    	
    
    	while (1) {
    		printk("Polling...\n");
    		ret = k_poll(async_evt, 1, K_MSEC(1000));
    		result = async_evt->signal->result;
    		k_sem_give(caller_sem);
    
    		/* Reinitializing for next call */
    		async_evt->signal->signaled = 0U;
    		async_evt->state = K_POLL_STATE_NOT_READY;
    	}
    }
    
    static int spi_async_call(const struct device *dev,
    			  struct spi_config *spi_conf)
    {
    	const struct spi_buf tx_bufs[] = {
    		{
    			.buf = buffer_tx,
    			.len = BUF_SIZE,
    		},
    	};
    	const struct spi_buf rx_bufs[] = {
    		{
    			.buf = buffer_rx,
    			.len = BUF_SIZE,
    		},
    	};
    	const struct spi_buf_set tx = {
    		.buffers = tx_bufs,
    		.count = ARRAY_SIZE(tx_bufs)
    	};
    	const struct spi_buf_set rx = {
    		.buffers = rx_bufs,
    		.count = ARRAY_SIZE(rx_bufs)
    	};
    	int ret;
    
    	printk("Start async call\n");
    
    	ret = spi_transceive_async(dev, spi_conf, &tx, &rx, &async_sig);
    	if (ret == -ENOTSUP) {
    		printk("Not supported\n");
    	}
    
    	if (ret) {
    		printk("spi_transceive_async failed %d\n", ret);
    	}
    
    	k_sem_take(&caller, K_FOREVER);
    
    	if (result)  {
    		printk("async_evt->signal returned %d\n", ret);
    	}
    	printk("Sent: '%s'\n", buffer_tx);
    	printk("received:");
    	for(int i=0; i<BUF_SIZE; i++)
    	{
    		printk(" %c",buffer_rx[i]);
    	}
    
    	return 0;
    }
    
    
    void spi_loopback(void)
    {
    	
    	const struct device *spi_fast;
    
    	printk("SPI test on buffers TX/RX %p/%p\n", buffer_tx, buffer_rx);
    
    	if (cs_ctrl_gpio_config()) {
    		return;
    	}
    
    	spi_fast = device_get_binding(SPI_DRV_NAME);
    	if (!spi_fast) {
    		printk("Cannot find %s!\n", SPI_DRV_NAME);
    	}
    
    	spi_async_call(spi_fast, &spi_cfg_fast);
    
    }
    
    void main(void)
    {
    	struct k_thread async_thread;
    	k_tid_t async_thread_id;
    	async_thread_id = k_thread_create(&async_thread,
    					spi_async_stack, STACK_SIZE,
    					(k_thread_entry_t)spi_async_call_cb,
    					&async_evt, &caller, NULL,
    					K_PRIO_COOP(7), 0, K_NO_WAIT);
    	while(true){
    		spi_loopback();
    		k_sleep(K_MSEC(5000));
    	}
    }
    

    Output:

    This helps, I just need your kind help in understanding what is happening here in the code with the way polling & async API is executing.

    I am to understand that there are two threads here:

    1. async_thread_id

    2. main thread


    Thread 1, the async thread is responsible to poll once every 1000ms as I have edited the code to

    ret = k_poll(async_evt, 1, K_MSEC(1000));

    Every 1000ms I am seeing the printed "Polling".


    Thread 2, being the main thread, is running in a while loop and calling the async spi api once every 5000ms as I have edited the code to:
    	while(true){
    		spi_loopback();
    		k_sleep(K_MSEC(5000));
    	}

    accordingly I am seeing data TX-RX every 5000ms in the console.

    Is this how polling should work..?

    That is In two different threads..?

    I was under the impression that since async_sig is registered with async SPI API, async_sig will poll & trigger the async API every 1000ms as in this case.

    Kindly help me understand.

    Thanking you,

    Ubaid

  • I added some illustrations to demonstrate how I understand how it works:

    Hopefully it's more clear now

    So k_poll() is just a way to know that spi_transceive has completed, so you can read the received data in buffer_tx. If you try to read it before spi_transceive_async() has completeted you can not read it.

Related