Hello !
I'm currently working on a SPI slave implementation for the nRF54L15.
I already read the spi-master-slave example.
The idea atm is basic and as follow :
My slave needs to listen if the master sent anything. If not, nothing happens.
If he received something, I'll do some operations on the received message.
On the other side, if my slave wants to send something, he triggers a WAKE GPIO that tells the master to clock.
He then send his message with spi_transceive_signal() and wait for the tx completion.
I have a thread running called "listening" that calls spi_read_signal().
In the main, I check either spi_read_signal() changed the poll signal.
If it changed it, I print the message and reset the signal_poll value.
It's pretty much the same thing as the example except that I want to read periodically.
The code for now is the following :
main.c :
#include <zephyr/kernel.h> #include <zephyr/device.h> #include <zephyr/devicetree.h> #include <zephyr/drivers/gpio.h> #include <zephyr/drivers/spi.h> #include <zephyr/logging/log.h> #include "svc_spi_nrf54.h" #include "drv_spi_nrf54.h" LOG_MODULE_REGISTER(spi_slave_log); #define SLEEP_TIME_MS 500 #define STACKSIZE 1024 #define THREADSPI_PRIORITY 7 #define SLEEPTIME 1000 void thread_spi_listening(void){ while(1){ LOG_INF("SPI THREAD!"); svc_nrf_listening_rx_v(); k_msleep(SLEEPTIME); } } K_THREAD_DEFINE(thread_spi_id, STACKSIZE, thread_spi_listening, NULL, NULL, NULL, THREADSPI_PRIORITY, 0, 0); int main(void){ svc_nrf_spi_init_v(); LOG_INF("SPI SLAVE STARTED !"); while(1){ LOG_INF("MAIN LOOP !"); svc_nrf_spi_hdlr_v(); k_sleep(K_MSEC(SLEEP_TIME_MS)); } }
svc calls the following :
void svc_nrf_spi_hdlr_v(){ rx_raised = drv_nrf_msg_check_u8(); if(rx_raised != 0){ //We received a msg. LOG_HEXDUMP_INF(spi_buffer_u8, sizeof(spi_buffer_u8),"MSG RECEIVED !"); drv_nrf_reset_rx_v(); } } void svc_nrf_listening_rx_v(){ if(rx_raised == 0){ drv_spi_slave_rx_v(spi_buffer_u8, spi_buffer_len_u8); } }
rx function :
//GPIOs declarations static const struct gpio_dt_spec wake_pin = GPIO_DT_SPEC_GET_OR(DT_NODELABEL(wake_pin),gpios,{0}); static const struct gpio_dt_spec cts_pin = GPIO_DT_SPEC_GET_OR(DT_NODELABEL(cts_pin),gpios,{0}); #define SPI_SLAVE DT_NODELABEL(spi_slave) const struct device *nrf_spi_slave; static struct k_poll_signal spi_rx_done_sig = K_POLL_SIGNAL_INITIALIZER(spi_rx_done_sig); uint8_t rx_raised; //SPI config static const struct spi_config spi_slave_cfg = { .operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_OP_MODE_SLAVE, .frequency = 4000000, .slave = 0, }; //Transfer buffers static uint8_t spi_rx_buffer[C_SPI_MSG_SIZE]; void drv_spi_slave_rx_v(uint8_t* rx_buffer_pt, uint8_t rx_buffer_size_u8){ if(NULL != rx_buffer_pt){ struct spi_buf rx_buf = { .buf = rx_buffer_pt, .len = rx_buffer_size_u8 }; struct spi_buf_set s_rx = { .buffers = &rx_buf, .count = 1 }; LOG_INF("LISTENING RX..."); int8_t error = spi_read_signal(nrf_spi_slave, &spi_slave_cfg,&s_rx,&spi_rx_done_sig); if(error < 0){ LOG_ERR("TRANSCEIVING ERROR !"); } }else{ LOG_ERR("POINTER ISSUE"); } }
msg check function & reset signal function :
uint8_t drv_nrf_msg_check_u8(){ uint8_t result; k_poll_signal_check(&spi_rx_done_sig, &rx_raised, &result); return(rx_raised); } void drv_nrf_reset_rx_v(){ k_poll_signal_reset(&spi_rx_done_sig); }
The issue is that the done signal is never raised and that the thread is paused indefinitely after 2 executions :
It seems to be a problem with a semaphore never released.
I may be lacking of understanding of the transceive_signal functions. I read the documentation about it but I'm not sure that I'm using it the right way to achieve what I want here.
If you could give me some help, it would be great !
Regards,
Hugo