Line data Source code
1 : /* 2 : LP5562 I2C driver 3 : */ 4 : /* 5 : This program is free software: you can redistribute it and/or modify 6 : it under the terms of the GNU General Public License as published by 7 : the Free Software Foundation, either version 3 of the License, or 8 : (at your option) any later version. 9 : 10 : This program is distributed in the hope that it will be useful, 11 : but WITHOUT ANY WARRANTY; without even the implied warranty of 12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 : GNU General Public License for more details. 14 : 15 : You should have received a copy of the GNU General Public License 16 : along with this program. If not, see <http://www.gnu.org/licenses/>. 17 : */ 18 : 19 : /* LED driver for LP5562 */ 20 : 21 : #include "LP5562.h" 22 : 23 : #if AP_NOTIFY_LP5562_ENABLED 24 : 25 : #include <AP_HAL/AP_HAL.h> 26 : 27 : extern const AP_HAL::HAL& hal; 28 : 29 : #define LP5562_LED_BRIGHT 255 // full brightness 30 : #define LP5562_LED_MEDIUM 170 // medium brightness 31 : #define LP5562_LED_DIM 85 // dim 32 : #define LP5562_LED_OFF 0 // off 33 : 34 : enum class Register { 35 : ENABLE = 0x00, 36 : B_PWM = 0x02, 37 : G_PWM = 0x03, 38 : R_PWM = 0x04, 39 : B_CURRENT= 0x05, 40 : G_CURRENT= 0x06, 41 : R_CURRENT= 0x07, 42 : CONFIG = 0x08, 43 : RESET = 0x0D, 44 : LED_MAP = 0x70, 45 : }; 46 : 47 10470 : LP5562::LP5562(uint8_t bus, uint8_t addr) 48 : : RGBLed(LP5562_LED_OFF, LP5562_LED_BRIGHT, LP5562_LED_MEDIUM, LP5562_LED_DIM) 49 10470 : , _bus(bus) 50 10470 : , _addr(addr) 51 : { 52 10470 : } 53 : 54 10470 : bool LP5562::init(void) 55 : { 56 10470 : _dev = hal.i2c_mgr->get_device_ptr(_bus, _addr); 57 10470 : if (!_dev) { 58 0 : return false; 59 : } 60 : 61 10470 : if (!configure_dev()) { 62 8376 : delete _dev; 63 8376 : _dev = nullptr; 64 8376 : return false; 65 : } 66 : 67 2094 : _dev->register_periodic_callback(20000, FUNCTOR_BIND_MEMBER(&LP5562::_timer, void)); 68 : 69 2094 : return true; 70 : } 71 : 72 10470 : bool LP5562::configure_dev() 73 : { 74 10470 : WITH_SEMAPHORE(_dev->get_semaphore()); 75 : 76 10470 : _dev->set_retries(10); 77 : 78 : // reset the device and probe to see if this device looks like an LP5662: 79 10470 : if (!_dev->write_register((uint8_t)Register::RESET, 0xff)) { 80 8376 : return false; 81 : } 82 : 83 : // reset delay; unsure if this is really required: 84 2094 : hal.scheduler->delay_microseconds(100); 85 : 86 : // check the GBR PWM control registers have their reset values: 87 8376 : for (uint8_t i=(uint8_t)Register::B_CURRENT; i<=(uint8_t)Register::R_CURRENT; i++) { 88 : uint8_t value; 89 6282 : if (!_dev->read_registers(i, &value, 1)) { 90 0 : return false; 91 : } 92 6282 : if (value != 0xAF) { // 0xAF is the startup value for these registers per datasheet 93 0 : return false; 94 : } 95 : } 96 : 97 : // values here are taken literally from 7.3.2 in the datasheet. 98 : // See the simulator for register breakdown. 99 : 100 : // chip enable: 101 2094 : if (!_dev->write_register((uint8_t)Register::ENABLE, 0b1000000)) { 102 0 : return false; 103 : } 104 : 105 : // start-up-delay: 106 2094 : hal.scheduler->delay_microseconds(500); 107 : 108 : // use internal clock: 109 2094 : if (!_dev->write_register((uint8_t)Register::CONFIG, 0b00000001)) { 110 0 : return false; 111 : } 112 : 113 : // set direct PWM control: 114 2094 : if (!_dev->write_register((uint8_t)Register::LED_MAP, 0b00000000)) { 115 0 : return false; 116 : } 117 : 118 2094 : _dev->set_retries(1); 119 : 120 2094 : return true; 121 10470 : } 122 : 123 : // set_rgb - set color as a combination of red, green and blue values 124 363999 : bool LP5562::hw_set_rgb(uint8_t red, uint8_t green, uint8_t blue) 125 : { 126 363999 : bgr[0] = blue; 127 363999 : bgr[1] = green; 128 363999 : bgr[2] = red; 129 363999 : _need_update = true; 130 363999 : return true; 131 : } 132 : 133 7790472 : void LP5562::_timer(void) 134 : { 135 7790472 : if (!_need_update) { 136 7426497 : return; 137 : } 138 363975 : _need_update = false; 139 : 140 1455900 : for (uint8_t i=0; i< ARRAY_SIZE(bgr); i++) { 141 1091925 : const uint8_t new_colour = bgr[i]; 142 1091925 : const uint8_t last_sent = last_sent_bgr[i]; 143 1091925 : if (new_colour == last_sent) { 144 582462 : continue; 145 : } 146 : // note that new_colour is already scaled by supplying 147 : // brightness values in the constructor. 148 : 149 : // take advantage of the linear layout of the registers. The 150 : // direct PWM registers start at 0x02 for blue: 151 509463 : _dev->write_register((uint8_t)0x02 + i, new_colour); 152 : 153 509463 : last_sent_bgr[i] = new_colour; 154 : } 155 : } 156 : 157 : #endif // AP_NOTIFY_LP5562_ENABLED