From f02c032ad989026b4a48439ba5508337ed375238 Mon Sep 17 00:00:00 2001 From: Roaming Date: Fri, 24 Jun 2016 07:40:18 +0530 Subject: [PATCH] Created a UART API definition in softuart.h to allow the example code to access printf() and scanf() functionality --- examples/download.sh | 15 ++ examples/uart_timer/Makefile | 8 + examples/uart_timer/uart_timer.c | 61 ++++++ include/uart/api.h | 79 +++++++ include/uart/timer_uart.h | 43 ++++ lib/Makefile | 2 +- lib/uart/soft_uart.c | 362 +++++++++++++++++++++++++++++++ 7 files changed, 569 insertions(+), 1 deletion(-) create mode 100755 examples/download.sh create mode 100644 examples/uart_timer/Makefile create mode 100644 examples/uart_timer/uart_timer.c create mode 100644 include/uart/api.h create mode 100644 include/uart/timer_uart.h create mode 100644 lib/uart/soft_uart.c diff --git a/examples/download.sh b/examples/download.sh new file mode 100755 index 0000000..9f0d06b --- /dev/null +++ b/examples/download.sh @@ -0,0 +1,15 @@ +#!/bin/bash -e + +DEVS=$(lsusb|grep -E '(2a19|16c0|04b4|1d50|fb9a|1443)' |sed 's/:.*//;s/Bus //;s/Device //;s/ /\//') + +if [ -z "$1" ]; then + echo "$0: usage: $0 " + exit 1; +fi + +for dev in $DEVS;do + echo "Downloading $1 to $dev" + /sbin/fxload -D /dev/bus/usb/$dev -t fx2lp -I $1 +done + +exit 0 diff --git a/examples/uart_timer/Makefile b/examples/uart_timer/Makefile new file mode 100644 index 0000000..a4b938c --- /dev/null +++ b/examples/uart_timer/Makefile @@ -0,0 +1,8 @@ +FX2LIBDIR=../.. +BASENAME = uart_timer +SOURCES=uart_timer.c +DSCR_AREA= +INT2JT= +include $(FX2LIBDIR)/lib/fx2.mk +fx2_download: + ../download.sh build/$(BASENAME).ihx diff --git a/examples/uart_timer/uart_timer.c b/examples/uart_timer/uart_timer.c new file mode 100644 index 0000000..2176fa6 --- /dev/null +++ b/examples/uart_timer/uart_timer.c @@ -0,0 +1,61 @@ +/** + * Copyright (C) 2009 Ubixum, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + **/ +#include +#include +#include +#include +#include +#include + +//Used for setting the baud rate. +//Currently unimplemented +enum uart_baud baud; +//Extern declaration. +extern void process_isr(); +void main(void) +{ + baud = BAUD_9600; + uartX_init(baud); + printf("Hello"); + while (TRUE) + { + uart_rx_service(); + uart_tx_service(); + + } +} + +void putchar(char c) +{ + uartX_tx(c); +} + + +/** + * \brief This function is actually an ISR + * It is called periodically to check if data is ready to be transmitted + * The receive logic looks at the rx pin, sampling it continously. The moment + * a start bit is detected, it begins shifting the data in + * and finally sets a flag stating the receive is complete. This flag is reset + * in the uart_rx_service. This helps achieve non blocking behaviour. + **/ +void timer1_isr () +__interrupt TF1_ISR +{ + process_isr(); +} diff --git a/include/uart/api.h b/include/uart/api.h new file mode 100644 index 0000000..1441929 --- /dev/null +++ b/include/uart/api.h @@ -0,0 +1,79 @@ +/** \file include/uart/api.h + * This file is for defining a common API for accessing UARTs. + **/ + +#ifndef UART_API_H +#define UART_API_H + +#include "fx2types.h" +#include "stdarg.h" + +/** + * enum Standard available baud rates + * +**/ +enum uart_baud { BAUD_2400, BAUD_4800, BAUD_9600, BAUD_19200, BAUD_38400, BAUD_57600, BAUD_115200, BAUD_ANY, BAUD_FASTEST }; + +/** + * \brief initalizes UART. + * Returns 0 if initialization is successful. + * \param rate See uartX_set_baud() + **/ +BOOL uartX_init(enum uart_baud rate, ...); + +/** + * \brief Sets the UART baud rate to one of the allowed parameters. + * Possible Baud rates: + * \li 2400 + * \li 4800 + * \li 9600 + * \li 19200 + * \li 28800 + * \li 38400 + * \li 57600 + * \li 115200 + * Returns 0 if successful. +**/ +BOOL uartX_set_baud(enum uart_baud rate); + +/** + * \brief Returns the baud rate currently being used. +**/ +enum uart_baud uartX_get_baud(); + +/** + * \brief transmits data through UART + * \param c The character to be sent out +**/ + +void uartX_tx(char c); + +/** + * \brief Returns if the transmit is blocking or not + * TRUE - Blocking + * FALSE -Non Blocking +**/ + +BOOL uartX_tx_willblock(); + +/** + * \brief receives data through UART. + * Returns one byte at a time from the queue + * +**/ +char uartX_rx(); + +/** + * \brief Returns if the receive is blocking or not + * 0 - Non Blocking + * 1 - Blocking +**/ +BOOL uartX_check_rx_blocking(); + +/** + * \brief Returns count number of bytes present in the buffer + * +**/ +BYTE uartX_check_receive_buffer(); + +#endif diff --git a/include/uart/timer_uart.h b/include/uart/timer_uart.h new file mode 100644 index 0000000..b4829bc --- /dev/null +++ b/include/uart/timer_uart.h @@ -0,0 +1,43 @@ +#ifndef TIMER_UART_H +#define TIMER_UART_H +#include "fx2regs.h" +#include "fx2types.h" + +/** + * Enum for controlling transmitter state + * Only 2 states in the enum, it is either + * in IDLE or BUSY +**/ +enum uart_tx_state{IDLE, BUSY}; + +/** + * Enum for controlling receiver state + * Only 4 states in the enum + * 0x00 - IDLE + * 0x01 - Data Reception complete + * 0x02 - Start bit detect + * 0x03 - Data currently being read +**/ +enum uart_rx_state{IDLE_RX,DATA_COMPLETE,START_DETECT,BUSY_RX}; + +void timer_init(); +void softuart_init( void ); +void uart_tx_service(); +void uart_rx_service(); +void QueueInitTX(void); +__bit QueuePutTX(unsigned char data); +__bit QueueGetTX(unsigned char *old); +__bit QueueCheckTX(); +void QueueInitRX(void); +__bit QueuePutRX(unsigned char data); +__bit QueueGetRX(unsigned char * old); +__bit QueueCheckRX(); +void process_isr(); +extern unsigned char volatile tx_buffer; +extern unsigned char volatile rx_buffer; +extern unsigned char volatile tx_count; +extern unsigned char volatile rx_count; +extern unsigned char volatile tx_bits_sent; +extern unsigned char volatile rx_bits_rcvd; +extern unsigned char volatile rx_busy; +#endif diff --git a/lib/Makefile b/lib/Makefile index 560c500..63999ad 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -15,7 +15,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA AS8051?=sdas8051 -SOURCES = serial.c i2c.c delay.c setupdat.c gpif.c eputils.c $(wildcard interrupts/*.c) +SOURCES = serial.c i2c.c delay.c setupdat.c gpif.c eputils.c $(wildcard interrupts/*.c) $(wildcard uart/*.c) FX2_OBJS = $(patsubst %.c,%.rel, $(SOURCES)) usbav.rel INCLUDES = -I../include SDCC = sdcc -mmcs51 $(SDCCFLAGS) diff --git a/lib/uart/soft_uart.c b/lib/uart/soft_uart.c new file mode 100644 index 0000000..131f2ea --- /dev/null +++ b/lib/uart/soft_uart.c @@ -0,0 +1,362 @@ +/** \file lib/uart/soft_uart.c + * This file is for defining a common API for accessing UARTs. + * Remarks By Roaring(for the FX2LP from cypress) + **/ +#include +#include +#include +#include +#include +#include +#include +#define SYNCDELAY SYNCDELAY4 +/** + * tx_buffer holds the byte which is being transmitted out +**/ +BYTE volatile tx_buffer; +/** + * rx_buffer holds the byte which is being received +**/ +BYTE volatile rx_buffer; +/** + * tx_count holds the number of bits in tx_buffer which have been + * sent out +**/ +BYTE volatile tx_count; +/** + * rx_count holds the number of bits in rx_buffer which have been + * moved in +**/ +BYTE volatile rx_count; +unsigned volatile char tx_bits_sent; +unsigned volatile char rx_bits_rcvd; +/* Queue structure */ +#define QUEUE_ELEMENTS 50 +#define QUEUE_SIZE (QUEUE_ELEMENTS + 1) +/* QueueTX is the transmit queue */ +__xdata BYTE QueueTX[QUEUE_SIZE]; +/* variables to access the transmit queue*/ +__xdata BYTE QueueInTX, QueueOutTX; +/* QueueRX is the receive queue */ +__xdata BYTE QueueRX[QUEUE_SIZE]; +/* variables to access the receive queue*/ +__xdata BYTE QueueInRX, QueueOutRX; + +/* Enum creation for transmitter*/ +enum uart_tx_state tx_uart_state; +enum uart_rx_state rx_uart_state; + +BOOL uartX_init(enum uart_baud rate, ...) +{ + //Start timer , set CPUCS , initialize the queue + softuart_init(); + /* If we arrive here we have succesfully initialized UART */ + return TRUE; +} + +/** + * \brief This function sets up TIMER1. + * It enables the interrupts and also enables global interrupts + **/ +void timer_init() +{ + TMOD |= 0x20; + SYNCDELAY; + TR1 = 0; + SYNCDELAY; + TH1 = 0x97; + SYNCDELAY; + TL1 = 0x97; + SYNCDELAY; + ENABLE_TIMER1(); + EA = 1; + TR1 = 1; +} + +/** + * \brief Wrapper function for UART initialization + **/ +void softuart_init( void ) +{ + timer_init(); + QueueInitRX(); + QueueInitTX(); + SETCPUFREQ(CLK_48M); + tx_uart_state = IDLE; + rx_uart_state = IDLE_RX; +} + +/** + * \brief Called periodically from main. If the queue is non-empty + * then it returns immediately(non blocking). If there is data, it sets + * up the ISR to transmit this data and then returns. +**/ +void uart_tx_service() +{ + //Data has been loaded by the calling function in a buffer + //Check if operation is ongoing + //fast_uart(tx_buffer); + if ( QueueCheckTX() != 1) + { + if ( tx_uart_state == IDLE ) + { + //Load value + QueueGetTX(&tx_buffer); + //Busy. Operation is ongoing + tx_uart_state = BUSY; + tx_count = 0; + } + } +} + +/** + * \brief Called periodically from main. If the data reception is + * complete, then the rx_buffer is automatically put into + * queue , if the queue is non empty. +**/ +void uart_rx_service() +{ + if (rx_uart_state == DATA_COMPLETE ) + { + //Load value + QueuePutTX(rx_buffer); + rx_uart_state = IDLE_RX; + } +} + +/* Very simple queue + * These are FIFO queues which discard the new data when full. + * + * Queue is empty when in == out. + * If in != out, then + * - items are placed into in before incrementing in + * - items are removed from out before incrementing out + * Queue is full when in == (out-1 + QUEUE_SIZE) % QUEUE_SIZE; + * + * The queue will hold QUEUE_ELEMENTS number of items before the + * calls to QueuePut fail. + * Code taken from StackOverflow.com + */ + +/** + * Initialize the TX queue + **/ +void QueueInitTX(void) +{ + QueueInTX = QueueOutTX = 0; +} + +__bit QueuePutTX(BYTE data) +{ + //Additional check to make sure there is space in the queue + if (QueueInTX == (( QueueOutTX - 1 + QUEUE_SIZE) % QUEUE_SIZE)) + { + return 1; /* Queue Full*/ + } + QueueTX[QueueInTX] = data; + QueueInTX = (QueueInTX + 1) % QUEUE_SIZE; + return 0; +} + +/** + * \brief This is called to get data from the TX queue + * + * \param old the data which is returned(pointer) + **/ +__bit QueueGetTX(BYTE *old) +{ + if ((QueueInTX == QueueOutTX)) + { + return 1; /* Queue Empty - nothing to get*/ + } + *old = QueueTX[QueueOutTX]; + QueueOutTX = (QueueOutTX + 1) % QUEUE_SIZE; + return 0; // No errors +} + +/** + * \brief Check if the tx_queue is full + **/ +__bit QueueCheckTX() +{ + if ((QueueInTX == QueueOutTX)) + { + return 1; /* Queue Empty - nothing to get*/ + } + return 0; // No errors +} + +/** + * \brief Initialize the rx_queue + * + **/ +void QueueInitRX(void) +{ + QueueInRX = QueueOutRX = 0; +} + +/** + * \brief Insert data into the RX queue + * + * \param data Data obtained from UART + **/ +__bit QueuePutRX(BYTE data) +{ + if (QueueInRX == (( QueueOutRX - 1 + QUEUE_SIZE) % QUEUE_SIZE)) + { + return 1; /* Queue Full*/ + } + QueueRX[QueueInRX] = data; + QueueInRX = (QueueInRX + 1) % QUEUE_SIZE; + return 0; // No errors +} + +/** + * \brief Get data from the rx_queue + * + * \param old Pointer to the data which is loaded when this function is called + **/ +__bit QueueGetRX(BYTE * old) +{ + if (QueueInRX == QueueOutRX) + { + return 1; /* Queue Empty - nothing to get*/ + } + *old = QueueRX[QueueOutRX]; + QueueOutRX = (QueueOutRX + 1) % QUEUE_SIZE; + return 0; // No errors +} + +/** + * \brief This function checks if Queue is full . If full, it returns 1 + **/ +__bit QueueCheckRX() +{ + if (QueueInRX == (( QueueOutRX - 1 + QUEUE_SIZE) % QUEUE_SIZE)) + { + return 1; /* Queue Full*/ + } + + return 0; // No errors +} + +/** + * \brief This function is called from putchar + **/ +void uartX_tx(char c) +{ + //Put the data into the buffer. + QueuePutTX(c); +} + +/** + * \brief This function is called from timer 1 ISR + * Optimized for use in RX and TX + **/ +void process_isr() +{ + tx_count = tx_count + 1; + if ( (tx_count % 4) == 0) + { + if (tx_uart_state == 0x01) + { + OEA |= 0x10; + tx_bits_sent ++; + //Writing bits out via UART + if (tx_bits_sent == 1) + { + PA4 = 0 ; + } + else if (tx_bits_sent > 1 && tx_bits_sent <= 10) + { + __asm + mov a, _tx_buffer; + rrc a; + mov _PA4, c; + mov _tx_buffer, a; + __endasm; + } + else + { + PA4 = 1; + tx_bits_sent = 0; + tx_uart_state = 0; + } + } + tx_count = 0x00; + } + rx_count = rx_count + 1; + if (rx_uart_state == IDLE_RX) + { + __asm + anl _OEA, #0xdf; + mov c, _PA5; + jc 0001$; + mov _rx_count, #0x00 + mov _rx_bits_rcvd, #0x00 + mov _rx_uart_state , #0x02 + 0001$: + __endasm; + } + if ( (rx_count % 4) == 0) + { + if ((rx_uart_state == START_DETECT) || (rx_uart_state == BUSY_RX)) + { + rx_uart_state = BUSY_RX; + OEA &= 0xdf; + rx_bits_rcvd ++; + //Writing bits out via UART + if (rx_bits_rcvd < 10) + { + __asm + mov a, _rx_buffer; + mov c, _PA5; + rrc a; + mov _rx_buffer, a; + __endasm; + } + else + { + __asm + mov c, _PA5; + __endasm; + rx_bits_rcvd = 0; + rx_uart_state = DATA_COMPLETE; + } + } + rx_count = 0x00; + } +} + +BOOL uartX_set_baud(enum uart_baud rate) +{ + return FALSE; +} + +enum uart_baud uartX_get_baud() +{ + return BAUD_9600; +} + +BOOL uartX_tx_willblock() +{ + return FALSE; +} + +char uartX_rx() +{ +//This function should never be called + return 0xFF; +} + +BOOL uartX_check_rx_blocking() +{ +//The timer based UART does not block + return FALSE; +} + +BYTE uartX_check_receive_buffer() +{ +//Read not implemented. Always return a 0. + return 0x00; +}