ASIF AHMAD / Mbed 2 deprecated cortexm0sleepmodes
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pmu.c Source File

pmu.c

Go to the documentation of this file.
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 }