view serial.cc @ 0:6dfcd8e5b8df

first release
author Frank Kingswood <frank@kingswood-consulting.co.uk>
date Tue, 25 Mar 2014 20:31:00 +0000
parents
children
line wrap: on
line source
1 /* #------------------------------------------------------------------------#
2 | |
3 | serial.cc |
4 | |
5 | Debugging (transmit only) serial port. |
6 | |
7 | Copyright 2014, Frank A. Kingswood, www.kingswood-consulting.co.uk |
8 | |
9 #------------------------------------------------------------------------# */
11 #include <avr/io.h>
12 #include <avr/wdt.h>
13 #include <avr/interrupt.h>
14 #include <stdint.h>
16 #include "serial.h"
18 #if !defined(SERIAL_PORT) || !defined(SERIAL_TXD)
19 #ifdef __AVR_ATtiny85__
20 #define SERIAL_PORT PORTB
21 #define SERIAL_TXD PB4
22 #elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
23 #define SERIAL_PORT PORTA
24 #define SERIAL_TXD PA7
25 #elif defined(__AVR_ATtiny441__) || defined(__AVR_ATtiny841__)
26 // These devices have hardware UART, not implemented here
27 #define SERIAL_PORT PORTA
28 #define SERIAL_TXD PA7
29 #define SERIAL_RXD PB2
30 #elif defined __AVR_ATmega32U4__
31 // These devices have hardware UART but using a spare port pin here
32 #define SERIAL_PORT PORTD
33 #define SERIAL_TXD PD5 // near switch
34 #endif
35 #endif
37 #if !defined(SERIAL_BAUD)
38 #define SERIAL_BAUD 38400
39 #endif
41 // Note on ABI: function calls R18-R27, R30, R31 clobbered
42 // R2-R17, R28, R29 saved
44 inline static void set_high()
45 { static const uint8_t port=_SFR_IO_ADDR(SERIAL_PORT);
46 static const uint8_t bit=SERIAL_TXD;
47 __asm__ __volatile__ ("sbi %0,%1"::"I"(port),"I"(bit):"memory");
48 }
50 inline static void set_low()
51 { static const uint8_t port=_SFR_IO_ADDR(SERIAL_PORT);
52 static const uint8_t bit=SERIAL_TXD;
53 __asm__ __volatile__ ("cbi %0,%1"::"I"(port),"I"(bit):"memory");
54 }
56 void __attribute__((noinline)) DebugSerial::delay()
57 {
58 // 38400bps -> 26us
59 // 19200bps -> 52us
60 // 9600bps -> 104us
61 // 7=fudge factor for call and loop overhead, below
62 #if SERIAL_BAUD==38400
63 uint8_t count=F_CPU*26/3-(F_CPU>1?8:6);
64 #elif SERIAL_BAUD==19200
65 uint8_t count=F_CPU*52/3-6;
66 #else // SERIAL_BAUD==9600
67 uint8_t count=F_CPU*104/3-7;
68 #endif
69 char dummy;
70 __asm__ __volatile__ (
71 "1: subi %0,1 \n"
72 " brne 1b \n"
73 #if SERIAL_BAUD==38400 && F_CPU==1
74 " breq 2f \n"
75 "2: \n"
76 #endif
77 : "=r"(dummy)
78 : "0"(count)
79 : "0"
80 );
81 }
83 void __attribute__((noinline)) DebugSerial::Send_(char byte)
84 {
85 static const uint8_t port=_SFR_IO_ADDR(SERIAL_PORT);
86 static const uint8_t bit=SERIAL_TXD;
88 cli();
90 // start bit
91 set_low();
93 for(uint8_t i=0;i<9;i++)
94 {
95 delay();
97 __asm__ __volatile__(
98 " asr %0 \n"
99 " brcs 1f \n"
100 " nop \n"
101 " cbi %2,%3 \n"
102 " brcc 2f \n"
103 "1: sbi %2,%3 \n"
104 " nop \n"
105 "2: \n"
106 :"=r"(byte)
107 :"0"(byte),"I"(port),"I"(bit));
108 }
110 // final data bit (MSB)
111 delay();
113 // safe to enable interrupts now, no problem if stop bit is a bit longer.
114 sei();
115 set_high();
116 delay();
117 #ifdef SERIAL_TWO_STOP_BITS
118 // two stop bits
119 delay();
120 #endif
121 }
123 DebugSerial::DebugSerial()
124 { Initialize();
125 }
127 void DebugSerial::Initialize()
128 { static const uint8_t port=_SFR_IO_ADDR(SERIAL_PORT)-1;
129 static const uint8_t bit=SERIAL_TXD;
130 __asm__ __volatile__ ("sbi %0,%1"::"I"(port),"I"(bit));
131 set_high();
132 }
134 const DebugSerial __attribute__((__progmem__)) Serial;
136 /* ----- EOF serial.cc ----- */