1 | /* |
---|
2 | * COPYRIGHT (c) 1989-2011. |
---|
3 | * On-Line Applications Research Corporation (OAR). |
---|
4 | * |
---|
5 | * The license and distribution terms for this file may be |
---|
6 | * found in the file LICENSE in this distribution or at |
---|
7 | * http://www.rtems.com/license/LICENSE. |
---|
8 | * |
---|
9 | * $Id$ |
---|
10 | */ |
---|
11 | |
---|
12 | #define LIB_DEFINED |
---|
13 | |
---|
14 | /* #define DEBUG 1 */ |
---|
15 | |
---|
16 | #include <bsp.h> |
---|
17 | #include <stdio.h> |
---|
18 | #include <stdlib.h> |
---|
19 | #include "rtd6425.h" |
---|
20 | #include <bsp/irq.h> |
---|
21 | |
---|
22 | /* RTEMS Ids for Wait Queues */ |
---|
23 | rtems_id rtd6425_dio_wq; |
---|
24 | unsigned int rtd6425_dio_missed_interrupts; |
---|
25 | |
---|
26 | |
---|
27 | typedef struct { |
---|
28 | uint16_t irq; |
---|
29 | uint8_t irqmask; |
---|
30 | uint8_t previous; |
---|
31 | } rtd6425_control_t; |
---|
32 | |
---|
33 | rtd6425_control_t rtd6425_info[2]; |
---|
34 | |
---|
35 | /* |
---|
36 | * Limits on number of buffered discrete input interrupts in |
---|
37 | * the message queue. |
---|
38 | */ |
---|
39 | #define MAXIMUM_BUFFERED_DISCRETE_INTERRUPTS 1024 |
---|
40 | |
---|
41 | typedef struct { |
---|
42 | struct timespec timestamp; |
---|
43 | int pin; |
---|
44 | } rtd6425_din_message_t; |
---|
45 | |
---|
46 | typedef struct { |
---|
47 | uint8_t p0_direction; /* each bit 1 == output, 0 == input */ |
---|
48 | bool p1_direction; /* true when all output */ |
---|
49 | uint8_t p2_direction; /* each bit 1 == output, 0 == input */ |
---|
50 | bool p3_direction; /* true when all output */ |
---|
51 | uint16_t control_reg; /* value to program the conrtol register */ |
---|
52 | uint16_t irq_reg; /* value to program the irq register */ |
---|
53 | } rtd6425_config_t; |
---|
54 | |
---|
55 | rtd6425_config_t rtd6425_configuration = { |
---|
56 | 0x00, /* p0_direction - each bit 1 == output, 0 == input */ |
---|
57 | false, /* p1_direction - true when all output */ |
---|
58 | 0x00, /* p2_direction - each bit 1 == output, 0 == input */ |
---|
59 | false, /* p3_direction - true when all output */ |
---|
60 | 0x00, |
---|
61 | 0x00 |
---|
62 | }; |
---|
63 | |
---|
64 | typedef enum { |
---|
65 | RTD6425_ADC_RANGE_NEG_5_TO_5 = 0x0, |
---|
66 | RTD6425_ADC_RANGE_NEG_10_TO_10 = 0x1, |
---|
67 | RTD6425_ADC_RANGE_0_TO_10 = 0x2 |
---|
68 | } rtd6425_adc_range_t; |
---|
69 | |
---|
70 | typedef enum { |
---|
71 | RTD6425_ADC_GAIN_NONE = 0x0, |
---|
72 | RTD6425_ADC_GAIN_X1 = 0x1, |
---|
73 | RTD6425_ADC_GAIN_X2 = 0x2, |
---|
74 | RTD6425_ADC_GAIN_X4 = 0x4, |
---|
75 | RTD6425_ADC_GAIN_X8 = 0x8, |
---|
76 | } rtd6425_adc_gain_t; |
---|
77 | |
---|
78 | typedef enum { |
---|
79 | RTD6425_ADC_SINGLE_ENDED = 0, |
---|
80 | RTD6425_ADC_DIFFERENTIAL = 1 |
---|
81 | } rtd6425_adc_se_diff_t; |
---|
82 | |
---|
83 | typedef struct { |
---|
84 | rtd6425_adc_range_t range; |
---|
85 | rtd6425_adc_gain_t gain; |
---|
86 | rtd6425_adc_se_diff_t se_diff; |
---|
87 | } rtd6425_adc_config_t; |
---|
88 | |
---|
89 | #define RTD6425_ADC_DEFAULT_CONFIGURATION \ |
---|
90 | { RTD6425_ADC_RANGE_NEG_10_TO_10, RTD6425_ADC_GAIN_NONE, RTD6425_ADC_SINGLE_ENDED } |
---|
91 | |
---|
92 | rtd6425_adc_config_t rtd6425_adc_configuration[ RTD6425_ADCs ] = { |
---|
93 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 00 */ |
---|
94 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 01 */ |
---|
95 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 02 */ |
---|
96 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 03 */ |
---|
97 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 04 */ |
---|
98 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 05 */ |
---|
99 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 06 */ |
---|
100 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 07 */ |
---|
101 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 08 */ |
---|
102 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 09 */ |
---|
103 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 10 */ |
---|
104 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 11 */ |
---|
105 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 12 */ |
---|
106 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 13 */ |
---|
107 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 14 */ |
---|
108 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 15 */ |
---|
109 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 16 */ |
---|
110 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 17 */ |
---|
111 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 18 */ |
---|
112 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 19 */ |
---|
113 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 20 */ |
---|
114 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 21 */ |
---|
115 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 22 */ |
---|
116 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 23 */ |
---|
117 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 24 */ |
---|
118 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 25 */ |
---|
119 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 26 */ |
---|
120 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 27 */ |
---|
121 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 28 */ |
---|
122 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 29 */ |
---|
123 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 30 */ |
---|
124 | RTD6425_ADC_DEFAULT_CONFIGURATION, /* ADC 31 */ |
---|
125 | }; |
---|
126 | |
---|
127 | bool rtd6425_is_writable( int pin ) |
---|
128 | { |
---|
129 | int port; |
---|
130 | int position; |
---|
131 | uint8_t mask; |
---|
132 | |
---|
133 | port = pin / 8; |
---|
134 | |
---|
135 | if ( port == 1 ) { |
---|
136 | if ( rtd6425_configuration.p1_direction == true ) |
---|
137 | return false; |
---|
138 | return true; |
---|
139 | } |
---|
140 | |
---|
141 | if ( port == 3 ) { |
---|
142 | if ( rtd6425_configuration.p3_direction == true ) |
---|
143 | return false; |
---|
144 | return true; |
---|
145 | } |
---|
146 | |
---|
147 | if ( port == 0 ) |
---|
148 | mask = rtd6425_configuration.p0_direction; |
---|
149 | else |
---|
150 | mask = rtd6425_configuration.p2_direction; |
---|
151 | |
---|
152 | position = pin / 8; |
---|
153 | if ( (mask & (1 << position)) != 0 ) |
---|
154 | return true; |
---|
155 | |
---|
156 | return false; |
---|
157 | } |
---|
158 | |
---|
159 | #if 1 |
---|
160 | #define DEBUG_PRINT(...) printk( __VA_ARGS__ ) |
---|
161 | #else |
---|
162 | #define DEBUG_PRINT(...) |
---|
163 | #endif |
---|
164 | |
---|
165 | #define rtd6425_outport_byte( _port, _value ) \ |
---|
166 | do { \ |
---|
167 | DEBUG_PRINT( "OUTB 0x%04x to 0x%04x\n", _value, _port ); \ |
---|
168 | outport_byte( _port, _value ); \ |
---|
169 | } while (0) |
---|
170 | |
---|
171 | #define rtd6425_inport_byte( _port, _value ) \ |
---|
172 | do { \ |
---|
173 | inport_byte( _port, _value ); \ |
---|
174 | DEBUG_PRINT( "INB 0x%04x from 0x%04x\n", _value, _port ); \ |
---|
175 | } while (0) |
---|
176 | |
---|
177 | #define rtd6425_outport_word( _port, _value ) \ |
---|
178 | do { \ |
---|
179 | DEBUG_PRINT( "OUTW 0x%04x to 0x%04x\n", _value, _port ); \ |
---|
180 | outport_word( _port, _value ); \ |
---|
181 | } while (0) |
---|
182 | |
---|
183 | #define rtd6425_inport_word( _port, _value ) \ |
---|
184 | do { \ |
---|
185 | inport_word( _port, _value ); \ |
---|
186 | DEBUG_PRINT( "INW 0x%04x from 0x%04x\n", _value, _port ); \ |
---|
187 | } while (0) |
---|
188 | |
---|
189 | uint16_t rtd6425_base; |
---|
190 | |
---|
191 | #define DIO_SELECT_CLEAR 0 |
---|
192 | #define DIO_SELECT_DIRECTION 1 |
---|
193 | #define DIO_SELECT_MASK 2 |
---|
194 | #define DIO_SELECT_COMPARE 3 |
---|
195 | |
---|
196 | void rtd6425_DIO_select_register(uint8_t port, uint8_t reg) |
---|
197 | { |
---|
198 | uint8_t value; |
---|
199 | |
---|
200 | rtd6425_inport_byte( |
---|
201 | rtd6425_base + RTD6425_MODE_5812 + (port * 0x400), |
---|
202 | value |
---|
203 | ); |
---|
204 | |
---|
205 | DEBUG_PRINT("select_reg1: port: %d, reg: %d, val: 0x%02x\n", port, reg, value); |
---|
206 | |
---|
207 | value &= 0xFC; |
---|
208 | value |= reg; |
---|
209 | |
---|
210 | rtd6425_outport_byte( rtd6425_base + RTD6425_MODE_5812 + (port * 0x400), value); |
---|
211 | |
---|
212 | rtd6425_inport_byte( |
---|
213 | rtd6425_base + RTD6425_MODE_5812 + (port * 0x400), |
---|
214 | value |
---|
215 | ); |
---|
216 | |
---|
217 | DEBUG_PRINT("select_reg2: port: %d, reg: %d, val: 0x%02x\n", port, reg, value); |
---|
218 | } |
---|
219 | |
---|
220 | void rtd6425_write_dio_status(uint8_t chip, uint8_t mask, uint8_t new) |
---|
221 | { |
---|
222 | uint8_t value; |
---|
223 | |
---|
224 | rtd6425_inport_byte( |
---|
225 | rtd6425_base + RTD6425_MODE_5812 + (chip * 0x400), |
---|
226 | value |
---|
227 | ); |
---|
228 | |
---|
229 | DEBUG_PRINT("write_dio_status1: chip: %d, mask: %d, val: 0x%02x\n", chip, mask, value); |
---|
230 | |
---|
231 | |
---|
232 | value &= 0xFC; |
---|
233 | value &= ~mask; |
---|
234 | value |= new; |
---|
235 | |
---|
236 | rtd6425_outport_byte( rtd6425_base + RTD6425_MODE_5812 + (chip * 0x400), value); |
---|
237 | |
---|
238 | rtd6425_inport_byte( |
---|
239 | rtd6425_base + RTD6425_MODE_5812 + (chip * 0x400), |
---|
240 | value |
---|
241 | ); |
---|
242 | |
---|
243 | DEBUG_PRINT("write_dio_status2: chip: %d, mask: %d, val: 0x%02x\n", chip, mask, value); |
---|
244 | |
---|
245 | } |
---|
246 | |
---|
247 | uint8_t rtd6425_read_dio_status( uint8_t chip ) |
---|
248 | { |
---|
249 | uint8_t value; |
---|
250 | |
---|
251 | rtd6425_inport_byte( |
---|
252 | rtd6425_base + RTD6425_MODE_5812 + (chip * 0x400), |
---|
253 | value |
---|
254 | ); |
---|
255 | |
---|
256 | DEBUG_PRINT("read_dio_status: chip: %d val: 0x%02x\n", chip, value); |
---|
257 | |
---|
258 | return value; |
---|
259 | } |
---|
260 | |
---|
261 | void rtd6425_din_queue_create( |
---|
262 | rtems_name name, |
---|
263 | rtems_id *id |
---|
264 | ) |
---|
265 | { |
---|
266 | rtems_status_code rc; |
---|
267 | |
---|
268 | rc = rtems_message_queue_create( |
---|
269 | name, |
---|
270 | MAXIMUM_BUFFERED_DISCRETE_INTERRUPTS, |
---|
271 | sizeof(rtd6425_din_message_t), |
---|
272 | RTEMS_DEFAULT_ATTRIBUTES, |
---|
273 | id |
---|
274 | ); |
---|
275 | if ( rc == RTEMS_SUCCESSFUL ) |
---|
276 | return; |
---|
277 | |
---|
278 | DEBUG_PRINT( "Unable to create RTD6425 DIN IRQ Message Queue\n" ); |
---|
279 | exit(1); |
---|
280 | } |
---|
281 | |
---|
282 | void rtd6425_initialize( |
---|
283 | unsigned short base_port, |
---|
284 | unsigned short irq0, |
---|
285 | unsigned short irq1 |
---|
286 | ) |
---|
287 | { |
---|
288 | uint16_t ignored; |
---|
289 | uint16_t value; |
---|
290 | int i; |
---|
291 | |
---|
292 | /* Create RTEMS Objects */ |
---|
293 | rtd6425_din_queue_create( |
---|
294 | rtems_build_name( 'd', 'i', 'o', ' ' ), |
---|
295 | &rtd6425_dio_wq |
---|
296 | ); |
---|
297 | rtd6425_dio_missed_interrupts = 0; |
---|
298 | |
---|
299 | printf( "RTD6426 Init( 0x%04x, 0x%04x, 0x%04x )\n", base_port, rtd6425_info[0].irq, rtd6425_info[1].irq ); |
---|
300 | rtd6425_base = base_port; |
---|
301 | rtd6425_info[0].irq = irq0; |
---|
302 | rtd6425_info[1].irq = irq1; |
---|
303 | |
---|
304 | /* |
---|
305 | * Validate ADC Table. |
---|
306 | */ |
---|
307 | for( i=0; i<RTD6425_ADCs; i=i+2 ) { |
---|
308 | if ( rtd6425_adc_configuration[i].se_diff != |
---|
309 | rtd6425_adc_configuration[i].se_diff ) { |
---|
310 | DEBUG_PRINT("Error==> ADC single ended mismatch\n"); |
---|
311 | exit (0); |
---|
312 | } |
---|
313 | |
---|
314 | if ( rtd6425_adc_configuration[i].se_diff == RTD6425_ADC_DIFFERENTIAL ) { |
---|
315 | if (rtd6425_adc_configuration[i].range != |
---|
316 | rtd6425_adc_configuration[i].range ) { |
---|
317 | DEBUG_PRINT("Error==> ADC range mismatch - Either choose single ended or match the range of the twisted pair\n"); |
---|
318 | exit (0); |
---|
319 | } |
---|
320 | } |
---|
321 | } |
---|
322 | |
---|
323 | /* |
---|
324 | * Reset Board and clear it out |
---|
325 | */ |
---|
326 | rtd6425_outport_word( rtd6425_base + RTD6425_CLEAR, 0x0001 ); |
---|
327 | rtd6425_inport_word( rtd6425_base + RTD6425_CLEAR, ignored ); |
---|
328 | |
---|
329 | /* |
---|
330 | * Clear ADDMADone |
---|
331 | */ |
---|
332 | rtd6425_outport_word( rtd6425_base + RTD6425_CLEAR, 0x0004 ); |
---|
333 | rtd6425_inport_word( rtd6425_base + RTD6425_CLEAR, ignored ); |
---|
334 | |
---|
335 | /* |
---|
336 | * Clear Gain Table |
---|
337 | */ |
---|
338 | rtd6425_outport_word( rtd6425_base + RTD6425_CLEAR, 0x0008 ); |
---|
339 | rtd6425_inport_word( rtd6425_base + RTD6425_CLEAR, ignored ); |
---|
340 | |
---|
341 | /* |
---|
342 | * Clear ADC FIFOs |
---|
343 | */ |
---|
344 | rtd6425_outport_word( rtd6425_base + RTD6425_CLEAR, 0x0002 ); |
---|
345 | rtd6425_inport_word( rtd6425_base + RTD6425_CLEAR, ignored ); |
---|
346 | |
---|
347 | /* |
---|
348 | * Clear DIN FIFOs |
---|
349 | */ |
---|
350 | rtd6425_outport_word( rtd6425_base + RTD6425_CLEAR, 0x0020 ); |
---|
351 | rtd6425_inport_word( rtd6425_base + RTD6425_CLEAR, ignored ); |
---|
352 | |
---|
353 | /* |
---|
354 | * Program Discrete I/O directions |
---|
355 | */ |
---|
356 | rtd6425_DIO_select_register( 0, DIO_SELECT_DIRECTION ); |
---|
357 | rtd6425_outport_word( |
---|
358 | rtd6425_base + RTD6425_PORT_DIR_5812 + (0*0x400), |
---|
359 | rtd6425_configuration.p0_direction |
---|
360 | ); |
---|
361 | |
---|
362 | rtd6425_write_dio_status( |
---|
363 | 0, |
---|
364 | 0x04, |
---|
365 | (rtd6425_configuration.p1_direction) ? 0x04 : 0x00 |
---|
366 | ); |
---|
367 | |
---|
368 | rtd6425_DIO_select_register( 1, DIO_SELECT_DIRECTION ); |
---|
369 | rtd6425_outport_word( |
---|
370 | rtd6425_base + RTD6425_PORT_DIR_5812 + (1*0x400), |
---|
371 | rtd6425_configuration.p2_direction |
---|
372 | ); |
---|
373 | |
---|
374 | rtd6425_write_dio_status( |
---|
375 | 1, |
---|
376 | 0x04, |
---|
377 | (rtd6425_configuration.p1_direction) ? 0x04 : 0x00 |
---|
378 | ); |
---|
379 | DEBUG_PRINT("END: Program discrete I/O directions\n"); |
---|
380 | |
---|
381 | rtd6425_outport_word( rtd6425_base + RTD6425_TRIGGER, 0x00 ); |
---|
382 | |
---|
383 | /* |
---|
384 | * Set the |
---|
385 | */ |
---|
386 | //Enable loading channel gain latch |
---|
387 | rtd6425_configuration.control_reg &= 0xFFFC; |
---|
388 | rtd6425_outport_word( rtd6425_base + RTD6425_CONTROL, rtd6425_configuration.control_reg ); |
---|
389 | |
---|
390 | for( i=0; i<RTD6425_ADCs; i++) { |
---|
391 | value = (i) | |
---|
392 | (rtd6425_adc_configuration[i].gain << 5) | |
---|
393 | (rtd6425_adc_configuration[i].range << 8) | |
---|
394 | (rtd6425_adc_configuration[i].se_diff << 10); |
---|
395 | |
---|
396 | rtd6425_outport_word( rtd6425_base + RTD6425_CHANNEL_GAIN, value ); |
---|
397 | } |
---|
398 | DEBUG_PRINT("End ADC setup\n"); |
---|
399 | } |
---|
400 | |
---|
401 | void rtd6425_chip_mode_select( uint8_t chip ) |
---|
402 | { |
---|
403 | uint8_t value; |
---|
404 | uint8_t mode = 0; /* Event Mode */ |
---|
405 | |
---|
406 | /* Clear Bit to set to event mode */ |
---|
407 | rtd6425_inport_byte( |
---|
408 | rtd6425_base + RTD6425_MODE_5812 + (chip * 0x400), |
---|
409 | value |
---|
410 | ); |
---|
411 | value &= 0xf7; |
---|
412 | value |= (mode << 3); |
---|
413 | rtd6425_outport_byte( |
---|
414 | rtd6425_base + RTD6425_MODE_5812 + (chip * 0x400), |
---|
415 | value |
---|
416 | ); |
---|
417 | } |
---|
418 | |
---|
419 | void rtd6425_set_IRQ(uint8_t chip, uint16_t source, uint16_t channel) |
---|
420 | { |
---|
421 | uint16_t value; |
---|
422 | |
---|
423 | switch(channel) { |
---|
424 | case 3: channel = 1; break; |
---|
425 | case 5: channel = 2; break; |
---|
426 | case 9: channel = 3; break; |
---|
427 | case 10: channel = 4; break; |
---|
428 | case 11: channel = 5; break; |
---|
429 | case 12: channel = 6; break; |
---|
430 | case 15: channel = 7; break; |
---|
431 | default: channel = 0; break; |
---|
432 | } |
---|
433 | |
---|
434 | if (chip == 0) |
---|
435 | rtd6425_configuration.irq_reg = |
---|
436 | rtd6425_configuration.irq_reg & 0xff00; |
---|
437 | else |
---|
438 | rtd6425_configuration.irq_reg = |
---|
439 | rtd6425_configuration.irq_reg & 0x00ff; |
---|
440 | |
---|
441 | value = source | (channel << 5); |
---|
442 | rtd6425_configuration.irq_reg |= value << (chip*8); |
---|
443 | rtd6425_outport_word( |
---|
444 | rtd6425_base + RTD6425_IRQ, |
---|
445 | rtd6425_configuration.irq_reg |
---|
446 | ); |
---|
447 | } |
---|
448 | |
---|
449 | void rtd6425_enable_interrupt(uint8_t chip, uint8_t enable) |
---|
450 | { |
---|
451 | uint8_t value; |
---|
452 | |
---|
453 | rtd6425_info[chip].irqmask = (enable) ? 0xff : 0; |
---|
454 | rtd6425_inport_byte( |
---|
455 | rtd6425_base + (chip * 0x400) + RTD6425_PORT_0_5812, |
---|
456 | rtd6425_info[chip].previous |
---|
457 | ); |
---|
458 | |
---|
459 | /* Clear Bit to set to event mode */ |
---|
460 | rtd6425_inport_byte( |
---|
461 | rtd6425_base + RTD6425_MODE_5812 + (chip * 0x400), |
---|
462 | value |
---|
463 | ); |
---|
464 | value &= 0xef; |
---|
465 | value |= (enable << 4); |
---|
466 | rtd6425_outport_byte( |
---|
467 | rtd6425_base + RTD6425_MODE_5812 + (chip * 0x400), |
---|
468 | value |
---|
469 | ); |
---|
470 | } |
---|
471 | |
---|
472 | void rtd6425_dio_check_pin_change( |
---|
473 | uint8_t base_bit, |
---|
474 | uint8_t previous, |
---|
475 | uint8_t current, |
---|
476 | uint8_t mask, |
---|
477 | rtd6425_din_message_t *din |
---|
478 | ) |
---|
479 | { |
---|
480 | uint8_t changed; |
---|
481 | int pin; |
---|
482 | int pin_mask; |
---|
483 | rtems_status_code rc; |
---|
484 | |
---|
485 | /* |
---|
486 | * Calculate which bits changed that we care about |
---|
487 | */ |
---|
488 | changed = (previous ^ current) & mask; |
---|
489 | |
---|
490 | // printk( "check: %d prev=0x%02x curr=0x%02x mask=0x%02x\n", |
---|
491 | // base_bit, previous, current, mask ); |
---|
492 | |
---|
493 | for ( pin=0 ; changed != 0 && pin<8 ; pin++ ) { |
---|
494 | pin_mask = 1 << pin; |
---|
495 | if ( (changed & pin_mask) == 0 ) |
---|
496 | continue; |
---|
497 | |
---|
498 | din->pin = base_bit + pin; |
---|
499 | // printk( "check: %d changed\n", din->pin ); |
---|
500 | rc = rtems_message_queue_send( |
---|
501 | rtd6425_dio_wq, |
---|
502 | din, |
---|
503 | sizeof(rtd6425_din_message_t) |
---|
504 | ); |
---|
505 | if ( rc != RTEMS_SUCCESSFUL ) { |
---|
506 | rtd6425_dio_missed_interrupts++; |
---|
507 | DEBUG_PRINT("<1>Missed DIO interrupt %d\n", rc ); |
---|
508 | } |
---|
509 | changed &= ~pin_mask; |
---|
510 | } |
---|
511 | } |
---|
512 | |
---|
513 | void rtd6425_clear_Irq6425( void ) |
---|
514 | { |
---|
515 | uint16_t value; |
---|
516 | |
---|
517 | /* ClearIRQ16425 */ |
---|
518 | rtd6425_outport_word( rtd6425_base + RTD6425_CLEAR, 0x00C0 ); |
---|
519 | rtd6425_inport_word( rtd6425_base + RTD6425_CLEAR, value ); |
---|
520 | } |
---|
521 | |
---|
522 | void rtd6425_clear_Irq5812(uint8_t chip) |
---|
523 | { |
---|
524 | uint8_t value; |
---|
525 | |
---|
526 | rtd6425_DIO_select_register(chip, 0); |
---|
527 | rtd6425_inport_byte( |
---|
528 | rtd6425_base + RTD6425_CLEAR_5812 + (chip * 0x400), |
---|
529 | value |
---|
530 | ); |
---|
531 | } |
---|
532 | |
---|
533 | rtems_isr rtd6425_dio_handler(void *arg); |
---|
534 | |
---|
535 | rtems_irq_connect_data rtd6425_dio_cd0 = { |
---|
536 | 0, rtd6425_dio_handler, (void *) &rtd6425_dio_cd0, NULL, NULL, NULL, NULL |
---|
537 | }; |
---|
538 | rtems_irq_connect_data rtd6425_dio_cd1 = { |
---|
539 | 0, rtd6425_dio_handler, (void *) &rtd6425_dio_cd1, NULL, NULL, NULL, NULL |
---|
540 | }; |
---|
541 | |
---|
542 | int rtd6425_enable_dio_interrupt(void) |
---|
543 | { |
---|
544 | int i; |
---|
545 | uint8_t mask, status; |
---|
546 | uint8_t v8; |
---|
547 | DEBUG_PRINT("Start rtd6425_enable_dio_interrupt\n"); |
---|
548 | |
---|
549 | /* Set IRQ Source Digital IO. */ |
---|
550 | /* XXX - Verify this */ |
---|
551 | rtd6425_set_IRQ(0, 10, rtd6425_info[0].irq ); |
---|
552 | rtd6425_set_IRQ(1, 16, rtd6425_info[1].irq ); |
---|
553 | |
---|
554 | rtd6425_dio_cd0.name = rtd6425_info[0].irq; |
---|
555 | rtd6425_dio_cd1.name = rtd6425_info[1].irq; |
---|
556 | |
---|
557 | /* Install handler for each irq */ |
---|
558 | BSP_install_rtems_shared_irq_handler( &rtd6425_dio_cd0 ); |
---|
559 | BSP_install_rtems_shared_irq_handler( &rtd6425_dio_cd1 ); |
---|
560 | |
---|
561 | // insure there won't be any interrupts from preset values on ports 0/1 |
---|
562 | rtd6425_outport_byte( |
---|
563 | rtd6425_base + RTD6425_PORT_0_5812 + (0 * 0x400) + (1 * 2), |
---|
564 | 0Xff |
---|
565 | ); |
---|
566 | rtd6425_outport_byte( |
---|
567 | rtd6425_base + RTD6425_PORT_0_5812 + (1 * 0x400) + (1 * 2), |
---|
568 | 0Xff |
---|
569 | ); |
---|
570 | |
---|
571 | // set event mode for port interrupt |
---|
572 | rtd6425_chip_mode_select( 0 ); |
---|
573 | rtd6425_chip_mode_select( 1 ); |
---|
574 | |
---|
575 | // insures that no bits will be masked for interrupts |
---|
576 | DEBUG_PRINT("Set Mask for chip\n"); |
---|
577 | rtd6425_DIO_select_register(0, 2 ); |
---|
578 | rtd6425_outport_byte( |
---|
579 | rtd6425_base + RTD6425_PORT_MASK_5812 + (0 * 0x400) , |
---|
580 | 0x00 |
---|
581 | ); |
---|
582 | rtd6425_DIO_select_register(1, 2 ); |
---|
583 | rtd6425_outport_byte( |
---|
584 | rtd6425_base + RTD6425_PORT_MASK_5812 + (1 * 0x400) , |
---|
585 | 0x00 |
---|
586 | ); |
---|
587 | |
---|
588 | DEBUG_PRINT("Turn interrupts on\n"); |
---|
589 | rtd6425_enable_interrupt(0, 1); // enable interrupt circuit at Port |
---|
590 | rtd6425_enable_interrupt(1, 1); // enable interrupt circuit at Port |
---|
591 | |
---|
592 | /* ClearIrq5812(PORTSELECT01); */ |
---|
593 | rtd6425_DIO_select_register( 0, 0 ); |
---|
594 | rtd6425_inport_byte( rtd6425_base + (0 * 0x400) + RTD6425_CLEAR_5812, v8 ); |
---|
595 | rtd6425_DIO_select_register( 1, 0 ); |
---|
596 | rtd6425_inport_byte( rtd6425_base + (1 * 0x400) + RTD6425_CLEAR_5812, v8 ); |
---|
597 | rtd6425_clear_Irq6425(); |
---|
598 | |
---|
599 | rtd6425_clear_Irq5812(0); |
---|
600 | rtd6425_clear_Irq5812(1); |
---|
601 | |
---|
602 | |
---|
603 | for (i=0; i<2;i++){ |
---|
604 | rtd6425_inport_byte( |
---|
605 | rtd6425_base + RTD6425_PORT_MASK_5812 + (i * 0x400), |
---|
606 | mask |
---|
607 | ); |
---|
608 | rtd6425_inport_byte( |
---|
609 | rtd6425_base + RTD6425_STATUS_5812 + (i * 0x400), |
---|
610 | status |
---|
611 | ); |
---|
612 | printk( "chip %d Mask: 0x%x Status: 0x%x IRQ: 0x%x\n", |
---|
613 | i,mask, status, rtd6425_configuration.irq_reg |
---|
614 | ); |
---|
615 | } |
---|
616 | |
---|
617 | DEBUG_PRINT("Return from rtd6425_enable_dio_interrupt\n"); |
---|
618 | |
---|
619 | return 0; |
---|
620 | } |
---|
621 | |
---|
622 | int rtd6425_dio_enab_bit_int(int bit_number, int polarity) |
---|
623 | { |
---|
624 | int dio_port; |
---|
625 | uint8_t value; |
---|
626 | uint8_t mask; |
---|
627 | uint16_t io_port; |
---|
628 | uint8_t new; |
---|
629 | |
---|
630 | if ( bit_number > RTD6425_DISCRETE_IO_BITS ) |
---|
631 | return -1; |
---|
632 | |
---|
633 | dio_port = bit_number / 8; |
---|
634 | mask = 1 << (bit_number % 8); |
---|
635 | new = ((polarity) ? mask : 0); |
---|
636 | mask = ~mask; |
---|
637 | |
---|
638 | switch ( dio_port ) { |
---|
639 | case 0: io_port = RTD6425_PORT_0_5812; break; |
---|
640 | case 1: io_port = RTD6425_PORT_1_5812; break; |
---|
641 | case 2: io_port = RTD6425_PORT_0_5812 + 0x400; break; |
---|
642 | case 3: io_port = RTD6425_PORT_1_5812 + 0x400; break; |
---|
643 | default: return -1; |
---|
644 | } |
---|
645 | |
---|
646 | rtd6425_DIO_select_register(0, 2 ); |
---|
647 | |
---|
648 | // read the mask register and calculate the field |
---|
649 | rtd6425_inport_byte( |
---|
650 | rtd6425_base + RTD6425_PORT_MASK_5812 + (0 * 0x400), |
---|
651 | value |
---|
652 | ); |
---|
653 | |
---|
654 | DEBUG_PRINT("read interrupt mask 0x%x\n", value); |
---|
655 | value &= mask; |
---|
656 | value |= ~mask; |
---|
657 | DEBUG_PRINT("write interrupt mask 0x%x\n", value); |
---|
658 | |
---|
659 | // write the value to the mask register |
---|
660 | rtd6425_DIO_select_register(0, 2 ); |
---|
661 | rtd6425_outport_byte( |
---|
662 | rtd6425_base + RTD6425_PORT_MASK_5812 + (0 * 0x400) , |
---|
663 | value |
---|
664 | ); |
---|
665 | |
---|
666 | |
---|
667 | return 0; |
---|
668 | } |
---|
669 | |
---|
670 | void rtd6425_flush_buffered_ints(void) |
---|
671 | { |
---|
672 | } |
---|
673 | |
---|
674 | int rtd6425_wait_dac_int_with_timeout(int dac_num, int milliseconds) |
---|
675 | { |
---|
676 | return 0; |
---|
677 | } |
---|
678 | |
---|
679 | int rtd6425_wait_dio_int_with_timeout(int milliseconds) |
---|
680 | { |
---|
681 | return 0; |
---|
682 | } |
---|
683 | |
---|
684 | int rtd6425_wait_dio_int_with_timestamp( |
---|
685 | int milliseconds, |
---|
686 | struct timespec *timestamp |
---|
687 | ) |
---|
688 | { |
---|
689 | rtems_status_code rc; |
---|
690 | rtd6425_din_message_t din; |
---|
691 | size_t received; |
---|
692 | |
---|
693 | mio_error_code = MIO_SUCCESS; |
---|
694 | |
---|
695 | rc = rtems_message_queue_receive( |
---|
696 | rtd6425_dio_wq, |
---|
697 | &din, |
---|
698 | &received, |
---|
699 | RTEMS_DEFAULT_OPTIONS, |
---|
700 | RTEMS_MILLISECONDS_TO_TICKS(milliseconds) |
---|
701 | ); |
---|
702 | if ( rc == RTEMS_UNSATISFIED ) { |
---|
703 | mio_error_code = MIO_READ_DATA_FAILURE; |
---|
704 | return -1; |
---|
705 | } |
---|
706 | |
---|
707 | if ( rc == RTEMS_TIMEOUT ) { |
---|
708 | mio_error_code = MIO_TIMEOUT_ERROR; |
---|
709 | return -1; |
---|
710 | } |
---|
711 | |
---|
712 | if ( rc != RTEMS_SUCCESSFUL ) { |
---|
713 | DEBUG_PRINT( "wait_dio_int_with_timestamp - error %d\n", rc ); |
---|
714 | exit( 0 ); |
---|
715 | } |
---|
716 | |
---|
717 | if (timestamp) |
---|
718 | *timestamp = din.timestamp; |
---|
719 | return din.pin; |
---|
720 | } |
---|
721 | |
---|
722 | int rtd6425_dio_get_missed_interrupts(void) |
---|
723 | { |
---|
724 | return 0; |
---|
725 | } |
---|
726 | |
---|
727 | float rtd6425_adc_get_channel_voltage(int channel) |
---|
728 | { |
---|
729 | int16_t value; |
---|
730 | float result = 0; |
---|
731 | |
---|
732 | rtd6425_outport_word( rtd6425_base + RTD6425_CLEAR, 0x0002 ); |
---|
733 | rtd6425_inport_word( rtd6425_base + RTD6425_CLEAR, value ); |
---|
734 | |
---|
735 | rtd6425_configuration.control_reg &= 0xFFFC; //Enable loading channel gain latch |
---|
736 | rtd6425_outport_word( rtd6425_base + RTD6425_CONTROL, rtd6425_configuration.control_reg ); |
---|
737 | |
---|
738 | value = (channel) | |
---|
739 | (rtd6425_adc_configuration[channel].gain << 5) | |
---|
740 | (rtd6425_adc_configuration[channel].range << 8) | |
---|
741 | (rtd6425_adc_configuration[channel].se_diff << 10); |
---|
742 | |
---|
743 | rtd6425_outport_word( rtd6425_base + RTD6425_CHANNEL_GAIN, value ); |
---|
744 | |
---|
745 | /* Start Conversion */ |
---|
746 | rtd6425_inport_word( rtd6425_base + RTD6425_START_CONVERSION, value ); |
---|
747 | |
---|
748 | /* Wait on Fifo to not be empty */ |
---|
749 | while ( ( value & 0x1 ) == 0 ) |
---|
750 | rtd6425_inport_word( rtd6425_base + RTD6425_STATUS, value ); |
---|
751 | |
---|
752 | rtd6425_inport_word( rtd6425_base + RTD6425_AD, value ); |
---|
753 | value = value >> 3; |
---|
754 | printf("ADC Read: 0x%03x\n", value ); |
---|
755 | |
---|
756 | switch( rtd6425_adc_configuration[channel].range ) { |
---|
757 | case RTD6425_ADC_RANGE_NEG_5_TO_5: |
---|
758 | result = (( 10.0 / 4095.0) * value); |
---|
759 | break; |
---|
760 | case RTD6425_ADC_RANGE_NEG_10_TO_10: |
---|
761 | result = (( 20.0 / 4095.0) * value); |
---|
762 | break; |
---|
763 | case RTD6425_ADC_RANGE_0_TO_10: |
---|
764 | result = (( 10.0 / 4095.0) * value); |
---|
765 | break; |
---|
766 | }; |
---|
767 | |
---|
768 | return result; |
---|
769 | } |
---|
770 | |
---|
771 | int rtd6425_set_dac_voltage(int channel, float voltage) |
---|
772 | { |
---|
773 | uint16_t value; |
---|
774 | float per_bit; |
---|
775 | uint16_t dac_setup; |
---|
776 | uint16_t range_select; |
---|
777 | |
---|
778 | // printf( "Write DAC %d %fV\n", channel, voltage ); |
---|
779 | /* |
---|
780 | * Read DAC Setup, clean out bits indicating DAC selected |
---|
781 | */ |
---|
782 | rtd6425_inport_word( rtd6425_base + RTD6425_DA_SETUP, dac_setup ); |
---|
783 | dac_setup &= ~(3 << (channel * 2)); |
---|
784 | |
---|
785 | /* |
---|
786 | * Do some magic per range |
---|
787 | */ |
---|
788 | if ( voltage >= 0.0 && voltage <= 5.0 ) { |
---|
789 | per_bit = 5.0 / 4095; |
---|
790 | value = (uint16_t) (voltage / per_bit); |
---|
791 | range_select = RTD6425_DAC_0V_to_5V; |
---|
792 | } else if ( voltage >= -5.0 && voltage <= 5.0 ) { |
---|
793 | per_bit = 10.0 / 4095; |
---|
794 | value = (uint16_t) ((voltage + 5.0) / per_bit); |
---|
795 | range_select = RTD6425_DAC_MINUS_5V_TO_5V; |
---|
796 | } else if ( voltage >= 0.0 && voltage <= 10.0 ) { |
---|
797 | per_bit = 10.0 / 4095; |
---|
798 | value = (uint16_t) (voltage / per_bit); |
---|
799 | range_select = RTD6425_DAC_0V_TO_10V; |
---|
800 | } else if ( voltage >= -10.0 && voltage <= 10.0 ) { |
---|
801 | per_bit = 20.0 / 4095; |
---|
802 | value = (uint16_t) ((voltage + 10.0) / per_bit); |
---|
803 | range_select = RTD6425_DAC_MINUS_10_TO_10V; |
---|
804 | } else { |
---|
805 | printf( "Voltage is out of range %f\n", voltage ); |
---|
806 | return -1; |
---|
807 | } |
---|
808 | |
---|
809 | /* |
---|
810 | * Select voltage range needed |
---|
811 | */ |
---|
812 | dac_setup |= range_select << (channel * 2); |
---|
813 | rtd6425_outport_word( rtd6425_base + RTD6425_DA_SETUP, dac_setup ); |
---|
814 | |
---|
815 | /* |
---|
816 | * Now write the selected voltage |
---|
817 | */ |
---|
818 | rtd6425_outport_word( rtd6425_base + RTD6425_DAC_BASE + (channel * 2), value ); |
---|
819 | return 0; |
---|
820 | } |
---|
821 | |
---|
822 | int rtd6425_dio_read_bit(int bit_number) |
---|
823 | { |
---|
824 | int dio_port; |
---|
825 | uint8_t value; |
---|
826 | uint8_t mask; |
---|
827 | uint16_t io_port; |
---|
828 | |
---|
829 | if ( bit_number > RTD6425_DISCRETE_IO_BITS ) |
---|
830 | return -1; |
---|
831 | |
---|
832 | dio_port = bit_number / 8; |
---|
833 | mask = 1 << (bit_number % 8); |
---|
834 | |
---|
835 | switch ( dio_port ) { |
---|
836 | case 0: io_port = RTD6425_PORT_0_5812; break; |
---|
837 | case 1: io_port = RTD6425_PORT_1_5812; break; |
---|
838 | case 2: io_port = RTD6425_PORT_0_5812 + 0x400; break; |
---|
839 | case 3: io_port = RTD6425_PORT_1_5812 + 0x400; break; |
---|
840 | default: return -1; |
---|
841 | } |
---|
842 | |
---|
843 | rtd6425_inport_byte( rtd6425_base + io_port, value ); |
---|
844 | return ((value & mask) ? 1 : 0); |
---|
845 | } |
---|
846 | |
---|
847 | int rtd6425_dio_write_bit(int bit_number, int val) |
---|
848 | { |
---|
849 | int dio_port; |
---|
850 | uint8_t value; |
---|
851 | uint8_t mask; |
---|
852 | uint16_t io_port; |
---|
853 | uint8_t new; |
---|
854 | |
---|
855 | if ( bit_number > RTD6425_DISCRETE_IO_BITS ) |
---|
856 | return -1; |
---|
857 | |
---|
858 | dio_port = bit_number / 8; |
---|
859 | mask = 1 << (bit_number % 8); |
---|
860 | new = ((val) ? mask : 0); |
---|
861 | mask = ~mask; |
---|
862 | |
---|
863 | switch ( dio_port ) { |
---|
864 | case 0: io_port = RTD6425_PORT_0_5812; break; |
---|
865 | case 1: io_port = RTD6425_PORT_1_5812; break; |
---|
866 | case 2: io_port = RTD6425_PORT_0_5812 + 0x400; break; |
---|
867 | case 3: io_port = RTD6425_PORT_1_5812 + 0x400; break; |
---|
868 | default: return -1; |
---|
869 | } |
---|
870 | |
---|
871 | rtd6425_inport_byte( rtd6425_base + io_port, value ); |
---|
872 | value = (value & mask) | new; |
---|
873 | rtd6425_outport_byte( rtd6425_base + io_port, value ); |
---|
874 | return 0; |
---|
875 | } |
---|
876 | |
---|
877 | bool rtd6425_is_chip_irq( uint8_t chip ) |
---|
878 | { |
---|
879 | uint8_t value; |
---|
880 | |
---|
881 | rtd6425_inport_word( rtd6425_base + RTD6425_STATUS, value ); |
---|
882 | if ( (value & 0x40) == 0 ) /* XXX - Validate this is correct bit. */ |
---|
883 | return false; |
---|
884 | |
---|
885 | return true; |
---|
886 | } |
---|
887 | |
---|
888 | /* |
---|
889 | * This is the RTD6425 DIO interrupt handler. It is called by the |
---|
890 | * actual hardware ISR. |
---|
891 | */ |
---|
892 | rtems_isr rtd6425_dio_handler(void *arg) |
---|
893 | { |
---|
894 | uint8_t chip; |
---|
895 | uint8_t v8; |
---|
896 | uint16_t v16; |
---|
897 | rtd6425_din_message_t din; |
---|
898 | rtems_irq_connect_data *irq_conn = (rtems_irq_connect_data *)arg; |
---|
899 | uint16_t base; |
---|
900 | |
---|
901 | rtems_clock_get_uptime( &din.timestamp ); |
---|
902 | |
---|
903 | printk("DIO ISR\n"); |
---|
904 | |
---|
905 | chip = (irq_conn == & rtd6425_dio_cd0) ? 0 : 1; |
---|
906 | base = rtd6425_base + (chip * 0x400); |
---|
907 | |
---|
908 | /* check pins changed for chip n, port 1 */ |
---|
909 | rtd6425_inport_word( base + RTD6425_PORT_0_5812, v8 ); |
---|
910 | rtd6425_dio_check_pin_change( |
---|
911 | (chip == 0) ? 0 : 16, /* pins 0-7 or 16-23 */ |
---|
912 | rtd6425_info[chip].previous, /* last value we saw */ |
---|
913 | v8, /* current value */ |
---|
914 | rtd6425_info[chip].irqmask, /* pins we care about */ |
---|
915 | &din /* message */ |
---|
916 | ); |
---|
917 | rtd6425_info[chip].previous = v8; |
---|
918 | |
---|
919 | /* ClearIRQ16425 */ |
---|
920 | rtd6425_outport_word( base + RTD6425_CLEAR, (0x0040<<chip) ); |
---|
921 | rtd6425_inport_word( base + RTD6425_CLEAR, v16 ); |
---|
922 | |
---|
923 | /* ClearIrq5812(PORTSELECT01); */ |
---|
924 | rtd6425_DIO_select_register( chip, 0 ); |
---|
925 | rtd6425_inport_byte( base + RTD6425_CLEAR_5812, v8 ); |
---|
926 | |
---|
927 | rtd6425_clear_Irq5812(chip); |
---|
928 | rtd6425_clear_Irq6425(); |
---|
929 | |
---|
930 | if ( irq_conn->name >= 8 ) { |
---|
931 | rtd6425_outport_byte( 0x20, 0x20 ); |
---|
932 | } else { |
---|
933 | rtd6425_outport_byte( 0xA0, 0x20 ); |
---|
934 | } |
---|
935 | |
---|
936 | #ifdef DEBUG |
---|
937 | DEBUG_PRINT("<1>Buffering DIO interrupt on bit %d\n",int_num); |
---|
938 | #endif |
---|
939 | } |
---|