Files
homeclaw/web-ui/vendor/avr8js/peripherals/adc.js
T
kim 209f3a3aef v3.0.6: RP2040 에뮬레이터 개선 — USB CDC, vendor화, 부팅 감지
- USB CDC 경로 복원: #define Serial Serial1 우회 제거
- rp2040js/avr8js/codemirror/xterm/monaco-editor vendor화
- /vendor 정적 라우팅 추가 (Express 5 catch-all 우회)
- 부팅 완료 타임아웃 감지 (Serial 출력 없어도 8초 후 RAF 전환)
- 리셋 시 Simulator 재생성으로 주변 장치 상태 초기화
- 시리얼 패널의 내부 메시지를 console.log로 이동
2026-06-19 15:49:36 +09:00

213 lines
7.7 KiB
JavaScript

// SPDX-License-Identifier: MIT
// Copyright (c) Uri Shaked and contributors
export var ADCReference;
(function (ADCReference) {
ADCReference[ADCReference["AVCC"] = 0] = "AVCC";
ADCReference[ADCReference["AREF"] = 1] = "AREF";
ADCReference[ADCReference["Internal1V1"] = 2] = "Internal1V1";
ADCReference[ADCReference["Internal2V56"] = 3] = "Internal2V56";
ADCReference[ADCReference["Reserved"] = 4] = "Reserved";
})(ADCReference || (ADCReference = {}));
export var ADCMuxInputType;
(function (ADCMuxInputType) {
ADCMuxInputType[ADCMuxInputType["SingleEnded"] = 0] = "SingleEnded";
ADCMuxInputType[ADCMuxInputType["Differential"] = 1] = "Differential";
ADCMuxInputType[ADCMuxInputType["Constant"] = 2] = "Constant";
ADCMuxInputType[ADCMuxInputType["Temperature"] = 3] = "Temperature";
})(ADCMuxInputType || (ADCMuxInputType = {}));
export const atmega328Channels = {
0: { type: ADCMuxInputType.SingleEnded, channel: 0 },
1: { type: ADCMuxInputType.SingleEnded, channel: 1 },
2: { type: ADCMuxInputType.SingleEnded, channel: 2 },
3: { type: ADCMuxInputType.SingleEnded, channel: 3 },
4: { type: ADCMuxInputType.SingleEnded, channel: 4 },
5: { type: ADCMuxInputType.SingleEnded, channel: 5 },
6: { type: ADCMuxInputType.SingleEnded, channel: 6 },
7: { type: ADCMuxInputType.SingleEnded, channel: 7 },
8: { type: ADCMuxInputType.Temperature },
14: { type: ADCMuxInputType.Constant, voltage: 1.1 },
15: { type: ADCMuxInputType.Constant, voltage: 0 },
};
const fallbackMuxInput = {
type: ADCMuxInputType.Constant,
voltage: 0,
};
export const adcConfig = {
ADMUX: 0x7c,
ADCSRA: 0x7a,
ADCSRB: 0x7b,
ADCL: 0x78,
ADCH: 0x79,
DIDR0: 0x7e,
adcInterrupt: 0x2a,
numChannels: 8,
muxInputMask: 0xf,
muxChannels: atmega328Channels,
adcReferences: [
ADCReference.AREF,
ADCReference.AVCC,
ADCReference.Reserved,
ADCReference.Internal1V1,
],
};
// Register bits:
const ADPS_MASK = 0x7;
const ADIE = 0x8;
const ADIF = 0x10;
const ADSC = 0x40;
const ADEN = 0x80;
const MUX_MASK = 0x1f;
const ADLAR = 0x20;
const MUX5 = 0x8;
const REFS2 = 0x8;
const REFS_MASK = 0x3;
const REFS_SHIFT = 6;
export class AVRADC {
constructor(cpu, config) {
this.cpu = cpu;
this.config = config;
/**
* ADC Channel values, in voltage (0..5). The number of channels depends on the chip.
*
* Changing the values here will change the ADC reading, unless you override onADCRead() with a custom implementation.
*/
this.channelValues = new Array(this.config.numChannels);
/** AVCC Reference voltage */
this.avcc = 5;
/** AREF Reference voltage */
this.aref = 5;
/**
* Invoked whenever the code performs an ADC read.
*
* The default implementation reads the result from the `channelValues` array, and then calls
* `completeADCRead()` after `sampleCycles` CPU cycles.
*
* If you override the default implementation, make sure to call `completeADCRead()` after
* `sampleCycles` cycles (or else the ADC read will never complete).
*/
this.onADCRead = (input) => {
var _a;
// Default implementation
let voltage = 0;
switch (input.type) {
case ADCMuxInputType.Constant:
voltage = input.voltage;
break;
case ADCMuxInputType.SingleEnded:
voltage = (_a = this.channelValues[input.channel]) !== null && _a !== void 0 ? _a : 0;
break;
case ADCMuxInputType.Differential:
voltage =
input.gain *
((this.channelValues[input.positiveChannel] || 0) -
(this.channelValues[input.negativeChannel] || 0));
break;
case ADCMuxInputType.Temperature:
voltage = 0.378125; // 25 celcius
break;
}
const rawValue = (voltage / this.referenceVoltage) * 1024;
const result = Math.min(Math.max(Math.floor(rawValue), 0), 1023);
this.cpu.addClockEvent(() => this.completeADCRead(result), this.sampleCycles);
};
this.converting = false;
this.conversionCycles = 25;
// Interrupts
this.ADC = {
address: this.config.adcInterrupt,
flagRegister: this.config.ADCSRA,
flagMask: ADIF,
enableRegister: this.config.ADCSRA,
enableMask: ADIE,
};
cpu.writeHooks[config.ADCSRA] = (value, oldValue) => {
var _a;
if (value & ADEN && !(oldValue && ADEN)) {
this.conversionCycles = 25;
}
cpu.data[config.ADCSRA] = value;
cpu.updateInterruptEnable(this.ADC, value);
if (!this.converting && value & ADSC) {
if (!(value & ADEN)) {
// Special case: reading while the ADC is not enabled should return 0
this.cpu.addClockEvent(() => this.completeADCRead(0), this.sampleCycles);
return true;
}
let channel = this.cpu.data[this.config.ADMUX] & MUX_MASK;
if (cpu.data[config.ADCSRB] & MUX5) {
channel |= 0x20;
}
channel &= config.muxInputMask;
const muxInput = (_a = config.muxChannels[channel]) !== null && _a !== void 0 ? _a : fallbackMuxInput;
this.converting = true;
this.onADCRead(muxInput);
return true; // don't update
}
};
}
completeADCRead(value) {
const { ADCL, ADCH, ADMUX, ADCSRA } = this.config;
this.converting = false;
this.conversionCycles = 13;
if (this.cpu.data[ADMUX] & ADLAR) {
this.cpu.data[ADCL] = (value << 6) & 0xff;
this.cpu.data[ADCH] = value >> 2;
}
else {
this.cpu.data[ADCL] = value & 0xff;
this.cpu.data[ADCH] = (value >> 8) & 0x3;
}
this.cpu.data[ADCSRA] &= ~ADSC;
this.cpu.setInterruptFlag(this.ADC);
}
get prescaler() {
const { ADCSRA } = this.config;
const adcsra = this.cpu.data[ADCSRA];
const adps = adcsra & ADPS_MASK;
switch (adps) {
case 0:
case 1:
return 2;
case 2:
return 4;
case 3:
return 8;
case 4:
return 16;
case 5:
return 32;
case 6:
return 64;
case 7:
default:
return 128;
}
}
get referenceVoltageType() {
var _a;
const { ADMUX, adcReferences } = this.config;
let refs = (this.cpu.data[ADMUX] >> REFS_SHIFT) & REFS_MASK;
if (adcReferences.length > 4 && this.cpu.data[ADMUX] & REFS2) {
refs |= 0x4;
}
return (_a = adcReferences[refs]) !== null && _a !== void 0 ? _a : ADCReference.Reserved;
}
get referenceVoltage() {
switch (this.referenceVoltageType) {
case ADCReference.AVCC:
return this.avcc;
case ADCReference.AREF:
return this.aref;
case ADCReference.Internal1V1:
return 1.1;
case ADCReference.Internal2V56:
return 2.56;
default:
return this.avcc;
}
}
get sampleCycles() {
return this.conversionCycles * this.prescaler;
}
}