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/>.
21 #include "Registers.h"
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
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 */
54 ADC::ADC(Bus
& bus
, unsigned int ccVec
) : Hardware(bus
), ccVec(ccVec
) {
55 bus
.claimInterrupt(ccVec
, this);
68 bool ADC::attachReg(const char *name
, IORegister
*reg
) {
69 if( strcmp(name
, "admux") == 0 )
71 else if( strcmp(name
, "adcsr") == 0 ) {
73 } else if( strcmp(name
, "adch") == 0 )
75 else if( strcmp(name
, "adcl") == 0 )
80 reg
->registerHW(this);
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.
93 val
= old
| (val
& ~ADIF
);
96 if( (val
& (ADIE
|ADIF
)) == (ADIE
|ADIF
) )
97 bus
.raiseInterrupt(ccVec
);
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
)) {
129 case (ADPS2
|ADPS1
|ADPS0
):
134 if( ((val
& ADSC
) != 0) && ((adcsr_old
& ADSC
) == 0) ) {
135 bus
.setBreakDelta( INIT_CYCLES
* prescaler
, this );
144 float ADC::refVoltage() const {
145 switch( *admux
& (REFS0
|REFS1
) ) {
147 return 5.0f
; // aref voltage
160 void ADC::regChanged( IORegister
*reg
) {
163 else if( reg
== adcsr
)
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 );
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
184 bus
.setBreakDelta( RUN_CYCLES
*prescaler
, this );
186 // Clear start conversion bit
190 adcsr
->set( adcsr_old
);
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
);