├── LICENSE ├── README.md └── software_uart.asm /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Constantine Bilous 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AVR-ASM-Software-UART 2 | Simple software UART for AVR microcontrollers, written in assembly 3 | -------------------------------------------------------------------------------- /software_uart.asm: -------------------------------------------------------------------------------- 1 | .include "tn13def.inc" 2 | 3 | ;***** Pin definitions ***** 4 | .equ UART_TxPort = PORTB 5 | .equ UART_TxDDR = DDRB 6 | .equ UART_RxPin = PINB 7 | .equ UART_RxDDR = DDRB 8 | .equ RxD = 2 9 | .equ TxD = 3 10 | 11 | ;***** Registers ***** 12 | .def bitcounter = R24 13 | .def temp = R17 14 | .def UART_buffer = R23 15 | 16 | ;***** Speed setting ***** 17 | .equ CRYSTAL_FREQ = 8000000 18 | .equ BAUD = 9600 19 | 20 | ;***** Etc ***** 21 | .equ stop_bits = 1 22 | ; hand-picked for easier auto-baud calculations (no division) 23 | .equ cycles_per_bit = 12 ;without delays + 4*nop 24 | .equ const_delay_cycles = 9 ;rjmp + ret + 2*nop 25 | 26 | ; byte in ram that keeps speed 27 | .dseg 28 | DELAY_VALUE: .byte 1 29 | .cseg 30 | 31 | ;***** Precalculations ***** 32 | ;pure cycles necessary per bit 33 | .equ c = CRYSTAL_FREQ / BAUD 34 | ;delay cycles 35 | .equ d = (c - cycles_per_bit - 2*const_delay_cycles)/2 36 | ;delay value 37 | .equ b = d / 3 38 | 39 | ; throw error if we're out of bounds 40 | .if b > 255 41 | .error "Baud rate is too low!" 42 | .elif b <= 0 43 | .error "Baud rate is too high!" 44 | .endif 45 | 46 | ;**************************************************** 47 | ;**********************CODE HERE********************* 48 | ;**************************************************** 49 | 50 | ;**************************************************** 51 | ;***** SEND BYTE ***** 52 | ;**************************************************** 53 | ; UART_buffer -> UART 54 | UART_send_byte: 55 | ldi bitcounter, 9 + stop_bits 56 | com UART_buffer 57 | sec 58 | 59 | ; 12 cycles here (without delays) 60 | uart_send_next_bit: 61 | brcc uart_send_1 62 | cbi UART_TxPort, TxD 63 | rjmp uart_wait 64 | 65 | uart_send_1: 66 | sbi UART_TxPort, TxD 67 | nop 68 | 69 | uart_wait: 70 | rcall UART_delay 71 | rcall UART_delay 72 | 73 | nop nop nop nop 74 | lsr UART_buffer 75 | dec bitcounter 76 | brne uart_send_next_bit 77 | 78 | sbi UART_TxPort, TxD 79 | ret 80 | 81 | ;**************************************************** 82 | ;***** GET BYTE ***** 83 | ;**************************************************** 84 | ; UART -> UART_buffer 85 | UART_get_byte: 86 | ldi bitcounter, 9 87 | 88 | uart_wait_for_start: 89 | sbic UART_RxPin, RxD 90 | rjmp uart_wait_for_start 91 | ;synchronize for 0.5 bit length 92 | rcall UART_delay 93 | 94 | ; 10 cycles here (without delays) 95 | uart_get_bit: 96 | rcall UART_delay 97 | rcall UART_delay 98 | 99 | clc 100 | sbic UART_RxPin, RxD 101 | sec 102 | 103 | nop nop nop nop 104 | dec bitcounter 105 | breq uart_bit_done 106 | 107 | ror UART_buffer 108 | rjmp uart_get_bit 109 | 110 | uart_bit_done: 111 | ret 112 | 113 | ;**************************************************** 114 | ;***** UART DELAY ***** 115 | ;**************************************************** 116 | ; 3*b + const_delay_cycles 117 | UART_delay: 118 | lds temp, DELAY_VALUE 119 | UART_delay1: 120 | dec temp 121 | brne UART_delay1 122 | nop 123 | ret 124 | 125 | ;**************************************************** 126 | ;***** UART AUTO-BAUD ***** 127 | ;**************************************************** 128 | ; calculates calc_b after receiving 0x55 129 | ; calc_b -> temp 130 | ; intermediate result is c/6 131 | ; sbis (2) + inc (1) + breq (2) + nop (1) 132 | 133 | UART_autocalibrate: 134 | clr temp 135 | 136 | uart_cal_wait_start: 137 | sbic UART_RxPin, RxD 138 | rjmp uart_cal_wait_start 139 | 140 | uart_cal_wait_bit: 141 | sbis UART_RxPin, RxD 142 | rjmp uart_cal_wait_bit 143 | 144 | uart_measure_bit: 145 | sbis UART_RxPin, RxD 146 | rjmp uart_calibration_done 147 | nop 148 | inc temp 149 | breq uart_calibration_fail 150 | 151 | uart_calibration_done: 152 | ; b = c/6 - cycles_per_bit/6 - const_delay_cycles/3 153 | ; temp = c/6 154 | cpi temp, cycles_per_bit/6 155 | brlo uart_calibration_fail 156 | subi temp, cycles_per_bit/6 157 | 158 | cpi temp, const_delay_cycles/3 159 | brlo uart_calibration_fail 160 | subi temp, const_delay_cycles/3 161 | 162 | sts DELAY_VALUE, temp 163 | 164 | uart_calibration_fail: 165 | ret 166 | 167 | ;**************************************************** 168 | ;***** UART REINIT ***** 169 | ;**************************************************** 170 | ; just resets DELAY_VALUE to default 171 | uart_reinit: 172 | in temp, UART_TxDDR 173 | ori temp, (1<