2024-09-09 17:37:41 +02:00

175 lines
5.8 KiB
C

#include <stdint.h>
#include "FreeRTOS.h"
#include "queue.h"
#include <xscugic.h>
#include <xuartps.h>
// 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. */
extern XScuGic xInterruptController; /* Interrupt controller instance */
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;
/*
* 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(XPS_UART0_BASEADDR)) {
RecievedByte = XUartPs_ReadReg(XPS_UART0_BASEADDR, XUARTPS_FIFO_OFFSET);
xQueueSendToBackFromISR(uart0_receive_queue, &RecievedByte,
&xHigherPriorityTaskWoken);
}
/* Clear the interrupt status. */
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 *) {
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);
xQueueSendToBackFromISR(uart1_receive_queue, &RecievedByte,
&xHigherPriorityTaskWoken);
}
/* Clear the interrupt status. */
XUartPs_WriteReg(XPS_UART1_BASEADDR, 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);
}
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;
while (len > 0) {
BaseType_t result = xQueueReceive(uart0_receive_queue, ptr, 0);
if (result == pdFAIL) {
return received;
}
received++;
ptr++;
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;
}