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