🎨
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
  • ILI9341.swift
  • Video
  • See Also
  • References

Was this helpful?

  1. Built-In Examples
  2. AdvancedIO

ILI9341

What you need

Circuit

Tips

Code

main.swift

import SwiftIO

let spi = SPI(Id.SPI0, speed: 36000000)
let dc = DigitalOut(Id.D0)
let rst = DigitalOut(Id.D1)

let lcd = ILI9341(spi: spi, dc: dc, rst: rst, direction: .vertical)

func clearScreenTest() {
    let white: UInt16 = 0xFFFF
    let red:   UInt16 = 0xF800
    let green: UInt16 = 0x07E0
    let blue:  UInt16 = 0x001F
    let black: UInt16 = 0x0000

    lcd.clearScreen(color: white)
    lcd.clearScreen(color: red)
    lcd.clearScreen(color: green)
    lcd.clearScreen(color: blue)
    lcd.clearScreen(color: black)
}

func pixelTest() {
    let rainbow: [UInt16] = [
        0xF800,
        0xFBE0,
        0xFFE0,
        0x07E0,
        0x07FF,
        0x001F,
        0x781F
    ]

    let colorHeight = lcd.height / rainbow.count

    for index in 0..<rainbow.count {
        for y in colorHeight * index ..< colorHeight * (index + 1) {
            for x in 0..<lcd.width {
                lcd.writePixel(x: x, y: y, color: rainbow[index])
            }
        }
    }
}

while true {
    clearScreenTest()
    pixelTest()
    sleep(ms: 2000)
}

ILI9341.swift

import SwiftIO

final class ILI9341 {

    public enum Direction {
        case vertical, verticalInverse, horizontal, horizontalInverse
    }

    private let step1Config: [(Command, [UInt8])] = [
        (.POWER_CTRL_B, [0x00, 0xC1, 0x30]),
        (.POWER_ON_SEQ_CTRL, [0x64, 0x03, 0x12, 0x81]),
        (.DRVR_TIMING_CTRL_A_I, [0x85, 0x00, 0x79]),
        (.POWER_CTRL_A, [0x39, 0x2C, 0x00, 0x34, 0x02]),
        (.PUMP_RATIO_CTRL, [0x20]),
        (.DRVR_TIMING_CTRL_B, [0x00, 0x00]),
        (.POWER_CTRL_1, [0x1D]),
        (.POWER_CTRL_2, [0x12]),
        (.VCOM_CTRL_1, [0x33, 0x3F]),
        (.VCOM_CTRL_2, [0x92]),
        (.PIXEL_FORMAT_SET, [0x55]),
    ]

    private var directionConfig: (Command, [UInt8]) {
        switch direction {
            case .vertical:
            return (.MEM_ACCESS_CTRL, [0x08])
            case .verticalInverse:
            return (.MEM_ACCESS_CTRL, [0xC8])
            case .horizontal:
            return (.MEM_ACCESS_CTRL, [0x78])
            case .horizontalInverse:
            return (.MEM_ACCESS_CTRL, [0xA8])
        } 
    }

    private let step2Config: [(Command, [UInt8])] = [
        (.FRAME_CTRL_NORMAL_MODE, [0x00, 0x12]),
        (.DISPLAY_FUNCTION_CTRL, [0x0A, 0xA2]),
        (.ENABLE_3G, [0x00]),
        (.GAMMA_SET, [0x01]),
        (.POSITIVE_GAMMA_CORRECTION, [0x0F, 0x22, 0x1C, 0x1B, 0x08, 0x0F, 0x48, 0xB8, 0x34, 0x05, 0x0C, 0x09, 0x0F, 0x07, 0x00]),
        (.NEGATIVE_GAMMA_CORRECTION, [0x00, 0x23, 0x24, 0x07, 0x10, 0x07, 0x38, 0x47, 0x4B, 0x0A, 0x13, 0x06, 0x30, 0x38, 0x0F]),
        (.EXIT_SLEEP, []),
        (.DISPLAY_ON, [])
    ]

    let spi: SPI
    let rst, dc: DigitalOut
    let direction: Direction
    public let width: Int
    public let height: Int

    public init(spi: SPI, dc: DigitalOut, rst: DigitalOut, direction: Direction = .horizontal) {
        self.spi = spi
        self.rst = rst
        self.dc = dc
        self.direction = direction

        switch direction {
            case .vertical, .verticalInverse:
            width = 240
            height = 320
            case .horizontal, .horizontalInverse:
            width = 320
            height = 240
        }

        reset()

        step1Config.forEach { config in
            writeConfig(config)
        }

        writeConfig(directionConfig)

        step2Config.forEach { config in
            writeConfig(config)
        }
    }

    @inline(__always)
    public func writePixel(x: Int, y: Int, color: UInt16) {
        setAddrWindow(x: x, y: y, width: 1, height: 1)
        writeData(color)
    }

    public func writeBitmap(x: Int, y: Int, width w: Int, height h: Int, data: [UInt8]) {
        setAddrWindow(x: x, y: y, width: w, height: h) 
        writeData(data)
    }

    public func writeBitmap(x: Int, y: Int, width w: Int, height h: Int, data: UnsafeRawBufferPointer) {
        setAddrWindow(x: x, y: y, width: w, height: h) 
        writeData(data)
    }

    public func writeScreen(_ data: [UInt8]) {
        guard data.count <= width * height * 2 else { return }
        setAddrWindow(x: 0, y: 0, width: width, height: height) 
        writeData(data)
    }

    public func writeScreen(_ data: UnsafeRawBufferPointer) {
        guard data.count <= width * height * 2 else { return }
        setAddrWindow(x: 0, y: 0, width: width, height: height) 
        writeData(data)
    }

    public func clearScreen(_ color: UInt16 = 0x0000) {
        let highByte = UInt8(color >> 8)
        let lowByte = UInt8(color & 0xFF)

        setAddrWindow(x: 0, y: 0, width: width, height: height)

        dc.write(true)
        for _ in 0..<width * height {
            spi.write(highByte)
            spi.write(lowByte)
        }
    }

    public func reset() {
        rst.write(false)
        sleep(ms: 100)
        rst.write(true)
        sleep(ms: 100)
    }

    public func setAddrWindow(x: Int, y: Int, width w: Int, height h: Int) {
        let x0 = UInt16(x)
        let y0 = UInt16(y)
        let x1 = UInt16(x + w - 1)
        let y1 = UInt16(y + h - 1)

        writeCommand(Command.COLUMN_ADDR.rawValue)
        writeData(x0)
        writeData(x1)

        writeCommand(Command.PAGE_ADDR.rawValue)
        writeData(y0)
        writeData(y1)

        writeCommand(Command.MEM_WRITE.rawValue)
    }
}

extension ILI9341 {
    private enum Command: UInt8 {
        case SOFTWARE_RESET = 0x01
        case ENTER_SLEEP = 0x10
        case EXIT_SLEEP = 0x11
        case GAMMA_SET = 0x26
        case DISPLAY_OFF = 0x28
        case DISPLAY_ON = 0x29
        case COLUMN_ADDR = 0x2A
        case PAGE_ADDR = 0x2B
        case MEM_WRITE = 0x2C
        case MEM_ACCESS_CTRL = 0x36
        case PIXEL_FORMAT_SET = 0x3A
        case FRAME_CTRL_NORMAL_MODE = 0xB1
        case DISPLAY_FUNCTION_CTRL = 0xB6
        case POWER_CTRL_1 = 0xC0
        case POWER_CTRL_2 = 0xC1
        case VCOM_CTRL_1 = 0xC5
        case VCOM_CTRL_2 = 0xC7
        case POSITIVE_GAMMA_CORRECTION = 0xE0
        case NEGATIVE_GAMMA_CORRECTION = 0xE1

        case POWER_CTRL_A = 0xCB
        case POWER_CTRL_B = 0xCF
        case DRVR_TIMING_CTRL_A_I = 0xE8
        case DRVR_TIMING_CTRL_A_E = 0xE9
        case DRVR_TIMING_CTRL_B = 0xEA
        case POWER_ON_SEQ_CTRL = 0xED
        case ENABLE_3G = 0xF2
        case PUMP_RATIO_CTRL = 0xF7
    }

    private enum DataAccessConfig: UInt8 {
        case MEM_ACCESS_CTRL_MY = 0x80
        case MEM_ACCESS_CTRL_MX = 0x40
        case MEM_ACCESS_CTRL_MV = 0x20
        case MEM_ACCESS_CTRL_ML = 0x10
        case MEM_ACCESS_CTRL_BGR = 0x08
        case MEM_ACCESS_CTRL_MH = 0x04

        case PIXEL_FORMAT_RGB_18_BIT = 0x60
        case PIXEL_FORMAT_RGB_16_BIT = 0x50
        case PIXEL_FORMAT_MCU_18_BIT = 0x06
        case PIXEL_FORMAT_MCU_16_BIT = 0x05
    }

    private func writeConfig(_ config: (Command, [UInt8])) {
        writeCommand(config.0.rawValue)
        if config.1.count > 0 {
            writeData(config.1)
        }
    }

    private func writeCommand(_ command: UInt8) {
        dc.write(false)
        spi.write(command)
    }

    private func writeData(_ data: UInt16) {
        let array = [UInt8(data >> 8), UInt8(data & 0xFF)]
        dc.write(true)
        spi.write(array)
    }

    private func writeData(_ data: [UInt8]) {
        dc.write(true)
        spi.write(data)
    }

    private func writeData(_ data: UnsafeRawBufferPointer) {
        dc.write(true)
        spi.write(data)
    }
}

Video

See Also

References

Last revision 2020/09/10 by Johnson

PreviousAdvancedIONextLCD1602

Last updated 4 years ago

Was this helpful?