UNPKG

obniz

Version:

obniz sdk for javascript

218 lines (185 loc) 5.04 kB
class PCA9685 { constructor() { /* https://www.nxp.com/docs/en/data-sheet/PCA9685.pdf */ this.keys = [ 'gnd', 'vcc', 'scl', 'sda', 'oe', 'i2c', 'enabled', 'address', 'drive', ]; this.requiredKeys = []; this.address = 0x40; this._commands = { MODE1: 0x00, MODE2: 0x01, SUBADR1: 0x02, SUBADR2: 0x03, SUBADR3: 0x04, PRESCALE: 0xfe, LED0_ON_L: 0x06, ALL_LED_ON_L: 0xfa, bits: { ALLCALL: 0x01, SLEEP_ENABLE: 0x10, AUTO_INCREMENT_ENABLED: 0x20, RESTART: 0x80, OUTDRV: 0x04, INVRT: 0x10, }, }; this._regs = new Array(1); this.pwmNum = 16; this.pwms = []; this._preparePWM(this.pwmNum); } static info() { return { name: 'PCA9685', }; } wired(obniz) { this.obniz = obniz; if (obniz.isValidIO(this.params.oe)) { this.io_oe = obniz.getIO(this.params.oe); } this.obniz.setVccGnd(this.params.vcc, this.params.gnd, '5v'); if (typeof this.params.address === 'number') { this.address = this.params.address; } this.params.clock = this.params.clock || 400 * 1000; //for i2c this.params.mode = this.params.mode || 'master'; //for i2c this.params.pull = this.params.pull || '5v'; //for i2c this.i2c = obniz.getI2CWithConfig(this.params); if (this.obniz.isValidIO(this.params.srclr)) { this.io_srclr = this.obniz.getIO(this.params.srclr); this.io_srclr.output(true); } if (typeof this.params.enabled !== 'boolean') { this.params.enabled = true; } if (this.io_oe && this.params.enabled) { this.io_oe.output(false); } if (this.params.drive === 'open-drain') { this.i2c.write(this.address, [ this._commands.MODE2, this._commands.bits.OUTDRV, ]); } let mode1 = this._commands.bits.AUTO_INCREMENT_ENABLED; mode1 = mode1 & ~this._commands.bits.SLEEP_ENABLE; this.i2c.write(this.address, [this._commands.MODE1, mode1]); this.i2c.write(this.address, [ this._commands.MODE1, mode1 | this._commands.bits.RESTART, ]); this._regs[this._commands.MODE1] = mode1; obniz.wait(10); } _preparePWM(num) { class PCA9685_PWM { constructor(chip, id) { this.chip = chip; this.id = id; this.value = 0; this.state = {}; } freq(frequency) { this.chip.freq(frequency); } pulse(value) { this.chip.pulse(this.id, value); } duty(value) { this.chip.duty(this.id, value); } } for (let i = 0; i < num; i++) { this.pwms.push(new PCA9685_PWM(this, i)); } } isValidPWM(id) { return typeof id === 'number' && id >= 0 && id < this.pwmNum; } getPWM(id) { if (!this.isValidPWM(id)) { throw new Error('pwm ' + id + ' is not valid pwm'); } return this.pwms[id]; } freq(frequency) { if (typeof frequency !== 'number') { return; } if (frequency < 24 || 1526 < frequency) { throw new Error('freq must be within 24-1526 hz'); } if (this._freq === frequency) { return; } let prescaleval = 25000000.0; // 25MHz prescaleval /= 4096.0; //12bit prescaleval /= frequency * 0.9; prescaleval -= 1.0; const prescale = parseInt(Math.floor(prescaleval + 0.5)); const mode1 = this._regs[this._commands.MODE1]; this.i2c.write(this.address, [ this._commands.MODE1, (mode1 & 0x7f) | this._commands.bits.SLEEP_ENABLE, ]); // enter sleep this.i2c.write(this.address, [this._commands.PRESCALE, prescale]); this.i2c.write(this.address, [this._commands.MODE1, mode1]); // recover from sleep this.obniz.wait(5); // save this._freq = frequency; for (let i = 0; i < this.pwms.length; i++) { this.pwms[i].state.freq = this._freq; } } pulse(id, pulse_width) { if (typeof this._freq !== 'number' || this._freq <= 0) { throw new Error('please provide freq first.'); } this.duty(id, (pulse_width / 1000.0 / (1.0 / this._freq)) * 100); } duty(id, duty) { duty *= 1.0; if (typeof this._freq !== 'number' || this._freq <= 0) { throw new Error('please provide freq first.'); } if (typeof duty !== 'number') { throw new Error('please provide duty in number'); } if (duty < 0) { duty = 0; } if (duty > 100) { duty = 100; } this.getPWM(id).state.duty = duty; this.writeSingleONOFF(id, 0, (duty / 100.0) * 4095); } writeSingleONOFF(id, on, off) { this.i2c.write(this.address, [ this._commands.LED0_ON_L + 4 * id, on & 0xff, on >> 8, off & 0xff, off >> 8, ]); } setEnable(enable) { if (!this.io_oe && enable == false) { throw new Error('pin "oe" is not specified'); } this.io_oe.output(!enable); } } if (typeof module === 'object') { module.exports = PCA9685; }