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/uart_main.c b/examples/uart_main/uart_main.c index cddda5e..dfdb575 100644 --- a/examples/uart_main/uart_main.c +++ b/examples/uart_main/uart_main.c @@ -22,23 +22,27 @@ #include #include -//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); } } diff --git a/include/uart/soft_uart.h b/include/uart/soft_uart.h index 10e98cb..30ee6cf 100644 --- a/include/uart/soft_uart.h +++ b/include/uart/soft_uart.h @@ -5,24 +5,142 @@ #ifndef SOFT_UART_H #define SOFT_UART_H - - -#define CREATE_FAST_UART(uart0,pinname) \ -__sbit __at pinname TX_PIN; \ -BOOL uart0##_init(enum uart_baud rate,...) \ -{__asm \ -.equ _TX_PIN , _PA2 \ -__endasm; \ +#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 uart0##_tx(char c) { \ +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(); -/** - * \brief Send data out via UART -**/ -void uart_tx(char 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; +} #endif - diff --git a/lib/uart/soft_uart.c b/lib/uart/soft_uart.c index 40ca188..c0b62bc 100644 --- a/lib/uart/soft_uart.c +++ b/lib/uart/soft_uart.c @@ -7,135 +7,16 @@ #include #include -/*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;