Skip to content

Commit

Permalink
Created a UART API definition in softuart.h to allow the example code…
Browse files Browse the repository at this point in the history
… to access printf() and scanf() functionality

Create UART functions using C macros according to the api.h file
  • Loading branch information
Roarin committed Jul 20, 2016
1 parent 0ddd377 commit 614a4c3
Show file tree
Hide file tree
Showing 6 changed files with 325 additions and 0 deletions.
15 changes: 15 additions & 0 deletions examples/download.sh
Original file line number Diff line number Diff line change
@@ -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 <file>"
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
6 changes: 6 additions & 0 deletions examples/uart_main/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FX2LIBDIR=../..
BASENAME = uart_main
SOURCES=uart_main.c
DSCR_AREA=
INT2JT=
include $(FX2LIBDIR)/lib/fx2.mk
54 changes: 54 additions & 0 deletions examples/uart_main/uart_main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* 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 <fx2regs.h>
#include <delay.h>
#include <stdio.h>
#include <uart/api.h>
#include <uart/soft_uart.h>
#include <fx2macros.h>
#include <fx2types.h>
#include <assert.h>



//Initialize UART, call it uart0 and set the tx pin on PA1
CREATE_FAST_UART(uart0,OEB,_PB2,bmBIT2,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);
}
79 changes: 79 additions & 0 deletions include/uart/api.h
Original file line number Diff line number Diff line change
@@ -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
169 changes: 169 additions & 0 deletions include/uart/soft_uart.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/** \file include/uart/soft_uart.h
* This file contains a MACRO for defining UART function wrappers
**/

#ifndef SOFT_UART_H
#define SOFT_UART_H

#define load_delay unsigned char
/**
* \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) \
unsigned char 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
//The mask which is to be written into the pin
//An efficient UART bitbang routine in assembly
__asm
//Like #define in C. Can easily be used to change the pin
//.equ _TX_PIN, _PA2
//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
mov _ea_hold,_EA //Store the EA bit
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
mov _EA, _ea_hold //Restore the EA register to enable or disable interrupts
__endasm;
}

#endif
2 changes: 2 additions & 0 deletions lib/fx2.mk
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,5 @@ clean:
clean-all: clean
$(MAKE) -C $(FX2LIBDIR)/lib clean

fx2_download:
../download.sh build/$(BASENAME).ihx

0 comments on commit 614a4c3

Please sign in to comment.