refer max channel number from pca9685 in servo motor
[apps/native/gear-racing-car.git] / src / resource / resource_PCA9685.c
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3  *
4  * Contact: Jeonghoon Park <jh1979.park@samsung.com>
5  *
6  * Licensed under the Flora License, Version 1.1 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://floralicense.org/license/
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an AS IS BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <math.h>
22 #include <peripheral_io.h>
23 #include "log.h"
24
25 #define RPI3_I2C_BUS 1
26
27 /* Registers/etc: */
28 #define PCA9685_ADDRESS    0x40
29 #define MODE1              0x00
30 #define MODE2              0x01
31 #define SUBADR1            0x02
32 #define SUBADR2            0x03
33 #define SUBADR3            0x04
34 #define PRESCALE           0xFE
35 #define LED0_ON_L          0x06
36 #define LED0_ON_H          0x07
37 #define LED0_OFF_L         0x08
38 #define LED0_OFF_H         0x09
39 #define ALL_LED_ON_L       0xFA
40 #define ALL_LED_ON_H       0xFB
41 #define ALL_LED_OFF_L      0xFC
42 #define ALL_LED_OFF_H      0xFD
43
44 /* Bits: */
45 #define RESTART            0x80
46 #define SLEEP              0x10
47 #define ALLCALL            0x01
48 #define INVRT              0x10
49 #define OUTDRV             0x04
50
51 typedef enum {
52         PCA9685_CH_STATE_NONE,
53         PCA9685_CH_STATE_USED,
54 } pca9685_ch_state_e;
55
56 static peripheral_i2c_h g_i2c_h = NULL;
57 static unsigned int ref_count = 0;
58 static pca9685_ch_state_e ch_state[PCA9685_CH_MAX] = {PCA9685_CH_STATE_NONE, };
59
60 int resource_pca9685_set_frequency(unsigned int freq_hz)
61 {
62         int ret = PERIPHERAL_ERROR_NONE;
63         double prescale_value = 0.0;
64         int prescale = 0;
65         uint8_t oldmode = 0;
66         uint8_t newmode = 0;
67
68         prescale_value = 25000000.0;    // 25MHz
69         prescale_value /= 4096.0;       // 12-bit
70         prescale_value /= (double)freq_hz;
71         prescale_value -= 1.0;
72
73         prescale = (int)floor(prescale_value + 0.5);
74
75         ret = peripheral_i2c_read_register_byte(g_i2c_h, MODE1, &oldmode);
76         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to read register");
77
78         newmode = (oldmode & 0x7F) | 0x10; // sleep
79         ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, newmode); // go to sleep
80         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
81
82         ret = peripheral_i2c_write_register_byte(g_i2c_h, PRESCALE, prescale);
83         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
84
85         ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, oldmode);
86         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
87
88         usleep(500);
89
90         ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, (oldmode | 0x80));
91         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
92
93         return 0;
94 }
95
96 int resource_pca9685_set_value_to_channel(unsigned int channel, int on, int off)
97 {
98         int ret = PERIPHERAL_ERROR_NONE;
99         retvm_if(g_i2c_h == NULL, -1, "Not initialized yet");
100
101         retvm_if(ch_state[channel] == PCA9685_CH_STATE_NONE, -1,
102                 "ch[%u] is not in used state", channel);
103
104         ret = peripheral_i2c_write_register_byte(g_i2c_h,
105                         LED0_ON_L + 4*channel, on & 0xFF);
106         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
107
108         ret = peripheral_i2c_write_register_byte(g_i2c_h,
109                         LED0_ON_H + 4*channel, on >> 8);
110         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
111
112         ret = peripheral_i2c_write_register_byte(g_i2c_h,
113                         LED0_OFF_L + 4*channel, off & 0xFF);
114         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
115
116         ret = peripheral_i2c_write_register_byte(g_i2c_h,
117                         LED0_OFF_H + 4*channel, off >> 8);
118         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
119
120         return 0;
121 }
122
123 static int resource_pca9685_set_value_to_all(int on, int off)
124 {
125         int ret = PERIPHERAL_ERROR_NONE;
126         retvm_if(g_i2c_h == NULL, -1, "Not initialized yet");
127
128         ret = peripheral_i2c_write_register_byte(g_i2c_h,
129                 ALL_LED_ON_L, on & 0xFF);
130         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
131
132         ret = peripheral_i2c_write_register_byte(g_i2c_h,
133                 ALL_LED_ON_H, on >> 8);
134         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
135
136         ret = peripheral_i2c_write_register_byte(g_i2c_h,
137                 ALL_LED_OFF_L, off & 0xFF);
138         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
139
140         ret = peripheral_i2c_write_register_byte(g_i2c_h,
141                 ALL_LED_OFF_H, off >> 8);
142         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
143
144         return 0;
145 }
146
147 int resource_pca9685_init(unsigned int ch)
148 {
149         uint8_t mode1 = 0;
150         int ret = PERIPHERAL_ERROR_NONE;
151
152         if (ch == 0 || ch >= PCA9685_CH_MAX) {
153                 _E("channel[%u] is out of range", ch);
154                 return -1;
155         }
156
157         if (ch_state[ch] == PCA9685_CH_STATE_USED) {
158                 _E("channel[%u] is already in used state", ch);
159                 return -1;
160         }
161
162         if (g_i2c_h)
163                 goto PASS_OPEN_HANDLE;
164
165         ret = peripheral_i2c_open(RPI3_I2C_BUS, PCA9685_ADDRESS, &g_i2c_h);
166         if (ret != PERIPHERAL_ERROR_NONE) {
167                 _E("failed to open pca9685-[bus:%d, addr:%d]",
168                         RPI3_I2C_BUS, PCA9685_ADDRESS);
169                 return -1;
170         }
171         ret = resource_pca9685_set_value_to_all(0, 0);
172         if (ret) {
173                 _E("failed to reset all value to register");
174                 goto ERROR;
175         }
176
177         ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE2, OUTDRV);
178         if (ret != PERIPHERAL_ERROR_NONE) {
179                 _E("failed to write register");
180                 goto ERROR;
181         }
182
183         ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, ALLCALL);
184         if (ret != PERIPHERAL_ERROR_NONE) {
185                 _E("failed to write register");
186                 goto ERROR;
187         }
188
189         usleep(500); // wait for oscillator
190
191         ret = peripheral_i2c_read_register_byte(g_i2c_h, MODE1, &mode1);
192         if (ret != PERIPHERAL_ERROR_NONE) {
193                 _E("failed to read register");
194                 goto ERROR;
195         }
196
197         mode1 = mode1 & (~SLEEP); // # wake up (reset sleep)
198         ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, mode1);
199         if (ret != PERIPHERAL_ERROR_NONE) {
200                 _E("failed to write register");
201                 goto ERROR;
202         }
203
204         usleep(500); // wait for oscillator
205
206         ret = resource_pca9685_set_frequency(60);
207         if (ret) {
208                 _E("failed to set frequency");
209                 goto ERROR;
210         }
211
212 PASS_OPEN_HANDLE:
213         ref_count++;
214         ch_state[ch] = PCA9685_CH_STATE_USED;
215         _D("pca9685 - ref_count[%u]", ref_count);
216         _D("sets ch[%u] used state", ch);
217
218         return 0;
219
220 ERROR:
221         if (g_i2c_h)
222                 peripheral_i2c_close(g_i2c_h);
223
224         g_i2c_h = NULL;
225         return -1;
226 }
227
228 int resource_pca9685_fini(unsigned int ch)
229 {
230         if (ch_state[ch] == PCA9685_CH_STATE_NONE) {
231                 _E("channel[%u] is not in used state", ch);
232                 return -1;
233         }
234         resource_pca9685_set_value_to_channel(ch, 0, 0);
235         ch_state[ch] = PCA9685_CH_STATE_NONE;
236
237         ref_count--;
238         _D("ref count - %u", ref_count);
239
240         if (ref_count == 0 && g_i2c_h) {
241                 _D("finalizing pca9685");
242                 resource_pca9685_set_value_to_all(0, 0);
243                 peripheral_i2c_close(g_i2c_h);
244                 g_i2c_h = NULL;
245         }
246
247         return 0;
248 }