49 #include <px4_platform_common/px4_config.h> 50 #include <px4_platform_common/defines.h> 54 #include <sys/types.h> 64 #include <px4_platform_common/getopt.h> 66 #include <px4_platform_common/px4_work_queue/ScheduledWorkItem.hpp> 67 #include <nuttx/clock.h> 75 #include <board_config.h> 78 #define PCA9685_SUBADR1 0x2 79 #define PCA9685_SUBADR2 0x3 80 #define PCA9685_SUBADR3 0x4 82 #define PCA9685_MODE1 0x0 83 #define PCA9685_PRESCALE 0xFE 87 #define LED0_OFF_L 0x8 88 #define LED0_OFF_H 0x9 90 #define ALLLED_ON_L 0xFA 91 #define ALLLED_ON_H 0xFB 92 #define ALLLED_OFF_L 0xFC 95 #define ADDR 0x40 // I2C adress 97 #define PCA9685_DEVICE_PATH "/dev/pca9685" 98 #define PCA9685_BUS PX4_I2C_BUS_EXPANSION 99 #define PCA9685_PWMFREQ 60.0f 100 #define PCA9685_NCHANS 16 // total amount of pwm outputs 102 #define PCA9685_PWMMIN 150 // this is the 'minimum' pulse length count (out of 4096) 103 #define PCA9685_PWMMAX 600 // this is the 'maximum' pulse length count (out of 4096)_PWMFREQ 60.0f 105 #define PCA9685_PWMCENTER ((PCA9685_PWMMAX + PCA9685_PWMMIN)/2) 106 #define PCA9685_MAXSERVODEG 90.0f 110 #define PCA9685_SCALE ((PCA9685_PWMMAX - PCA9685_PWMCENTER)/(M_DEG_TO_RAD_F * PCA9685_MAXSERVODEG)) // scales from rad to PWM 114 class PCA9685 :
public device::I2C,
public px4::ScheduledWorkItem
122 virtual int ioctl(
struct file *filp,
int cmd,
unsigned long arg);
139 uint16_t _current_values[actuator_controls_s::NUM_ACTUATOR_CONTROLS];
149 int setPWMFreq(
float freq);
155 int setPWM(uint8_t num, uint16_t on, uint16_t off);
164 int setPin(uint8_t num, uint16_t val,
bool invert =
false);
168 int read8(uint8_t addr, uint8_t &value);
171 int write8(uint8_t addr, uint8_t value);
187 ScheduledWorkItem(MODULE_NAME,
px4::device_bus_to_wq(get_device_id())),
190 _i2cpwm_interval(1_s / 60.0
f),
193 _actuator_controls_sub(-1),
194 _actuator_controls(),
195 _mode_on_initialized(false)
235 warnx(
"shutting down");
243 warnx(
"test starting");
264 ret = CDev::ioctl(filp, cmd, arg);
280 warnx(
"Driver started but not running");
316 for (
int i = 0; i < actuator_controls_s::NUM_ACTUATOR_CONTROLS; i++) {
360 ret = transfer(
_msg, 5,
nullptr, 0);
381 return setPWM(num, 4096, 0);
383 }
else if (val == 4095) {
385 return setPWM(num, 0, 4096);
388 return setPWM(num, 0, 4095 - val);
394 return setPWM(num, 4096, 0);
396 }
else if (val == 0) {
398 return setPWM(num, 0, 4096);
401 return setPWM(num, 0, val);
414 float prescaleval = 25000000;
418 uint8_t prescale = uint8_t(prescaleval + 0.5
f);
426 uint8_t newmode = (oldmode & 0x7F) | 0x10;
464 ret = transfer(&addr,
sizeof(addr),
nullptr, 0);
471 ret = transfer(
nullptr, 0, &value, 1);
500 ret = transfer(
_msg, 2,
nullptr, 0);
513 warnx(
"missing command: try 'start', 'test', 'stop', 'info'");
515 warnx(
" -b i2cbus (%d)", PX4_I2C_BUS_EXPANSION);
527 const char *myoptarg =
nullptr;
531 while ((ch = px4_getopt(argc, argv,
"a:b:", &myoptind, &myoptarg)) != EOF) {
534 i2caddr = strtol(myoptarg, NULL, 0);
538 i2cdevice = strtol(myoptarg, NULL, 0);
547 if (myoptind >= argc) {
552 const char *verb = argv[myoptind];
557 if (!strcmp(verb,
"start")) {
558 if (g_pca9685 !=
nullptr) {
559 errx(1,
"already started");
562 if (i2cdevice == -1) {
564 i2cdevice = PX4_I2C_BUS_EXPANSION;
565 g_pca9685 =
new PCA9685(PX4_I2C_BUS_EXPANSION, i2caddr);
567 if (g_pca9685 !=
nullptr &&
OK != g_pca9685->init()) {
572 if (g_pca9685 ==
nullptr) {
573 errx(1,
"init failed");
577 if (g_pca9685 ==
nullptr) {
578 g_pca9685 =
new PCA9685(i2cdevice, i2caddr);
580 if (g_pca9685 ==
nullptr) {
581 errx(1,
"new failed");
584 if (
OK != g_pca9685->init()) {
587 errx(1,
"init failed");
605 if (g_pca9685 ==
nullptr) {
606 warnx(
"not started, run pca9685 start");
610 if (!strcmp(verb,
"info")) {
615 if (!strcmp(verb,
"reset")) {
621 if (!strcmp(verb,
"test")) {
634 if (!strcmp(verb,
"stop")) {
645 for (
unsigned i = 0; i < 15; i++) {
646 if (!g_pca9685->is_running()) {
658 if (!g_pca9685->is_running()) {
661 warnx(
"stopped, exiting");
665 warnx(
"stop failed.");
__EXPORT int pca9685_main(int argc, char *argv[])
#define PCA9685_PWMCENTER
int orb_copy(const struct orb_metadata *meta, int handle, void *buffer)
API for the uORB lightweight object broker.
int write8(uint8_t addr, uint8_t value)
int orb_set_interval(int handle, unsigned interval)
int info()
Print a little info about the driver.
int _actuator_controls_sub
bool _mode_on_initialized
int reset(enum LPS22HB_BUS busid)
Reset the driver.
void Run() override
Set to true after the first call of i2cpwm in mode IOX_MODE_ON.
count the number of times an event occurs
int setPWM(uint8_t num, uint16_t on, uint16_t off)
Helper function to set the demanded pwm value.
perf_counter_t _comms_errors
#define IOX_SET_MODE
set device mode (non-blocking)
int orb_subscribe(const struct orb_metadata *meta)
int setPin(uint8_t num, uint16_t val, bool invert=false)
Sets pin without having to deal with on/off tick placement and properly handles a zero value as compl...
int read8(uint8_t addr, uint8_t &value)
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
uint16_t _current_values[actuator_controls_s::NUM_ACTUATOR_CONTROLS]
stores the current pwm output values as sent to the setPin()
void perf_count(perf_counter_t handle)
Count a performance event.
void init()
Activates/configures the hardware registers.
#define DEVICE_LOG(FMT,...)
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
#define PCA9685_DEVICE_PATH
uint64_t _i2cpwm_interval
Simple error/warning functions, heavily inspired by the BSD functions of the same names...
virtual int ioctl(struct file *filp, int cmd, unsigned long arg)
int setPWMFreq(float freq)
Helper function to set the pwm frequency.
PCA9685(int bus=PCA9685_BUS, uint8_t address=ADDR)
struct @83::@85::@87 file
int orb_check(int handle, bool *updated)
#define DEVICE_DEBUG(FMT,...)
struct actuator_controls_s _actuator_controls
Performance measuring tools.
Base class for devices connected via I2C.