-/*\r
-\r
- uart_soft\r
-\r
- v0.2\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
-#include "SoftUARTConf.h"\r
-\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
- \r
- .global status\r
-status:\r
- .byte 0\r
-\r
- .section .text\r
-\r
-\r
- .global RX_PIN_INT\r
-\r
-/*********************************************\r
- * External interrupt\r
- * \r
- * RX pin has gone low.\r
- */\r
-RX_PIN_INT:\r
- push r16\r
- lds r16,SREG\r
- push r16\r
-\r
-#if (RXPORT>=32)\r
- lds r16,RXPORT\r
- sbrc r16,0 // anti glitch\r
-\r
-#else\r
- sbic RXPORT,0\r
-#endif\r
-\r
- rjmp ignore\r
- nop\r
- nop\r
- nop\r
- nop\r
-\r
-#if (RXPORT>=32)\r
- lds r16,RXPORT\r
- sbrc r16,0 // anti glitch\r
-\r
-#else\r
- sbic RXPORT,0\r
-#endif\r
-\r
- rjmp ignore\r
-\r
- push r17\r
-\r
- // grab timer value\r
- lds r16,TC_COUNTL \r
- lds r17,TC_COUNTH\r
- \r
- // set trigger for RX timer (will need to add a little more though)\r
- sts TC_RX_COMPH,r17\r
- sts TC_RX_COMPL,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 EXTI_MASK_REG,EXTI_MASK_BIT\r
-\r
- // turn on interrupt on compare match\r
-\r
- sbi TC_INTFLAG_REG,TC_RX_IF_BIT \r
-\r
- lds r16,TC_INT_MASK_REG\r
- ori r16,(1<<TC_RX_COMPEN)\r
- sts TC_INT_MASK_REG,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
-#if (TXPORT>=32)\r
- lds r17, TXPORT\r
- sbrs r16,0\r
- andi r17,~(1<<TXPIN)\r
- sbrc r16,0\r
- ori r17,(1<<TXPIN)\r
- sts TXPORT,r17\r
-\r
-#else\r
- sbrs r16,0\r
- cbi TXPORT,TXPIN\r
- sbrc r16,0\r
- sbi TXPORT,TXPIN\r
-\r
-#endif\r
- sec\r
- ror r16\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,TC_INT_MASK_REG\r
- andi r16,~(1<<TC_TX_COMPEN)\r
- sts TC_INT_MASK_REG,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
-#ifdef DEBUG\r
-\r
-#if RXPORT>64\r
- lds r16,RXPORT\r
- andi r16,~(1<<TXPIN)\r
- sts TXPORT,r16\r
-#else\r
- cbi TXPORT,TXPIN // marker\r
-#endif\r
-#endif\r
-\r
-loopGetBit:\r
-\r
-#if (RXPORT>=32)\r
- lds r16,RXPORT\r
- sbrs r16,RXPIN\r
-#else \r
- sbic RXPORT,RXPIN\r
-\r
-#endif\r
-\r
- inc r17\r
- dec r18\r
- nop\r
- nop\r
- nop\r
- nop\r
- brne loopGetBit\r
-\r
-#ifdef DEBUG\r
-\r
-#if RXPORT>64\r
- lds r16,RXPORT\r
- ori r16,1<<TXPIN\r
- sts r16\r
-\r
-#else\r
- sbi TXPORT,TXPIN // marker\r
-\r
-#endif\r
-#endif\r
-\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
-\r
-#if (RXPORT>=32)\r
- lds r16,RXPORT\r
- sbrc r16,RXPIN\r
-\r
-#else\r
- sbic RXPORT,RXPIN \r
-\r
-#endif\r
-\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 EXTI_FLAG_REG,EXTI_MASK_BIT // clear interrupt flag\r
- sbi EXTI_MASK_REG,EXTI_MASK_BIT // enable external interrupt 0 (RX)\r
-\r
- // switch off rx bit timer\r
- lds r16,TC_INT_MASK_REG\r
- andi r16,~(1<<TC_RX_COMPEN)\r
- sts TC_INT_MASK_REG,r16\r
-\r
- rjmp lastBitOut // loud and clear\r
-\r
-rx1stbit:\r
- lds r16,TC_COUNTL\r
- lds r17,TC_COUNTH\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 TC_RX_COMPH,r17\r
- sts TC_RX_COMPL,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
-#if (TXPORT>=32)\r
- lds r18,TXPORT\r
- ori r18,0x02\r
- sts TXPORT,r18\r
-\r
- lds r18,TXDIR_REG\r
- ori r18,0x02\r
- sts TXDIR_REG,r18\r
-\r
-#else\r
- sbi TXPORT,TXPIN\r
- sbi TXDIR_REG,TXPIN\r
-\r
-#endif\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 TC_CTRLB,r18\r
-\r
- // Interrupt on pin change INT0\r
- sbi EXTI_FLAG_REG,EXTI_MASK_BIT\r
- sbi EXTI_MASK_REG,EXTI_MASK_BIT\r
-\r
- ret\r
-\r
-\r
-/*********************************************\r
- * char SoftUART_RxByte(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 SoftUART_TxByte_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
- cli // Atomic section start\r
- lds r18,TC_COUNTL\r
- lds r19,TC_COUNTH\r
-\r
- // drop down tx line for start bit\r
-\r
-#if (TXPORT>=32)\r
- lds r20, TXPORT\r
- andi r20,~(1<<TXPIN)\r
- sts TXPORT,r20\r
-\r
-#else\r
- cbi TXPORT,TXPIN\r
-#endif\r
-\r
- // set trigger for tx timer\r
- sts TC_TX_COMPH,r19\r
- sts TC_TX_COMPL,r18\r
- sei // Atomic section end\r
-\r
- // clear interrupt flag and enable tx interrupt\r
-\r
- sbi TC_INTFLAG_REG,TC_TX_IF_BIT\r
-\r
- lds r18,TC_INT_MASK_REG\r
- ori r18,(1<<TC_TX_COMPEN)\r
- sts TC_INT_MASK_REG,r18\r
-\r
-SoftUART_TxByte_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