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