🎨
MadMachine-Examples
  • Introduction
  • About our project
  • Getting Started
  • Tutorial
    • What is SwiftIO
    • How to use IDE
    • Libraries
    • MM SDK
  • Built-In Examples
    • GettingStarted
      • Blink
      • ReadDigitalInput
      • ReadAnalogInput
      • PWMBrightnessControl
    • SimpleIO
      • ButtoncontrolLED
      • BlinkAnalogIn
      • BlinkTimer
      • BrightnessAnalogIn
      • Debounce
      • LEDsBrightnessControl
      • PWMSoundOutput
      • PWMMelody
    • AdvancedIO
      • ILI9341
      • LCD1602
      • MidiPlayer
      • PCA9685
      • SHT3x
      • SSD1315
    • Challenge
      • LCDFamily
      • RobotArm
      • Tetris
    • MakerKit
      • Mission 01 Blink
      • Mission 02 RGB LED
      • Mission 03 Push Button
      • Mission 04 Potentiometer RGB
      • Mission 05 Buzzer
      • Mission 06 Seven Segment Display
      • Mission 07 DC Motor
      • Mission 08 Servo Motor
      • Mission 09 LCD
      • Mission 10 Humiture Sensor
  • Library Reference
  • FAQ
Powered by GitBook
On this page
  • What you need
  • Circuit
  • Tips
  • Code
  • main.swift
  • PCA9685.swift
  • Video
  • See Also
  • References

Was this helpful?

  1. Built-In Examples
  2. AdvancedIO

PCA9685

What you need

Circuit

Tips

Code

main.swift

import SwiftIO

extension PCA9685 {
    func setServoPulse(_ channel: Int, _ pulse: Int) {
        if pulse < 500 || pulse > 2500 {
            return
        }

        let value: UInt32 = UInt32(pulse) * 4096 / 2_0000
        setPWM(UInt8(channel), 0, UInt16(value))
    } 
}

let i2c = I2C(Id.I2C0)
let pwm = PCA9685(i2c)

while true {
    for pulse in stride(from: 500, through: 2500, by: 10)  {
        for channel in 0..<16 {
            pwm.setServoPulse(channel, pulse)
        }
        sleep(ms: 20)
    }
}

PCA9685.swift

import SwiftIO

final class PCA9685 {
    private struct Mode1: OptionSet {
        let rawValue: UInt8

        static let ALLCALL = Mode1(rawValue: 0x01)
        static let SUB3    = Mode1(rawValue: 0x02)
        static let SUB2    = Mode1(rawValue: 0x04)
        static let SUB1    = Mode1(rawValue: 0x08)
        static let SLEEP   = Mode1(rawValue: 0x10)
        static let AI      = Mode1(rawValue: 0x20)
        static let EXTCLK  = Mode1(rawValue: 0x40)
        static let RESTART = Mode1(rawValue: 0x80)

        static let all     = Mode1(rawValue: 0xFF)
    }

    private struct Mode2: OptionSet {
        let rawValue: UInt8

        static let OUTNE0 = Mode2(rawValue: 0x01)
        static let OUTNE1 = Mode2(rawValue: 0x02)
        static let OUTDRV = Mode2(rawValue: 0x04)
        static let OCH    = Mode2(rawValue: 0x08)
        static let INVRT  = Mode2(rawValue: 0x10)

        static let all    = Mode2(rawValue: 0xFF)
    }

    private enum Register: UInt8 {
        case MODE1 = 0x00
        case MODE2 = 0x01
        case SUBADR1 = 0x02
        case SUBADR2 = 0x03
        case SUBADR3 = 0x04
        case ALLCALLADR = 0x05
        case LED0_ON_L = 0x06
        case LED0_ON_H = 0x07
        case LED0_OFF_L = 0x08
        case LED0_OFF_H = 0x09
        case ALLLED_ON_L = 0xFA
        case ALLLED_ON_H = 0xFB
        case ALLLED_OFF_L = 0xFC
        case ALLLED_OFF_H = 0xFD
        case PRESCALE = 0xFE
        case TESTMODE = 0xFF
    }

    let i2c: I2C
    let address = UInt8(0x40)
    let oscFrequency = Int(25_000_000)
    let prescaleMin = Float(3)
    let prescaleMax = Float(255)

    init(_ i2c: I2C) {
        self.i2c = i2c

        reset()
        setPWMFreq(1000)
    }

    func reset() {
        writeMode1(.RESTART)
        sleep(ms: 10)
    }

    func standby() {
        let oldMode = Mode1(rawValue: readRegister(.MODE1))
        let setting = oldMode.union(.SLEEP)               //[oldMode, .SLEEP]
        writeMode1(setting)
        sleep(ms: 5)
    }

    func wakeup() {
        let oldMode = Mode1(rawValue: readRegister(.MODE1))
        var setting: Mode1 = .all
        setting.subtract(.SLEEP)
        setting.formIntersection(oldMode)

        writeMode1(setting)
    }

    func setPWMFreq(_ freq: Float) {
        var freq = freq

        if freq < 1 {
            freq = 1.0
        } else if freq > 3500 {
            freq = 3500.0
        }

        var prescaleval = (Float(oscFrequency) / (freq * 4096.0)) + 0.5 - 1
        if prescaleval < prescaleMin {
            prescaleval = prescaleMin
        } else if prescaleval > prescaleMax {
            prescaleval = prescaleMax
        }

        let prescale = UInt8(prescaleval)

        let oldMode = Mode1(rawValue: readRegister(.MODE1))
        var newMode: Mode1 = .all
        newMode.subtract(.RESTART)
        newMode.formIntersection(oldMode)
        newMode.formUnion(.SLEEP)

        writeMode1(newMode)
        writeRegister(.PRESCALE, prescale)
        writeMode1(oldMode)
        sleep(ms: 5)

        newMode = oldMode.union([.RESTART, .AI])
        writeMode1(newMode)
    }

    func setOutputMode(_ totempole: Bool) {
        let oldMode = Mode2(rawValue: readRegister(.MODE2))
        var newMode: Mode2

        if totempole {
            newMode = oldMode.union(.OUTDRV) 
        } else {
            newMode = .all
            newMode.subtract(.OUTDRV)
            newMode.formIntersection(oldMode)
        }

        writeMode2(newMode)
    }

    func readPrescale() -> UInt8 {
        return readRegister(.PRESCALE)
    }

    func getPWM(_ channel: UInt8) -> UInt8 {
        let data: [UInt8] = [Register.LED0_ON_L.rawValue + 4 * channel, 4]
        i2c.write(data, to: address)
        return i2c.readByte(from: address)
    }

    func setPWM(_ channel: UInt8, _ on: UInt16, _ off: UInt16) {
        let data: [UInt8] = [Register.LED0_ON_L.rawValue + 4 * channel,
                             UInt8(on & 0xFF),
                             UInt8(on >> 8),
                             UInt8(off & 0xFF),
                             UInt8(off >> 8)]
        i2c.write(data, to: address)
    }

    func setPin(_ channel: UInt8, _ val: UInt16, _ invert: Bool) {
        var val = val
        val = min(val, 4095)

        if invert {
            if val == 0 {
                setPWM(channel, 4096, 0)
            } else if val == 4095 {
                setPWM(channel, 0, 4096)
            } else {
                setPWM(channel, 0, 4095 - val)
            }
        } else {
            if val == 4095 {
                setPWM(channel, 4096, 0)
            } else if val == 0 {
                setPWM(channel, 0, 4096)
            } else {
                setPWM(channel, 0, val)
            }
        }
    }

    func writeMicroseconds(_ channel: UInt8, _ microseconds: UInt16) {
        var pulse = Double(microseconds)
        var pulseLength = Double(1_000_000.0)

        var prescale = Double(readPrescale())

        prescale += 1
        pulseLength *= prescale
        pulseLength /= Double(oscFrequency)

        pulse /= pulseLength
        setPWM(channel, 0, UInt16(pulse))
    }


    @inline(__always)
    private func readRegister(_ r: Register) -> UInt8 {
        i2c.write(r.rawValue, to: address)
        return i2c.readByte(from: address)
    }

    @inline(__always)
    private func writeRegister(_ r: Register, _ setting: UInt8) {
        let data: [UInt8] = [r.rawValue, setting]
        i2c.write(data, to: address)
    } 


    private func writeMode1(_ setting: Mode1) {
        let data: [UInt8] = [Register.MODE1.rawValue, setting.rawValue]
        i2c.write(data, to: address)
    }

    private func writeMode2(_ setting: Mode2) {
        let data: [UInt8] = [Register.MODE2.rawValue, setting.rawValue]
        i2c.write(data, to: address)
    }
}

Video

See Also

References

Last revision 2020/09/10 by Johnson

PreviousMidiPlayerNextSHT3x

Last updated 4 years ago

Was this helpful?