This commit is contained in:
Ulrich Mohr 2024-08-29 14:48:16 +02:00
parent 8e7424bb2f
commit 5ad8853fef
5 changed files with 127 additions and 16 deletions

View File

@ -27,6 +27,7 @@ int hw_device_open(const char *path, size_t path_len) {
return UART_0; return UART_0;
} }
if (compare_string_chars("uart1", path, path_len) == 1) { if (compare_string_chars("uart1", path, path_len) == 1) {
uart1_enable_receiver();
return UART_1; return UART_1;
} }
@ -67,7 +68,7 @@ int hw_interface_read(int fd, char *ptr, int len) {
case UART_0: case UART_0:
return uart0_read(ptr,len); return uart0_read(ptr,len);
case UART_1: case UART_1:
return 0; return uart1_read(ptr,len);;
} }
return -1; return -1;
} }

View File

@ -6,6 +6,9 @@
#include <xscugic.h> #include <xscugic.h>
#include <xuartps.h> #include <xuartps.h>
// TODO deduplicate calls
// TODO add semaphore to make QueueSets smaller
#undef XUARTPS_IXR_RXOVR #undef XUARTPS_IXR_RXOVR
#define XUARTPS_IXR_RXOVR 0x00000020U /**< Rx Overrun error interrupt */ #define XUARTPS_IXR_RXOVR 0x00000020U /**< Rx Overrun error interrupt */
#define XUARTPS_IXR_RTRIG 0x00000001U /**< RX FIFO trigger 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; StaticQueue_t uart0_static_queue;
QueueHandle_t uart0_receive_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*/ /** this is based on XUartPs_InterruptHandler() in xuartps_intr.c*/
void uart0_handle_interrupt(void *) { void uart0_handle_interrupt(void *) {
u32 IsrStatus; u32 IsrStatus;
@ -33,19 +40,55 @@ void uart0_handle_interrupt(void *) {
// available into the stack // available into the stack
uint8_t RecievedByte; uint8_t RecievedByte;
BaseType_t xHigherPriorityTaskWoken; BaseType_t xHigherPriorityTaskWoken;
while (XUartPs_IsReceiveData(STDIN_BASEADDRESS)) { while (XUartPs_IsReceiveData(XPS_UART0_BASEADDR)) {
RecievedByte = XUartPs_ReadReg(STDIN_BASEADDRESS, XUARTPS_FIFO_OFFSET); RecievedByte = XUartPs_ReadReg(XPS_UART0_BASEADDR, XUARTPS_FIFO_OFFSET);
xQueueSendToBackFromISR(uart0_receive_queue, &RecievedByte, xQueueSendToBackFromISR(uart0_receive_queue, &RecievedByte,
&xHigherPriorityTaskWoken); &xHigherPriorityTaskWoken);
} }
/* Clear the interrupt status. */ /* 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 */ /* directly yield if sending to the queue woke something in ourselves */
portYIELD_FROM_ISR(xHigherPriorityTaskWoken); 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() { void uart0_enable_receiver() {
uart0_receive_queue = uart0_receive_queue =
xQueueCreateStatic(sizeof(uart0_receive_buffer), 1, uart0_receive_buffer, xQueueCreateStatic(sizeof(uart0_receive_buffer), 1, uart0_receive_buffer,
@ -76,6 +119,36 @@ void uart0_enable_receiver() {
XScuGic_Enable(&xInterruptController, XPAR_XUARTPS_0_INTR); 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) { int uart0_read(char *ptr, int len) {
// TODO for blocking, if first call was successfull, further calls need to be delay=0 // TODO for blocking, if first call was successfull, further calls need to be delay=0
int received = 0; int received = 0;
@ -89,4 +162,19 @@ int uart0_read(char *ptr, int len) {
len--; len--;
} }
return received; 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;
} }

View File

@ -1,4 +1,6 @@
#pragma once #pragma once
void uart0_enable_receiver(); void uart0_enable_receiver();
int uart0_read(char *ptr, int len); int uart0_read(char *ptr, int len);
void uart1_enable_receiver();
int uart1_read(char *ptr, int len);

View File

@ -498,6 +498,8 @@ void setup_rx_bds(xemacpsif_s *xemacpsif, XEmacPs_BdRing *rxring)
void emacps_recv_handler(void *arg) void emacps_recv_handler(void *arg)
{ {
outbyte('D');
struct pbuf *p; struct pbuf *p;
XEmacPs_Bd *rxbdset, *curbdptr; XEmacPs_Bd *rxbdset, *curbdptr;
struct xemac_s *xemac; struct xemac_s *xemac;
@ -585,7 +587,7 @@ void emacps_recv_handler(void *arg)
sys_sem_signal(&xemac->sem_rx_data_available); sys_sem_signal(&xemac->sem_rx_data_available);
xInsideISR--; xInsideISR--;
#endif #endif
outbyte('M');
return; return;
} }

View File

@ -12,9 +12,10 @@
#include "hardware/interfaces.h" #include "hardware/interfaces.h"
#include <unistd.h> #include <unistd.h>
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 uart0_receive_queue;
extern QueueHandle_t uart1_receive_queue;
void udp_echo_thread(void *_) { void udp_echo_thread(void *_) {
vTaskDelay(5000 * portTICK_RATE_MS); vTaskDelay(5000 * portTICK_RATE_MS);
@ -51,8 +52,8 @@ void udp_echo_thread(void *_) {
xil_printf("no addr"); xil_printf("no addr");
} }
int uart_sock = hw_device_open("uart0", 5); int uart0_fd = hw_device_open("uart0", 5);
write(uart_sock, "1234", 4); int uart1_fd = hw_device_open("uart1", 5);
// char buffer[] = {'1','2','3','4'}; // char buffer[] = {'1','2','3','4'};
// ret = sendto(sock, buffer, sizeof(buffer), 0, (struct sockaddr *) // ret = sendto(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)
@ -73,6 +74,7 @@ void udp_echo_thread(void *_) {
xQueueAddToSet(queue_id, listening_set); xQueueAddToSet(queue_id, listening_set);
xQueueAddToSet(uart0_receive_queue, listening_set); xQueueAddToSet(uart0_receive_queue, listening_set);
xQueueAddToSet(uart1_receive_queue, listening_set);
while (1) { while (1) {
QueueSetMemberHandle_t readable = QueueSetMemberHandle_t readable =
@ -80,8 +82,8 @@ void udp_echo_thread(void *_) {
if (readable == queue_id) { if (readable == queue_id) {
socklen_t peer_len = sizeof(peer_addr); socklen_t peer_len = sizeof(peer_addr);
ret = lwip_recvfrom(sock, rec_buffer, sizeof(rec_buffer), 0, (struct sockaddr *) &peer_addr, ret = lwip_recvfrom(sock, rec_buffer, sizeof(rec_buffer), 0,
&peer_len); (struct sockaddr *)&peer_addr, &peer_len);
if (peer_len > sizeof(peer_addr)) { if (peer_len > sizeof(peer_addr)) {
xil_printf("invalid peer"); xil_printf("invalid peer");
continue; continue;
@ -93,14 +95,30 @@ void udp_echo_thread(void *_) {
switch (port) { switch (port) {
case 8100: case 8100:
xil_printf("udp rec 8100 len: %i\n", ret); 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; break;
default: default:
xil_printf("invalid port %i\n", port); xil_printf("invalid port %i\n", port);
break; 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) { } 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); xil_printf("uart got %i\n", ret);
// Do not send empty packets // Do not send empty packets
@ -109,9 +127,9 @@ void udp_echo_thread(void *_) {
} }
peer_addr.sin_port = htons(8100); 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, lwip_sendto(sock, rec_buffer, ret, 0, (struct sockaddr *)&peer_addr,
sizeof(peer_addr)); sizeof(peer_addr));
} else { } else {
xil_printf("invalid handle"); xil_printf("invalid handle");
} }