From 471605bbe4f004fa2cd5d32debf1c9bff0725a65 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Sat, 15 Aug 2020 01:10:51 +0200 Subject: [PATCH 1/2] [driver] Add IS31FL3733 matrix driver --- README.md | 13 +- src/modm/driver/display/is31fl3733.hpp | 236 +++++++++++++++++++++++++ src/modm/driver/display/is31fl3733.lb | 26 +++ 3 files changed, 269 insertions(+), 6 deletions(-) create mode 100644 src/modm/driver/display/is31fl3733.hpp create mode 100644 src/modm/driver/display/is31fl3733.lb diff --git a/README.md b/README.md index f69d6ee8ed..79a9df804b 100644 --- a/README.md +++ b/README.md @@ -206,46 +206,47 @@ can easily configure them for you specific needs. HX711 I2C-EEPROM +IS31FL3733 ITG3200 L3GD20 LAWICEL -LIS302DL +LIS302DL LIS3DSH LIS3MDL LM75 LP503X LSM303A -LSM6DS33 +LSM6DS33 LTC2984 MAX6966 MAX7219 MCP23X17 MCP2515 -NOKIA5110 +NOKIA5110 NRF24 TFT-DISPLAY PAT9125EL PCA8574 PCA9535 -PCA9548A +PCA9548A PCA9685 SIEMENS-S65 SIEMENS-S75 SK6812 SK9822 -SSD1306 +SSD1306 SX1276 TCS3414 TCS3472 TLC594X TMP102 -TMP175 +TMP175 VL53L0 VL6180 WS2812 diff --git a/src/modm/driver/display/is31fl3733.hpp b/src/modm/driver/display/is31fl3733.hpp new file mode 100644 index 0000000000..8afa348a10 --- /dev/null +++ b/src/modm/driver/display/is31fl3733.hpp @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2020, Niklas Hauser + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#pragma once + +#include +#include +#include +#include + +namespace modm +{ + +/// @ingroup modm_driver_is31fl3733 +struct is31fl3733 +{ + enum class + Addr : uint8_t + { + GND = 0b00, + SCL = 0b01, + SDA = 0b10, + VCC = 0b11 + }; + + /// Available I2C addresses + static constexpr uint8_t + addr(Addr addr2 = Addr::GND, Addr addr1 = Addr::GND) + { + return 0b1010000 | (uint8_t(addr2) << 2) | uint8_t(addr1); + }; + + enum class + Register : uint16_t + { + // Page 0 + LED_ON_OFF = 0x8000, + LED_OPEN = 0x8018, + LED_SHORT = 0x8030, + + // Page 1 + PWM = 0x8100, + + // Page 2 + AUTO_BREATH_MODE = 0x8200, + + // Page 3 + CONFIGURATION = 0x8300, + GLOBAL_CURRENT_CONTROL = 0x8301, + ABM_1 = 0x8302, + ABM_2 = 0x8306, + ABM_3 = 0x830A, + TIME_UPDATE = 0x830E, + SW_PULL_UP = 0x830F, + CS_PULL_DOWN = 0x8310, + RESET = 0x8311, + + // Global + COMMAND = 0xFD, + COMMAND_WRITE_LOCK = 0xFE, + INTERRUPT_MASK = 0xF0, + INTERRUPT_STATUS = 0xF1 + }; + +protected: + static constexpr uint8_t LED_ON_OFF_size = 0x18; + static constexpr uint8_t LED_OPEN_size = LED_ON_OFF_size; + static constexpr uint8_t LED_SHORT_size = LED_ON_OFF_size; + static constexpr uint8_t PWM_size = 0xC0; + static constexpr uint8_t AUTO_BREATH_MODE_size = PWM_size; + + static constexpr bool + hasPage(Register reg) + { return uint16_t(reg) & 0x8000; } + + static constexpr uint8_t + getPage(Register reg) + { return ((uint16_t(reg) >> 8) & 0x0f); } +}; + +/** + * @ingroup modm_driver_is31fl3733 + * @author Niklas Hauser + */ +template < class I2cMaster > +class Is31fl3733 : public is31fl3733, public modm::I2cDevice +{ +public: + Is31fl3733(uint8_t address=addr()): + I2cDevice(address) + {} + + bool + enable(uint8_t x, uint8_t y) + { + if (x < 12 and y < 16) + { + data.led_on_off[x] |= (1u << y); + return true; + } + return false; + } + void enableAll() + { std::memset(data.led_on_off, 0xff, sizeof(data.led_on_off)); } + + bool + disable(uint8_t x, uint8_t y) + { + if (x < 12 and y < 16) + { + data.led_on_off[x] &= ~(1u << y); + return true; + } + return false; + } + void disableAll() + { std::memset(data.led_on_off, 0, sizeof(data.led_on_off)); } + + bool + setPwm(uint8_t x, uint8_t y, uint8_t pwm) + { + if (x < 12 and y < 16) + { + data.led_pwm[x][y] = pwm; + return true; + } + return false; + } + void setAllPwm(uint8_t pwm) + { std::memset(data.led_pwm, pwm, sizeof(data.led_pwm)); } + +public: + modm::ResumableResult + reset() + { return readRegister(Register::RESET, buffer); } + + modm::ResumableResult + setGlobalCurrent(uint8_t current) + { return writeRegister(Register::GLOBAL_CURRENT_CONTROL, current); } + + modm::ResumableResult + clearSoftwareShutdown() + { return writeRegister(Register::CONFIGURATION, 0x01); } + + modm::ResumableResult + writeOnOff() + { + RF_BEGIN(); + if (not RF_CALL(setPage(Register::LED_ON_OFF))) RF_RETURN(false); + + this->transaction.configureWrite(&data.addr_led_on_off, LED_ON_OFF_size+1); + RF_END_RETURN_CALL(this->runTransaction()); + } + + modm::ResumableResult + writePwm() + { + RF_BEGIN(); + if (not RF_CALL(setPage(Register::PWM))) RF_RETURN(false); + + this->transaction.configureWrite(&data.addr_led_pwm, PWM_size+1); + RF_END_RETURN_CALL(this->runTransaction()); + } + +public: + modm::ResumableResult + writeRegister(Register reg, uint8_t value, uint8_t offset=0) + { + RF_BEGIN(); + if (not RF_CALL(setPage(reg))) RF_RETURN(false); + + buffer[0] = uint8_t(reg) + offset; + buffer[1] = value; + + this->transaction.configureWrite(buffer, 2); + RF_END_RETURN_CALL(this->runTransaction()); + } + + modm::ResumableResult + readRegister(Register reg, uint8_t *const value, uint8_t offset=0) + { + RF_BEGIN(); + if (not RF_CALL( setPage(reg) )) RF_RETURN(false); + + buffer[0] = uint8_t(reg) + offset; + this->transaction.configureWriteRead(buffer, 1, value, 1); + + RF_END_RETURN_CALL(this->runTransaction()); + } + +protected: + modm::ResumableResult + setPage(Register reg) + { + RF_BEGIN(); + + if (hasPage(reg) and (getPage(reg) != current_page)) + { + buffer[0] = uint8_t(Register::COMMAND_WRITE_LOCK); + buffer[1] = 0xC5; // command write key + this->transaction.configureWrite(buffer, 2); + if (not RF_CALL(this->runTransaction())) RF_RETURN(false); + + buffer[0] = uint8_t(Register::COMMAND); + buffer[1] = getPage(reg); + if (not RF_CALL(this->runTransaction())) RF_RETURN(false); + current_page = getPage(reg); + } + + RF_END_RETURN(true); + } + +private: + struct LedData + { + const uint8_t addr_led_on_off{uint8_t(Register::LED_ON_OFF)}; + uint16_t led_on_off[12]; + + const uint8_t addr_led_pwm{uint8_t(Register::PWM)}; + uint8_t led_pwm[12][16]; + } modm_packed; + + LedData data; + uint8_t current_page{0xff}; + uint8_t buffer[2]; +}; + +} // namespace modm diff --git a/src/modm/driver/display/is31fl3733.lb b/src/modm/driver/display/is31fl3733.lb new file mode 100644 index 0000000000..9eb03af216 --- /dev/null +++ b/src/modm/driver/display/is31fl3733.lb @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2020, Niklas Hauser +# +# This file is part of the modm project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# ----------------------------------------------------------------------------- + + +def init(module): + module.name = ":driver:is31fl3733" + module.description = "IS31FL3733 Matrix Driver" + +def prepare(module, options): + module.depends( + ":architecture:i2c.device", + ":architecture:register") + return True + +def build(env): + env.outbasepath = "modm/src/modm/driver/display" + env.copy("is31fl3733.hpp") From 9b6aeee3956446e483f0b66ad8111914868f1a9e Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Sat, 15 Aug 2020 01:11:08 +0200 Subject: [PATCH 2/2] [example] Add IS31FL3733 driver on STM32G071 --- examples/nucleo_g071rb/matrix/main.cpp | 62 +++++++++++++++++++++++ examples/nucleo_g071rb/matrix/project.xml | 12 +++++ 2 files changed, 74 insertions(+) create mode 100644 examples/nucleo_g071rb/matrix/main.cpp create mode 100644 examples/nucleo_g071rb/matrix/project.xml diff --git a/examples/nucleo_g071rb/matrix/main.cpp b/examples/nucleo_g071rb/matrix/main.cpp new file mode 100644 index 0000000000..b91f620719 --- /dev/null +++ b/examples/nucleo_g071rb/matrix/main.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019, Niklas Hauser + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include + +using namespace Board; + +using PinReset = GpioC8; +using PinSda = GpioA11; +using PinScl = GpioA12; + +using I2cInstance = BitBangI2cMaster; +static modm::Is31fl3733 driver(modm::is31fl3733::addr()); + +// ---------------------------------------------------------------------------- +int +main() +{ + Board::initialize(); + LedD13::setOutput(modm::Gpio::Low); + + MODM_LOG_ERROR << "error" << modm::endl; + + // Reset the I2C interface of the chip + PinReset::setOutput(modm::Gpio::High); + modm::delay(20ms); + PinReset::setOutput(modm::Gpio::Low); + + I2cInstance::initialize(); + I2cInstance::connect(); + + RF_CALL_BLOCKING(driver.reset()); + RF_CALL_BLOCKING(driver.clearSoftwareShutdown()); + RF_CALL_BLOCKING(driver.setGlobalCurrent(1)); + + driver.enableAll(); + RF_CALL_BLOCKING(driver.writeOnOff()); + + uint8_t pwm{0}; + while (true) + { + for (uint8_t y=0, pi=pwm; y<16; y++) { + for (uint8_t x=0; x<12; x++) { + driver.setPwm(x, y, pi++); + } + } + RF_CALL_BLOCKING(driver.writePwm()); + modm::delay(10ms); + pwm++; + } + + return 0; +} diff --git a/examples/nucleo_g071rb/matrix/project.xml b/examples/nucleo_g071rb/matrix/project.xml new file mode 100644 index 0000000000..3893ddf9d3 --- /dev/null +++ b/examples/nucleo_g071rb/matrix/project.xml @@ -0,0 +1,12 @@ + + modm:nucleo-g071rb + + + + + modm:platform:gpio + modm:platform:i2c.bitbang + modm:driver:is31fl3733 + modm:build:scons + +