Added new XPLAIN serial Bridge project (thanks to John Steggall for the software...
[pub/lufa.git] / Projects / XPLAINBridge / Lib / SoftUART.S
diff --git a/Projects/XPLAINBridge/Lib/SoftUART.S b/Projects/XPLAINBridge/Lib/SoftUART.S
new file mode 100644 (file)
index 0000000..8951387
--- /dev/null
@@ -0,0 +1,389 @@
+/*\r
+\r
+       uart_soft\r
+\r
+       copyright John Steggall 2009\r
+\r
+*/\r
+\r
+\r
+/*\r
+  Copyright 2009  John Steggall (steggall.j@gmail.com)\r
+\r
+  Permission to use, copy, modify, and distribute this software\r
+  and its documentation for any purpose and without fee is hereby\r
+  granted, provided that the above copyright notice appear in all\r
+  copies and that both that the copyright notice and this\r
+  permission notice and warranty disclaimer appear in supporting\r
+  documentation, and that the name of the author not be used in\r
+  advertising or publicity pertaining to distribution of the\r
+  software without specific, written prior permission.\r
+\r
+  The author disclaim all warranties with regard to this\r
+  software, including all implied warranties of merchantability\r
+  and fitness.  In no event shall the author be liable for any\r
+  special, indirect or consequential damages or any damages\r
+  whatsoever resulting from loss of use, data or profits, whether\r
+  in an action of contract, negligence or other tortious action,\r
+  arising out of or in connection with the use or performance of\r
+  this software.\r
+*/\r
+\r
+#include <avr/io.h>\r
+\r
+/* BITLENGTH is the time for a bit cycle worked out at F_CPU / BAUD. Gives a rough but usable figure. Wouldn't like to try\r
+ * anything faster than 9600! */\r
+#define BITLENGTH 833\r
+\r
+#define SFT_TX_EN 7\r
+\r
+#define SF_UART_TX     1\r
+#define SF_UART_RX     2\r
+\r
+       .section        .data\r
+\r
+rxdata:\r
+       .byte   0\r
+txShifter:\r
+       .byte   0\r
+txBitcount:\r
+       .byte   0\r
+rxShifter:\r
+       .byte   0\r
+rxBitcount:\r
+       .byte   0\r
+status:\r
+       .byte   0\r
+\r
+       .section        .text\r
+\r
+/*********************************************\r
+ * External interrupt\r
+ * \r
+ * RX pin has gone low.\r
+ */\r
+       .global INT0_vect\r
+\r
+INT0_vect:\r
+       push            r16\r
+       lds             r16,SREG\r
+       push            r16\r
+\r
+       lds             r16,PIND\r
+       sbrc            r16,0           // anti glitch\r
+       rjmp            ignore\r
+       nop\r
+       nop\r
+       nop\r
+       nop\r
+       lds             r16,PIND\r
+       sbrc            r16,0           // just make sure\r
+       rjmp            ignore\r
+\r
+       push            r17\r
+\r
+       // grab timer value\r
+       lds             r16,TCNT3L              \r
+       lds             r17,TCNT3H\r
+       \r
+       // set trigger for RX timer (will need to add a little more though)\r
+       sts             OCR3CH,r17\r
+       sts             OCR3CL,r16\r
+       \r
+       pop             r17\r
+\r
+       // set bitcount to 0\r
+       ldi             r16,0\r
+       sts             rxBitcount,r16\r
+\r
+\r
+       // turn off interrupt, will get annoying.\r
+       cbi             0x1D,0\r
+\r
+       // turn on interrupt on compare match\r
+       sbi             0x18,OCF3C\r
+       lds             r16,TIMSK3\r
+       ori             r16,(1<<OCIE3C)\r
+       sts             TIMSK3,r16\r
+\r
+ignore:\r
+       pop             r16\r
+       sts             SREG,r16\r
+       pop             r16\r
+       reti\r
+\r
+\r
+/*********************************************\r
+ * interrupt routine, timer compare match.\r
+ * \r
+ * TX bit rate timing\r
+ */\r
+       .global TIMER3_COMPB_vect\r
+\r
+TIMER3_COMPB_vect:\r
+       push            r16\r
+       lds             r16,SREG\r
+       push            r16\r
+       push            r17\r
+       push            r18\r
+\r
+       // check if the last bit was sent\r
+       lds             r17,txBitcount\r
+       inc             r17\r
+       cpi             r17,0x0A\r
+       sts             txBitcount,r17\r
+       breq            lastBitTX\r
+\r
+       lds             r16,txShifter\r
+\r
+       lds             r17, PORTD\r
+\r
+       sbrs            r16,0\r
+       andi            r17,0xFD\r
+       sbrc            r16,0\r
+       ori             r17,0x02\r
+\r
+       sts             PORTD,r17\r
+\r
+       lsr             r16\r
+       ori             r16,0x80\r
+\r
+txout:\r
+       sts             txShifter,r16\r
+lastBitOut:\r
+       pop             r18\r
+       pop             r17\r
+       pop             r16\r
+       sts             SREG,r16\r
+       pop             r16\r
+       reti\r
+\r
+// section handles the last bit (stop bit sent/received and sets the flag to say done //\r
+lastBitTX:\r
+       lds             r17,status              // get status\r
+       ori             r17,SF_UART_TX          // set TXC/DRE flag\r
+       sts             status,r17\r
+\r
+       lds             r16,TIMSK3\r
+       andi            r16,~(1<<OCIE3B)\r
+       sts             TIMSK3,r16\r
+\r
+       rjmp            lastBitOut              // over and out\r
+\r
+\r
+\r
+/*********************************************\r
+ * interrupt routine, timer compare match.\r
+ * \r
+ * RX bit rate timing\r
+ */\r
+       .global TIMER3_COMPC_vect\r
+\r
+TIMER3_COMPC_vect:\r
+       push            r16\r
+       lds             r16,SREG\r
+       push            r16\r
+       push            r17\r
+       push            r18\r
+\r
+       // check if the last bit has been recieved\r
+       lds             r17,rxBitcount\r
+       inc             r17\r
+       cpi             r17,0x0A\r
+       sts             rxBitcount,r17\r
+       breq            lastBitRX\r
+\r
+       cpi             r17,0x01\r
+       breq            rx1stbit\r
+\r
+       ldi             r18,3                   // set counter to 3\r
+       ldi             r17,0\r
+\r
+//     cbi             0x0B,1                  // marker\r
+\r
+loopGetBit:\r
+       lds             r16,PIND                        \r
+       sbrc            r16,0\r
+       inc             r17\r
+       dec             r18\r
+       nop\r
+       nop\r
+       nop\r
+       nop\r
+       brne            loopGetBit\r
+\r
+//     sbi             0x0B,1                  // marker\r
+\r
+       lds             r16,rxShifter\r
+       lsr             r16\r
+\r
+       cpi             r17,2\r
+       brlo            skipBitSet\r
+       ori             r16,0x80\r
+skipBitSet:\r
+       sts             rxShifter,r16\r
+       rjmp            lastBitOut\r
+\r
+lastBitRX:\r
+       lds             r17,status              // store status\r
+       lds             r16,PIND                        // get status of stop bit\r
+       sbrc            r16,0\r
+       ori             r17,0x02                        // set flag if stop bit was high\r
+       sts             status,r17\r
+\r
+       lds             r16,rxShifter           // get contents of shifter\r
+       sbrc            r17,1                   // check if we just received a valid byte\r
+       sts             rxdata,r16              // if valid rxdata = shifter\r
+\r
+       // switch interrupt back on to get another go\r
+\r
+       sbi             0x1C,0                  // clear interrupt flag\r
+       sbi             0x1D,0                  // enable external interrupt 0 (RX)\r
+\r
+       // switch off rx bit timer\r
+       lds             r16,TIMSK3\r
+       andi            r16,~(1<<OCIE3C)\r
+       sts             TIMSK3,r16\r
+\r
+       rjmp            lastBitOut              // loud and clear\r
+\r
+rx1stbit:\r
+       lds             r16,TCNT3L\r
+       lds             r17,TCNT3H\r
+\r
+       subi            r16,lo8(BITLENGTH / 2)\r
+       sbci            r17,hi8(BITLENGTH / 2)\r
+       brcc            skipOverflow\r
+\r
+       subi            r16,lo8(0xFFFF - BITLENGTH)\r
+       sbci            r17,hi8(0xFFFF - BITLENGTH)\r
+\r
+skipOverflow:\r
+       sts             OCR3CH,r17\r
+       sts             OCR3CL,r17\r
+       rjmp            lastBitOut\r
+\r
+                       \r
+/*********************************************\r
+ * void SoftUART_Init(void)\r
+ *\r
+ * initialises software uart and enables transmit\r
+ */\r
+       .global SoftUART_Init\r
+\r
+SoftUART_Init:\r
+\r
+       lds             r18,PORTD\r
+       ori             r18,0x02\r
+       sts             PORTD,r18\r
+       lds             r18,DDRD\r
+       ori             r18,0x02\r
+       sts             DDRD,r18\r
+\r
+       ldi             r18,(1<<SFT_TX_EN)|SF_UART_TX\r
+       sts             status,r18\r
+       \r
+       ldi             r18,lo8(BITLENGTH)\r
+       ldi             r19,hi8(BITLENGTH)\r
+       sts             OCR3AH,r19\r
+       sts             OCR3AL,r18\r
+\r
+       // Start timer 3\r
+       ldi             r18,0b00001001                  // ctc count mode, clock div 1\r
+       sts             TCCR3B,r18\r
+\r
+       // Interrupt on low level INT0\r
+       sbi             0x1C,0\r
+       sbi             0x1D,0\r
+\r
+       ret\r
+\r
+\r
+/*********************************************\r
+ * char SoftUART_TxByte(char)\r
+ *\r
+ * starts a byte send and returns the byte to be sent\r
+ */\r
+       .global SoftUART_TxByte\r
+\r
+SoftUART_TxByte:\r
+       lds             r18,status\r
+       sbrs            r18,SFT_TX_EN\r
+       rjmp            uart_putchar_end\r
+\r
+       andi            r18,0xFE                                                // clear tx empty flag\r
+       sts             status,r18\r
+\r
+       sts             txShifter,r24\r
+\r
+       ldi             r18,0\r
+       sts             txBitcount,r18\r
+\r
+       // grab timer value\r
+\r
+       lds             r18,TCNT3L\r
+       lds             r19,TCNT3H\r
+\r
+       // drop down tx line for start bit\r
+       lds             r20, PORTD\r
+       andi            r20,0xFD\r
+       sts             PORTD,r20\r
+       \r
+       // set trigger for tx timer\r
+       cli\r
+       sts             OCR3BH,r19\r
+       sts             OCR3BL,r18\r
+       sei\r
+\r
+       // clear interrupt flag and enable tx interrupt\r
+       sbi             0x18,OCF3B\r
+       lds             r18,TIMSK3\r
+       ori             r18,(1<<OCIE3B)\r
+       sts             TIMSK3,r18\r
+\r
+uart_putchar_end:\r
+       ret\r
+\r
+\r
+/*********************************************\r
+ * char SoftUART_RxByte(void)\r
+ *\r
+ * returns the received byte\r
+ */\r
+       .global SoftUART_RxByte\r
+\r
+SoftUART_RxByte:\r
+       lds             r24,rxdata\r
+       lds             r18,status\r
+       andi            r18,0xFD\r
+       sts             status,r18\r
+       ret\r
+\r
+\r
+/*********************************************\r
+ * char SoftUART_IsReceived(void)\r
+ *\r
+ * checks if there is a byte in the receive buffer\r
+ */\r
+       .global SoftUART_IsReceived\r
+\r
+SoftUART_IsReceived:\r
+       lds             r24,status\r
+       andi            r24,SF_UART_RX\r
+       lsr             r24\r
+       ret\r
+\r
+\r
+/*********************************************\r
+ * char SoftUART_IsReady(void)\r
+ *\r
+ * Simulates polling UDRE to see if tx buffer is empty and ready\r
+ *\r
+ * returns 1 if empty 0 if not\r
+ */\r
+       .global SoftUART_IsReady\r
+\r
+SoftUART_IsReady:\r
+       lds             r24,status\r
+       andi            r24,SF_UART_TX\r
+       ret\r