ADC: Fully functional core
[simavr] / simavr / sim / avr_adc.c
1 /*
2         avr_adc.c
3
4         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
5
6         This file is part of simavr.
7
8         simavr is free software: you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 3 of the License, or
11         (at your option) any later version.
12
13         simavr is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include "avr_adc.h"
26
27 static avr_cycle_count_t avr_adc_int_raise(struct avr_t * avr, avr_cycle_count_t when, void * param)
28 {
29         avr_adc_t * p = (avr_adc_t *)param;
30         if (avr_regbit_get(avr, p->aden)) {
31                 // if the interrupts are not used, still raised the UDRE and TXC flag
32                 avr_raise_interrupt(avr, &p->adc);
33                 avr_regbit_clear(avr, p->adsc);
34                 p->first = 0;
35                 p->read_status = 0;
36         }
37         return 0;
38 }
39
40 static uint8_t avr_adc_read_l(struct avr_t * avr, avr_io_addr_t addr, void * param)
41 {
42         avr_adc_t * p = (avr_adc_t *)param;
43
44         if (p->read_status)     // conversion already done
45                 return avr_core_watch_read(avr, addr);
46
47         uint8_t refi = avr_regbit_get_array(avr, p->ref, ARRAY_SIZE(p->ref));
48         uint16_t ref = p->ref_values[refi];
49         uint8_t muxi = avr_regbit_get_array(avr, p->mux, ARRAY_SIZE(p->mux));
50         avr_adc_mux_t mux = p->muxmode[muxi];
51         // optional shift left/right
52         uint8_t shift = avr_regbit_get(avr, p->adlar) ? 0 : 6;
53
54         uint32_t reg = 0;
55         switch (mux.kind) {
56                 case ADC_MUX_SINGLE:
57                         reg = p->adc_values[mux.src];
58                         break;
59                 case ADC_MUX_DIFF:
60                         if (mux.gain == 0)
61                                 mux.gain = 1;
62                         reg = ((uint32_t)p->adc_values[mux.src] * mux.gain) -
63                                         ((uint32_t)p->adc_values[mux.diff] * mux.gain);
64                         break;
65                 case ADC_MUX_TEMP:
66                         reg = p->temp; // assumed to be already calibrated somehow
67                         break;
68                 case ADC_MUX_REF:
69                         reg = mux.src; // reference voltage
70                         break;
71         }
72         uint32_t vref = 3300;
73         switch (ref) {
74                 case ADC_VREF_AREF:
75                         if (!avr->aref)
76                                 printf("ADC Warning : missing AREF analog voltage\n");
77                         else
78                                 vref = avr->aref;
79                         break;
80                 case ADC_VREF_AVCC:
81                         if (!avr->avcc)
82                                 printf("ADC Warning : missing AVCC analog voltage\n");
83                         else
84                                 vref = avr->avcc;
85                         break;
86                 default:
87                         vref = ref;
88         }
89 //      printf("ADCL %d:%3d:%3d read %4d vref %d:%d=%d\n",
90 //                      mux.kind, mux.diff, mux.src,
91 //                      reg, refi, ref, vref);
92         reg = (reg * 0x3ff) / vref;     // scale to 10 bits ADC
93 //      printf("ADC to 10 bits 0x%x %d\n", reg, reg);
94         if (reg > 0x3ff) {
95                 printf("ADC Warning channel %d clipped %u/%u VREF %d\n", mux.kind, reg, 0x3ff, vref);
96                 reg = 0x3ff;
97         }
98         reg <<= shift;
99 //      printf("ADC to 10 bits %x shifted %d\n", reg, shift);
100         avr->data[p->r_adcl] = reg;
101         avr->data[p->r_adch] = reg >> 8;
102         p->read_status = 1;
103         return avr_core_watch_read(avr, addr);
104 }
105
106 /*
107  * From Datasheet:
108  * "When ADCL is read, the ADC Data Register is not updated until ADCH is read.
109  * Consequently, if the result is left adjusted and no more than 8-bit
110  * precision is required, it is sufficient to read ADCH.
111  * Otherwise, ADCL must be read first, then ADCH."
112  * So here if the H is read before the L, we still call the L to update the
113  * register value.
114  */
115 static uint8_t avr_adc_read_h(struct avr_t * avr, avr_io_addr_t addr, void * param)
116 {
117         avr_adc_t * p = (avr_adc_t *)param;
118         // no "break" here on purpose
119         switch (p->read_status) {
120                 case 0:
121                         avr_adc_read_l(avr, p->r_adcl, param);
122                 case 1:
123                         p->read_status = 2;
124                 default:
125                         return avr_core_watch_read(avr, addr);
126         }
127 }
128
129 static void avr_adc_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
130 {
131         avr_adc_t * p = (avr_adc_t *)param;
132         uint8_t adsc = avr_regbit_get(avr, p->adsc);
133         uint8_t aden = avr_regbit_get(avr, p->aden);
134
135         avr->data[p->adsc.reg] = v;
136
137         // can't write zero to adsc
138         if (adsc && !avr_regbit_get(avr, p->adsc)) {
139                 avr_regbit_set(avr, p->adsc);
140                 v = avr->data[p->adsc.reg];
141         }
142         if (!aden && avr_regbit_get(avr, p->aden)) {
143                 // first conversion
144                 p->first = 1;
145                 printf("ADC Start AREF %d AVCC %d\n", avr->aref, avr->avcc);
146         }
147         if (aden && !avr_regbit_get(avr, p->aden)) {
148                 // stop ADC
149                 avr_cycle_timer_cancel(avr, avr_adc_int_raise, p);
150                 avr_regbit_clear(avr, p->adsc);
151         }
152         if (!adsc && avr_regbit_get(avr, p->adsc)) {
153                 // start one!
154                 uint8_t muxi = avr_regbit_get_array(avr, p->mux, ARRAY_SIZE(p->mux));
155                 union {
156                         avr_adc_mux_t mux;
157                         uint32_t v;
158                 } e = { .mux = p->muxmode[muxi] };
159                 avr_raise_irq(p->io.irq + ADC_IRQ_OUT_TRIGGER, e.v);
160
161                 // clock prescaler are just a bit shift.. and 0 means 1
162                 uint32_t div = avr_regbit_get_array(avr, p->adps, ARRAY_SIZE(p->adps));
163                 if (!div) div++;
164
165                 div = avr->frequency >> div;
166                 if (p->first)
167                         printf("ADC starting at %uKHz\n", div / 13 / 100);
168                 div /= p->first ? 25 : 13;      // first cycle is longer
169
170                 avr_cycle_timer_register(avr,
171                                 avr_hz_to_cycles(avr, div),
172                                 avr_adc_int_raise, p);
173         }
174         avr_core_watch_write(avr, addr, v);
175 }
176
177 static void avr_adc_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param)
178 {
179         avr_adc_t * p = (avr_adc_t *)param;
180         avr_t * avr = p->io.avr;
181
182         switch (irq->irq) {
183                 case ADC_IRQ_ADC0 ... ADC_IRQ_ADC7: {
184                         p->adc_values[irq->irq] = value;
185                 }       break;
186                 case ADC_IRQ_TEMP: {
187                         p->temp = value;
188                 }       break;
189                 case ADC_IRQ_IN_TRIGGER: {
190                         if (avr_regbit_get(avr, p->adate)) {
191                                 // start a conversion
192                         }
193                 }       break;
194         }
195 }
196
197 static void avr_adc_reset(avr_io_t * port)
198 {
199         avr_adc_t * p = (avr_adc_t *)port;
200
201         // stop ADC
202         avr_cycle_timer_cancel(p->io.avr, avr_adc_int_raise, p);
203         avr_regbit_clear(p->io.avr, p->adsc);
204
205         for (int i = 0; i < ADC_IRQ_COUNT; i++)
206                 avr_irq_register_notify(p->io.irq + i, avr_adc_irq_notify, p);
207 }
208
209 static  avr_io_t        _io = {
210         .kind = "adc",
211         .reset = avr_adc_reset,
212 };
213
214 void avr_adc_init(avr_t * avr, avr_adc_t * p)
215 {
216         p->io = _io;
217
218         // allocate this module's IRQ
219         p->io.irq_count = ADC_IRQ_COUNT;
220         p->io.irq = avr_alloc_irq(0, p->io.irq_count);
221         p->io.irq_ioctl_get = AVR_IOCTL_ADC_GETIRQ;
222
223         avr_register_io(avr, &p->io);
224         avr_register_vector(avr, &p->adc);
225
226         avr_register_io_write(avr, p->r_adcsra, avr_adc_write, p);
227         avr_register_io_read(avr, p->r_adcl, avr_adc_read_l, p);
228         avr_register_io_read(avr, p->r_adch, avr_adc_read_h, p);
229 }