-
Notifications
You must be signed in to change notification settings - Fork 80
/
Copy pathadc.spec.ts
138 lines (108 loc) · 3.63 KB
/
adc.spec.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import { CPU } from '../cpu/cpu';
import { asmProgram, TestProgramRunner } from '../utils/test-utils';
import { AVRADC, ADCMuxInputType } from './adc';
import { adcConfig } from './adc_atmega328p';
const R16 = 16;
const R17 = 17;
const ADMUX = 0x7c;
const REFS0 = 1 << 6;
const ADCSRA = 0x7a;
const ADEN = 1 << 7;
const ADSC = 1 << 6;
const ADPS0 = 1 << 0;
const ADPS1 = 1 << 1;
const ADPS2 = 1 << 2;
const ADCH = 0x79;
const ADCL = 0x78;
describe('ADC', () => {
it('should successfuly perform an ADC conversion', () => {
const { program } = asmProgram(`
; register addresses
_REPLACE ADMUX, ${ADMUX}
_REPLACE ADCSRA, ${ADCSRA}
_REPLACE ADCH, ${ADCH}
_REPLACE ADCL, ${ADCL}
; Configure mux - channel 0, reference: AVCC with external capacitor at AREF pin
ldi r24, ${REFS0}
sts ADMUX, r24
; Start conversion with 128 prescaler
ldi r24, ${ADEN | ADSC | ADPS0 | ADPS1 | ADPS2}
sts ADCSRA, r24
; Wait until conversion is complete
waitComplete:
lds r24, ${ADCSRA}
andi r24, ${ADSC}
brne waitComplete
; Read the result
lds r16, ${ADCL}
lds r17, ${ADCH}
break
`);
const cpu = new CPU(program);
const adc = new AVRADC(cpu, adcConfig);
const runner = new TestProgramRunner(cpu);
const adcReadSpy = jest.spyOn(adc, 'onADCRead');
adc.channelValues[0] = 2.56; // should result in 2.56/5*1024 = 524
// Setup
runner.runInstructions(4);
expect(adcReadSpy).toHaveBeenCalledWith({ channel: 0, type: ADCMuxInputType.SingleEnded });
// Run the "waitComplete" loop for a few cycles
runner.runInstructions(12);
cpu.cycles += 128 * 25; // skip to the end of the conversion
cpu.tick();
// Now read the result
runner.runInstructions(5);
const low = cpu.data[R16];
const high = cpu.data[R17];
expect((high << 8) | low).toEqual(524); // 2.56 volts - see above
});
it('should read 0 when the ADC peripheral is not enabled', () => {
// This behavior was verified on real hardware, using the following test program:
// https://wokwi.com/arduino/projects/309156042450666050
// Thanks Oscar Oomens for spotting this!
const { program } = asmProgram(`
; register addresses
_REPLACE ADMUX, ${ADMUX}
_REPLACE ADCSRA, ${ADCSRA}
_REPLACE ADCH, ${ADCH}
_REPLACE ADCL, ${ADCL}
; Load some initial value into r16/r17 to make sure we actually read 0 later
ldi r16, 0xff
ldi r17, 0xff
; Configure mux - channel 0, reference: AVCC with external capacitor at AREF pin
ldi r24, ${REFS0}
sts ADMUX, r24
; Start conversion with 128 prescaler, but without enabling the ADC
ldi r24, ${ADSC | ADPS0 | ADPS1 | ADPS2}
sts ADCSRA, r24
; Wait until conversion is complete
waitComplete:
lds r24, ${ADCSRA}
andi r24, ${ADSC}
brne waitComplete
; Read the result
lds r16, ${ADCL}
lds r17, ${ADCH}
break
`);
const cpu = new CPU(program);
const adc = new AVRADC(cpu, adcConfig);
const runner = new TestProgramRunner(cpu, () => {
/* do nothing on break */
});
const adcReadSpy = jest.spyOn(adc, 'onADCRead');
adc.channelValues[0] = 2.56; // should result in 2.56/5*1024 = 524
// Setup
runner.runInstructions(6);
expect(adcReadSpy).not.toHaveBeenCalled();
// Run the "waitComplete" loop for a few cycles
runner.runInstructions(12);
cpu.cycles += 128 * 25; // skip to the end of the conversion
cpu.tick();
// Now read the result
runner.runToBreak();
const low = cpu.data[R16];
const high = cpu.data[R17];
expect((high << 8) | low).toEqual(0); // We should read 0 since the ADC hasn't been enabled
});
});