add pca9685(pwm generator) api in resource module
authorJeonghoon Park <jh1979.park@samsung.com>
Fri, 15 Dec 2017 01:02:09 +0000 (10:02 +0900)
committerJeonghoon Park <jh1979.park@samsung.com>
Fri, 15 Dec 2017 01:02:09 +0000 (10:02 +0900)
inc/resource/resource_PCA9685.h [new file with mode: 0644]
src/resource/resource_PCA9685.c [new file with mode: 0644]

diff --git a/inc/resource/resource_PCA9685.h b/inc/resource/resource_PCA9685.h
new file mode 100644 (file)
index 0000000..b1c1fca
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jeonghoon Park <jh1979.park@samsung.com>
+ *
+ * Licensed under the Flora License, Version 1.1 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __RESOURCE_PCA9685_H__
+#define __RESOURCE_PCA9685_H__
+
+int resource_pca9685_init(void);
+int resource_pca9685_fini(void);
+int resource_pca9685_set_frequency(unsigned int freq_hz);
+int resource_pca9685_set_value_to_channel(unsigned int channel, int on, int off);
+int resource_pca9685_set_value_to_all(int on, int off);
+
+#endif /* __RESOURCE_PCA9685_H__ */
diff --git a/src/resource/resource_PCA9685.c b/src/resource/resource_PCA9685.c
new file mode 100644 (file)
index 0000000..642ad4e
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Jeonghoon Park <jh1979.park@samsung.com>
+ *
+ * Licensed under the Flora License, Version 1.1 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <math.h>
+#include <peripheral_io.h>
+#include "log.h"
+
+#define RPI3_I2C_BUS 1
+
+/* Registers/etc: */
+#define PCA9685_ADDRESS    0x40
+#define MODE1              0x00
+#define MODE2              0x01
+#define SUBADR1            0x02
+#define SUBADR2            0x03
+#define SUBADR3            0x04
+#define PRESCALE           0xFE
+#define LED0_ON_L          0x06
+#define LED0_ON_H          0x07
+#define LED0_OFF_L         0x08
+#define LED0_OFF_H         0x09
+#define ALL_LED_ON_L       0xFA
+#define ALL_LED_ON_H       0xFB
+#define ALL_LED_OFF_L      0xFC
+#define ALL_LED_OFF_H      0xFD
+
+/* Bits: */
+#define RESTART            0x80
+#define SLEEP              0x10
+#define ALLCALL            0x01
+#define INVRT              0x10
+#define OUTDRV             0x04
+
+static peripheral_i2c_h g_i2c_h = NULL;
+static unsigned int ref_count = 0;
+
+int resource_pca9685_set_frequency(unsigned int freq_hz)
+{
+       int ret = PERIPHERAL_ERROR_NONE;
+       double prescale_value = 0.0;
+       int prescale = 0;
+       uint8_t oldmode = 0;
+       uint8_t newmode = 0;
+
+       prescale_value = 25000000.0;    // 25MHz
+       prescale_value /= 4096.0;       // 12-bit
+       prescale_value /= (double)freq_hz;
+       prescale_value -= 1.0;
+
+       prescale = (int)floor(prescale_value + 0.5);
+
+       ret = peripheral_i2c_read_register_byte(g_i2c_h, MODE1, &oldmode);
+       retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to read register");
+
+       newmode = (oldmode & 0x7F) | 0x10; // sleep
+       ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, newmode); // go to sleep
+       retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+       ret = peripheral_i2c_write_register_byte(g_i2c_h, PRESCALE, prescale);
+       retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+       ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, oldmode);
+       retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+       usleep(500);
+
+       ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, (oldmode | 0x80));
+       retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+       return 0;
+}
+
+int resource_pca9685_set_value_to_channel(unsigned int channel, int on, int off)
+{
+       int ret = PERIPHERAL_ERROR_NONE;
+       retvm_if(g_i2c_h == NULL, -1, "Not initialized yet");
+
+       ret = peripheral_i2c_write_register_byte(g_i2c_h,
+                       LED0_ON_L + 4*channel, on & 0xFF);
+       retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+       ret = peripheral_i2c_write_register_byte(g_i2c_h,
+                       LED0_ON_H + 4*channel, on >> 8);
+       retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+       ret = peripheral_i2c_write_register_byte(g_i2c_h,
+                       LED0_OFF_L + 4*channel, off & 0xFF);
+       retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+       ret = peripheral_i2c_write_register_byte(g_i2c_h,
+                       LED0_OFF_H + 4*channel, off >> 8);
+       retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+       return 0;
+}
+
+int resource_pca9685_set_value_to_all(int on, int off)
+{
+       int ret = PERIPHERAL_ERROR_NONE;
+       retvm_if(g_i2c_h == NULL, -1, "Not initialized yet");
+
+       ret = peripheral_i2c_write_register_byte(g_i2c_h,
+               ALL_LED_ON_L, on & 0xFF);
+       retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+       ret = peripheral_i2c_write_register_byte(g_i2c_h,
+               ALL_LED_ON_H, on >> 8);
+       retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+       ret = peripheral_i2c_write_register_byte(g_i2c_h,
+               ALL_LED_OFF_L, off & 0xFF);
+       retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+       ret = peripheral_i2c_write_register_byte(g_i2c_h,
+               ALL_LED_OFF_H, off >> 8);
+       retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+       return 0;
+}
+
+int resource_pca9685_init(void)
+{
+       uint8_t mode1 = 0;
+       int ret = PERIPHERAL_ERROR_NONE;
+
+       if (g_i2c_h) {
+               ref_count++;
+               _D("Already initialized - ref_count[%u]\n", ref_count);
+               return 0;
+       }
+
+       ret = peripheral_i2c_open(RPI3_I2C_BUS, PCA9685_ADDRESS, &g_i2c_h);
+       if (ret != PERIPHERAL_ERROR_NONE) {
+               _E("failed to open pca9685-[bus:%d, addr:%d]",
+                       RPI3_I2C_BUS, PCA9685_ADDRESS);
+               return -1;
+       }
+       ret = resource_pca9685_set_value_to_all(0, 0);
+       retvm_if(ret, -1, "failed to set value to register");
+
+       ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE2, OUTDRV);
+       retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+       ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, ALLCALL);
+       retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+       usleep(500); // wait for oscillator
+
+       ret = peripheral_i2c_read_register_byte(g_i2c_h, MODE1, &mode1);
+       retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to read register");
+
+       mode1 = mode1 & (~SLEEP); // # wake up (reset sleep)
+       ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, mode1);
+       retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
+
+       usleep(500); // wait for oscillator
+
+       ret = resource_pca9685_set_frequency(60);
+       if (ret) {
+               _E("failed to set frequency");
+               peripheral_i2c_close(g_i2c_h);
+               g_i2c_h = NULL;
+               return -1;
+       }
+       ref_count++;
+
+       return 0;
+}
+
+int resource_pca9685_fini(void)
+{
+       ref_count--;
+
+       _D("ref count - %u", ref_count);
+
+       if (g_i2c_h) {
+               _D("finalizing pca9685");
+               resource_pca9685_set_value_to_all(0, 0);
+               peripheral_i2c_close(g_i2c_h);
+               g_i2c_h = NULL;
+       }
+
+       return 0;
+}