Fixed problem in DeviceSettings::strParam, returned wrong string
[avr-sim.git] / src / ADC.cpp
blob0c87f0024181c0aa89ff56a297ef05d8b6340ed1
1 /*
2 * avr-sim: An atmel AVR simulator
3 * Copyright (C) 2008 Tom Haber
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "ADC.h"
20 #include "Bus.h"
21 #include "Registers.h"
23 #include <cstring>
25 #define INIT_CYCLES ((int)(13.5*2))
26 #define RUN_CYCLES ((int)(1.5*2))
27 #define CONV_CYCLES ((int)(13*2) - RUN_CYCLES)
28 #define INT_CYCLES CONV_CYCLES
30 enum {
31 MUX0 = 1<<0,
32 MUX1 = 1<<1,
33 MUX2 = 1<<2,
34 MUX3 = 1<<3,
35 MUX4 = 1<<4,
36 ADLAR = 1<<5,
37 REFS0 = 1<<6,
38 REFS1 = 1<<7
41 enum {
42 ADPS0 = 1<<0, /* Clock Rate Select 0 */
43 ADPS1 = 1<<1, /* Clock Rate Select 1 */
44 ADPS2 = 1<<2, /* Clock Rate Select 1 */
45 ADIE = 1<<3, /* ADC Interrupt Enable */
46 ADIF = 1<<4, /* ADC Interrupt Flag */
47 ADFR = 1<<5, /* Free Run Select */
48 ADSC = 1<<6, /* ADC Start Conversion */
49 ADEN = 1<<7, /* ADC Enable */
52 namespace avr {
54 ADC::ADC(Bus & bus, unsigned int ccVec) : Hardware(bus), ccVec(ccVec) {
55 bus.claimInterrupt(ccVec, this);
58 ADC::~ADC() {
61 void ADC::reset() {
62 adcsr_old = *adcsr;
63 prescaler = 0;
64 clk = 0;
65 sample = 0.0f;
68 bool ADC::attachReg(const char *name, IORegister *reg) {
69 if( strcmp(name, "admux") == 0 )
70 admux = reg;
71 else if( strcmp(name, "adcsr") == 0 ) {
72 adcsr = reg;
73 } else if( strcmp(name, "adch") == 0 )
74 adch = reg;
75 else if( strcmp(name, "adcl") == 0 )
76 adcl = reg;
77 else
78 return false;
80 reg->registerHW(this);
81 return true;
84 bool ADC::finishBuild() {
85 return ((admux != 0) && (adcsr != 0) && (adch != 0) && (adcl != 0) );
88 void ADC::setAdcsr(unsigned char val) {
89 unsigned char old = adcsr_old & (ADIF|ADSC);
90 if( (val & ADIF) != 0 ) // Clear interrupt flag if written.
91 old &= ~ADIF;
93 val = old | (val & ~ADIF);
95 // Check interrupt
96 if( (val & (ADIE|ADIF)) == (ADIE|ADIF) )
97 bus.raiseInterrupt(ccVec);
98 else
99 bus.clearInterrupt(ccVec);
101 // We trigger the adc at twice the speed to allow
102 // starting with sampling at half a cycle.
103 switch ( val & ( ADPS2|ADPS1|ADPS0)) {
104 case 0:
105 case ADPS0:
106 prescaler = 1;
107 break;
109 case ADPS1:
110 prescaler = 2;
111 break;
113 case (ADPS1|ADPS0):
114 prescaler = 4;
115 break;
117 case (ADPS2):
118 prescaler = 8;
119 break;
121 case (ADPS2|ADPS0):
122 prescaler = 16;
123 break;
125 case (ADPS2|ADPS1):
126 prescaler = 32;
127 break;
129 case (ADPS2|ADPS1|ADPS0):
130 prescaler = 64;
131 break;
134 if( ((val & ADSC) != 0) && ((adcsr_old & ADSC) == 0) ) {
135 bus.setBreakDelta( INIT_CYCLES * prescaler, this );
136 clk = 0;
137 sample = 0.0f;
140 adcsr->set( val );
141 adcsr_old = val;
144 float ADC::refVoltage() const {
145 switch( *admux & (REFS0|REFS1) ) {
146 case 0:
147 return 5.0f; // aref voltage
149 case REFS0:
150 return 5.0f; // avcc
152 case REFS1|REFS0:
153 return 2.56f;
155 default:
156 return 0.0f;
160 void ADC::regChanged( IORegister *reg ) {
161 if( reg == admux )
163 else if( reg == adcsr )
164 setAdcsr( *adcsr );
167 void ADC::step() {
168 if( clk++ == CONV_CYCLES ) {
169 // TODO gain, differential
170 unsigned int adc = (unsigned int)((sample / INT_CYCLES) * (1<<10));
171 // TODO adlar register locking
172 adch->set( adc >> 8 );
173 adcl->set( adc & 0xff );
175 adcsr_old |= ADIF;
177 if( (adcsr_old & (ADIE|ADIF)) == (ADIE|ADIF) )
178 bus.raiseInterrupt(ccVec);
180 if( (adcsr_old & ADFR) != 0 ) {
181 // Start again if free running mode
182 clk = 0;
183 sample = 0.0f;
184 bus.setBreakDelta( RUN_CYCLES*prescaler, this );
185 } else {
186 // Clear start conversion bit
187 adcsr_old &= ~ADSC;
190 adcsr->set( adcsr_old );
191 } else {
192 int chan = *admux & (MUX2|MUX1|MUX0);
193 float V = 0.0f; //adpin[chan].voltage();
194 float Vref = refVoltage();
196 if( V > Vref ) V = Vref;
197 sample += (V / Vref);
199 bus.setBreakDelta( prescaler, this );
203 void ADC::beforeInvokeInterrupt(unsigned int vector) {
204 if( vector == ccVec )
205 adcsr->set( *adcsr & ~ADIF );