sleep library for cortex m0

Dependencies:   mbed

Fork of cortexm0sleepmodes by ASIF AHMAD

Committer:
asifahmad
Date:
Fri Sep 27 18:13:20 2013 +0000
Revision:
0:e8a124690cda
sleep

Who changed what in which revision?

UserRevisionLine numberNew contents of line
asifahmad 0:e8a124690cda 1
asifahmad 0:e8a124690cda 2 /**************************************************************************/
asifahmad 0:e8a124690cda 3 /*!
asifahmad 0:e8a124690cda 4 @file pca9685.c
asifahmad 0:e8a124690cda 5 @author K. Townsend (microBuilder.eu)
asifahmad 0:e8a124690cda 6
asifahmad 0:e8a124690cda 7 @brief Drivers for NXP's PCA9685 12-bit 16-channel PWM Driver
asifahmad 0:e8a124690cda 8
asifahmad 0:e8a124690cda 9 @section DESCRIPTION
asifahmad 0:e8a124690cda 10
asifahmad 0:e8a124690cda 11 The PCA9685 is an I2C-bus controlled 16-channel LED controller
asifahmad 0:e8a124690cda 12 optimized for LCD Red/Green/Blue/Amber (RGBA) color backlighting
asifahmad 0:e8a124690cda 13 applications. Each LED output has its own 12-bit resolution (4096
asifahmad 0:e8a124690cda 14 steps) fixed frequency individual PWM controller that operates at a
asifahmad 0:e8a124690cda 15 programmable frequency from 40 Hz to 1000 Hz with a duty cycle that
asifahmad 0:e8a124690cda 16 is adjustable from 0 % to 100 % to allow the LED to be set to a
asifahmad 0:e8a124690cda 17 specific brightness value. All outputs are set to the same PWM
asifahmad 0:e8a124690cda 18 frequency.
asifahmad 0:e8a124690cda 19
asifahmad 0:e8a124690cda 20 @section LICENSE
asifahmad 0:e8a124690cda 21
asifahmad 0:e8a124690cda 22 Software License Agreement (BSD License)
asifahmad 0:e8a124690cda 23
asifahmad 0:e8a124690cda 24 Copyright (c) 2012, K. Townsend
asifahmad 0:e8a124690cda 25 All rights reserved.
asifahmad 0:e8a124690cda 26
asifahmad 0:e8a124690cda 27 Redistribution and use in source and binary forms, with or without
asifahmad 0:e8a124690cda 28 modification, are permitted provided that the following conditions are met:
asifahmad 0:e8a124690cda 29 1. Redistributions of source code must retain the above copyright
asifahmad 0:e8a124690cda 30 notice, this list of conditions and the following disclaimer.
asifahmad 0:e8a124690cda 31 2. Redistributions in binary form must reproduce the above copyright
asifahmad 0:e8a124690cda 32 notice, this list of conditions and the following disclaimer in the
asifahmad 0:e8a124690cda 33 documentation and/or other materials provided with the distribution.
asifahmad 0:e8a124690cda 34 3. Neither the name of the copyright holders nor the
asifahmad 0:e8a124690cda 35 names of its contributors may be used to endorse or promote products
asifahmad 0:e8a124690cda 36 derived from this software without specific prior written permission.
asifahmad 0:e8a124690cda 37
asifahmad 0:e8a124690cda 38 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
asifahmad 0:e8a124690cda 39 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
asifahmad 0:e8a124690cda 40 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
asifahmad 0:e8a124690cda 41 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
asifahmad 0:e8a124690cda 42 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
asifahmad 0:e8a124690cda 43 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
asifahmad 0:e8a124690cda 44 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
asifahmad 0:e8a124690cda 45 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
asifahmad 0:e8a124690cda 46 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
asifahmad 0:e8a124690cda 47 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
asifahmad 0:e8a124690cda 48 */
asifahmad 0:e8a124690cda 49 /**************************************************************************/
asifahmad 0:e8a124690cda 50 #include <string.h>
asifahmad 0:e8a124690cda 51 #include "pca9685.h"
asifahmad 0:e8a124690cda 52 #include "core/gpio/gpio.h"
asifahmad 0:e8a124690cda 53 #include "core/delay/delay.h"
asifahmad 0:e8a124690cda 54
asifahmad 0:e8a124690cda 55 extern volatile uint8_t I2CMasterBuffer[I2C_BUFSIZE];
asifahmad 0:e8a124690cda 56 extern volatile uint8_t I2CSlaveBuffer[I2C_BUFSIZE];
asifahmad 0:e8a124690cda 57 extern volatile uint32_t I2CReadLength, I2CWriteLength;
asifahmad 0:e8a124690cda 58
asifahmad 0:e8a124690cda 59 static bool _pca9685Initialised = false;
asifahmad 0:e8a124690cda 60 static uint8_t _pca9685Address = PCA9685_ADDRESS;
asifahmad 0:e8a124690cda 61
asifahmad 0:e8a124690cda 62 /**************************************************************************/
asifahmad 0:e8a124690cda 63 /*!
asifahmad 0:e8a124690cda 64 @brief Writes the specified number of bytes over I2C
asifahmad 0:e8a124690cda 65 */
asifahmad 0:e8a124690cda 66 /**************************************************************************/
asifahmad 0:e8a124690cda 67 error_t pca9685WriteBytes(uint8_t reg, uint8_t *buffer, size_t length)
asifahmad 0:e8a124690cda 68 {
asifahmad 0:e8a124690cda 69 uint32_t i;
asifahmad 0:e8a124690cda 70
asifahmad 0:e8a124690cda 71 /* Try to avoid buffer overflow */
asifahmad 0:e8a124690cda 72 ASSERT(length <= I2C_BUFSIZE - 2, ERROR_BUFFEROVERFLOW);
asifahmad 0:e8a124690cda 73
asifahmad 0:e8a124690cda 74 /* Fill write buffer */
asifahmad 0:e8a124690cda 75 for ( i = 2; i < length+2; i++ )
asifahmad 0:e8a124690cda 76 {
asifahmad 0:e8a124690cda 77 I2CMasterBuffer[i] = buffer[i-2];
asifahmad 0:e8a124690cda 78 }
asifahmad 0:e8a124690cda 79
asifahmad 0:e8a124690cda 80 /* Write transaction */
asifahmad 0:e8a124690cda 81 I2CWriteLength = 2+length;
asifahmad 0:e8a124690cda 82 I2CReadLength = 0;
asifahmad 0:e8a124690cda 83 I2CMasterBuffer[0] = _pca9685Address;
asifahmad 0:e8a124690cda 84 I2CMasterBuffer[1] = reg;
asifahmad 0:e8a124690cda 85 /* Check if we got an ACK or TIMEOUT error */
asifahmad 0:e8a124690cda 86 ASSERT_I2C_STATUS(i2cEngine());
asifahmad 0:e8a124690cda 87
asifahmad 0:e8a124690cda 88 return ERROR_NONE;
asifahmad 0:e8a124690cda 89 }
asifahmad 0:e8a124690cda 90
asifahmad 0:e8a124690cda 91 /**************************************************************************/
asifahmad 0:e8a124690cda 92 /*!
asifahmad 0:e8a124690cda 93 @brief Reads the specified number of bytes over I2C
asifahmad 0:e8a124690cda 94 */
asifahmad 0:e8a124690cda 95 /**************************************************************************/
asifahmad 0:e8a124690cda 96 error_t pca9685ReadBytes(uint8_t reg, uint8_t *buffer, size_t length)
asifahmad 0:e8a124690cda 97 {
asifahmad 0:e8a124690cda 98 uint32_t i;
asifahmad 0:e8a124690cda 99
asifahmad 0:e8a124690cda 100 /* Try to avoid buffer overflow */
asifahmad 0:e8a124690cda 101 ASSERT(length <= I2C_BUFSIZE, ERROR_BUFFEROVERFLOW);
asifahmad 0:e8a124690cda 102
asifahmad 0:e8a124690cda 103 /* Read and write need to be handled in separate transactions or the
asifahmad 0:e8a124690cda 104 PCA9685 increments the current register one step ahead of where
asifahmad 0:e8a124690cda 105 we should be. */
asifahmad 0:e8a124690cda 106
asifahmad 0:e8a124690cda 107 /* Write transaction */
asifahmad 0:e8a124690cda 108 I2CWriteLength = 2;
asifahmad 0:e8a124690cda 109 I2CReadLength = 0;
asifahmad 0:e8a124690cda 110 I2CMasterBuffer[0] = _pca9685Address;
asifahmad 0:e8a124690cda 111 I2CMasterBuffer[1] = reg;
asifahmad 0:e8a124690cda 112 i2cEngine();
asifahmad 0:e8a124690cda 113
asifahmad 0:e8a124690cda 114 /* Read transaction */
asifahmad 0:e8a124690cda 115 I2CWriteLength = 0;
asifahmad 0:e8a124690cda 116 I2CReadLength = length;
asifahmad 0:e8a124690cda 117 I2CMasterBuffer[0] = _pca9685Address | PCA9685_READBIT;
asifahmad 0:e8a124690cda 118 /* Check if we got an ACK or TIMEOUT error */
asifahmad 0:e8a124690cda 119 ASSERT_I2C_STATUS(i2cEngine());
asifahmad 0:e8a124690cda 120
asifahmad 0:e8a124690cda 121 /* Fill the buffer with the I2C response */
asifahmad 0:e8a124690cda 122 for ( i = 0; i < length; i++ )
asifahmad 0:e8a124690cda 123 {
asifahmad 0:e8a124690cda 124 buffer[i] = I2CSlaveBuffer[i];
asifahmad 0:e8a124690cda 125 }
asifahmad 0:e8a124690cda 126
asifahmad 0:e8a124690cda 127 return ERROR_NONE;
asifahmad 0:e8a124690cda 128 }
asifahmad 0:e8a124690cda 129
asifahmad 0:e8a124690cda 130 /**************************************************************************/
asifahmad 0:e8a124690cda 131 /*!
asifahmad 0:e8a124690cda 132 @brief Writes an 8 bit value over I2C
asifahmad 0:e8a124690cda 133 */
asifahmad 0:e8a124690cda 134 /**************************************************************************/
asifahmad 0:e8a124690cda 135 error_t pca9685Write8 (uint8_t reg, uint8_t value)
asifahmad 0:e8a124690cda 136 {
asifahmad 0:e8a124690cda 137 uint8_t buffer = value;
asifahmad 0:e8a124690cda 138 return pca9685WriteBytes(reg, &buffer, 1);
asifahmad 0:e8a124690cda 139 }
asifahmad 0:e8a124690cda 140
asifahmad 0:e8a124690cda 141 /**************************************************************************/
asifahmad 0:e8a124690cda 142 /*!
asifahmad 0:e8a124690cda 143 @brief Reads a single byte over I2C
asifahmad 0:e8a124690cda 144 */
asifahmad 0:e8a124690cda 145 /**************************************************************************/
asifahmad 0:e8a124690cda 146 error_t pca9685Read8(uint8_t reg, uint8_t *result)
asifahmad 0:e8a124690cda 147 {
asifahmad 0:e8a124690cda 148 return pca9685ReadBytes(reg, result, 1);
asifahmad 0:e8a124690cda 149 }
asifahmad 0:e8a124690cda 150
asifahmad 0:e8a124690cda 151 /**************************************************************************/
asifahmad 0:e8a124690cda 152 /*!
asifahmad 0:e8a124690cda 153 @brief Initialises the I2C block
asifahmad 0:e8a124690cda 154
asifahmad 0:e8a124690cda 155 @param address The device I2C address (left-shifted 1 bit)
asifahmad 0:e8a124690cda 156 */
asifahmad 0:e8a124690cda 157 /**************************************************************************/
asifahmad 0:e8a124690cda 158 error_t pca9685Init(uint8_t address)
asifahmad 0:e8a124690cda 159 {
asifahmad 0:e8a124690cda 160 // Initialise I2C
asifahmad 0:e8a124690cda 161 i2cInit(I2CMASTER);
asifahmad 0:e8a124690cda 162
asifahmad 0:e8a124690cda 163 /* Ping the I2C device first to see if it exists! */
asifahmad 0:e8a124690cda 164 ASSERT(!(i2cCheckAddress(_pca9685Address)), ERROR_I2C_DEVICENOTFOUND);
asifahmad 0:e8a124690cda 165
asifahmad 0:e8a124690cda 166 ASSERT_STATUS(pca9685Write8(PCA9685_REG_MODE1, 0x00));
asifahmad 0:e8a124690cda 167
asifahmad 0:e8a124690cda 168 _pca9685Initialised = true;
asifahmad 0:e8a124690cda 169
asifahmad 0:e8a124690cda 170 return ERROR_NONE;
asifahmad 0:e8a124690cda 171 }
asifahmad 0:e8a124690cda 172
asifahmad 0:e8a124690cda 173 /**************************************************************************/
asifahmad 0:e8a124690cda 174 /*!
asifahmad 0:e8a124690cda 175 @brief Sets the PWM clock frequency (40-1000Hz)
asifahmad 0:e8a124690cda 176
asifahmad 0:e8a124690cda 177 @param freqHz Approximate frequency in Hz (40-1000)
asifahmad 0:e8a124690cda 178 */
asifahmad 0:e8a124690cda 179 /**************************************************************************/
asifahmad 0:e8a124690cda 180 error_t pca9685SetFrequency(uint16_t freqHz)
asifahmad 0:e8a124690cda 181 {
asifahmad 0:e8a124690cda 182 uint32_t prescaleValue;
asifahmad 0:e8a124690cda 183 uint8_t oldMode, newMode;
asifahmad 0:e8a124690cda 184
asifahmad 0:e8a124690cda 185 ASSERT(_pca9685Initialised, ERROR_DEVICENOTINITIALISED);
asifahmad 0:e8a124690cda 186
asifahmad 0:e8a124690cda 187 if (freqHz < 40)
asifahmad 0:e8a124690cda 188 {
asifahmad 0:e8a124690cda 189 freqHz = 40;
asifahmad 0:e8a124690cda 190 }
asifahmad 0:e8a124690cda 191
asifahmad 0:e8a124690cda 192 if (freqHz > 1000)
asifahmad 0:e8a124690cda 193 {
asifahmad 0:e8a124690cda 194 freqHz = 1000;
asifahmad 0:e8a124690cda 195 }
asifahmad 0:e8a124690cda 196
asifahmad 0:e8a124690cda 197 // prescaleValue = round(25MHz / (4096*updateRate)) - 1
asifahmad 0:e8a124690cda 198 prescaleValue = 25000000; // 25 MHz
asifahmad 0:e8a124690cda 199 prescaleValue /= 4096; // 12-bit
asifahmad 0:e8a124690cda 200 prescaleValue /= freqHz;
asifahmad 0:e8a124690cda 201 prescaleValue -= 1;
asifahmad 0:e8a124690cda 202
asifahmad 0:e8a124690cda 203 ASSERT_STATUS(pca9685Read8(PCA9685_REG_MODE1, &oldMode));
asifahmad 0:e8a124690cda 204 newMode = (oldMode & 0x7F) | 0x10;
asifahmad 0:e8a124690cda 205
asifahmad 0:e8a124690cda 206 // Go to sleep
asifahmad 0:e8a124690cda 207 ASSERT_STATUS(pca9685Write8(PCA9685_REG_MODE1, newMode));
asifahmad 0:e8a124690cda 208
asifahmad 0:e8a124690cda 209 // Set prescale
asifahmad 0:e8a124690cda 210 ASSERT_STATUS(pca9685Write8(PCA9685_REG_PRESCALE, prescaleValue & 0xFF));
asifahmad 0:e8a124690cda 211
asifahmad 0:e8a124690cda 212 // Wakeup
asifahmad 0:e8a124690cda 213 ASSERT_STATUS(pca9685Write8(PCA9685_REG_MODE1, oldMode));
asifahmad 0:e8a124690cda 214 delay(5);
asifahmad 0:e8a124690cda 215 ASSERT_STATUS(pca9685Write8(PCA9685_REG_MODE1, oldMode | 0x80));
asifahmad 0:e8a124690cda 216
asifahmad 0:e8a124690cda 217 return ERROR_NONE;
asifahmad 0:e8a124690cda 218 }
asifahmad 0:e8a124690cda 219
asifahmad 0:e8a124690cda 220 /**************************************************************************/
asifahmad 0:e8a124690cda 221 /*!
asifahmad 0:e8a124690cda 222 @brief Sets the PWM output of the specified channel
asifahmad 0:e8a124690cda 223
asifahmad 0:e8a124690cda 224 @param channel The channel number [0..15]
asifahmad 0:e8a124690cda 225 @param on The 12-bit start point (low to high transition)
asifahmad 0:e8a124690cda 226 @param off The 12-bit stop point (high to low transition)
asifahmad 0:e8a124690cda 227 */
asifahmad 0:e8a124690cda 228 /**************************************************************************/
asifahmad 0:e8a124690cda 229 error_t pca9685SetPWM(uint16_t channel, uint16_t on, uint16_t off)
asifahmad 0:e8a124690cda 230 {
asifahmad 0:e8a124690cda 231 ASSERT(_pca9685Initialised, ERROR_DEVICENOTINITIALISED);
asifahmad 0:e8a124690cda 232
asifahmad 0:e8a124690cda 233 if (on > 0xFFF)
asifahmad 0:e8a124690cda 234 {
asifahmad 0:e8a124690cda 235 on = 0xFFF;
asifahmad 0:e8a124690cda 236 }
asifahmad 0:e8a124690cda 237
asifahmad 0:e8a124690cda 238 if (off < on)
asifahmad 0:e8a124690cda 239 {
asifahmad 0:e8a124690cda 240 off = on;
asifahmad 0:e8a124690cda 241 }
asifahmad 0:e8a124690cda 242
asifahmad 0:e8a124690cda 243 if (off > 0xFFF)
asifahmad 0:e8a124690cda 244 {
asifahmad 0:e8a124690cda 245 off = 0xFFF;
asifahmad 0:e8a124690cda 246 }
asifahmad 0:e8a124690cda 247
asifahmad 0:e8a124690cda 248 /* Set the on and off values */
asifahmad 0:e8a124690cda 249 ASSERT_STATUS(pca9685Write8(PCA9685_REG_LED0_ON_L+4*channel, on & 0xFF));
asifahmad 0:e8a124690cda 250 ASSERT_STATUS(pca9685Write8(PCA9685_REG_LED0_ON_H+4*channel, on >> 8));
asifahmad 0:e8a124690cda 251 ASSERT_STATUS(pca9685Write8(PCA9685_REG_LED0_OFF_L+4*channel, off & 0xFF));
asifahmad 0:e8a124690cda 252 ASSERT_STATUS(pca9685Write8(PCA9685_REG_LED0_OFF_H+4*channel, off >> 8));
asifahmad 0:e8a124690cda 253
asifahmad 0:e8a124690cda 254 return ERROR_NONE;
asifahmad 0:e8a124690cda 255 }