Line data Source code
1 : /* 2 : PCA9685LED 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 : #include "PCA9685LED_I2C.h" 19 : 20 : #if AP_NOTIFY_PCA9685_ENABLED 21 : 22 : #include <AP_HAL/AP_HAL.h> 23 : 24 : #define NAVIO_LED_BRIGHT 0x0 // full brightness 25 : #define NAVIO_LED_MEDIUM 0x7F // medium brightness 26 : #define NAVIO_LED_DIM 0x4F // dim brightness 27 : #define NAVIO_LED_OFF 0xFF // off 28 : 29 : #define PCA9685_ADDRESS 0x40 30 : #define PCA9685_MODE1 0x00 31 : #define PCA9685_PWM 0x6 32 : #define PCA9685_MODE_SLEEP (1 << 4) 33 : #define PCA9685_MODE_AUTO_INCREMENT (1 << 5) 34 : 35 : extern const AP_HAL::HAL& hal; 36 : 37 0 : PCA9685LED_I2C::PCA9685LED_I2C() : 38 0 : RGBLed(NAVIO_LED_OFF, NAVIO_LED_BRIGHT, NAVIO_LED_MEDIUM, NAVIO_LED_DIM) 39 : { 40 0 : } 41 : 42 0 : bool PCA9685LED_I2C::init() 43 : { 44 0 : _dev = hal.i2c_mgr->get_device(1, PCA9685_ADDRESS); 45 : 46 0 : if (!_dev) { 47 0 : return false; 48 : } 49 : 50 0 : _dev->get_semaphore()->take_blocking(); 51 : 52 0 : _dev->set_retries(5); 53 : 54 : // read the current mode1 configuration 55 0 : uint8_t mode1 = 0; 56 0 : if (!_dev->read_registers(PCA9685_MODE1, &mode1, sizeof(mode1))) { 57 0 : _dev->get_semaphore()->give(); 58 0 : return false; 59 : } 60 : 61 : // bring the device out of sleep, and enable auto register increment 62 0 : uint8_t new_mode1 = (mode1 | PCA9685_MODE_AUTO_INCREMENT) & ~PCA9685_MODE_SLEEP; 63 0 : const uint8_t config[2] = {PCA9685_MODE1, new_mode1}; 64 0 : if (!_dev->transfer(config, sizeof(config), nullptr, 0)) { 65 0 : _dev->get_semaphore()->give(); 66 0 : return false; 67 : } 68 : 69 0 : _dev->set_retries(1); 70 : 71 0 : _dev->get_semaphore()->give(); 72 : 73 0 : _dev->register_periodic_callback(20000, FUNCTOR_BIND_MEMBER(&PCA9685LED_I2C::_timer, void)); 74 : 75 0 : return true; 76 : } 77 : 78 : // set_rgb - set color as a combination of red, green and blue values 79 0 : bool PCA9685LED_I2C::hw_set_rgb(uint8_t red, uint8_t green, uint8_t blue) 80 : { 81 0 : rgb.r = red; 82 0 : rgb.g = green; 83 0 : rgb.b = blue; 84 0 : _need_update = true; 85 0 : return true; 86 : } 87 : 88 0 : void PCA9685LED_I2C::_timer(void) 89 : { 90 0 : if (!_need_update) { 91 0 : return; 92 : } 93 0 : _need_update = false; 94 : 95 0 : uint16_t red_adjusted = rgb.r * 0x10; 96 0 : uint16_t green_adjusted = rgb.g * 0x10; 97 0 : uint16_t blue_adjusted = rgb.b * 0x10; 98 : 99 0 : uint8_t blue_channel_lsb = blue_adjusted & 0xFF; 100 0 : uint8_t blue_channel_msb = blue_adjusted >> 8; 101 : 102 0 : uint8_t green_channel_lsb = green_adjusted & 0xFF; 103 0 : uint8_t green_channel_msb = green_adjusted >> 8; 104 : 105 0 : uint8_t red_channel_lsb = red_adjusted & 0xFF; 106 0 : uint8_t red_channel_msb = red_adjusted >> 8; 107 : 108 : 109 0 : uint8_t transaction[] = {PCA9685_PWM, 0x00, 0x00, blue_channel_lsb, blue_channel_msb, 110 : 0x00, 0x00, green_channel_lsb, green_channel_msb, 111 0 : 0x00, 0x00, red_channel_lsb, red_channel_msb}; 112 : 113 0 : _dev->transfer(transaction, sizeof(transaction), nullptr, 0); 114 : } 115 : 116 : #endif // AP_NOTIFY_PCA9685_ENABLED