Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
pmu.c
00001 00002 /**************************************************************************/ 00003 /*! 00004 @file pca9685.c 00005 @author K. Townsend (microBuilder.eu) 00006 00007 @brief Drivers for NXP's PCA9685 12-bit 16-channel PWM Driver 00008 00009 @section DESCRIPTION 00010 00011 The PCA9685 is an I2C-bus controlled 16-channel LED controller 00012 optimized for LCD Red/Green/Blue/Amber (RGBA) color backlighting 00013 applications. Each LED output has its own 12-bit resolution (4096 00014 steps) fixed frequency individual PWM controller that operates at a 00015 programmable frequency from 40 Hz to 1000 Hz with a duty cycle that 00016 is adjustable from 0 % to 100 % to allow the LED to be set to a 00017 specific brightness value. All outputs are set to the same PWM 00018 frequency. 00019 00020 @section LICENSE 00021 00022 Software License Agreement (BSD License) 00023 00024 Copyright (c) 2012, K. Townsend 00025 All rights reserved. 00026 00027 Redistribution and use in source and binary forms, with or without 00028 modification, are permitted provided that the following conditions are met: 00029 1. Redistributions of source code must retain the above copyright 00030 notice, this list of conditions and the following disclaimer. 00031 2. Redistributions in binary form must reproduce the above copyright 00032 notice, this list of conditions and the following disclaimer in the 00033 documentation and/or other materials provided with the distribution. 00034 3. Neither the name of the copyright holders nor the 00035 names of its contributors may be used to endorse or promote products 00036 derived from this software without specific prior written permission. 00037 00038 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 00039 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00040 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00041 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 00042 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00043 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00044 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00045 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00046 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00047 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00048 */ 00049 /**************************************************************************/ 00050 #include <string.h> 00051 #include "pca9685.h" 00052 #include "core/gpio/gpio.h" 00053 #include "core/delay/delay.h" 00054 00055 extern volatile uint8_t I2CMasterBuffer[I2C_BUFSIZE]; 00056 extern volatile uint8_t I2CSlaveBuffer[I2C_BUFSIZE]; 00057 extern volatile uint32_t I2CReadLength, I2CWriteLength; 00058 00059 static bool _pca9685Initialised = false; 00060 static uint8_t _pca9685Address = PCA9685_ADDRESS; 00061 00062 /**************************************************************************/ 00063 /*! 00064 @brief Writes the specified number of bytes over I2C 00065 */ 00066 /**************************************************************************/ 00067 error_t pca9685WriteBytes(uint8_t reg, uint8_t *buffer, size_t length) 00068 { 00069 uint32_t i; 00070 00071 /* Try to avoid buffer overflow */ 00072 ASSERT(length <= I2C_BUFSIZE - 2, ERROR_BUFFEROVERFLOW); 00073 00074 /* Fill write buffer */ 00075 for ( i = 2; i < length+2; i++ ) 00076 { 00077 I2CMasterBuffer[i] = buffer[i-2]; 00078 } 00079 00080 /* Write transaction */ 00081 I2CWriteLength = 2+length; 00082 I2CReadLength = 0; 00083 I2CMasterBuffer[0] = _pca9685Address; 00084 I2CMasterBuffer[1] = reg; 00085 /* Check if we got an ACK or TIMEOUT error */ 00086 ASSERT_I2C_STATUS(i2cEngine()); 00087 00088 return ERROR_NONE; 00089 } 00090 00091 /**************************************************************************/ 00092 /*! 00093 @brief Reads the specified number of bytes over I2C 00094 */ 00095 /**************************************************************************/ 00096 error_t pca9685ReadBytes(uint8_t reg, uint8_t *buffer, size_t length) 00097 { 00098 uint32_t i; 00099 00100 /* Try to avoid buffer overflow */ 00101 ASSERT(length <= I2C_BUFSIZE, ERROR_BUFFEROVERFLOW); 00102 00103 /* Read and write need to be handled in separate transactions or the 00104 PCA9685 increments the current register one step ahead of where 00105 we should be. */ 00106 00107 /* Write transaction */ 00108 I2CWriteLength = 2; 00109 I2CReadLength = 0; 00110 I2CMasterBuffer[0] = _pca9685Address; 00111 I2CMasterBuffer[1] = reg; 00112 i2cEngine(); 00113 00114 /* Read transaction */ 00115 I2CWriteLength = 0; 00116 I2CReadLength = length; 00117 I2CMasterBuffer[0] = _pca9685Address | PCA9685_READBIT; 00118 /* Check if we got an ACK or TIMEOUT error */ 00119 ASSERT_I2C_STATUS(i2cEngine()); 00120 00121 /* Fill the buffer with the I2C response */ 00122 for ( i = 0; i < length; i++ ) 00123 { 00124 buffer[i] = I2CSlaveBuffer[i]; 00125 } 00126 00127 return ERROR_NONE; 00128 } 00129 00130 /**************************************************************************/ 00131 /*! 00132 @brief Writes an 8 bit value over I2C 00133 */ 00134 /**************************************************************************/ 00135 error_t pca9685Write8 (uint8_t reg, uint8_t value) 00136 { 00137 uint8_t buffer = value; 00138 return pca9685WriteBytes(reg, &buffer, 1); 00139 } 00140 00141 /**************************************************************************/ 00142 /*! 00143 @brief Reads a single byte over I2C 00144 */ 00145 /**************************************************************************/ 00146 error_t pca9685Read8(uint8_t reg, uint8_t *result) 00147 { 00148 return pca9685ReadBytes(reg, result, 1); 00149 } 00150 00151 /**************************************************************************/ 00152 /*! 00153 @brief Initialises the I2C block 00154 00155 @param address The device I2C address (left-shifted 1 bit) 00156 */ 00157 /**************************************************************************/ 00158 error_t pca9685Init(uint8_t address) 00159 { 00160 // Initialise I2C 00161 i2cInit(I2CMASTER); 00162 00163 /* Ping the I2C device first to see if it exists! */ 00164 ASSERT(!(i2cCheckAddress(_pca9685Address)), ERROR_I2C_DEVICENOTFOUND); 00165 00166 ASSERT_STATUS(pca9685Write8(PCA9685_REG_MODE1, 0x00)); 00167 00168 _pca9685Initialised = true; 00169 00170 return ERROR_NONE; 00171 } 00172 00173 /**************************************************************************/ 00174 /*! 00175 @brief Sets the PWM clock frequency (40-1000Hz) 00176 00177 @param freqHz Approximate frequency in Hz (40-1000) 00178 */ 00179 /**************************************************************************/ 00180 error_t pca9685SetFrequency(uint16_t freqHz) 00181 { 00182 uint32_t prescaleValue; 00183 uint8_t oldMode, newMode; 00184 00185 ASSERT(_pca9685Initialised, ERROR_DEVICENOTINITIALISED); 00186 00187 if (freqHz < 40) 00188 { 00189 freqHz = 40; 00190 } 00191 00192 if (freqHz > 1000) 00193 { 00194 freqHz = 1000; 00195 } 00196 00197 // prescaleValue = round(25MHz / (4096*updateRate)) - 1 00198 prescaleValue = 25000000; // 25 MHz 00199 prescaleValue /= 4096; // 12-bit 00200 prescaleValue /= freqHz; 00201 prescaleValue -= 1; 00202 00203 ASSERT_STATUS(pca9685Read8(PCA9685_REG_MODE1, &oldMode)); 00204 newMode = (oldMode & 0x7F) | 0x10; 00205 00206 // Go to sleep 00207 ASSERT_STATUS(pca9685Write8(PCA9685_REG_MODE1, newMode)); 00208 00209 // Set prescale 00210 ASSERT_STATUS(pca9685Write8(PCA9685_REG_PRESCALE, prescaleValue & 0xFF)); 00211 00212 // Wakeup 00213 ASSERT_STATUS(pca9685Write8(PCA9685_REG_MODE1, oldMode)); 00214 delay(5); 00215 ASSERT_STATUS(pca9685Write8(PCA9685_REG_MODE1, oldMode | 0x80)); 00216 00217 return ERROR_NONE; 00218 } 00219 00220 /**************************************************************************/ 00221 /*! 00222 @brief Sets the PWM output of the specified channel 00223 00224 @param channel The channel number [0..15] 00225 @param on The 12-bit start point (low to high transition) 00226 @param off The 12-bit stop point (high to low transition) 00227 */ 00228 /**************************************************************************/ 00229 error_t pca9685SetPWM(uint16_t channel, uint16_t on, uint16_t off) 00230 { 00231 ASSERT(_pca9685Initialised, ERROR_DEVICENOTINITIALISED); 00232 00233 if (on > 0xFFF) 00234 { 00235 on = 0xFFF; 00236 } 00237 00238 if (off < on) 00239 { 00240 off = on; 00241 } 00242 00243 if (off > 0xFFF) 00244 { 00245 off = 0xFFF; 00246 } 00247 00248 /* Set the on and off values */ 00249 ASSERT_STATUS(pca9685Write8(PCA9685_REG_LED0_ON_L+4*channel, on & 0xFF)); 00250 ASSERT_STATUS(pca9685Write8(PCA9685_REG_LED0_ON_H+4*channel, on >> 8)); 00251 ASSERT_STATUS(pca9685Write8(PCA9685_REG_LED0_OFF_L+4*channel, off & 0xFF)); 00252 ASSERT_STATUS(pca9685Write8(PCA9685_REG_LED0_OFF_H+4*channel, off >> 8)); 00253 00254 return ERROR_NONE; 00255 }
Generated on Wed Jul 13 2022 09:22:30 by
1.7.2