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"
23 #define INIT_CYCLES ((int)(13.5*2))
24 #define RUN_CYCLES ((int)(1.5*2))
25 #define CONV_CYCLES ((int)(13*2) - RUN_CYCLES)
26 #define INT_CYCLES CONV_CYCLES
40 ADPS0
= 1<<0, /* Clock Rate Select 0 */
41 ADPS1
= 1<<1, /* Clock Rate Select 1 */
42 ADPS2
= 1<<2, /* Clock Rate Select 1 */
43 ADIE
= 1<<3, /* ADC Interrupt Enable */
44 ADIF
= 1<<4, /* ADC Interrupt Flag */
45 ADFR
= 1<<5, /* Free Run Select */
46 ADSC
= 1<<6, /* ADC Start Conversion */
47 ADEN
= 1<<7, /* ADC Enable */
52 ADC::ADC(Bus
& bus
, unsigned int ccVec
) : Hardware(bus
), ccVec(ccVec
) {
53 bus
.claimInterrupt(ccVec
, this);
66 bool ADC::attachReg(const char *name
, IORegister
*reg
) {
67 if( strcmp(name
, "admux") == 0 )
69 else if( strcmp(name
, "adcsr") == 0 ) {
71 } else if( strcmp(name
, "adch") == 0 )
73 else if( strcmp(name
, "adcl") == 0 )
78 reg
->registerHW(this);
82 bool ADC::finishBuild() {
83 return ((admux
!= 0) && (adcsr
!= 0) && (adch
!= 0) && (adcl
!= 0) );
86 void ADC::setAdcsr(unsigned char val
) {
87 unsigned char old
= adcsr_old
& (ADIF
|ADSC
);
88 if( (val
& ADIF
) != 0 ) // Clear interrupt flag if written.
91 val
= old
| (val
& ~ADIF
);
94 if( (val
& (ADIE
|ADIF
)) == (ADIE
|ADIF
) )
95 bus
.raiseInterrupt(ccVec
);
97 bus
.clearInterrupt(ccVec
);
99 // We trigger the adc at twice the speed to allow
100 // starting with sampling at half a cycle.
101 switch ( val
& ( ADPS2
|ADPS1
|ADPS0
)) {
127 case (ADPS2
|ADPS1
|ADPS0
):
132 if( ((val
& ADSC
) != 0) && ((adcsr_old
& ADSC
) == 0) ) {
133 bus
.setBreakDelta( INIT_CYCLES
* prescaler
, this );
142 float ADC::refVoltage() const {
143 switch( *admux
& (REFS0
|REFS1
) ) {
145 return 5.0f
; // aref voltage
158 void ADC::regChanged( IORegister
*reg
) {
161 else if( reg
== adcsr
)
166 if( clk
++ == CONV_CYCLES
) {
167 // TODO gain, differential
168 unsigned int adc
= (unsigned int)((sample
/ INT_CYCLES
) * (1<<10));
169 // TODO adlar register locking
170 adch
->set( adc
>> 8 );
171 adcl
->set( adc
& 0xff );
175 if( (adcsr_old
& (ADIE
|ADIF
)) == (ADIE
|ADIF
) )
176 bus
.raiseInterrupt(ccVec
);
178 if( (adcsr_old
& ADFR
) != 0 ) {
179 // Start again if free running mode
182 bus
.setBreakDelta( RUN_CYCLES
*prescaler
, this );
184 // Clear start conversion bit
188 adcsr
->set( adcsr_old
);
190 int chan
= *admux
& (MUX2
|MUX1
|MUX0
);
191 float V
= 0.0f
; //adpin[chan].voltage();
192 float Vref
= refVoltage();
194 if( V
> Vref
) V
= Vref
;
195 sample
+= (V
/ Vref
);
197 bus
.setBreakDelta( prescaler
, this );
201 void ADC::beforeInvokeInterrupt(unsigned int vector
) {
202 if( vector
== ccVec
)
203 adcsr
->set( *adcsr
& ~ADIF
);