From d0519f9120d4f32e5336397127b7df586b9d2415 Mon Sep 17 00:00:00 2001 From: Roaming Date: Fri, 24 Jun 2016 07:40:18 +0530 Subject: [PATCH] Create UART functions using C macros according to the api.h file. --- examples/download.sh | 15 +++ examples/uart_main/Makefile | 6 ++ examples/uart_main/uart_main.c | 52 +++++++++++ include/uart/api.h | 79 ++++++++++++++++ include/uart/soft_uart.h | 164 +++++++++++++++++++++++++++++++++ lib/fx2.mk | 2 + 6 files changed, 318 insertions(+) create mode 100755 examples/download.sh create mode 100644 examples/uart_main/Makefile create mode 100644 examples/uart_main/uart_main.c create mode 100644 include/uart/api.h create mode 100644 include/uart/soft_uart.h 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_main/Makefile b/examples/uart_main/Makefile new file mode 100644 index 0000000..96e0cde --- /dev/null +++ b/examples/uart_main/Makefile @@ -0,0 +1,6 @@ +FX2LIBDIR=../.. +BASENAME = uart_main +SOURCES=uart_main.c +DSCR_AREA= +INT2JT= +include $(FX2LIBDIR)/lib/fx2.mk diff --git a/examples/uart_main/uart_main.c b/examples/uart_main/uart_main.c new file mode 100644 index 0000000..8d79d57 --- /dev/null +++ b/examples/uart_main/uart_main.c @@ -0,0 +1,52 @@ +/** + * 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 +#include +#include + +//Initialize UART, call it uart0 and set the tx pin on PA1. +CREATE_FAST_UART(uart0,OEB,_PB0,bmBIT0,TRUE,FALSE) +CREATE_FAST_UART(uart1,OEA,_PA4,bmBIT4,TRUE,FALSE) +//Used for setting the baud rate. +enum uart_baud baud; + +void main(void) +{ + baud = BAUD_115200; + SETCPUFREQ(CLK_48M); + while (!uart0_init(baud)); + while (!uart1_init(baud)); + uart0_set_baud(baud); + baud = BAUD_115200; + uart1_set_baud(baud); + while (TRUE) + { + printf("Hello\r\n"); + uart1_tx(0x44); + } +} + +void putchar(char c) +{ + uart0_tx(c); +} diff --git a/include/uart/api.h b/include/uart/api.h new file mode 100644 index 0000000..a2a643b --- /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 + * 0 - Non Blocking + * 1 - 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/soft_uart.h b/include/uart/soft_uart.h new file mode 100644 index 0000000..a557383 --- /dev/null +++ b/include/uart/soft_uart.h @@ -0,0 +1,164 @@ +/** \file include/uart/soft_uart.h + * This file contains a MACRO for defining UART function wrappers. + **/ +#ifndef SOFT_UART_H +#define SOFT_UART_H + +/** + * \brief Automatically generates the function calls to allow multiple + * UARTS to be created. The main parameters for the UART is the pin number + * as well as the speed of the operation. These should be passed as an argument + * to the macro. The load_delay element controls the speed. This is created with the + * uart name. + **/ +#define CREATE_FAST_UART(uartname,port,pinname,bitnum,TX_BLOCKING,RX_ENABLED) \ +BYTE uartname##_load_delay; \ +enum uart_baud uartname##rate; \ +BOOL uartname##_init(enum uart_baud rate,...) \ +{ \ + uartX_init(rate); \ + return TRUE; \ +} \ +void uartname##_tx(char c) { \ + __asm \ + .equ _TX_PIN1,pinname \ + .equ _load_delay,_##uartname##_load_delay \ + __endasm; \ + port = bitnum; \ + uart_tx(c); \ +} \ +BOOL uartname##_set_baud(enum uart_baud rate) { \ + uartname##rate = rate; \ + switch(rate) \ + { \ + case BAUD_2400: \ + return FALSE; \ + case BAUD_4800: \ + return FALSE; \ + case BAUD_9600: \ + return FALSE; \ + case BAUD_19200: \ + uartname##_load_delay = 0xd0; \ + break; \ + case BAUD_38400: \ + uartname##_load_delay = 0x68; \ + break; \ + case BAUD_57600: \ + uartname##_load_delay = 0x45; \ + break; \ + case BAUD_115200: \ + uartname##_load_delay = 0x20; \ + break; \ + case BAUD_ANY: \ + break; \ + case BAUD_FASTEST: \ + uartname##_load_delay = 0x20; \ + uartname##rate = BAUD_115200; \ + break; \ + default: \ + uartname##_load_delay = 0x20; \ + break; \ + } \ + return TRUE; \ +} \ +enum uart_baud uartname##_get_baud() \ +{ \ + return uartname##rate; \ +} \ +BOOL uartname##_tx_willblock() \ +{ \ + return TX_BLOCKING; \ +} \ +char uartname##_rx() \ +{ \ + assert(FALSE); \ + return 0xFF; \ +} \ +BOOL uartname##_check_rx_blocking() \ +{ \ + return FALSE; \ +} \ +BYTE uartname##_check_receive_buffer() \ +{ \ + return FALSE; \ +} \ +BOOL uartname##_init(enum uart_baud rate,...); \ +void uartname##_tx(char c); \ +BOOL uartname##_set_baud(enum uart_baud rate); \ +enum uart_baud uartname##_get_baud(); \ +BOOL uartname##_tx_willblock(); \ +char uartname##_rx(); \ +BOOL uartname##_check_rx_blocking(); \ +BYTE uartname##_check_receive_buffer(); + +/*Holds the value of the EA register.*/ +__bit ea_hold; + +static inline void uart_tx(char c) +{ + + //Done in ASM to improve performance. It takes only 6 + //cycles to move the data out, however a delay has been + //introduced in order to get a baud rate of 115200. + //An efficient UART bitbang routine in assembly. + __asm + //Disable interrupts. + //This is used because timing is critical. + //If the FX2 jumps into the ISR temporarily , it may cause transmit + //errors. By clearing EA, we can disable interrupts + //Store the EA bit. + mov _ea_hold,_EA + 0002$: + clr _EA //(2 cycles) + //Move the data to be sent into the ACC. //(--) + //The data which is to be shifted out is held in the dpl register. //(--) + //We move the data into A for easy access to subsequent instructions. //(--) + mov a , dpl //(2 cyles) + clr c //(1 cycle ) + //We need to send out 8 bits of data. //(--) + //Load r0 with value 8. //(--) + mov r0, #0x08 //(2 cycles) + //Create the start bit. //(--) + clr _TX_PIN1 //(2 cycles) + //Precalculated delay since 1 cycle takes 88ns. //(--) + //At 12Mhz, it should be about 83.33ns. //(--) + //But it appears to be about 88ns. //(--) + //These numbers have been verified using an analyzer. //(--) + mov r1, _load_delay //(2 cycles) + 0003$: //(--) + //1 bit is about 8.6us. //(--) + djnz r1, 0003$ //(3 cycles) + //DJNZ on Rn takes 3 cycles. //(--) + //NOP takes about 1 cycle. //(--) + //Add 2 more cycles of delay. //(--) + //97 cycles //(--) + nop //(1 cycle ) + nop //(1 cycle ) + 0004$: //(--) + rrc a //(2 cycles) + //The above rotates the accumulator right through the carry. //(--) + //Move the carry into the port. //(--) + mov _TX_PIN1, c //(2 cycles) + //Now we need to add delay for the next. //(--) + mov r1, _load_delay //(2 cycles) + //31*3 , 93 cycles of delay. //(--) + 0005$: //(--) + djnz r1, 0005$ //(3 cycles) + nop //(1 cycle ) + //3 more cycles of delay. //(--) + //97 cycles. //(--) + djnz r0, 0004$ //(3 cycles) + setb _TX_PIN1 //(2 cycles) + //This is for stop bit. //(--) + //We need to delay the stop bit, otherwise we may get errors. //(--) + mov r1, _load_delay //(2 cycles) + 0006$: //(--) + djnz r1, 0006$ //(3 cycles) + //for DJNZ , Jump for 32*3 , 96 cycles. //(--) + nop //(1 cycle ) + //97 cycles of delay. //(--) + //Restore the EA register to enable or disable interrupts. //(--) + mov _EA, _ea_hold //(--) + __endasm; +} +#endif diff --git a/lib/fx2.mk b/lib/fx2.mk index 700799d..32c5e35 100644 --- a/lib/fx2.mk +++ b/lib/fx2.mk @@ -115,3 +115,5 @@ clean: clean-all: clean $(MAKE) -C $(FX2LIBDIR)/lib clean +fx2_download: + ../download.sh build/$(BASENAME).ihx