-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(gpio): working GPIO implementation #20
It's still not unit-tested, but at least hello_gpio_irq runs successfully: ```typescript import * as fs from 'fs'; import { RP2040 } from '../src'; import { bootromB1 } from './bootrom'; import { loadHex } from './intelhex'; import { GPIOPinState } from '../src/gpio-pin'; // Create an array with the compiled code of blink // Execute the instructions from this array, one by one. const hex = fs.readFileSync('hello_gpio_irq.hex', 'utf-8'); const mcu = new RP2040(); mcu.logMissingInstructions = false; mcu.loadBootrom(bootromB1); loadHex(hex, mcu.flash, 0x10000000); mcu.gpio[25].addListener((state) => { console.log('GPIO 25', GPIOPinState[state]); }); mcu.uart[0].onByte = (value) => { process.stdout.write(new Uint8Array([value])); }; mcu.PC = 0x10000000; mcu.execute(); let gpio2Value = false; setInterval(() => { gpio2Value = !gpio2Value; console.log('Changing GPIO 2 value to', gpio2Value); mcu.gpio[2].setInputValue(gpio2Value); }, 1000); ``` close #20
- Loading branch information
Showing
5 changed files
with
411 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import { RP2040 } from '../rp2040'; | ||
import { BasePeripheral, Peripheral } from './peripheral'; | ||
|
||
const GPIO_CTRL_LAST = 0x0ec; | ||
const INTR0 = 0xf0; | ||
const PROC0_INTE0 = 0x100; | ||
const PROC0_INTF0 = 0x110; | ||
const PROC0_INTS0 = 0x120; | ||
const PROC0_INTS3 = 0x12c; | ||
|
||
export class RPIO extends BasePeripheral implements Peripheral { | ||
constructor(rp2040: RP2040, name: string) { | ||
super(rp2040, name); | ||
} | ||
|
||
getPinFromOffset(offset: number) { | ||
const gpioIndex = offset >>> 3; | ||
return { | ||
gpio: this.rp2040.gpio[gpioIndex], | ||
isCtrl: !!(offset & 0x4), | ||
}; | ||
} | ||
|
||
readUint32(offset: number) { | ||
if (offset <= GPIO_CTRL_LAST) { | ||
const { gpio, isCtrl } = this.getPinFromOffset(offset); | ||
return isCtrl ? gpio.ctrl : gpio.status; | ||
} | ||
if (offset >= INTR0 && offset <= PROC0_INTS3) { | ||
const startIndex = (offset & 0xf) * 2; | ||
const register = offset & ~0xf; | ||
const { gpio } = this.rp2040; | ||
let result = 0; | ||
for (let index = 7; index >= 0; index--) { | ||
const pin = gpio[index + startIndex]; | ||
if (!pin) { | ||
continue; | ||
} | ||
result <<= 4; | ||
switch (register) { | ||
case INTR0: | ||
result |= pin.irqStatus; | ||
break; | ||
case PROC0_INTE0: | ||
result |= pin.irqEnableMask; | ||
break; | ||
case PROC0_INTF0: | ||
result |= pin.irqForceMask; | ||
break; | ||
case PROC0_INTS0: | ||
result |= (pin.irqStatus & pin.irqEnableMask) | pin.irqForceMask; | ||
break; | ||
} | ||
} | ||
return result; | ||
} | ||
return super.readUint32(offset); | ||
} | ||
|
||
writeUint32(offset: number, value: number) { | ||
if (offset <= GPIO_CTRL_LAST) { | ||
const { gpio, isCtrl } = this.getPinFromOffset(offset); | ||
if (isCtrl) { | ||
gpio.ctrl = value; | ||
gpio.checkForUpdates(); | ||
} | ||
return; | ||
} | ||
if (offset >= INTR0 && offset <= PROC0_INTS3) { | ||
const startIndex = (offset & 0xf) * 2; | ||
const register = offset & ~0xf; | ||
const { gpio } = this.rp2040; | ||
for (let index = 0; index < 8; index++) { | ||
const pin = gpio[index + startIndex]; | ||
if (!pin) { | ||
continue; | ||
} | ||
const pinValue = (value >> (index * 4)) & 0xf; | ||
const pinRawWriteValue = (this.rawWriteValue >> (index * 4)) & 0xf; | ||
switch (register) { | ||
case INTR0: | ||
pin.updateIRQValue(pinRawWriteValue); | ||
break; | ||
case PROC0_INTE0: | ||
pin.irqEnableMask = pinValue; | ||
break; | ||
case PROC0_INTF0: | ||
pin.irqForceMask = pinValue; | ||
break; | ||
} | ||
} | ||
return; | ||
} | ||
|
||
super.writeUint32(offset, value); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { RP2040 } from '../rp2040'; | ||
import { BasePeripheral, Peripheral } from './peripheral'; | ||
|
||
const VOLTAGE_SELECT = 0; | ||
const GPIO_FIRST = 0x4; | ||
const GPIO_LAST = 0x78; | ||
|
||
const QSPI_FIRST = 0x4; | ||
const QSPI_LAST = 0x18; | ||
|
||
export type IIOBank = 'qspi' | 'bank0'; | ||
|
||
export class RPPADS extends BasePeripheral implements Peripheral { | ||
voltageSelect = 0; | ||
|
||
private readonly firstPadRegister = this.bank === 'qspi' ? QSPI_FIRST : GPIO_FIRST; | ||
private readonly lastPadRegister = this.bank === 'qspi' ? QSPI_LAST : GPIO_LAST; | ||
|
||
constructor(rp2040: RP2040, name: string, readonly bank: IIOBank) { | ||
super(rp2040, name); | ||
} | ||
|
||
getPinFromOffset(offset: number) { | ||
const gpioIndex = (offset - this.firstPadRegister) >>> 2; | ||
if (this.bank === 'qspi') { | ||
return this.rp2040.qspi[gpioIndex]; | ||
} else { | ||
return this.rp2040.gpio[gpioIndex]; | ||
} | ||
} | ||
|
||
readUint32(offset: number) { | ||
if (offset >= this.firstPadRegister && offset <= this.lastPadRegister) { | ||
const gpio = this.getPinFromOffset(offset); | ||
return gpio.padValue; | ||
} | ||
switch (offset) { | ||
case VOLTAGE_SELECT: | ||
return this.voltageSelect; | ||
} | ||
return super.readUint32(offset); | ||
} | ||
|
||
writeUint32(offset: number, value: number) { | ||
if (offset >= this.firstPadRegister && offset <= this.lastPadRegister) { | ||
const gpio = this.getPinFromOffset(offset); | ||
gpio.padValue = value; | ||
gpio.checkForUpdates(); | ||
return; | ||
} | ||
switch (offset) { | ||
case VOLTAGE_SELECT: | ||
this.voltageSelect = value & 1; | ||
break; | ||
default: | ||
super.writeUint32(offset, value); | ||
} | ||
} | ||
} |
Oops, something went wrong.