]> cloudbase.mooo.com Git - z180-stamp.git/blob - avr/gpio.c
Card detect over cs pin: clean initialisation/power up
[z180-stamp.git] / avr / gpio.c
1 #include "common.h"
2 #include <util/atomic.h>
3 #include <limits.h>
4 #include "debug.h"
5 #include "gpio.h"
6
7
8 /*
9
10 Pin Name Port Timer Mode max div max div min f [Hz]
11 --------------------------------------------------------------------------------
12 0 PG5 OC0B PWM (2**8)*1024 262144 70.31
13 1 PG4
14 2 CLK2 PB4 OC2A Toggle (2**8)*1024*2 524288 35.16
15 3 ZCLK PB5 OC1A PWM (2**16)*1024 67108864 0.2746
16 4 PB6 OC1B PWM (2**16)*1024 67108864 0.2746
17 5 PB7 OC0A Toggle (2**8)*1024*2 524288 35.16
18 6 PG3
19 7 PG2
20 8 PG1
21 9 PG0
22 10 CLKO PE7
23 --------------------------------------------------------------------------------
24
25
26 pre Timer0 Timer1 Timer2
27 --------------------------------------------------
28 0 0 0 0
29 1 1 1 1
30 2 8 x8 8 x8 8 x8
31 3 64 x8 64 x8 32 x4
32 4 256 x4 256 x4 64 x2
33 5 1024 x4 1024 x4 128 x2
34 6 256 x2
35 7 1024 x4
36 --------------------------------------------------
37 */
38
39 #define PWMTOGGLE 0b01
40 #define PWMPOS 0b10
41 #define PWMNEG 0b11
42
43
44 const FLASH uint8_t prescale_factors_01[] =
45 { 8, 8, 4, 4, 0 };
46
47 const FLASH uint8_t prescale_factors_2[] =
48 { 8, 4, 2, 2, 2, 4, 0 };
49
50 typedef volatile struct {
51 uint8_t pin;
52 uint8_t ddr;
53 uint8_t pout;
54 } port_t ;
55
56 struct pindef_s {
57 port_t * const adr;
58 const uint8_t mask;
59 #define NO_TIMER 0
60 #define TIMER0 (1 << 0)
61 #define TIMER1 (2 << 0)
62 #define TIMER2 (3 << 0)
63 #define TIMER (3 << 0)
64 #define T_16BIT (1 << 3)
65 #define CHANA (1 << 4)
66 #define CHANB (0 << 4)
67 const uint8_t timer;
68 };
69
70
71 const FLASH struct pindef_s pinlist[GPIO_MAX] = {
72 { (port_t *) &PING, _BV(5), TIMER0 | CHANB },
73 { (port_t *) &PING, _BV(4), NO_TIMER },
74 { (port_t *) &PINB, _BV(4), TIMER2 | CHANA },
75 { (port_t *) &PINB, _BV(5), TIMER1 | CHANA | T_16BIT },
76 { (port_t *) &PINB, _BV(6), TIMER1 | CHANB | T_16BIT },
77 { (port_t *) &PINB, _BV(7), TIMER0 | CHANA },
78 { (port_t *) &PING, _BV(3), NO_TIMER },
79 { (port_t *) &PING, _BV(2), NO_TIMER },
80 { (port_t *) &PING, _BV(1), NO_TIMER },
81 { (port_t *) &PING, _BV(0), NO_TIMER },
82 { (port_t *) &PINE, _BV(7), NO_TIMER },
83 };
84
85 void gpio_timer_off(uint8_t timertype)
86 {
87 uint8_t chan_mask;
88
89 if (timertype & CHANA)
90 chan_mask = 0xc0;
91 else
92 chan_mask = 0x30;
93
94 switch (timertype & TIMER) {
95 case TIMER0:
96 if (TCCR0A & chan_mask) {
97 TCCR0B = 0;
98 TCCR0A = 0;
99 PRR0 |= _BV(PRTIM0);
100 }
101 break;
102 case TIMER1:
103 if (TCCR1A & chan_mask) {
104 TCCR1B = 0;
105 TCCR1A = 0;
106 PRR0 |= _BV(PRTIM1);
107 }
108 break;
109 case TIMER2:
110 if (TCCR2A & chan_mask) {
111 TCCR2B = 0;
112 TCCR2A = 0;
113 PRR0 |= _BV(PRTIM2);
114 }
115 break;
116 }
117 }
118
119 int gpio_config(int pin, gpiomode_t mode)
120 {
121 if ((unsigned) pin >= ARRAY_SIZE(pinlist)) {
122 /* Invalid pin number */
123 return -1;
124 } else {
125
126 port_t *p = pinlist[pin].adr;
127 uint8_t bit = pinlist[pin].mask;
128
129 switch (mode) {
130 case INPUT:
131 gpio_timer_off(pinlist[pin].timer);
132 ATOMIC_BLOCK(ATOMIC_FORCEON) {
133 p->ddr &= ~bit;
134 p->pout &= ~bit;
135 }
136 break;
137 case INPUT_PULLUP:
138 gpio_timer_off(pinlist[pin].timer);
139 ATOMIC_BLOCK(ATOMIC_FORCEON) {
140 p->ddr &= ~bit;
141 p->pout |= bit;
142 }
143 break;
144 case OUTPUT:
145 gpio_timer_off(pinlist[pin].timer);
146 case OUTPUT_TIMER:
147 ATOMIC_BLOCK(ATOMIC_FORCEON) {
148 p->ddr |= bit;
149 }
150 break;
151 default:
152 /* Invalid pin mode */
153 return -1;
154 }
155 }
156 return 0;
157 }
158
159 void gpio_write(int pin, uint8_t val)
160 {
161 port_t *p = pinlist[pin].adr;
162 uint8_t bit = pinlist[pin].mask;
163
164 ATOMIC_BLOCK(ATOMIC_FORCEON) {
165 if (val)
166 p->pout |= bit;
167 else
168 p->pout &= ~bit;
169 }
170 }
171
172 int gpio_read(int pin)
173 {
174 port_t *p = pinlist[pin].adr;
175 uint8_t bit = pinlist[pin].mask;
176
177 return (p->pin & bit) != 0;
178 }
179
180 gpiomode_t gpio_config_get(int pin)
181 {
182 uint8_t timertype = pinlist[pin].timer;
183
184 if (timertype & TIMER) {
185
186 uint8_t chan_mask;
187 if (timertype & CHANA)
188 chan_mask = 0xc0;
189 else
190 chan_mask = 0x30;
191
192 switch (timertype & TIMER) {
193 case TIMER0:
194 if (TCCR0A & chan_mask)
195 return OUTPUT_TIMER;
196 break;
197 case TIMER1:
198 if (TCCR1A & chan_mask)
199 return OUTPUT_TIMER;
200 break;
201 case TIMER2:
202 if (TCCR2A & chan_mask)
203 return OUTPUT_TIMER;
204 break;
205 }
206 }
207
208 port_t *p = pinlist[pin].adr;
209 uint8_t bit = pinlist[pin].mask;
210
211 if (p->ddr & bit)
212 return OUTPUT;
213
214 if (p->pout & bit)
215 return INPUT_PULLUP;
216
217 return INPUT;
218 }
219
220 /*
221 * return -1: pin has no timer output
222 * 0: pin is not configured for timer output
223 * > 0: divider
224 */
225
226 long gpio_clockdiv_get(int pin)
227 {
228 long divider;
229 uint8_t prescale;
230 const FLASH uint8_t *pstab;
231
232 uint8_t timertype = pinlist[pin].timer;
233 if ((timertype & TIMER) == 0)
234 return -1;
235
236 if (gpio_config_get(pin) != OUTPUT_TIMER)
237 return 0;
238
239 switch (timertype & TIMER) {
240 case TIMER0:
241 prescale = TCCR0B;
242 divider = OCR0A;
243 break;
244
245 case TIMER1:
246 prescale = TCCR1B;
247 divider = ICR1;
248 break;
249
250 case TIMER2:
251 prescale = TCCR2B;
252 divider = OCR2A;
253 break;
254 }
255
256 prescale = (prescale & 0x07) - 1;
257 divider += 1;
258
259 pstab = (timertype & TIMER) == TIMER2 ?
260 prescale_factors_2 : prescale_factors_01;
261
262 while (prescale--)
263 divider *= pstab[prescale];
264
265 if ((timertype & (CHANA|T_16BIT)) == CHANA)
266 divider *= 2;
267
268 return divider;
269 }
270
271 int gpio_clockdiv_set(int pin, unsigned long divider)
272 {
273 unsigned long ltop;
274 uint16_t top;
275 uint8_t prescale;
276 const FLASH uint8_t *pstab;
277
278 uint8_t timertype = pinlist[pin].timer;
279 if ((timertype & TIMER) == 0)
280 return 0;
281
282 if (divider < 2)
283 return -1;
284
285 ltop = divider;
286 if ((timertype & (CHANA|T_16BIT)) == CHANA)
287 ltop /= 2;
288
289 if (ltop > 1024 * ((timertype & T_16BIT) ? (1L<<16) : (1L<<8)))
290 return -1;
291
292 prescale = 1;
293 pstab = (timertype & TIMER) == TIMER2 ?
294 prescale_factors_2 : prescale_factors_01;
295
296 // debug("** clockdiv_set: pin: %d, ltop: %lu, prescale: %d\n",
297 // pin, ltop, prescale);
298
299 while (ltop > ((timertype & T_16BIT) ? (1L<<16) : (1L<<8))) {
300 // debug("** clockdiv_set: pin: %d, ltop: %lu, prescale: %d, *pstab %d\n",
301 // pin, ltop, prescale, *pstab);
302
303 if (*pstab == 0)
304 return -1;
305 ltop /= *pstab++;
306 prescale++;
307 }
308
309 if (ltop == 0)
310 return -1;
311
312 top = ltop - 1;
313
314 // PING |= _BV(0); /* Debug */
315
316 switch (timertype & TIMER) {
317 case TIMER0:
318 PRR0 &= ~_BV(PRTIM0);
319 TCCR0B = (1 << WGM02);
320 TCNT0 = 0;
321 OCR0A = top;
322 if (timertype & CHANA) {
323 TCCR0A = (PWMTOGGLE << COM0A0) | (0b11 << WGM00);
324 } else {
325 OCR0B = top/2;
326 TCCR0A = (PWMPOS << COM0B0) | (0b11 << WGM10);
327 }
328 TCCR0B = (1 << WGM02) | (prescale << CS10);
329 break;
330
331 case TIMER1:
332 PRR0 &= ~_BV(PRTIM1);
333 TCCR1B = (0b11 << WGM12);
334 TCNT1 = 0;
335 ICR1 = top;
336 if (timertype & CHANA) {
337 OCR1A = top/2;
338 TCCR1A = (PWMPOS << COM1A0) | (0b10 << WGM10);
339 } else {
340 OCR1B = top/2;
341 TCCR1A = (PWMPOS << COM1B0) | (0b10 << WGM10);
342 }
343 // debug("pin: %d, top: %u,"
344 // " ICR1: %u, OCR1A: %u, OCR1B: %u\n",
345 // pin, top, ICR1, OCR1A, OCR1B);
346
347 TCCR1B = (0b11 << WGM12) | (prescale << CS10);
348 break;
349
350 case TIMER2:
351 PRR0 &= ~_BV(PRTIM2);
352 TCCR2B = (1 << WGM22);
353 TCNT2 = 0;
354 OCR2A = top;
355 if (timertype & CHANA) {
356 TCCR2A = (PWMTOGGLE << COM2A0) | (0b11 << WGM20);
357 } else {
358 OCR2B = top/2;
359 TCCR2A = (PWMPOS << COM2B0) | (0b11 << WGM10);
360 }
361 TCCR2B = (1 << WGM22) | (prescale << CS10);
362 break;
363 }
364
365 // PING |= _BV(0); /* Debug */
366
367 gpio_config(pin, OUTPUT_TIMER);
368
369 return 0;
370 }