Skip to content

Commit

Permalink
Create UART functions using C macros according to the api.h file
Browse files Browse the repository at this point in the history
  • Loading branch information
Roarin committed Jul 5, 2016
1 parent bc7b0f4 commit 82ae218
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 144 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
16 changes: 10 additions & 6 deletions examples/uart_main/uart_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,27 @@
#include <uart/soft_uart.h>
#include <fx2macros.h>

//We need this declaration
void uart0_tx(char c);


//Initialize UART, call it uart0 and set the tx pin on PA1
CREATE_FAST_UART(uart0,0x82)
CREATE_FAST_UART(uart0,_PA2,bmBIT2)
CREATE_FAST_UART(uart1,_PA3,bmBIT3)

//Used for setting the baud rate.
enum uart_baud baud;
void main(void)
{
baud = BAUD_115200;
uartX_init(baud);
uartX_set_baud(baud);
baud = BAUD_19200;
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);
}
}

Expand Down
152 changes: 135 additions & 17 deletions include/uart/soft_uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,142 @@
#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,pinname,bitnum) \
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; \
OEA = bitnum; \
uart_tx(c); \
} \
BOOL uartname##_set_baud(enum uart_baud rate) { \
uartname##rate = rate; \
switch(rate) \
{ \
case BAUD_2400: \
break; \
case BAUD_4800: \
break; \
case BAUD_9600: \
break; \
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: \
break; \
default: \
uartname##_load_delay = 0x20; \
break; \
} \
return TRUE; \
} \
enum uart_baud uartname##_get_baud() \
{ \
return uartname##rate; \
} \
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();


#define CREATE_FAST_UART(uart0,pinname) \
__sbit __at pinname TX_PIN; \
BOOL uart0##_init(enum uart_baud rate,...) \
{__asm \
.equ _TX_PIN , _PA2 \
__endasm; \
return TRUE; \
} \
void uart0##_tx(char c) { \
uart_tx(c); \
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
jnb _EA,0001$//Check if the EA bit is set to 1 or not
setb _ea_hold //Store the EA bit
sjmp 0002$
0001$:
clr _ea_hold //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 c,_ea_hold //Restore the EA register to enable or disable interrupts
mov _EA,c //(2 cycles)
__endasm;
}

/**
* \brief Send data out via UART
**/
void uart_tx(char c);

#endif

123 changes: 2 additions & 121 deletions lib/uart/soft_uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,135 +7,16 @@
#include <uart/api.h>
#include <assert.h>

/*This is set by calling the uartX_set_baud() function.*/
unsigned char load_delay;
/*Holds the value of the EA register*/
__bit ea_hold;
BOOL uartX_init(enum uart_baud rate, ...)
{
unsigned char clk_cmp;
//Clear all bits except the CLKSPD[1:0]
clk_cmp = CPUCS & 0x18;
//If clock is currently set to 48Mhz,return TRUE
if(clk_cmp == 0x10)
return TRUE;
return FALSE;
}


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
OEA |= 0x04;
//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
jnb _EA,set_ea_enable//Check if the EA bit is set to 1 or not
setb _ea_hold //Store the EA bit
sjmp start
set_ea_enable:
clr _ea_hold //Store the EA bit
start:
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_PIN //(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)
delay_1$:
//1 bit is about 8.6us
djnz r1, delay_1$ //(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 )
next_bit$:
rrc a //(2 cycles)
//The above rotates the accumulator right through the carry
//Move the carry into the port
mov _TX_PIN, c //(2 cycles)
//Now we need to add delay for the next
mov r1, _load_delay //(2 cycles)
//31*3 , 93 cycles of delay
delay_2$:
djnz r1, delay_2$ //(3 cycles)
nop //(1 cycle )
//3 more cycles of delay
//97 cycles
djnz r0, next_bit$ //(3 cycles)
setb _TX_PIN //(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)
delay_3$:
djnz r1, delay_3$ //(3 cycles)
//for DJNZ , Jump for 32*3 , 96 cycles
nop //(1 cycle )
//97 cycles of delay
mov c,_ea_hold //Restore the EA register to enable or disable interrupts
mov _EA,c //(2 cycles)
__endasm;
}

BOOL uartX_set_baud(enum uart_baud rate)
{
switch(rate)
{
case BAUD_2400:
load_delay = 0xd0;
break;
case BAUD_4800:
break;
case BAUD_9600:
break;
case BAUD_19200:
load_delay = 0xd0;
break;
case BAUD_38400:
load_delay = 0x68;
break;
case BAUD_57600:
load_delay = 0x45;
break;
case BAUD_115200:
load_delay = 0x20;
break;
case BAUD_ANY:
break;
case BAUD_FASTEST:
break;
default:
load_delay = 0x20;
break;
}
if(CPUFREQ!=CLK_48M)
return FALSE;
return TRUE;
}

enum uart_baud uartX_get_baud()
{
return BAUD_115200;
}

BOOL uartX_tx_willblock()
{
return TRUE;
Expand Down

0 comments on commit 82ae218

Please sign in to comment.