Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented UART in accordance with the API definition in softuart.h to allow the example code to access printf() functionality #18

Open
wants to merge 1 commit into
base: linux-descriptors
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
52 changes: 52 additions & 0 deletions examples/uart_main/uart_main.c
Original file line number Diff line number Diff line change
@@ -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 <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,_PB0,bmBIT0,TRUE,FALSE)
CREATE_FAST_UART(uart1,OEA,_PA4,bmBIT4,TRUE,FALSE)
//Used for setting the baud rate.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't define things you are not using at the moment.

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)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Formatting...

{
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
164 changes: 164 additions & 0 deletions include/uart/soft_uart.h
Original file line number Diff line number Diff line change
@@ -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
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just move _EA into the holder?

Copy link
Author

@RacingTornado RacingTornado Jul 11, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me try that.

//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
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