Skip to content
Snippets Groups Projects
uart.c 9.10 KiB
/*
 * uart.c
 *
 *  Created on: Nov 10, 2014
 *      Author: ucart
 */


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "uart.h"
#include <xuartps.h>
#include <xstatus.h>

// Global PS's
XUartPs* _Uart0PS;
XUartPs* _Uart1PS;
static INTC Intc;

//This is copied from xuart driver
/***************************************************/

#define XUARTPS_MAX_BAUD_ERROR_RATE		 3	/* max % error allowed */
int XUartPs_SetBaudRate_ours(XUartPs *InstancePtr, u32 BaudRate)
{
	u8 IterBAUDDIV;		/* Iterator for available baud divisor values */
	u32 BRGR_Value;		/* Calculated value for baud rate generator */
	u32 CalcBaudRate;	/* Calculated baud rate */
	u32 BaudError;		/* Diff between calculated and requested baud rate */
	u32 Best_BRGR = 0;	/* Best value for baud rate generator */
	u8 Best_BAUDDIV = 0;	/* Best value for baud divisor */
	u32 Best_Error = 0xFFFFFFFF;
	u32 PercentError;
	u32 ModeReg;
	u32 InputClk;

	/*
	 * Asserts validate the input arguments
	 */
	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
	//Xil_AssertNonvoid(BaudRate <= XUARTPS_MAX_RATE);
	Xil_AssertNonvoid(BaudRate >= XUARTPS_MIN_RATE);

	/*
	 * Make sure the baud rate is not impossilby large.
	 * Fastest possible baud rate is Input Clock / 2.
	 */
	if ((BaudRate * 2) > InstancePtr->Config.InputClockHz) {
		return XST_UART_BAUD_ERROR;
	}
	/*
	 * Check whether the input clock is divided by 8
	 */
	ModeReg = XUartPs_ReadReg( InstancePtr->Config.BaseAddress,
				 XUARTPS_MR_OFFSET);

	InputClk = InstancePtr->Config.InputClockHz;
	if(ModeReg & XUARTPS_MR_CLKSEL) {
		InputClk = InstancePtr->Config.InputClockHz / 8;
	}

	/*
	 * Determine the Baud divider. It can be 4to 254.
	 * Loop through all possible combinations
	 */
	for (IterBAUDDIV = 4; IterBAUDDIV < 255; IterBAUDDIV++) {

		/*
		 * Calculate the value for BRGR register
		 */
		BRGR_Value = InputClk / (BaudRate * (IterBAUDDIV + 1));

		/*
		 * Calculate the baud rate from the BRGR value
		 */
		CalcBaudRate = InputClk/ (BRGR_Value * (IterBAUDDIV + 1));

		/*
		 * Avoid unsigned integer underflow
		 */
		if (BaudRate > CalcBaudRate) {
			BaudError = BaudRate - CalcBaudRate;
		}
		else {
			BaudError = CalcBaudRate - BaudRate;
		}

		/*
		 * Find the calculated baud rate closest to requested baud rate.
		 */
		if (Best_Error > BaudError) {

			Best_BRGR = BRGR_Value;
			Best_BAUDDIV = IterBAUDDIV;
			Best_Error = BaudError;
		}
	}

	/*
	 * Make sure the best error is not too large.
	 */
	PercentError = (Best_Error * 100) / BaudRate;
	if (XUARTPS_MAX_BAUD_ERROR_RATE < PercentError) {
		return XST_UART_BAUD_ERROR;
	}

	/*
	 * Disable TX and RX to avoid glitches when setting the baud rate.
	 */
	XUartPs_DisableUart(InstancePtr);

	XUartPs_WriteReg(InstancePtr->Config.BaseAddress,
			   XUARTPS_BAUDGEN_OFFSET, Best_BRGR);
	XUartPs_WriteReg(InstancePtr->Config.BaseAddress,
			   XUARTPS_BAUDDIV_OFFSET, Best_BAUDDIV);

	/*
	 * Enable device
	 */
	XUartPs_EnableUart(InstancePtr);

	InstancePtr->BaudRate = BaudRate;

	return XST_SUCCESS;

}

/***************************************************/

/************************************************/
/************** Main UART Interface *************/

XUartPs* uart_init(XUartPs* uartps_ptr, u16 deviceID, int baudRate) {
	XUartPs_Config* config = XUartPs_LookupConfig(deviceID);

	//Configure XUartPs instance
	int Status = XUartPs_CfgInitialize(uartps_ptr, config, config->BaseAddress);
	if (Status != XST_SUCCESS){
		return NULL;
	}

	//Set Baudrate for BT
	//XUartPs_SetBaudRate(uartps_ptr, baudRate);
	XUartPs_SetBaudRate_ours(uartps_ptr, baudRate);

	return uartps_ptr;
}

void uart_clearFIFOs(XUartPs* uartps_ptr) {
	//Get UART0 Control Register and clear the TX and RX Fifos
	int* uart_ctrl_reg = (int*) uartps_ptr->Config.BaseAddress;
	*uart_ctrl_reg |= 0x00000003; // clear TX & RX
}

void uart_sendByte(XUartPs* uartps_ptr, char data) {
	XUartPs_SendByte(uartps_ptr->Config.BaseAddress, data);
}

void uart_sendStr(XUartPs* uartps_ptr, char* str) {
	uart_sendBytes(uartps_ptr, str, strlen(str));
}

void uart_sendBytes(XUartPs* uartps_ptr, char* data, int numBytes) {
	while (uart_isSending(uartps_ptr))
		;

	int done = 0;
	while (done < numBytes) {
		done += XUartPs_Send(uartps_ptr, (unsigned char*) (&data[done]), numBytes - done);
	}
}

int uart_isSending(XUartPs* uartps_ptr) {
	return XUartPs_IsSending(uartps_ptr);
}

int uart_hasData(XUartPs* uartps_ptr) {
	return XUartPs_IsReceiveData(uartps_ptr->Config.BaseAddress);
}

void uart_recvBytes(XUartPs* uartps_ptr, char* buffer, int numBytes) {
	int received = 0;
	while (received < numBytes) {
		received += XUartPs_Recv(uartps_ptr, (unsigned char*) &buffer[received], (numBytes - received));
	}
}

char uart_recvByte(XUartPs* uartps_ptr) {
	return XUartPs_RecvByte(uartps_ptr->Config.BaseAddress);
	//char buffer[1];
	//XUartPs_Recv(uartps_ptr, (unsigned char*) &buffer[0], 1);

//	return buffer[0];
}


/*****************************************************************************/
/**
*
* This function sets up the interrupt system so interrupts can occur for the
* Uart. This function is application-specific.
*
* @param	IntcInstancePtr is a pointer to the instance of the INTC.
* @param	UartInstancePtr contains a pointer to the instance of the UART
*		driver which is going to be connected to the interrupt
*		controller.
* @param	UartIntrId is the interrupt Id and is typically
*		XPAR_<UARTPS_instance>_INTR value from xparameters.h.
*
* @return	XST_SUCCESS if successful, otherwise XST_FAILURE.
*
* @note		None.
*
****************************************************************************/
int SetupInterruptSystem(XUartPs *UartInstancePtr, u16 UartIntrId, Xil_ExceptionHandler handler)
{
	int Status;

	XScuGic_Config *IntcConfig; /* Config for interrupt controller */

	/* Initialize the interrupt controller driver */
	IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
	if (NULL == IntcConfig) {
		return XST_FAILURE;
	}

	Status = XScuGic_CfgInitialize(&Intc, IntcConfig,
					IntcConfig->CpuBaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Connect the interrupt controller interrupt handler to the
	 * hardware interrupt handling logic in the processor.
	 */
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
				(Xil_ExceptionHandler) XScuGic_InterruptHandler,
				&Intc);

	/*
	 * Connect a device driver handler that will be called when an
	 * interrupt for the device occurs, the device driver handler
	 * performs the specific interrupt processing for the device
	 */
	Status = XScuGic_Connect(&Intc, UartIntrId,
				  handler,
				  (void *) UartInstancePtr);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/* Enable the interrupt for the device */
	XScuGic_Enable(&Intc, UartIntrId);

	/* Enable interrupts */
	 Xil_ExceptionEnable();

	return XST_SUCCESS;
}
/************************************************/
/************************************************/





/************************************************/
/********** UART 0 convenience methods **********/

XUartPs* uart0_init(u16 deviceID, int baudRate){
	if (_Uart0PS) {
		free(_Uart0PS);
	}
	_Uart0PS = malloc(sizeof(XUartPs));
	return uart_init(_Uart0PS, deviceID, baudRate);
}
// Initializes the interrupt system for UART 0
int uart0_int_init(u16 UartIntrId, Xil_ExceptionHandler handler) {
	return SetupInterruptSystem(_Uart0PS, UartIntrId, handler);
}

void uart0_clearFIFOs(){
	uart_clearFIFOs(_Uart0PS);
}

void uart0_sendByte(u8 data){
	uart_sendByte(_Uart0PS, data);
}

void uart0_sendStr(char* str) {
	uart_sendStr(_Uart0PS, str);
}

void uart0_sendMetaData(metadata_t md)
{
	uart0_sendByte(md.begin_char);
	uart0_sendByte(md.msg_type & 0x00ff);
	uart0_sendByte((md.msg_type >> 8) & 0x00ff);
	uart0_sendByte(md.msg_id & 0x00ff);
	uart0_sendByte((md.msg_id >> 8) & 0x00ff);
	uart0_sendByte(md.data_len & 0x00ff);
	uart0_sendByte((md.data_len >> 8) & 0x00ff);
}

void uart0_sendBytes(char* data, int numBytes){
	uart_sendBytes(_Uart0PS, data, numBytes);
}

int uart0_isSending(){
	return uart_isSending(_Uart0PS);
}

int uart0_hasData(){
	return uart_hasData(_Uart0PS);
}

void uart0_recvBytes(char* buffer, int numBytes) {
	uart_recvBytes(_Uart0PS, buffer, numBytes);
}

char uart0_recvByte() {
	return uart_recvByte(_Uart0PS);
}

/************************************************/
/************************************************/






/************************************************/
/********** UART 1 convenience methods **********/

XUartPs* uart1_init(u16 deviceID, int baudRate){
	if (_Uart1PS) {
		free(_Uart1PS);
	}
	_Uart1PS = malloc(sizeof(XUartPs));
	return uart_init(_Uart1PS, deviceID, baudRate);
}

void uart1_clearFIFOs(){
	uart_clearFIFOs(_Uart1PS);
}

void uart1_sendByte(char data){
	uart_sendByte(_Uart1PS, data);
}

void uart1_sendStr(char* str) {
	uart_sendStr(_Uart1PS, str);
}

void uart1_sendBytes(char* data, int numBytes){
	uart_sendBytes(_Uart1PS, data, numBytes);
}

int uart1_isSending(){
	return uart_isSending(_Uart1PS);
}

int uart1_hasData(){
	return uart_hasData(_Uart1PS);
}

void uart1_recvBytes(char* buffer, int numBytes) {
	uart_recvBytes(_Uart1PS, buffer, numBytes);
}

char uart1_recvByte() {
	return uart_recvByte(_Uart1PS);
}

/************************************************/