aboutsummaryrefslogtreecommitdiff
path: root/src/peripherals/gpio.ts
diff options
context:
space:
mode:
authorUri Shaked2021-08-15 20:27:41 +0300
committerUri Shaked2021-08-15 20:27:41 +0300
commiteff7111c3b08e8bc9030edc284074dfa2e9b7171 (patch)
tree4909fdec5c6602c1da192c0ddd77a801890e941a /src/peripherals/gpio.ts
parentchore(deps): prettier 2.3.2 (diff)
downloadavr8js-eff7111c3b08e8bc9030edc284074dfa2e9b7171.tar.gz
avr8js-eff7111c3b08e8bc9030edc284074dfa2e9b7171.tar.bz2
avr8js-eff7111c3b08e8bc9030edc284074dfa2e9b7171.zip
feat(timer): external timer support #97
also refactor timer/GPIO interaction to be more generic. close #97
Diffstat (limited to '')
-rw-r--r--src/peripherals/gpio.ts72
1 files changed, 42 insertions, 30 deletions
diff --git a/src/peripherals/gpio.ts b/src/peripherals/gpio.ts
index bf5e53c..6d1dae8 100644
--- a/src/peripherals/gpio.ts
+++ b/src/peripherals/gpio.ts
@@ -87,6 +87,7 @@ export const PCINT2 = {
};
export type GPIOListener = (value: u8, oldValue: u8) => void;
+export type ExternalClockListener = (pinValue: boolean) => void;
export const portAConfig: AVRPortConfig = {
PIN: 0x20,
@@ -198,6 +199,8 @@ enum InterruptMode {
}
export class AVRIOPort {
+ readonly externalClockListeners: (ExternalClockListener | null)[] = [];
+
private readonly externalInts: (AVRInterruptConfig | null)[];
private readonly PCINT: AVRInterruptConfig | null;
private listeners: GPIOListener[] = [];
@@ -208,8 +211,10 @@ export class AVRIOPort {
private lastDdr: u8 = 0;
private lastPin: u8 = 0;
- constructor(private cpu: CPU, private portConfig: AVRPortConfig) {
+ constructor(private cpu: CPU, readonly portConfig: Readonly<AVRPortConfig>) {
cpu.gpioPorts.add(this);
+ cpu.gpioByPort[portConfig.PORT] = this;
+
cpu.writeHooks[portConfig.DDR] = (value: u8) => {
const portValue = cpu.data[portConfig.PORT];
cpu.data[portConfig.DDR] = value;
@@ -234,34 +239,6 @@ export class AVRIOPort {
this.updatePinRegister(ddrMask);
return true;
};
- // The following hook is used by the timer compare output to override GPIO pins:
- cpu.gpioTimerHooks[portConfig.PORT] = (pin: u8, mode: PinOverrideMode) => {
- const pinMask = 1 << pin;
- if (mode === PinOverrideMode.None) {
- this.overrideMask |= pinMask;
- this.overrideValue &= ~pinMask;
- } else {
- this.overrideMask &= ~pinMask;
- switch (mode) {
- case PinOverrideMode.Enable:
- this.overrideValue &= ~pinMask;
- this.overrideValue |= cpu.data[portConfig.PORT] & pinMask;
- break;
- case PinOverrideMode.Set:
- this.overrideValue |= pinMask;
- break;
- case PinOverrideMode.Clear:
- this.overrideValue &= ~pinMask;
- break;
- case PinOverrideMode.Toggle:
- this.overrideValue ^= pinMask;
- break;
- }
- }
- const ddrMask = cpu.data[portConfig.DDR];
- this.writeGpio(cpu.data[portConfig.PORT], ddrMask);
- this.updatePinRegister(ddrMask);
- };
// External interrupts
const { externalInterrupts } = portConfig;
@@ -360,13 +337,48 @@ export class AVRIOPort {
this.updatePinRegister(this.cpu.data[this.portConfig.DDR]);
}
+ /**
+ * Internal method - do not call this directly!
+ * Used by the timer compare output units to override GPIO pins.
+ */
+ timerOverridePin(pin: u8, mode: PinOverrideMode) {
+ const { cpu, portConfig } = this;
+ const pinMask = 1 << pin;
+ if (mode === PinOverrideMode.None) {
+ this.overrideMask |= pinMask;
+ this.overrideValue &= ~pinMask;
+ } else {
+ this.overrideMask &= ~pinMask;
+ switch (mode) {
+ case PinOverrideMode.Enable:
+ this.overrideValue &= ~pinMask;
+ this.overrideValue |= cpu.data[portConfig.PORT] & pinMask;
+ break;
+ case PinOverrideMode.Set:
+ this.overrideValue |= pinMask;
+ break;
+ case PinOverrideMode.Clear:
+ this.overrideValue &= ~pinMask;
+ break;
+ case PinOverrideMode.Toggle:
+ this.overrideValue ^= pinMask;
+ break;
+ }
+ }
+ const ddrMask = cpu.data[portConfig.DDR];
+ this.writeGpio(cpu.data[portConfig.PORT], ddrMask);
+ this.updatePinRegister(ddrMask);
+ }
+
private updatePinRegister(ddr: u8) {
const newPin = (this.pinValue & ~ddr) | (this.lastValue & ddr);
this.cpu.data[this.portConfig.PIN] = newPin;
if (this.lastPin !== newPin) {
for (let index = 0; index < 8; index++) {
if ((newPin & (1 << index)) !== (this.lastPin & (1 << index))) {
- this.toggleInterrupt(index, !!(newPin & (1 << index)));
+ const value = !!(newPin & (1 << index));
+ this.toggleInterrupt(index, value);
+ this.externalClockListeners[index]?.(value);
}
}
this.lastPin = newPin;