]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/gpio.c
Card detect over cs pin: clean initialisation/power up
[z180-stamp.git] / avr / gpio.c
CommitLineData
41d36f28
L
1#include "common.h"
2#include <util/atomic.h>
3#include <limits.h>
4#include "debug.h"
05994bd9 5#include "gpio.h"
41d36f28
L
6
7
8/*
9
15e476bc
L
10Pin Name Port Timer Mode max div max div min f [Hz]
11--------------------------------------------------------------------------------
120 PG5 OC0B PWM (2**8)*1024 262144 70.31
131 PG4
142 CLK2 PB4 OC2A Toggle (2**8)*1024*2 524288 35.16
153 ZCLK PB5 OC1A PWM (2**16)*1024 67108864 0.2746
164 PB6 OC1B PWM (2**16)*1024 67108864 0.2746
175 PB7 OC0A Toggle (2**8)*1024*2 524288 35.16
186 PG3
197 PG2
208 PG1
219 PG0
2210 CLKO PE7
23--------------------------------------------------------------------------------
24
25
26pre Timer0 Timer1 Timer2
41d36f28 27--------------------------------------------------
15e476bc
L
280 0 0 0
291 1 1 1
302 8 x8 8 x8 8 x8
313 64 x8 64 x8 32 x4
324 256 x4 256 x4 64 x2
335 1024 x4 1024 x4 128 x2
346 256 x2
357 1024 x4
05994bd9 36--------------------------------------------------
41d36f28
L
37*/
38
41d36f28
L
39#define PWMTOGGLE 0b01
40#define PWMPOS 0b10
41#define PWMNEG 0b11
42
43
05994bd9 44const FLASH uint8_t prescale_factors_01[] =
41d36f28
L
45 { 8, 8, 4, 4, 0 };
46
05994bd9 47const FLASH uint8_t prescale_factors_2[] =
41d36f28
L
48 { 8, 4, 2, 2, 2, 4, 0 };
49
50typedef volatile struct {
51 uint8_t pin;
52 uint8_t ddr;
53 uint8_t pout;
54} port_t ;
55
56struct 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
05994bd9 71const FLASH struct pindef_s pinlist[GPIO_MAX] = {
41d36f28
L
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};
05994bd9
L
84
85void gpio_timer_off(uint8_t timertype)
41d36f28
L
86{
87 uint8_t chan_mask;
05994bd9 88
41d36f28
L
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
05994bd9 119int gpio_config(int pin, gpiomode_t mode)
41d36f28
L
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;
05994bd9 128
41d36f28
L
129 switch (mode) {
130 case INPUT:
05994bd9 131 gpio_timer_off(pinlist[pin].timer);
8a7decea 132 ATOMIC_BLOCK(ATOMIC_FORCEON) {
41d36f28
L
133 p->ddr &= ~bit;
134 p->pout &= ~bit;
135 }
136 break;
137 case INPUT_PULLUP:
05994bd9 138 gpio_timer_off(pinlist[pin].timer);
8a7decea 139 ATOMIC_BLOCK(ATOMIC_FORCEON) {
41d36f28
L
140 p->ddr &= ~bit;
141 p->pout |= bit;
142 }
143 break;
144 case OUTPUT:
05994bd9 145 gpio_timer_off(pinlist[pin].timer);
41d36f28 146 case OUTPUT_TIMER:
8a7decea 147 ATOMIC_BLOCK(ATOMIC_FORCEON) {
41d36f28
L
148 p->ddr |= bit;
149 }
150 break;
151 default:
152 /* Invalid pin mode */
153 return -1;
154 }
155 }
156 return 0;
157}
158
05994bd9 159void gpio_write(int pin, uint8_t val)
41d36f28
L
160{
161 port_t *p = pinlist[pin].adr;
162 uint8_t bit = pinlist[pin].mask;
05994bd9 163
8a7decea 164 ATOMIC_BLOCK(ATOMIC_FORCEON) {
41d36f28
L
165 if (val)
166 p->pout |= bit;
167 else
168 p->pout &= ~bit;
169 }
170}
171
05994bd9 172int gpio_read(int pin)
41d36f28
L
173{
174 port_t *p = pinlist[pin].adr;
175 uint8_t bit = pinlist[pin].mask;
05994bd9 176
41d36f28
L
177 return (p->pin & bit) != 0;
178}
179
05994bd9 180gpiomode_t gpio_config_get(int pin)
41d36f28
L
181{
182 uint8_t timertype = pinlist[pin].timer;
183
184 if (timertype & TIMER) {
05994bd9 185
41d36f28
L
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 }
05994bd9 207
41d36f28
L
208 port_t *p = pinlist[pin].adr;
209 uint8_t bit = pinlist[pin].mask;
210
211 if (p->ddr & bit)
212 return OUTPUT;
05994bd9 213
41d36f28
L
214 if (p->pout & bit)
215 return INPUT_PULLUP;
05994bd9 216
41d36f28
L
217 return INPUT;
218}
05994bd9 219
41d36f28
L
220/*
221 * return -1: pin has no timer output
222 * 0: pin is not configured for timer output
223 * > 0: divider
224 */
05994bd9
L
225
226long gpio_clockdiv_get(int pin)
41d36f28
L
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
05994bd9 236 if (gpio_config_get(pin) != OUTPUT_TIMER)
41d36f28 237 return 0;
05994bd9 238
41d36f28
L
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
05994bd9 259 pstab = (timertype & TIMER) == TIMER2 ?
41d36f28 260 prescale_factors_2 : prescale_factors_01;
05994bd9 261
41d36f28
L
262 while (prescale--)
263 divider *= pstab[prescale];
05994bd9 264
41d36f28
L
265 if ((timertype & (CHANA|T_16BIT)) == CHANA)
266 divider *= 2;
05994bd9 267
41d36f28
L
268 return divider;
269}
270
05994bd9 271int gpio_clockdiv_set(int pin, unsigned long divider)
41d36f28
L
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;
05994bd9 284
41d36f28
L
285 ltop = divider;
286 if ((timertype & (CHANA|T_16BIT)) == CHANA)
287 ltop /= 2;
05994bd9 288
41d36f28
L
289 if (ltop > 1024 * ((timertype & T_16BIT) ? (1L<<16) : (1L<<8)))
290 return -1;
291
292 prescale = 1;
05994bd9 293 pstab = (timertype & TIMER) == TIMER2 ?
41d36f28 294 prescale_factors_2 : prescale_factors_01;
05994bd9 295
41d36f28
L
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
15e476bc 314// PING |= _BV(0); /* Debug */
41d36f28
L
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
15e476bc 365// PING |= _BV(0); /* Debug */
41d36f28 366
05994bd9 367 gpio_config(pin, OUTPUT_TIMER);
41d36f28
L
368
369 return 0;
370}