Hello,
I am trying to establish communication between the nRF9160 SoC and the nRF52840 on the Thingy:91. I have two arrays: one of 774 bytes and another of 8 bytes. Currently, I am only sending the first array from the nRF52840 to the nRF9160. However, I have observed that the entire 774 bytes are not sent at once. Sometimes, it sends 700 bytes followed by 74 bytes, and on the other side (nRF9160) it receives sometimes 256 bytes three times and then 10 bytes.
The issue is that I need a solution to send the 774 bytes in one chunk and to receive it correctly on the other side, as I have no way to define the end of my array. For reference, my application is based on the lpuart sample, but I am using uart1 instead of lpuart.
Here's my app of nRF9160 side :
#include "uart_nrf91_to_nrf52.h" #include <zephyr/kernel.h> #include <zephyr/device.h> #include <zephyr/devicetree.h> #include <zephyr/sys/ring_buffer.h> #include <zephyr/drivers/gpio.h> #include <zephyr/drivers/uart.h> #include <string.h> #include <stdio.h> #include <zephyr/logging/log.h> #include <date_time.h> LOG_MODULE_REGISTER(NRF52_LOG,4); #define UART_BUF_SIZE 776 #define UART_TX_TIMEOUT_MS 100 #define UART_RX_TIMEOUT_MS 100 K_SEM_DEFINE(tx_done, 1, 1); K_SEM_DEFINE(rx_disabled, 0, 1); K_SEM_DEFINE(connected_lte, 0, 1); #define UART_TX_BUF_SIZE 256 #define UART_RX_MSG_QUEUE_SIZE 8 #define TOTAL_DATA_RX_SIZE 778 struct uart_msg_queue_item { uint8_t bytes[UART_BUF_SIZE]; uint32_t length; }; uint8_t ts_bytes[9]; // Timestamp bytes // UART TX fifo RING_BUF_DECLARE(app_tx_fifo, UART_TX_BUF_SIZE); volatile int bytes_claimed; // UART RX primary buffers uint8_t uart_double_buffer[2][UART_BUF_SIZE]; uint8_t *uart_buf_next = uart_double_buffer[1]; // UART RX message queue K_MSGQ_DEFINE(uart_rx_msgq, sizeof(struct uart_msg_queue_item), UART_RX_MSG_QUEUE_SIZE, 4); static const struct device *dev_uart; void app_uart_async_callback(const struct device *uart_dev, struct uart_event *evt, void *user_data) { static struct uart_msg_queue_item new_message; switch (evt->type) { case UART_TX_DONE: // Free up the written bytes in the TX FIFO ring_buf_get_finish(&app_tx_fifo, bytes_claimed); printk("number of bytes sent is : %d\n",evt->data.tx.len); // If there is more data in the TX fifo, start the transmission if(uart_tx_get_from_queue() == 0) { // Or release the semaphore if the TX fifo is empty printk("ALL data is transmitted\n"); k_sem_give(&tx_done); } break; case UART_RX_RDY: // LOG_DBG("message received : length %d\n", evt->data.rx.len); memcpy(new_message.bytes, evt->data.rx.buf + evt->data.rx.offset, evt->data.rx.len); new_message.length = evt->data.rx.len; if(k_msgq_put(&uart_rx_msgq, &new_message, K_NO_WAIT) != 0){ printk("Error: Uart RX message queue full!\n"); } break; case UART_RX_BUF_REQUEST: uart_rx_buf_rsp(dev_uart, uart_buf_next, UART_BUF_SIZE); break; case UART_RX_BUF_RELEASED: uart_buf_next = evt->data.rx_buf.buf; break; case UART_RX_DISABLED: k_sem_give(&rx_disabled); break; default: break; } } void app_uart_init(void) { dev_uart = DEVICE_DT_GET(DT_NODELABEL(uart1)); if (!dev_uart) { printk("Impossible de trouver le périphérique UART\n"); return; } if(device_is_ready(dev_uart) == false) { printk("Périphérique UART non prêt\n"); return -1; } uart_callback_set(dev_uart, app_uart_async_callback, NULL); uart_rx_enable(dev_uart, uart_double_buffer[0], UART_BUF_SIZE, UART_RX_TIMEOUT_MS); } void uart_get_rx(void *p1, void *p2, void *p3){ struct uart_msg_queue_item incoming_message; static uint8_t string_buffer[TOTAL_DATA_RX_SIZE + 2] = {0}; int buffer_length = 0; uint16_t size = 0; while (1) { // printk("Waiting for new message\n"); // This function will not return until a new message is ready k_msgq_get(&uart_rx_msgq, &incoming_message, K_FOREVER); // printk("New message received\n"); // Copy incoming_message.bytes to string_buffer for (int i = 0; i < incoming_message.length; i++) { string_buffer[buffer_length] = incoming_message.bytes[i]; if(buffer_length == 0){ if(string_buffer[buffer_length] == 255){ size = 775; }else{ size = 778; } printk("size = %d, string_buffer[0] = %d \n",size, string_buffer[buffer_length]); } buffer_length++; if (buffer_length == size) { // End of message detected // buffer_length -= 3; // Remove the end marker string_buffer[buffer_length] = '\0'; // Null-terminate the string printk("length of string_buffer : %d\n", buffer_length); // printk("RX : %s\n", string_buffer); memset(string_buffer, 0, sizeof(string_buffer)); // Clear the buffer buffer_length = 0; // Reset buffer length break; } } } } K_THREAD_DEFINE(uart_rx_get_from_nrf52, 1024, uart_get_rx, NULL, NULL, NULL, 5, 0, 0);
The app of nRF52840 side :
void receive_data(const uint8_t *data, size_t length) { uint8_t all_data[TOTAL_DATA_TEMP_SIZE]; // Si la taille des données reçues est égale à 7, alors c'est le capteur de courant if(length == TOTAL_DATA_CURRENT_SIZE){ // Capteur de courant printk("Current sensor data received\n"); } // Sinon, c'est le capteur de température else{ if ((data_received_len + length) > TOTAL_DATA_TEMP_SIZE) { // Gérer l'erreur : données reçues dépassent la taille du tableau printk("Erreur : dépassement de capacité du tableau\n"); return; } // Copier les données reçues dans le tableau global memcpy(&all_data[data_received_len], data, length); // Mettre à jour l'index data_received_len += length; // printk("data_received_len : %d\n", data_received_len); // Si toutes les données ont été reçues if (data_received_len == TOTAL_DATA_TEMP_SIZE) { printk("%d received \n", data_received_len); send_data_to_nrf91(255, 1); // Envoie la taille des données reçues à la carte nRF91 // send_data_in_chunks(all_data, TOTAL_DATA_TEMP_SIZE); send_data_to_nrf91(all_data, TOTAL_DATA_TEMP_SIZE); // Envoie les données reçues à la carte nRF91 // Réinitialiser l'index si vous attendez une nouvelle série de données data_received_len = 0; /*for(int i = 0; i < 24; i++){ for(int j = 0; j < 32; j++){ printk("%d , ", all_data[i*32+j]); }*/ // printk("\n"); // send_data_to_nrf91(END_OF_ARRAY_MARKER, sizeof(END_OF_ARRAY_MARKER)); // Envoie le caractère de fin de message à la carte nRF91 // k_sem_give(&send_uart_data); // Donne le semaphore pour débloquer la fonction app_uart_send } } // printk("\n--------------------\n"); } #define UART_BUF_SIZE 23 #define UART_TX_TIMEOUT_MS 100 #define UART_RX_TIMEOUT_MS 100 K_SEM_DEFINE(tx_done, 1, 1); K_SEM_DEFINE(rx_disabled, 0, 1); K_SEM_DEFINE(send_uart_data, 0, 1); #define UART_TX_BUF_SIZE 800 #define UART_RX_MSG_QUEUE_SIZE 8 struct uart_msg_queue_item { uint8_t bytes[UART_BUF_SIZE]; uint32_t length; }; // UART TX fifo RING_BUF_DECLARE(app_tx_fifo, UART_TX_BUF_SIZE); volatile int bytes_claimed; // UART RX primary buffers uint8_t uart_double_buffer[2][UART_BUF_SIZE]; uint8_t *uart_buf_next = uart_double_buffer[1]; // UART RX message queue K_MSGQ_DEFINE(uart_rx_msgq, sizeof(struct uart_msg_queue_item), UART_RX_MSG_QUEUE_SIZE, 4); static const struct device *dev_uart; static int uart_tx_get_from_queue(void) { uint8_t *data_ptr; // Try to claim any available bytes in the FIFO bytes_claimed = ring_buf_get_claim(&app_tx_fifo, &data_ptr, UART_TX_BUF_SIZE); if(bytes_claimed > 0) { // Start a UART transmission based on the number of available bytes uart_tx(dev_uart, data_ptr, bytes_claimed, SYS_FOREVER_MS); } return bytes_claimed; } void app_uart_async_callback(const struct device *uart_dev, struct uart_event *evt, void *user_data) { static struct uart_msg_queue_item new_message; switch (evt->type) { case UART_TX_DONE: // Free up the written bytes in the TX FIFO ring_buf_get_finish(&app_tx_fifo, bytes_claimed); LOG_DBG("TX done , %d bytes written\n", evt->data.tx.len); // If there is more data in the TX fifo, start the transmission if(uart_tx_get_from_queue() == 0) { // Or release the semaphore if the TX fifo is empty k_sem_give(&tx_done); } break; case UART_RX_RDY: memcpy(new_message.bytes, evt->data.rx.buf + evt->data.rx.offset, evt->data.rx.len); new_message.length = evt->data.rx.len; LOG_DBG("new_message.length : %d\n",new_message.length); if(k_msgq_put(&uart_rx_msgq, &new_message, K_NO_WAIT) != 0){ printk("Error: Uart RX message queue full!\n"); } break; case UART_RX_BUF_REQUEST: uart_rx_buf_rsp(dev_uart, uart_buf_next, UART_BUF_SIZE); break; case UART_RX_BUF_RELEASED: uart_buf_next = evt->data.rx_buf.buf; break; case UART_RX_DISABLED: k_sem_give(&rx_disabled); break; default: break; } } static void app_uart_init(void) { dev_uart = DEVICE_DT_GET(DT_NODELABEL(uart1)); if (!dev_uart) { LOG_ERR("Impossible de trouver le périphérique UART\n"); return; } if(device_is_ready(dev_uart) == false) { LOG_ERR("Périphérique UART non prêt\n"); return -1; } uart_callback_set(dev_uart, app_uart_async_callback, NULL); uart_rx_enable(dev_uart, uart_double_buffer[0], UART_BUF_SIZE, UART_RX_TIMEOUT_MS); } void send_data_to_nrf91(const uint8_t * data_ptr, uint32_t data_len) { uint32_t written_to_buf = ring_buf_put(&app_tx_fifo, data_ptr, data_len); // In case the UART TX is idle, start transmission if(k_sem_take(&tx_done, K_NO_WAIT) == 0) { LOG_DBG("Transmission started\n"); uart_tx_get_from_queue(); } }
Best Regards
Youssef