diff --git a/bsp_z7/freeRTOS/FreeRTOSConfig.h b/bsp_z7/freeRTOS/FreeRTOSConfig.h index e667c02..8c01db6 100644 --- a/bsp_z7/freeRTOS/FreeRTOSConfig.h +++ b/bsp_z7/freeRTOS/FreeRTOSConfig.h @@ -89,7 +89,7 @@ #define configUSE_APPLICATION_TASK_TAG 0 #define configUSE_COUNTING_SEMAPHORES 1 #define configUSE_QUEUE_SETS 1 -#define configSUPPORT_STATIC_ALLOCATION 0 +#define configSUPPORT_STATIC_ALLOCATION 1 #define configSUPPORT_DYNAMIC_ALLOCATION 1 /* Include the query-heap CLI command to query the free heap space. */ diff --git a/bsp_z7/hardware/CMakeLists.txt b/bsp_z7/hardware/CMakeLists.txt index e3fa27e..e7befc2 100644 --- a/bsp_z7/hardware/CMakeLists.txt +++ b/bsp_z7/hardware/CMakeLists.txt @@ -1 +1 @@ -target_sources(${TARGET_NAME} PRIVATE interfaces.c) \ No newline at end of file +target_sources(${TARGET_NAME} PRIVATE interfaces.c uart.c) \ No newline at end of file diff --git a/bsp_z7/hardware/interfaces.c b/bsp_z7/hardware/interfaces.c index c067f78..165ad14 100644 --- a/bsp_z7/hardware/interfaces.c +++ b/bsp_z7/hardware/interfaces.c @@ -5,6 +5,7 @@ #include "interface_access.h" #include "interface_fds.h" +#include "uart.h" int compare_string_chars(const char *c_string, const char *chars, size_t chars_len) { @@ -19,8 +20,10 @@ int compare_string_chars(const char *c_string, const char *chars, return 1; } +//TODO no dual open int hw_device_open(const char *path, size_t path_len) { if (compare_string_chars("uart0", path, path_len) == 1) { + uart0_enable_receiver(); return UART_0; } if (compare_string_chars("uart1", path, path_len) == 1) { @@ -38,7 +41,7 @@ ssize_t hw_device_transfer(int fd, void *sendbuffer, void *receivebuffer, // we could implement interrupt based nonblocking sending using a queue // like we do receiving (where we need it for the small hw buffer) // but in the end, we do not want too many interrupts, so we do it blocking -void send_uart(uint32_t BaseAddress, const char *data, int data_len) { +void uart_send(uint32_t BaseAddress, const char *data, int data_len) { int todo; for (todo = 0; todo < data_len; todo++) { XUartPs_SendByte(BaseAddress, *data++); @@ -49,10 +52,10 @@ int hw_interface_write(int fd, const char *ptr, int len) { enum InterfaceFileDescriptors fd_enum = fd; switch (fd) { case UART_0: - send_uart(XPS_UART0_BASEADDR, ptr, len); + uart_send(XPS_UART0_BASEADDR, ptr, len); return len; case UART_1: - send_uart(XPS_UART1_BASEADDR, ptr, len); + uart_send(XPS_UART1_BASEADDR, ptr, len); return len; } return -1; @@ -62,7 +65,7 @@ int hw_interface_read(int fd, char *ptr, int len) { enum InterfaceFileDescriptors fd_enum = fd; switch (fd) { case UART_0: - return 0; + return uart0_read(ptr,len); case UART_1: return 0; } diff --git a/bsp_z7/hardware/uart.c b/bsp_z7/hardware/uart.c new file mode 100644 index 0000000..bfec1f1 --- /dev/null +++ b/bsp_z7/hardware/uart.c @@ -0,0 +1,91 @@ +#include + +#include "FreeRTOS.h" +#include "queue.h" + +#include +#include + +#undef XUARTPS_IXR_RXOVR +#define XUARTPS_IXR_RXOVR 0x00000020U /**< Rx Overrun error interrupt */ +#define XUARTPS_IXR_RTRIG 0x00000001U /**< RX FIFO trigger interrupt. */ + +extern XScuGic xInterruptController; /* Interrupt controller instance */ + +uint8_t uart0_receive_buffer[1024 * 1]; +StaticQueue_t uart0_static_queue; +QueueHandle_t uart0_receive_queue; + +/** this is based on XUartPs_InterruptHandler() in xuartps_intr.c*/ +void uart0_handle_interrupt(void *) { + u32 IsrStatus; + + /* + * Read the interrupt ID register to determine which + * interrupt is active + */ + IsrStatus = XUartPs_ReadReg(XPS_UART0_BASEADDR, XUARTPS_IMR_OFFSET); + + IsrStatus &= XUartPs_ReadReg(XPS_UART0_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(STDIN_BASEADDRESS)) { + RecievedByte = XUartPs_ReadReg(STDIN_BASEADDRESS, XUARTPS_FIFO_OFFSET); + xQueueSendToBackFromISR(uart0_receive_queue, &RecievedByte, + &xHigherPriorityTaskWoken); + } + + /* Clear the interrupt status. */ + XUartPs_WriteReg(STDIN_BASEADDRESS, XUARTPS_ISR_OFFSET, IsrStatus); + + /* 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, + &uart0_static_queue); + + /* Install the UART Interrupt handler. */ + BaseType_t xStatus = + XScuGic_Connect(&xInterruptController, XPAR_XUARTPS_0_INTR, + (Xil_ExceptionHandler)uart0_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_UART0_BASEADDR, XUARTPS_RXWM_OFFSET, 62); + + // Setting the rx timeout to n*4 -1 bits + XUartPs_WriteReg(XPS_UART0_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_UART0_BASEADDR, XUARTPS_IER_OFFSET, mask); + /* Write the inverse of the Mask to the IDR register */ + XUartPs_WriteReg(XPS_UART0_BASEADDR, XUARTPS_IDR_OFFSET, (~mask)); + + /* Enable the interrupt for the UART0 in the interrupt controller. */ + XScuGic_Enable(&xInterruptController, XPAR_XUARTPS_0_INTR); +} + +int uart0_read(char *ptr, int len) { + int received = 0; + while (len > 0) { + BaseType_t result = xQueueReceive(uart0_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 new file mode 100644 index 0000000..f1da8f7 --- /dev/null +++ b/bsp_z7/hardware/uart.h @@ -0,0 +1,4 @@ +#pragma once + +void uart0_enable_receiver(); +int uart0_read(char *ptr, int len); \ No newline at end of file diff --git a/bsp_z7/newlib/read.c b/bsp_z7/newlib/read.c index f0538ce..c76c6d9 100644 --- a/bsp_z7/newlib/read.c +++ b/bsp_z7/newlib/read.c @@ -1,5 +1,34 @@ +#include "xil_printf.h" +#include "xparameters.h" +#include "../hardware/interface_access.h" +#include "../hardware/interface_fds.h" -int _read(int file, char *ptr, int len) { - return 0; +// newlib offers a (weak) write implementation which +// is reentrant by calling _read_r which in turn +// relies on _read which we implement here. +// This way, we get a global, reentrant read implementation +// NOTE: This might be architecture dependent, so check your +// newlib implementation! +int _read(int fd, char *ptr, int len) { + if (ptr == NULL) { + return 0; + } + + // 0 is stdin, TODO: do we support it? + if (fd < 1) { + return -1; + } + + // stdout and stderr + if (fd < 3) { + return -1; + } + + if (fd < INTERFACE_FDS_NEXT) { + return hw_interface_read(fd, ptr, len); + } + + // we do not have dynamic fds, so fd is invalid + return -1; } \ No newline at end of file diff --git a/bsp_z7/newlib/write.c b/bsp_z7/newlib/write.c index 8d76e1b..e388653 100644 --- a/bsp_z7/newlib/write.c +++ b/bsp_z7/newlib/write.c @@ -22,7 +22,7 @@ int _write(int fd, const char *ptr, int len) { } // we only support a single debug UART, so // stdout and stderr are the same and go to the xiling stdout UART - // TODO switch to a hw_interface_write() instead? + // We output directely to avoid loops and allow debugging (not via a write) if (fd < 3) { int todo; diff --git a/bsp_z7/ps7_cortexa9_0/libsrc/standalone/CMakeLists.txt b/bsp_z7/ps7_cortexa9_0/libsrc/standalone/CMakeLists.txt index bfb6e99..daa92ab 100644 --- a/bsp_z7/ps7_cortexa9_0/libsrc/standalone/CMakeLists.txt +++ b/bsp_z7/ps7_cortexa9_0/libsrc/standalone/CMakeLists.txt @@ -31,8 +31,8 @@ target_sources(${TARGET_NAME} PUBLIC src/getentropy.c src/xil_testmem.c src/isatty.c - src/read.c - src/inbyte.c + #src/read.c + #src/inbyte.c src/close.c src/xil_sleeptimer.c src/print.c diff --git a/bsp_z7/testIp.c b/bsp_z7/testIp.c index 250b35e..786918b 100644 --- a/bsp_z7/testIp.c +++ b/bsp_z7/testIp.c @@ -160,71 +160,71 @@ static const uint16_t stackSizeWords = 512; StaticTask_t xTaskBuffer; StackType_t xStack[512]; -// void testIp() { +void testIp() { -// uartIsrQueue = -// xQueueCreateStatic(QUEUE_LENGTH, 1, ucQueueStorageArea, &xStaticQueue); + uartIsrQueue = + xQueueCreateStatic(QUEUE_LENGTH, 1, ucQueueStorageArea, &xStaticQueue); -// lwip_init(); + lwip_init(); -// ip4_addr_t slip_addr = {PP_HTONL(LWIP_MAKEU32(10, 0, 0, 32))}, -// slip_mask = {PP_HTONL(LWIP_MAKEU32(255, 255, 255, 0))}, -// slip_gw = {PP_HTONL(LWIP_MAKEU32(10, 0, 0, 1))}; + ip4_addr_t slip_addr = {PP_HTONL(LWIP_MAKEU32(10, 0, 0, 32))}, + slip_mask = {PP_HTONL(LWIP_MAKEU32(255, 255, 255, 0))}, + slip_gw = {PP_HTONL(LWIP_MAKEU32(10, 0, 0, 1))}; -// netif_add(&netif, &slip_addr, &slip_mask, &slip_gw, NULL, slipif_init, -// netif_input); + netif_add(&netif, &slip_addr, &slip_mask, &slip_gw, NULL, slipif_init, + netif_input); -// netif_set_default(&netif); -// // should be done by driver, which does not do it, so we do it here -// netif_set_link_up(&netif); -// netif_set_up(&netif); + netif_set_default(&netif); + // should be done by driver, which does not do it, so we do it here + netif_set_link_up(&netif); + netif_set_up(&netif); -// udpecho_raw_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); -// if (udpecho_raw_pcb != NULL) { -// err_t err; + udpecho_raw_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); + if (udpecho_raw_pcb != NULL) { + err_t err; -// err = udp_bind(udpecho_raw_pcb, IP_ANY_TYPE, 7); -// if (err == ERR_OK) { -// udp_recv(udpecho_raw_pcb, udpecho_raw_recv, NULL); -// } else { -// /* TODO */ -// } -// } else { -// /* TODO */ -// } + err = udp_bind(udpecho_raw_pcb, IP_ANY_TYPE, 7); + if (err == ERR_OK) { + udp_recv(udpecho_raw_pcb, udpecho_raw_recv, NULL); + } else { + /* TODO */ + } + } else { + /* TODO */ + } -// /* Install the UART Interrupt handler. */ -// BaseType_t xStatus = -// XScuGic_Connect(&xInterruptController, STDIN_INT_NR, -// (Xil_ExceptionHandler)handleUARTInt, NULL); -// configASSERT(xStatus == XST_SUCCESS); -// (void)xStatus; /* Remove compiler warning if configASSERT() is not defined. */ + /* Install the UART Interrupt handler. */ + BaseType_t xStatus = + XScuGic_Connect(&xInterruptController, STDIN_INT_NR, + (Xil_ExceptionHandler)handleUARTInt, 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(STDIN_BASEADDRESS, XUARTPS_RXWM_OFFSET, 62); + // Set trigger level to 62 of 64 bytes, giving interrupt some time to react + XUartPs_WriteReg(STDIN_BASEADDRESS, XUARTPS_RXWM_OFFSET, 62); -// // Setting the rx timeout to n*4 -1 bits -// XUartPs_WriteReg(STDIN_BASEADDRESS, XUARTPS_RXTOUT_OFFSET, 50); + // Setting the rx timeout to n*4 -1 bits + XUartPs_WriteReg(STDIN_BASEADDRESS, 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(STDIN_BASEADDRESS, XUARTPS_IER_OFFSET, mask); -// /* Write the inverse of the Mask to the IDR register */ -// XUartPs_WriteReg(STDIN_BASEADDRESS, XUARTPS_IDR_OFFSET, (~mask)); + // 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(STDIN_BASEADDRESS, XUARTPS_IER_OFFSET, mask); + /* Write the inverse of the Mask to the IDR register */ + XUartPs_WriteReg(STDIN_BASEADDRESS, XUARTPS_IDR_OFFSET, (~mask)); -// /* Enable the interrupt for the UART1 in the interrupt controller. */ -// XScuGic_Enable(&xInterruptController, STDIN_INT_NR); + /* Enable the interrupt for the UART1 in the interrupt controller. */ + XScuGic_Enable(&xInterruptController, STDIN_INT_NR); -// // Start lwip task -// xTaskCreateStatic( -// lwip_main, /* The function that implements the task. */ -// "lwip", /* The text name assigned to the task - for debug -// only as it is not used by the kernel. */ -// stackSizeWords, /* The size of the stack to allocate to the task. */ -// NULL, /* The parameter passed to the task - not used in this -// simple case. */ -// 4, /* The priority assigned to the task. */ -// xStack, &xTaskBuffer); -// } \ No newline at end of file + // Start lwip task + xTaskCreateStatic( + lwip_main, /* The function that implements the task. */ + "lwip", /* The text name assigned to the task - for debug + only as it is not used by the kernel. */ + stackSizeWords, /* The size of the stack to allocate to the task. */ + NULL, /* The parameter passed to the task - not used in this + simple case. */ + 4, /* The priority assigned to the task. */ + xStack, &xTaskBuffer); +} \ No newline at end of file diff --git a/mission/mission.c b/mission/mission.c index 5e404b7..02d330e 100644 --- a/mission/mission.c +++ b/mission/mission.c @@ -9,6 +9,24 @@ void rust_main(); +#include +#include + +void test_hardware() { + int fd0 = hw_device_open("uart0", 5); + write(fd0, "uart0\n", 6); + int fd1 = hw_device_open("uart1", 5); + write(fd1, "uart1\n", 6); + + vTaskDelay(3000 / portTICK_PERIOD_MS); + + uint8_t buffer[100]; + int read_bytes = read(fd0, buffer, sizeof(buffer)); + write(1, buffer, read_bytes); + read_bytes = read(fd1, buffer, sizeof(buffer)); + write(1, buffer, read_bytes); +} + // called to stop execution (either a panic or program ended) // to be implemented by bsp (do not return from it!) void done(); @@ -16,6 +34,8 @@ void done(); void init_task(void *) { // printf("Starting Mission\n"); + test_hardware(); + rust_main(); // printf("Started Tasks, deleting init task\n"); @@ -25,14 +45,9 @@ void init_task(void *) { vTaskDelete(NULL); } -#include -#include + void mission(void) { - int fd0 = hw_device_open("uart0", 5); - write(fd0, "uart0\n", 6); - int fd1 = hw_device_open("uart1", 5); - write(fd1, "uart1\n", 6); int taskParameters = 0;