|
1 /** @brief driver for Pi ADC card xxx |
|
2 * |
|
3 */ |
|
4 #include <stdio.h> |
|
5 #include <stdint.h> |
|
6 #include <stdlib.h> |
|
7 #include <string.h> |
|
8 #include <errno.h> |
|
9 #include <unistd.h> |
|
10 #include <sys/types.h> |
|
11 #include <sys/stat.h> |
|
12 #include <sys/ioctl.h> |
|
13 #include <fcntl.h> |
|
14 #include <linux/i2c-dev.h> |
|
15 |
|
16 #include <epicsThread.h> |
|
17 #include <epicsTime.h> |
|
18 #include <epicsTypes.h> |
|
19 #include <devLib.h> |
|
20 #include <drvSup.h> |
|
21 #include <epicsExport.h> |
|
22 #include <errlog.h> |
|
23 |
|
24 #include <iocsh.h> |
|
25 |
|
26 #include "drvAdcPi.h" |
|
27 |
|
28 /* crc("adcPi") */ |
|
29 #define MYMAGIC 1729550187U |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 #define MCP3424_NEW_CONV 0x80 |
|
35 #define MCP3424_CHANNEL_1 0x00 |
|
36 #define MCP3424_CHANNEL_2 0x20 |
|
37 #define MCP3424_CHANNEL_3 0x40 |
|
38 #define MCP3424_CHANNEL_4 0x60 |
|
39 #define MCP3424_CONT_CONV 0x10 |
|
40 #define MCP3424_ONE_SHOT_CONV 0x00 |
|
41 #define MCP3424_12BIT_240SPS 0x00 |
|
42 #define MCP3424_14BIT_60SPS 0x04 |
|
43 #define MCP3424_16BIT_15SPS 0x08 |
|
44 #define MCP3424_18BIT_3_75SPS 0x0c |
|
45 #define MCP3424_GAIN_1 0x00 |
|
46 #define MCP3424_GAIN_2 0x01 |
|
47 #define MCP3424_GAIN_4 0x02 |
|
48 #define MCP3424_GAIN_8 0x03 |
|
49 #define MCP3424_CONT_MASK 0x6f |
|
50 |
|
51 // adcPi definitions, on i2c-bus |
|
52 #define ADC_1 0x68 |
|
53 #define ADC_2 0x69 |
|
54 #define ADC_CHANNEL1 (MCP3424_NEW_CONV | MCP3424_CHANNEL_1 | MCP3424_CONT_CONV | MCP3424_14BIT_60SPS | MCP3424_GAIN_1 ) |
|
55 #define ADC_CHANNEL2 (MCP3424_NEW_CONV | MCP3424_CHANNEL_2 | MCP3424_CONT_CONV | MCP3424_14BIT_60SPS | MCP3424_GAIN_1 ) |
|
56 #define ADC_CHANNEL3 (MCP3424_NEW_CONV | MCP3424_CHANNEL_3 | MCP3424_CONT_CONV | MCP3424_14BIT_60SPS | MCP3424_GAIN_1 ) |
|
57 #define ADC_CHANNEL4 (MCP3424_NEW_CONV | MCP3424_CHANNEL_4 | MCP3424_CONT_CONV | MCP3424_14BIT_60SPS | MCP3424_GAIN_1 ) |
|
58 |
|
59 /** @brief linked list of card structures |
|
60 * |
|
61 */ |
|
62 struct adcPiCard { |
|
63 epicsUInt32 magic; |
|
64 adcPiCard *next; |
|
65 int cardNumber; |
|
66 unsigned int i2cAddress; |
|
67 char* baseAddress; // not used with i2c |
|
68 unsigned int fh; // file handle |
|
69 |
|
70 }; |
|
71 static adcPiCard *firstCard = NULL; |
|
72 |
|
73 int adcPiDebug = 1; |
|
74 epicsExportAddress (int, adcPiDebug); |
|
75 |
|
76 static long adcPiReport (int detail); |
|
77 |
|
78 typedef struct { |
|
79 long number; |
|
80 DRVSUPFUN report; |
|
81 DRVSUPFUN init; |
|
82 } drvAdcPi_drvet; |
|
83 drvAdcPi_drvet adcPi = { |
|
84 2, |
|
85 adcPiReport, |
|
86 NULL |
|
87 }; |
|
88 |
|
89 epicsExportAddress (drvet, adcPi); |
|
90 |
|
91 static epicsUInt16 getAdc(adcPiCard* card, int signal) |
|
92 { |
|
93 static __u8 res[4]; |
|
94 static unsigned int dummy; |
|
95 static __u8 adc, adc_channel; |
|
96 static int ret; |
|
97 //static unsigned int threadPrio; |
|
98 //epicsTimeStamp startTime, endTime; |
|
99 //double elapsedTime; |
|
100 //static int loopCounter; |
|
101 |
|
102 if (signal < 0 || signal > ADC_PI_MAX_CHANNEL) { |
|
103 errMessage (-1, "Signal Number out of range"); |
|
104 return 0; |
|
105 } |
|
106 //threadPrio = epicsThreadGetPrioritySelf(); |
|
107 //epicsThreadSetPriority( epicsThreadGetIdSelf(),epicsThreadPriorityMin ); |
|
108 |
|
109 //printf(" card->fh : %d, signal : %d (prio: %d)\n", card->fh, signal, epicsThreadGetPrioritySelf()); |
|
110 |
|
111 switch (signal){ |
|
112 case 0: { adc=ADC_1; adc_channel=ADC_CHANNEL1; }; break; |
|
113 case 1: { adc=ADC_1; adc_channel=ADC_CHANNEL2; }; break; |
|
114 case 2: { adc=ADC_1; adc_channel=ADC_CHANNEL3; }; break; |
|
115 case 3: { adc=ADC_1; adc_channel=ADC_CHANNEL4; }; break; |
|
116 case 4: { adc=ADC_2; adc_channel=ADC_CHANNEL1; }; break; |
|
117 case 5: { adc=ADC_2; adc_channel=ADC_CHANNEL2; }; break; |
|
118 case 6: { adc=ADC_2; adc_channel=ADC_CHANNEL3; }; break; |
|
119 case 7: { adc=ADC_2; adc_channel=ADC_CHANNEL4; }; break; |
|
120 default: { adc=ADC_1; adc_channel=ADC_CHANNEL1; }; break; |
|
121 } |
|
122 |
|
123 |
|
124 // choose device |
|
125 if (ioctl(card->fh,I2C_SLAVE,adc) != 0) errMessage (0, "ioctl failed"); |
|
126 //if (usleep (50000) < 0) errMessage (0, "usleep failed"); |
|
127 //printf ("adc_channel = 0x%02X \n", adc_channel); |
|
128 //epicsTimeGetCurrent(&startTime); |
|
129 if (i2c_smbus_write_byte (card->fh, adc_channel) != 0) errMessage (0, "i2c_smbus_write_byte failed"); |
|
130 // wait a little bit for end of conversion |
|
131 if (usleep (50000) < 0) errMessage (0, "usleep failed"); |
|
132 // 3 for != 18bit mode |
|
133 //loopCounter = 0; |
|
134 do { |
|
135 ret = i2c_smbus_read_i2c_block_data(card->fh, adc_channel, 3, res); |
|
136 // printf(" res[0] = 0x%02X, res[1] = 0x%02X, res[2] = 0x%02X\n", res[0], res[1], res[2]); |
|
137 if (ret != 3) { |
|
138 errMessage (0, "i2c_smbus_read_i2c_block_data"); |
|
139 fprintf (stderr, "i2c_smbus_read_i2c_block_data returns %d bytes != 3\n", ret); |
|
140 } |
|
141 //if (res[2] & 0x80) { |
|
142 // fprintf (stderr, "i2c_smbus_read_i2c_block_data, output register (0x%02X) not updated yet\n", res[2]); |
|
143 //} |
|
144 //loopCounter++; |
|
145 } while (res[2] & 0x80); |
|
146 |
|
147 //epicsTimeGetCurrent(&endTime); |
|
148 //elapsedTime = epicsTimeDiffInSeconds(&endTime, &startTime); |
|
149 //printf("Elapsed time %f\n", elapsedTime); |
|
150 //printf(" res[0] = 0x%02X, res[1] = 0x%02X, res[2] = 0x%02X, loopCounter = %d\n", res[0], res[1], res[2], loopCounter); |
|
151 |
|
152 |
|
153 dummy = (res[0]<<8|res[1]); |
|
154 if (dummy>=32768) dummy=65536-dummy; |
|
155 //val = dummy * 0.000154; |
|
156 // printf(" dummy = %d, val = %lf\n", dummy, val); |
|
157 //return val; |
|
158 //if (adcPiDebug) printf ("dummy = 0x%x\n", dummy); |
|
159 // epicsThreadSetPriority( epicsThreadGetIdSelf(), threadPrio); |
|
160 return dummy; |
|
161 } |
|
162 |
|
163 |
|
164 /** @brief configure function |
|
165 * |
|
166 * The configure function is called from the startup script |
|
167 */ |
|
168 int adcPiConfigure (int cardNumber, unsigned int i2cAddress) |
|
169 { |
|
170 // long status; |
|
171 // volatile void* baseAddress; |
|
172 // char id[6]; |
|
173 adcPiCard **pCard; |
|
174 |
|
175 /** @brief Check card number for sanity */ |
|
176 if (cardNumber != 1) { |
|
177 fprintf (stderr, "adcPiConfigure: cardNumber %d must be 1\n", cardNumber); |
|
178 return S_dev_noDevice; |
|
179 } |
|
180 |
|
181 /** @brief Find end of card list and check for duplicates */ |
|
182 for (pCard = &firstCard; *pCard; pCard=&(*pCard)->next) { |
|
183 if ((*pCard)->cardNumber == cardNumber) { |
|
184 fprintf (stderr, "adcPiConfigure: cardnumber %d already in use\n", cardNumber); |
|
185 return S_dev_identifyOverlap; |
|
186 } |
|
187 } // pCard points to the end of the list |
|
188 |
|
189 |
|
190 /** @brief Check address for sanity |
|
191 * |
|
192 * We use /dev/i2c-1, should be fixed/solved, so a "1" should be used*/ |
|
193 if (i2cAddress != 1) { |
|
194 fprintf (stderr, "adcPiConfigure: i2cAddress %d must be 1\n", i2cAddress); |
|
195 return S_dev_noDevice; |
|
196 } |
|
197 |
|
198 // check VMEaddress for sanity |
|
199 |
|
200 // translate address to local address, check for overlap |
|
201 |
|
202 // check that correct hardware is installed, devReadProbe |
|
203 // read i2c? |
|
204 |
|
205 /** @brief create new card structure |
|
206 * |
|
207 */ |
|
208 *pCard = malloc (sizeof(adcPiCard)); |
|
209 if (!*pCard) { |
|
210 fprintf (stderr, "adcPiConfigure: out of memory\n"); |
|
211 return S_dev_noMemory; |
|
212 } |
|
213 |
|
214 (*pCard)->fh = open("/dev/i2c-1", O_RDWR); // "1" hardcoded! |
|
215 if ((*pCard)->fh <= 0) { |
|
216 fprintf (stderr, "adcPiConfigure: could not open /dev/i2c-1\n"); |
|
217 return S_dev_noDevice; |
|
218 } |
|
219 |
|
220 (*pCard)->magic = MYMAGIC; |
|
221 (*pCard)->next = NULL; |
|
222 (*pCard)->cardNumber = cardNumber; |
|
223 (*pCard)->i2cAddress = i2cAddress; |
|
224 |
|
225 return 0; |
|
226 } |
|
227 |
|
228 adcPiCard* adcPiOpen (int cardNumber) |
|
229 { |
|
230 adcPiCard* card; |
|
231 for (card = firstCard; card; card=card->next) |
|
232 if (card->cardNumber == cardNumber) return card; |
|
233 return NULL; |
|
234 } |
|
235 |
|
236 int adcPiGet (adcPiCard* card, int signal, epicsUInt16* pValue) |
|
237 { |
|
238 |
|
239 if (adcPiDebug>1) |
|
240 printf("adcPiGet card %d signal %d (adcPiDebug: %d)\n", |
|
241 card->cardNumber, signal, adcPiDebug); |
|
242 |
|
243 if (!card) return S_dev_noDevice; |
|
244 if (card->magic != MYMAGIC) return S_dev_wrongDevice; |
|
245 |
|
246 if (signal < 0 || signal > ADC_PI_MAX_CHANNEL) return S_dev_badSignalNumber; |
|
247 |
|
248 *pValue = getAdc(card, signal); |
|
249 |
|
250 if (adcPiDebug>1) |
|
251 printf("adcPiGet card %d signal %d @%p = 0x%4X\n", |
|
252 card->cardNumber, signal, (void *)&getAdc, (epicsUInt16)*pValue); |
|
253 return 0; |
|
254 } |
|
255 |
|
256 /** @brief report function |
|
257 * |
|
258 */ |
|
259 static long adcPiReport (int detail) |
|
260 { |
|
261 adcPiCard *card; |
|
262 for (card = firstCard; card; card = card->next) { |
|
263 printf (" card %d at address %p \n", card->cardNumber, card->baseAddress); |
|
264 if (detail >= 1) { |
|
265 int signal; |
|
266 unsigned short value; |
|
267 for (signal = 0; signal < ADC_PI_MAX_CHANNEL; signal++) { |
|
268 value = getAdc(card, signal); |
|
269 printf(" ADC %d = 0x%04x = %+8.4f V\n", signal, value, value * 0.000154); // tobedef |
|
270 } |
|
271 } |
|
272 } |
|
273 return 0; |
|
274 } |
|
275 |
|
276 |
|
277 |
|
278 |
|
279 static const iocshArg adcPiConfigureArg0 = { "cardNumber", iocshArgInt }; |
|
280 static const iocshArg adcPiConfigureArg1 = { "i2cAddress", iocshArgInt }; |
|
281 |
|
282 static const iocshArg * const adcPiConfigureArgs[] = { |
|
283 &adcPiConfigureArg0, |
|
284 &adcPiConfigureArg1 |
|
285 }; |
|
286 static const iocshFuncDef adcPiConfigureDef = { "adcPiConfigure", 2, adcPiConfigureArgs }; |
|
287 static void adcPiConfigureFunc (const iocshArgBuf *args) |
|
288 { |
|
289 adcPiConfigure (args[0].ival, args[1].ival); |
|
290 } |
|
291 |
|
292 static void adcPiRegister () |
|
293 { |
|
294 iocshRegister (&adcPiConfigureDef, adcPiConfigureFunc); |
|
295 } |
|
296 |
|
297 epicsExportRegistrar (adcPiRegister); |