From 5ad8853fefdeeee3662ec3b5b35f3439b54de6a8 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Thu, 29 Aug 2024 14:48:16 +0200 Subject: [PATCH] uart1 IO --- bsp_z7/hardware/interfaces.c | 3 +- bsp_z7/hardware/uart.c | 94 ++++++++++++++++++++++++++++++- bsp_z7/hardware/uart.h | 4 +- bsp_z7/lwip/netif/xemacpsif_dma.c | 4 +- bsp_z7/testEth.c | 38 +++++++++---- 5 files changed, 127 insertions(+), 16 deletions(-) diff --git a/bsp_z7/hardware/interfaces.c b/bsp_z7/hardware/interfaces.c index 165ad14..7e6b638 100644 --- a/bsp_z7/hardware/interfaces.c +++ b/bsp_z7/hardware/interfaces.c @@ -27,6 +27,7 @@ int hw_device_open(const char *path, size_t path_len) { return UART_0; } if (compare_string_chars("uart1", path, path_len) == 1) { + uart1_enable_receiver(); return UART_1; } @@ -67,7 +68,7 @@ int hw_interface_read(int fd, char *ptr, int len) { case UART_0: return uart0_read(ptr,len); case UART_1: - return 0; + return uart1_read(ptr,len);; } return -1; } \ No newline at end of file diff --git a/bsp_z7/hardware/uart.c b/bsp_z7/hardware/uart.c index ddfe8a6..49ff7ab 100644 --- a/bsp_z7/hardware/uart.c +++ b/bsp_z7/hardware/uart.c @@ -6,6 +6,9 @@ #include #include +// TODO deduplicate calls +// TODO add semaphore to make QueueSets smaller + #undef XUARTPS_IXR_RXOVR #define XUARTPS_IXR_RXOVR 0x00000020U /**< Rx Overrun error interrupt */ #define XUARTPS_IXR_RTRIG 0x00000001U /**< RX FIFO trigger interrupt. */ @@ -16,6 +19,10 @@ uint8_t uart0_receive_buffer[1024 * 1]; StaticQueue_t uart0_static_queue; QueueHandle_t uart0_receive_queue; +uint8_t uart1_receive_buffer[1024 * 1]; +StaticQueue_t uart1_static_queue; +QueueHandle_t uart1_receive_queue; + /** this is based on XUartPs_InterruptHandler() in xuartps_intr.c*/ void uart0_handle_interrupt(void *) { u32 IsrStatus; @@ -33,19 +40,55 @@ void uart0_handle_interrupt(void *) { // available into the stack uint8_t RecievedByte; BaseType_t xHigherPriorityTaskWoken; - while (XUartPs_IsReceiveData(STDIN_BASEADDRESS)) { - RecievedByte = XUartPs_ReadReg(STDIN_BASEADDRESS, XUARTPS_FIFO_OFFSET); + while (XUartPs_IsReceiveData(XPS_UART0_BASEADDR)) { + RecievedByte = XUartPs_ReadReg(XPS_UART0_BASEADDR, XUARTPS_FIFO_OFFSET); xQueueSendToBackFromISR(uart0_receive_queue, &RecievedByte, &xHigherPriorityTaskWoken); } /* Clear the interrupt status. */ - XUartPs_WriteReg(STDIN_BASEADDRESS, XUARTPS_ISR_OFFSET, IsrStatus); + XUartPs_WriteReg(XPS_UART0_BASEADDR, XUARTPS_ISR_OFFSET, IsrStatus); /* directly yield if sending to the queue woke something in ourselves */ portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } +void uart1_handle_interrupt(void *) { + outbyte('R'); + u32 IsrStatus; + + /* + * Read the interrupt ID register to determine which + * interrupt is active + */ + IsrStatus = XUartPs_ReadReg(XPS_UART1_BASEADDR, XUARTPS_IMR_OFFSET); + + IsrStatus &= XUartPs_ReadReg(XPS_UART1_BASEADDR, XUARTPS_ISR_OFFSET); + + // Onlx RX intterupts are enabled + // We do not care which interrupt actually triggered, just get all bytes + // available into the stack + uint8_t RecievedByte; + BaseType_t xHigherPriorityTaskWoken; + + while (XUartPs_IsReceiveData(XPS_UART1_BASEADDR)) { + RecievedByte = XUartPs_ReadReg(XPS_UART1_BASEADDR, XUARTPS_FIFO_OFFSET); + outbyte(RecievedByte); + outbyte(XUartPs_ReadReg(XPS_UART1_BASEADDR, XUARTPS_ISR_OFFSET)); + xQueueSendToBackFromISR(uart1_receive_queue, &RecievedByte, + &xHigherPriorityTaskWoken); + } + + + /* Clear the interrupt status. */ + XUartPs_WriteReg(XPS_UART1_BASEADDR, XUARTPS_ISR_OFFSET, IsrStatus); + + outbyte('X'); + outbyte('\n'); + /* directly yield if sending to the queue woke something in ourselves */ + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} + void uart0_enable_receiver() { uart0_receive_queue = xQueueCreateStatic(sizeof(uart0_receive_buffer), 1, uart0_receive_buffer, @@ -76,6 +119,36 @@ void uart0_enable_receiver() { XScuGic_Enable(&xInterruptController, XPAR_XUARTPS_0_INTR); } +void uart1_enable_receiver() { + uart1_receive_queue = + xQueueCreateStatic(sizeof(uart1_receive_buffer), 1, uart1_receive_buffer, + &uart1_static_queue); + + /* Install the UART Interrupt handler. */ + BaseType_t xStatus = + XScuGic_Connect(&xInterruptController, XPAR_XUARTPS_1_INTR, + (Xil_ExceptionHandler)uart1_handle_interrupt, NULL); + configASSERT(xStatus == XST_SUCCESS); + (void)xStatus; /* Remove compiler warning if configASSERT() is not defined. */ + + // Set trigger level to 62 of 64 bytes, giving interrupt some time to react + XUartPs_WriteReg(XPS_UART1_BASEADDR, XUARTPS_RXWM_OFFSET, 62); + + // Setting the rx timeout to n*4 -1 bits + XUartPs_WriteReg(XPS_UART1_BASEADDR, XUARTPS_RXTOUT_OFFSET, 50); + + // enable UART Interrupts + u32 mask = XUARTPS_IXR_RTRIG | XUARTPS_IXR_RXOVR | XUARTPS_IXR_RXFULL | + XUARTPS_IXR_TOUT; + /* Write the mask to the IER Register */ + XUartPs_WriteReg(XPS_UART1_BASEADDR, XUARTPS_IER_OFFSET, mask); + /* Write the inverse of the Mask to the IDR register */ + XUartPs_WriteReg(XPS_UART1_BASEADDR, XUARTPS_IDR_OFFSET, (~mask)); + + /* Enable the interrupt for the UART1 in the interrupt controller. */ + XScuGic_Enable(&xInterruptController, XPAR_XUARTPS_1_INTR); +} + int uart0_read(char *ptr, int len) { // TODO for blocking, if first call was successfull, further calls need to be delay=0 int received = 0; @@ -89,4 +162,19 @@ int uart0_read(char *ptr, int len) { len--; } return received; +} + +int uart1_read(char *ptr, int len) { + // TODO for blocking, if first call was successfull, further calls need to be delay=0 + int received = 0; + while (len > 0) { + BaseType_t result = xQueueReceive(uart1_receive_queue, ptr, 0); + if (result == pdFAIL) { + return received; + } + received++; + ptr++; + len--; + } + return received; } \ No newline at end of file diff --git a/bsp_z7/hardware/uart.h b/bsp_z7/hardware/uart.h index f1da8f7..8ee06b2 100644 --- a/bsp_z7/hardware/uart.h +++ b/bsp_z7/hardware/uart.h @@ -1,4 +1,6 @@ #pragma once void uart0_enable_receiver(); -int uart0_read(char *ptr, int len); \ No newline at end of file +int uart0_read(char *ptr, int len); +void uart1_enable_receiver(); +int uart1_read(char *ptr, int len); \ No newline at end of file diff --git a/bsp_z7/lwip/netif/xemacpsif_dma.c b/bsp_z7/lwip/netif/xemacpsif_dma.c index fd4f884..adededb 100644 --- a/bsp_z7/lwip/netif/xemacpsif_dma.c +++ b/bsp_z7/lwip/netif/xemacpsif_dma.c @@ -498,6 +498,8 @@ void setup_rx_bds(xemacpsif_s *xemacpsif, XEmacPs_BdRing *rxring) void emacps_recv_handler(void *arg) { + outbyte('D'); + struct pbuf *p; XEmacPs_Bd *rxbdset, *curbdptr; struct xemac_s *xemac; @@ -585,7 +587,7 @@ void emacps_recv_handler(void *arg) sys_sem_signal(&xemac->sem_rx_data_available); xInsideISR--; #endif - + outbyte('M'); return; } diff --git a/bsp_z7/testEth.c b/bsp_z7/testEth.c index cdb8c0e..40e8de6 100644 --- a/bsp_z7/testEth.c +++ b/bsp_z7/testEth.c @@ -12,9 +12,10 @@ #include "hardware/interfaces.h" #include -struct lwip_sock *get_socket(int fd); - +// Those three are a hack, but a quite performant one +struct lwip_sock *get_socket(int fd); // only works with a patched lwip extern QueueHandle_t uart0_receive_queue; +extern QueueHandle_t uart1_receive_queue; void udp_echo_thread(void *_) { vTaskDelay(5000 * portTICK_RATE_MS); @@ -51,8 +52,8 @@ void udp_echo_thread(void *_) { xil_printf("no addr"); } - int uart_sock = hw_device_open("uart0", 5); - write(uart_sock, "1234", 4); + int uart0_fd = hw_device_open("uart0", 5); + int uart1_fd = hw_device_open("uart1", 5); // char buffer[] = {'1','2','3','4'}; // ret = sendto(sock, buffer, sizeof(buffer), 0, (struct sockaddr *) @@ -73,6 +74,7 @@ void udp_echo_thread(void *_) { xQueueAddToSet(queue_id, listening_set); xQueueAddToSet(uart0_receive_queue, listening_set); + xQueueAddToSet(uart1_receive_queue, listening_set); while (1) { QueueSetMemberHandle_t readable = @@ -80,8 +82,8 @@ void udp_echo_thread(void *_) { if (readable == queue_id) { socklen_t peer_len = sizeof(peer_addr); - ret = lwip_recvfrom(sock, rec_buffer, sizeof(rec_buffer), 0, (struct sockaddr *) &peer_addr, - &peer_len); + ret = lwip_recvfrom(sock, rec_buffer, sizeof(rec_buffer), 0, + (struct sockaddr *)&peer_addr, &peer_len); if (peer_len > sizeof(peer_addr)) { xil_printf("invalid peer"); continue; @@ -93,14 +95,30 @@ void udp_echo_thread(void *_) { switch (port) { case 8100: xil_printf("udp rec 8100 len: %i\n", ret); - write(uart_sock, rec_buffer, ret); + write(uart0_fd, rec_buffer, ret); + break; + case 8101: + xil_printf("udp rec 8101 len: %i\n", ret); + write(uart1_fd, rec_buffer, ret); break; default: xil_printf("invalid port %i\n", port); break; } + } else if (readable == uart1_receive_queue) { + ret = read(uart1_fd, rec_buffer, sizeof(rec_buffer)); + // Do not send empty packets + if (ret <= 0) { + continue; + } + xil_printf("uart got %i\n", ret); + peer_addr.sin_port = htons(8101); + + // TODO sending 1 byte gives invalid UDP checksum + lwip_sendto(sock, rec_buffer, ret, 0, (struct sockaddr *)&peer_addr, + sizeof(peer_addr)); } else if (readable == uart0_receive_queue) { - ret = read(uart_sock, rec_buffer, sizeof(rec_buffer)); + ret = read(uart0_fd, rec_buffer, sizeof(rec_buffer)); xil_printf("uart got %i\n", ret); // Do not send empty packets @@ -109,9 +127,9 @@ void udp_echo_thread(void *_) { } peer_addr.sin_port = htons(8100); - //TODO sending 1 byte gives invalid UDP checksum + // TODO sending 1 byte gives invalid UDP checksum lwip_sendto(sock, rec_buffer, ret, 0, (struct sockaddr *)&peer_addr, - sizeof(peer_addr)); + sizeof(peer_addr)); } else { xil_printf("invalid handle"); }