--- /dev/null
+/*\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