Commit 38d40ee7 authored by jiajunjie's avatar jiajunjie

update pca9685 cpp source code

parent ff1fb8ba
cmake_minimum_required(VERSION 2.6)
project(PCA9685)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR})
# compile flags
SET(CMAKE_CXX_FLAGS "-W -Wall -Wno-sign-compare -shared -fPIC -std=c++11 -O2")
ADD_SUBDIRECTORY(src)
cmake_minimum_required(VERSION 2.6)
project(PCA9685s)
# source
file(GLOB LIB_SRCS ./*.cpp)
# shared library
ADD_LIBRARY(${CMAKE_PROJECT_NAME} SHARED ${LIB_SRCS})
TARGET_LINK_LIBRARIES(${CMAKE_PROJECT_NAME} )
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Name : I2C.cpp
* Author : Georgi Todorov
* Version :
* Created on : Dec 30, 2012
*
* Copyright © 2012 Georgi Todorov <terahz@geodar.com>
*/
#include <sys/ioctl.h>
#include <errno.h>
#include <stdio.h> /* Standard I/O functions */
#include <fcntl.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <syslog.h> /* Syslog functionality */
#include "I2C.h"
I2C::I2C(int bus, int address) {
_i2cbus = bus;
_i2caddr = address;
snprintf(busfile, sizeof(busfile), "/dev/i2c-%d", bus);
printf("busfile:%s\n", busfile);
openfd();
}
I2C::~I2C() {
close(fd);
}
//! Read a single byte from I2C Bus
/*!
\param address register address to read from
*/
uint8_t I2C::read_byte(uint8_t address) {
if (fd != -1) {
uint8_t buff[BUFFER_SIZE];
buff[0] = address;
if (write(fd, buff, BUFFER_SIZE) != BUFFER_SIZE) {
syslog(LOG_ERR,
"I2C slave 0x%x failed to go to register 0x%x [read_byte():write %d]",
_i2caddr, address, errno);
return (-1);
} else {
if (read(fd, dataBuffer, BUFFER_SIZE) != BUFFER_SIZE) {
syslog(LOG_ERR,
"Could not read from I2C slave 0x%x, register 0x%x [read_byte():read %d]",
_i2caddr, address, errno);
return (-1);
} else {
return dataBuffer[0];
}
}
} else {
syslog(LOG_ERR, "Device File not available. Aborting read");
return (-1);
}
}
//! Write a single byte from a I2C Device
/*!
\param address register address to write to
\param data 8 bit data to write
*/
uint8_t I2C::write_byte(uint8_t address, uint8_t data) {
if (fd != -1) {
uint8_t buff[2];
buff[0] = address;
buff[1] = data;
if (write(fd, buff, sizeof(buff)) != 2) {
syslog(LOG_ERR,
"Failed to write to I2C Slave 0x%x @ register 0x%x [write_byte():write %d]",
_i2caddr, address, errno);
return (-1);
} else {
syslog(LOG_INFO, "Wrote to I2C Slave 0x%x @ register 0x%x [0x%x]",
_i2caddr, address, data);
return (-1);
}
} else {
syslog(LOG_INFO, "Device File not available. Aborting write");
return (-1);
}
return 0;
}
//! Open device file for I2C Device
void I2C::openfd() {
if ((fd = open(busfile, O_RDWR)) < 0) {
syslog(LOG_ERR, "Couldn't open I2C Bus %d [openfd():open %d]", _i2cbus,
errno);
}
if (ioctl(fd, I2C_SLAVE, _i2caddr) < 0) {
syslog(LOG_ERR, "I2C slave %d failed [openfd():ioctl %d]", _i2caddr,
errno);
}
}
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Name : I2C.h
* Author : Georgi Todorov
* Version :
* Created on : Dec 30, 2012
*
* Copyright © 2012 Georgi Todorov <terahz@geodar.com>
*/
#ifndef I2C_H_
#define I2C_H_
#include <inttypes.h>
#define BUFFER_SIZE 0x01 //1 byte buffer
class I2C {
public:
I2C(int, int);
virtual ~I2C();
uint8_t dataBuffer[BUFFER_SIZE];
uint8_t read_byte(uint8_t);
uint8_t write_byte(uint8_t, uint8_t);
private:
int _i2caddr;
int _i2cbus;
void openfd();
char busfile[64];
int fd;
};
#endif /* I2C_H_ */
#INCLUDES := -I../../I2C/src
#LIBRARIES := -L../../I2C/src
#LIBS := -lI2C
CXXFLAGS := -O3 -fPIC -g -Wall -Werror
CXX := g++
#CXX := arm-unknown-linux-gnueabi-g++
MAJOR := 0
MINOR := 1
NAME := PCA9685
VERSION := $(MAJOR).$(MINOR)
RM := rm -rf
all: lib copy
lib: lib$(NAME).so.$(VERSION) lib$(NAME).so
lib$(NAME).so: lib$(NAME).so.$(VERSION)
ldconfig -v -n .
ln -s lib$(NAME).so.$(MAJOR) lib$(NAME).so
lib$(NAME).so.$(VERSION): $(NAME).o
$(CXX) -pg -shared -Wl,-soname,lib$(NAME).so.$(MAJOR) $^ -o $@
clean:
$(RM) *.o *.so*
copy:
ifdef DISTPATH
cp lib$(NAME)* $(DISTPATH)
endif
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Name : PCA9685.cpp
* Author : Georgi Todorov
* Version :
* Created on : Dec 9, 2012
*
* Copyright © 2012 Georgi Todorov <terahz@geodar.com>
*/
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <stdio.h> /* Standard I/O functions */
#include <fcntl.h>
#include <syslog.h> /* Syslog functionallity */
#include <inttypes.h>
#include <errno.h>
#include <math.h>
#include "PCA9685.h"
//! Constructor takes bus and address arguments
/*!
\param bus the bus to use in /dev/i2c-%d.
\param address the device address on bus
*/
PCA9685::PCA9685() {
i2c = new I2C(1,PCA9685_ADDRESS);
reset();
setPWMFreq(1000);
}
PCA9685::~PCA9685() {
delete i2c;
}
//! Sets PCA9685 mode to 00
void PCA9685::reset() {
i2c->write_byte(MODE1, 0x01); //Normal mode
i2c->write_byte(MODE2, 0x04); //totem pole
}
//! Set the frequency of PWM
/*!
\param freq desired frequency. 40Hz to 1000Hz using internal 25MHz oscillator.
*/
void PCA9685::setPWMFreq(int freq) {
uint8_t prescale_val = (CLOCK_FREQ / 4096 / freq) - 1;
i2c->write_byte(MODE1, 0x10); //sleep
i2c->write_byte(PRE_SCALE, prescale_val); // multiplyer for PWM frequency
i2c->write_byte(MODE1, 0x80); //restart
i2c->write_byte(MODE2, 0x04); //totem pole (default)
}
//! PWM a single channel
/*!
\param led channel (1-16) to set PWM value for
\param value 0-4095 value for PWM
*/
void PCA9685::setPWM(uint8_t led, int value) {
setPWM(led, 0, value);
}
//! PWM a single channel with custom on time
/*!
\param led channel (1-16) to set PWM value for
\param on_value 0-4095 value to turn on the pulse
\param off_value 0-4095 value to turn off the pulse
*/
void PCA9685::setPWM(uint8_t led, int on_value, int off_value) {
i2c->write_byte(LED0_ON_L + 4 * led , on_value & 0xFF);
i2c->write_byte(LED0_ON_H + 4 * led , on_value >> 8);
i2c->write_byte(LED0_OFF_L + 4 * led , off_value & 0xFF);
i2c->write_byte(LED0_OFF_H + 4 * led , off_value >> 8);
}
//! Get current PWM value
/*!
\param led channel (1-16) to get PWM value from
*/
int PCA9685::getPWM(uint8_t led){
int ledval = 0;
ledval = i2c->read_byte(LED0_OFF_H + LED_MULTIPLYER * (led-1));
ledval = ledval & 0xf;
ledval <<= 8;
ledval += i2c->read_byte(LED0_OFF_L + LED_MULTIPLYER * (led-1));
return ledval;
}
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Name : PCA9685.h
* Author : Georgi Todorov
* Version :
* Created on : Dec 9, 2012
*
* Copyright © 2012 Georgi Todorov <terahz@geodar.com>
*/
#ifndef _PCA9685_H
#define _PCA9685_H
#include <inttypes.h>
#include "I2C.h"
// Register Definitions
#define PCA9685_ADDRESS 0x00000041
#define MODE1 0x00 //Mode register 1
#define MODE2 0x01 //Mode register 2
#define SUBADR1 0x02 //I2C-bus subaddress 1
#define SUBADR2 0x03 //I2C-bus subaddress 2
#define SUBADR3 0x04 //I2C-bus subaddress 3
#define ALLCALLADR 0x05 //LED All Call I2C-bus address
#define LED0 0x6 //LED0 start register
#define LED0_ON_L 0x6 //LED0 output and brightness control byte 0
#define LED0_ON_H 0x7 //LED0 output and brightness control byte 1
#define LED0_OFF_L 0x8 //LED0 output and brightness control byte 2
#define LED0_OFF_H 0x9 //LED0 output and brightness control byte 3
#define LED_MULTIPLYER 4 // For the other 15 channels
#define ALLLED_ON_L 0xFA //load all the LEDn_ON registers, byte 0 (turn 0-7 channels on)
#define ALLLED_ON_H 0xFB //load all the LEDn_ON registers, byte 1 (turn 8-15 channels on)
#define ALLLED_OFF_L 0xFC //load all the LEDn_OFF registers, byte 0 (turn 0-7 channels off)
#define ALLLED_OFF_H 0xFD //load all the LEDn_OFF registers, byte 1 (turn 8-15 channels off)
#define PRE_SCALE 0xFE //prescaler for output frequency
#define CLOCK_FREQ 25000000.0 //25MHz default osc clock
//! Main class that exports features for PCA9685 chip
class PCA9685 {
public:
PCA9685();
virtual ~PCA9685();
void setPWMFreq(int);
void setPWM(uint8_t, int);
int getPWM(uint8_t);
private:
I2C *i2c;
void reset(void);
void setPWM(uint8_t, int, int);
};
extern "C" {
PCA9685 pwm;
void setPWMFreq(int freg) {
pwm.setPWMFreq(freg);
}
void setPWM(uint8_t channel, int angle) {
pwm.setPWM(channel, angle);
}
int getPWM(uint8_t channel) {
return pwm.getPWM(channel);
}
}
#endif
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment