1 | /* |
2 | wiring_digital.c - digital input and output functions |
3 | Part of Arduino - http://www.arduino.cc/ |
4 | |
5 | Copyright (c) 2005-2006 David A. Mellis |
6 | |
7 | This library is free software; you can redistribute it and/or |
8 | modify it under the terms of the GNU Lesser General Public |
9 | License as published by the Free Software Foundation; either |
10 | version 2.1 of the License, or (at your option) any later version. |
11 | |
12 | This library is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | Lesser General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU Lesser General |
18 | Public License along with this library; if not, write to the |
19 | Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
20 | Boston, MA 02111-1307 USA |
21 | |
22 | Modified 28 September 2010 by Mark Sproul |
23 | */ |
24 |
|
25 | #define ARDUINO_MAIN |
26 | #include "wiring_private.h" |
27 | #include "pins_arduino.h" |
28 |
|
29 | void pinMode(uint8_t pin, uint8_t mode) |
30 | { |
31 | uint8_t bit = digitalPinToBitMask(pin); |
32 | uint8_t port = digitalPinToPort(pin); |
33 | volatile uint8_t *reg, *out; |
34 |
|
35 | if (port == NOT_A_PIN) return; |
36 |
|
37 | // JWS: can I let the optimizer do this? |
38 | reg = portModeRegister(port); |
39 | out = portOutputRegister(port); |
40 |
|
41 | if (mode == INPUT) { |
42 | uint8_t oldSREG = SREG; |
43 | cli(); |
44 | *reg &= ~bit; |
45 | *out &= ~bit; |
46 | SREG = oldSREG; |
47 | } else if (mode == INPUT_PULLUP) { |
48 | uint8_t oldSREG = SREG; |
49 | cli(); |
50 | *reg &= ~bit; |
51 | *out |= bit; |
52 | SREG = oldSREG; |
53 | } else { |
54 | uint8_t oldSREG = SREG; |
55 | cli(); |
56 | *reg |= bit; |
57 | SREG = oldSREG; |
58 | } |
59 | } |
60 |
|
61 | // Forcing this inline keeps the callers from having to push their own stuff |
62 | // on the stack. It is a good performance win and only takes 1 more byte per |
63 | // user than calling. (It will take more bytes on the 168.) |
64 | // |
65 | // But shouldn't this be moved into pinMode? Seems silly to check and do on |
66 | // each digitalread or write. |
67 | // |
68 | // Mark Sproul: |
69 | // - Removed inline. Save 170 bytes on atmega1280 |
70 | // - changed to a switch statment; added 32 bytes but much easier to read and maintain. |
71 | // - Added more #ifdefs, now compiles for atmega645 |
72 | // |
73 | //static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline)); |
74 | //static inline void turnOffPWM(uint8_t timer) |
75 | static void turnOffPWM(uint8_t timer) |
76 | { |
77 | switch (timer) |
78 | { |
79 | #if defined(TCCR1A) && defined(COM1A1) |
80 | case TIMER1A: cbi(TCCR1A, COM1A1); break; |
81 | #endif |
82 | #if defined(TCCR1A) && defined(COM1B1) |
83 | case TIMER1B: cbi(TCCR1A, COM1B1); break; |
84 | #endif |
85 | #if defined(TCCR1A) && defined(COM1C1) |
86 | case TIMER1C: cbi(TCCR1A, COM1C1); break; |
87 | #endif |
88 | |
89 | #if defined(TCCR2) && defined(COM21) |
90 | case TIMER2: cbi(TCCR2, COM21); break; |
91 | #endif |
92 | |
93 | #if defined(TCCR0A) && defined(COM0A1) |
94 | case TIMER0A: cbi(TCCR0A, COM0A1); break; |
95 | #endif |
96 | |
97 | #if defined(TCCR0A) && defined(COM0B1) |
98 | case TIMER0B: cbi(TCCR0A, COM0B1); break; |
99 | #endif |
100 | #if defined(TCCR2A) && defined(COM2A1) |
101 | case TIMER2A: cbi(TCCR2A, COM2A1); break; |
102 | #endif |
103 | #if defined(TCCR2A) && defined(COM2B1) |
104 | case TIMER2B: cbi(TCCR2A, COM2B1); break; |
105 | #endif |
106 | |
107 | #if defined(TCCR3A) && defined(COM3A1) |
108 | case TIMER3A: cbi(TCCR3A, COM3A1); break; |
109 | #endif |
110 | #if defined(TCCR3A) && defined(COM3B1) |
111 | case TIMER3B: cbi(TCCR3A, COM3B1); break; |
112 | #endif |
113 | #if defined(TCCR3A) && defined(COM3C1) |
114 | case TIMER3C: cbi(TCCR3A, COM3C1); break; |
115 | #endif |
116 |
|
117 | #if defined(TCCR4A) && defined(COM4A1) |
118 | case TIMER4A: cbi(TCCR4A, COM4A1); break; |
119 | #endif |
120 | #if defined(TCCR4A) && defined(COM4B1) |
121 | case TIMER4B: cbi(TCCR4A, COM4B1); break; |
122 | #endif |
123 | #if defined(TCCR4A) && defined(COM4C1) |
124 | case TIMER4C: cbi(TCCR4A, COM4C1); break; |
125 | #endif |
126 | #if defined(TCCR4C) && defined(COM4D1) |
127 | case TIMER4D: cbi(TCCR4C, COM4D1); break; |
128 | #endif |
129 | |
130 | #if defined(TCCR5A) |
131 | case TIMER5A: cbi(TCCR5A, COM5A1); break; |
132 | case TIMER5B: cbi(TCCR5A, COM5B1); break; |
133 | case TIMER5C: cbi(TCCR5A, COM5C1); break; |
134 | #endif |
135 | } |
136 | } |
137 |
|
138 | void digitalWrite(uint8_t pin, uint8_t val) |
139 | { |
140 | uint8_t timer = digitalPinToTimer(pin); |
141 | uint8_t bit = digitalPinToBitMask(pin); |
142 | uint8_t port = digitalPinToPort(pin); |
143 | volatile uint8_t *out; |
144 |
|
145 | if (port == NOT_A_PIN) return; |
146 |
|
147 | // If the pin that support PWM output, we need to turn it off |
148 | // before doing a digital write. |
149 | if (timer != NOT_ON_TIMER) turnOffPWM(timer); |
150 |
|
151 | out = portOutputRegister(port); |
152 |
|
153 | uint8_t oldSREG = SREG; |
154 | cli(); |
155 |
|
156 | if (val == LOW) { |
157 | *out &= ~bit; |
158 | } else { |
159 | *out |= bit; |
160 | } |
161 |
|
162 | SREG = oldSREG; |
163 | } |
164 |
|
165 | int digitalRead(uint8_t pin) |
166 | { |
167 | uint8_t timer = digitalPinToTimer(pin); |
168 | uint8_t bit = digitalPinToBitMask(pin); |
169 | uint8_t port = digitalPinToPort(pin); |
170 |
|
171 | if (port == NOT_A_PIN) return LOW; |
172 |
|
173 | // If the pin that support PWM output, we need to turn it off |
174 | // before getting a digital reading. |
175 | if (timer != NOT_ON_TIMER) turnOffPWM(timer); |
176 |
|
177 | if (*portInputRegister(port) & bit) return HIGH; |
178 | return LOW; |
179 | } |
180 |
|