Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
360 | f9daq | 1 | /** |
2 | * $Id: fpga_osc.c 881 2013-12-16 05:37:34Z rp_jmenart $ |
||
3 | * |
||
4 | * @brief Red Pitaya Oscilloscope FPGA controller. |
||
5 | * |
||
6 | * @Author Jure Menart <juremenart@gmail.com> |
||
7 | * |
||
8 | * (c) Red Pitaya http://www.redpitaya.com |
||
9 | * |
||
10 | * This part of code is written in C programming language. |
||
11 | * Please visit http://en.wikipedia.org/wiki/C_(programming_language) |
||
12 | * for more details on the language used herein. |
||
13 | */ |
||
14 | |||
15 | #include <stdio.h> |
||
16 | #include <stdlib.h> |
||
17 | #include <string.h> |
||
18 | #include <math.h> |
||
19 | #include <errno.h> |
||
20 | #include <sys/mman.h> |
||
21 | #include <sys/types.h> |
||
22 | #include <sys/stat.h> |
||
23 | #include <unistd.h> |
||
24 | #include <fcntl.h> |
||
25 | |||
26 | #include "fpga_osc.h" |
||
27 | |||
28 | /** |
||
29 | * GENERAL DESCRIPTION: |
||
30 | * |
||
31 | * This module initializes and provides for other SW modules the access to the |
||
32 | * FPGA OSC module. The oscilloscope memory space is divided to three parts: |
||
33 | * - registers (control and status) |
||
34 | * - input signal buffer (Channel A) |
||
35 | * - input signal buffer (Channel B) |
||
36 | * |
||
37 | * This module maps physical address of the oscilloscope core to the logical |
||
38 | * address, which can be used in the GNU/Linux user-space. To achieve this, |
||
39 | * OSC_FPGA_BASE_ADDR from CPU memory space is translated automatically to |
||
40 | * logical address with the function mmap(). After all the initialization is done, |
||
41 | * other modules can use this module to controll oscilloscope FPGA core. Before |
||
42 | * any functions or functionality from this module can be used it needs to be |
||
43 | * initialized with osc_fpga_init() function. When this module is no longer |
||
44 | * needed osc_fpga_exit() must be called. |
||
45 | * |
||
46 | * FPGA oscilloscope state machine in various modes. Basic principle is that |
||
47 | * SW sets the machine, 'arm' the writting machine (FPGA writes from ADC to |
||
48 | * input buffer memory) and then set the triggers. FPGA machine is continue |
||
49 | * writting to the buffers until the trigger is detected plus the amount set |
||
50 | * in trigger delay register. For more detauled description see the FPGA OSC |
||
51 | * registers description. |
||
52 | * |
||
53 | * Nice example how to use this module can be seen in worker.c module. |
||
54 | */ |
||
55 | |||
56 | /* internal structures */ |
||
57 | /** The FPGA register structure (defined in fpga_osc.h) */ |
||
58 | osc_fpga_reg_mem_t *g_osc_fpga_reg_mem = NULL; |
||
59 | /** The FPGA input signal buffer pointer for channel A */ |
||
60 | uint32_t *g_osc_fpga_cha_mem = NULL; |
||
61 | /** The FPGA input signal buffer pointer for channel B */ |
||
62 | uint32_t *g_osc_fpga_chb_mem = NULL; |
||
63 | |||
64 | /** The memory file descriptor used to mmap() the FPGA space */ |
||
65 | int g_osc_fpga_mem_fd = -1; |
||
66 | |||
67 | /* Constants */ |
||
68 | /** ADC number of bits */ |
||
69 | const int c_osc_fpga_adc_bits = 14; |
||
70 | /** @brief Max and min voltage on ADCs. |
||
71 | * Symetrical - Max Voltage = +14, Min voltage = -1 * c_osc_fpga_max_v |
||
72 | */ |
||
73 | const float c_osc_fpga_adc_max_v = +14; |
||
74 | /** Sampling frequency = 125Mspmpls (non-decimated) */ |
||
75 | const float c_osc_fpga_smpl_freq = 125e6; |
||
76 | /** Sampling period (non-decimated) - 8 [ns] */ |
||
77 | const float c_osc_fpga_smpl_period = (1. / 125e6); |
||
78 | |||
79 | /** |
||
80 | * @brief Internal function used to clean up memory. |
||
81 | * |
||
82 | * This function un-maps FPGA register and signal buffers, closes memory file |
||
83 | * descriptor and cleans all memory allocated by this module. |
||
84 | * |
||
85 | * @retval 0 Success |
||
86 | * @retval -1 Error happened during cleanup. |
||
87 | */ |
||
88 | int __osc_fpga_cleanup_mem(void) |
||
89 | { |
||
90 | /* If register structure is NULL we do not need to un-map and clean up */ |
||
91 | if(g_osc_fpga_reg_mem) { |
||
92 | if(munmap(g_osc_fpga_reg_mem, OSC_FPGA_BASE_SIZE) < 0) { |
||
93 | fprintf(stderr, "munmap() failed: %s\n", strerror(errno)); |
||
94 | return -1; |
||
95 | } |
||
96 | g_osc_fpga_reg_mem = NULL; |
||
97 | if(g_osc_fpga_cha_mem) |
||
98 | g_osc_fpga_cha_mem = NULL; |
||
99 | if(g_osc_fpga_chb_mem) |
||
100 | g_osc_fpga_chb_mem = NULL; |
||
101 | } |
||
102 | if(g_osc_fpga_mem_fd >= 0) { |
||
103 | close(g_osc_fpga_mem_fd); |
||
104 | g_osc_fpga_mem_fd = -1; |
||
105 | } |
||
106 | return 0; |
||
107 | } |
||
108 | |||
109 | /** |
||
110 | * @brief Maps FPGA memory space and prepares register and buffer variables. |
||
111 | * |
||
112 | * This function opens memory device (/dev/mem) and maps physical memory address |
||
113 | * OSC_FPGA_BASE_ADDR (of length OSC_FPGA_BASE_SIZE) to logical addresses. It |
||
114 | * initializes the pointers g_osc_fpga_reg_mem, g_osc_fpga_cha_mem and |
||
115 | * g_osc_fpga_chb_mem to point to FPGA OSC. |
||
116 | * If function failes FPGA variables must not be used. |
||
117 | * |
||
118 | * @retval 0 Success |
||
119 | * @retval -1 Failure, error is printed to standard error output. |
||
120 | */ |
||
121 | int osc_fpga_init(void) |
||
122 | { |
||
123 | /* Page variables used to calculate correct mapping addresses */ |
||
124 | void *page_ptr; |
||
125 | long page_addr, page_off, page_size = sysconf(_SC_PAGESIZE); |
||
126 | |||
127 | /* If module was already initialized once, clean all internals. */ |
||
128 | if(__osc_fpga_cleanup_mem() < 0) |
||
129 | return -1; |
||
130 | |||
131 | /* Open /dev/mem to access directly system memory */ |
||
132 | g_osc_fpga_mem_fd = open("/dev/mem", O_RDWR | O_SYNC); |
||
133 | if(g_osc_fpga_mem_fd < 0) { |
||
134 | fprintf(stderr, "open(/dev/mem) failed: %s\n", strerror(errno)); |
||
135 | return -1; |
||
136 | } |
||
137 | |||
138 | /* Calculate correct page address and offset from OSC_FPGA_BASE_ADDR and |
||
139 | * OSC_FPGA_BASE_SIZE |
||
140 | */ |
||
141 | page_addr = OSC_FPGA_BASE_ADDR & (~(page_size-1)); |
||
142 | page_off = OSC_FPGA_BASE_ADDR - page_addr; |
||
143 | |||
144 | /* Map FPGA memory space to page_ptr. */ |
||
145 | page_ptr = mmap(NULL, OSC_FPGA_BASE_SIZE, PROT_READ | PROT_WRITE, |
||
146 | MAP_SHARED, g_osc_fpga_mem_fd, page_addr); |
||
147 | if((void *)page_ptr == MAP_FAILED) { |
||
148 | fprintf(stderr, "mmap() failed: %s\n", strerror(errno)); |
||
149 | __osc_fpga_cleanup_mem(); |
||
150 | return -1; |
||
151 | } |
||
152 | |||
153 | /* Set FPGA OSC module pointers to correct values. */ |
||
154 | g_osc_fpga_reg_mem = page_ptr + page_off; |
||
155 | g_osc_fpga_cha_mem = (uint32_t *)g_osc_fpga_reg_mem + |
||
156 | (OSC_FPGA_CHA_OFFSET / sizeof(uint32_t)); |
||
157 | g_osc_fpga_chb_mem = (uint32_t *)g_osc_fpga_reg_mem + |
||
158 | (OSC_FPGA_CHB_OFFSET / sizeof(uint32_t)); |
||
159 | |||
160 | return 0; |
||
161 | } |
||
162 | |||
163 | /** |
||
164 | * @brief Cleans up FPGA OSC module internals. |
||
165 | * |
||
166 | * This function closes the memory file descriptor, unmap the FPGA memory space |
||
167 | * and cleans also all other internal things from FPGA OSC module. |
||
168 | * @retval 0 Sucess |
||
169 | * @retval -1 Failure |
||
170 | */ |
||
171 | int osc_fpga_exit(void) |
||
172 | { |
||
173 | return __osc_fpga_cleanup_mem(); |
||
174 | } |
||
175 | |||
176 | // TODO: Move to a shared folder and share with scope & spectrum. |
||
177 | /** |
||
178 | * @brief Provides equalization & shaping filter coefficients. |
||
179 | * |
||
180 | * |
||
181 | * This function provides equalization & shaping filter coefficients, based on |
||
182 | * the type of use and gain settings. |
||
183 | * |
||
184 | * @param [in] equal Enable(1)/disable(0) equalization filter. |
||
185 | * @param [in] shaping Enable(1)/disable(0) shaping filter. |
||
186 | * @param [in] gain Gain setting (0 = LV, 1 = HV). |
||
187 | * @param [out] filt Filter coefficients. |
||
188 | */ |
||
189 | void get_equ_shape_filter(ecu_shape_filter_t *filt, uint32_t equal, |
||
190 | uint32_t shaping, uint32_t gain) |
||
191 | { |
||
192 | /* Equalization filter */ |
||
193 | if (equal) { |
||
194 | if (gain == 0) { |
||
195 | /* High gain = LV */ |
||
196 | filt->aa = 0x7D93; |
||
197 | filt->bb = 0x437C7; |
||
198 | } else { |
||
199 | /* Low gain = HV */ |
||
200 | filt->aa = 0x4C5F; |
||
201 | filt->bb = 0x2F38B; |
||
202 | } |
||
203 | } else { |
||
204 | filt->aa = 0; |
||
205 | filt->bb = 0; |
||
206 | } |
||
207 | |||
208 | /* Shaping filter */ |
||
209 | if (shaping) { |
||
210 | filt->pp = 0x2666; |
||
211 | filt->kk = 0xd9999a; |
||
212 | } else { |
||
213 | filt->pp = 0; |
||
214 | filt->kk = 0xffffff; |
||
215 | } |
||
216 | } |
||
217 | |||
218 | |||
219 | /** |
||
220 | * @brief Updates triggering parameters in FPGA registers. |
||
221 | * |
||
222 | * This function updates trigger related parameters in FPGA registers. |
||
223 | * |
||
224 | * @param [in] trig_imm Trigger immediately - if set to 1, FPGA state machine |
||
225 | * will trigger immediately and other trigger parameters |
||
226 | * will be ignored. |
||
227 | * @param [in] trig_source Trigger source, as defined in rp_main_params. |
||
228 | * @param [in] trig_edge Trigger edge, as defined in rp_main_params. |
||
229 | * @param [in] trig_delay Trigger delay in [s]. |
||
230 | * @param [in] trig_level Trigger level in [V]. |
||
231 | * @param [in] time_range Time range, as defined in rp_main_params. |
||
232 | * @param [in] equal Enable(1)/disable(0) equalization filter. |
||
233 | * @param [in] shaping Enable(1)/disable(0) shaping filter. |
||
234 | * @param [in] gain1 Gain setting for Channel1 (0 = LV, 1 = HV). |
||
235 | * @param [in] gain2 Gain setting for Channel2 (0 = LV, 1 = HV). |
||
236 | * |
||
237 | * |
||
238 | * @retval 0 Success |
||
239 | * @retval -1 Failure |
||
240 | * |
||
241 | * @see rp_main_params |
||
242 | */ |
||
243 | int osc_fpga_update_params(int trig_imm, int trig_source, int trig_edge, |
||
244 | float trig_delay, float trig_level, int time_range, |
||
245 | int equal, int shaping, int gain1, int gain2) |
||
246 | { |
||
247 | int fpga_trig_source = osc_fpga_cnv_trig_source(trig_imm, trig_source, |
||
248 | trig_edge); |
||
249 | int fpga_dec_factor = osc_fpga_cnv_time_range_to_dec(time_range); |
||
250 | int fpga_delay; |
||
251 | float after_trigger; /* how much after trigger FPGA should write */ |
||
252 | int fpga_trig_thr = osc_fpga_cnv_v_to_cnt(trig_level); |
||
253 | |||
254 | /* Equalization filter coefficients */ |
||
255 | ecu_shape_filter_t cha_filt; |
||
256 | ecu_shape_filter_t chb_filt; |
||
257 | get_equ_shape_filter(&cha_filt, equal, shaping, gain1); |
||
258 | get_equ_shape_filter(&chb_filt, equal, shaping, gain2); |
||
259 | |||
260 | if((fpga_trig_source < 0) || (fpga_dec_factor < 0)) { |
||
261 | fprintf(stderr, "osc_fpga_update_params() failed\n"); |
||
262 | return -1; |
||
263 | } |
||
264 | |||
265 | /* Pre-trigger - we need to limit after trigger acquisition so we can |
||
266 | * readout historic (pre-trigger) values */ |
||
267 | |||
268 | if (trig_imm) |
||
269 | after_trigger=OSC_FPGA_SIG_LEN* c_osc_fpga_smpl_period * fpga_dec_factor; |
||
270 | else |
||
271 | after_trigger = |
||
272 | ((OSC_FPGA_SIG_LEN-7) * c_osc_fpga_smpl_period * fpga_dec_factor) + |
||
273 | trig_delay; |
||
274 | |||
275 | if(after_trigger < 0) |
||
276 | after_trigger = 0; |
||
277 | |||
278 | fpga_delay = osc_fpga_cnv_time_to_smpls(after_trigger, fpga_dec_factor); |
||
279 | |||
280 | /* Trig source is written after ARM */ |
||
281 | /* g_osc_fpga_reg_mem->trig_source = fpga_trig_source;*/ |
||
282 | if(trig_source == 0) |
||
283 | g_osc_fpga_reg_mem->cha_thr = fpga_trig_thr; |
||
284 | else |
||
285 | g_osc_fpga_reg_mem->chb_thr = fpga_trig_thr; |
||
286 | |||
287 | g_osc_fpga_reg_mem->data_dec = fpga_dec_factor; |
||
288 | g_osc_fpga_reg_mem->trigger_delay = (uint32_t)fpga_delay; |
||
289 | |||
290 | /* Update equalization filter with desired coefficients. */ |
||
291 | g_osc_fpga_reg_mem->cha_filt_aa = cha_filt.aa; |
||
292 | g_osc_fpga_reg_mem->cha_filt_bb = cha_filt.bb; |
||
293 | g_osc_fpga_reg_mem->cha_filt_pp = cha_filt.pp; |
||
294 | g_osc_fpga_reg_mem->cha_filt_kk = cha_filt.kk; |
||
295 | |||
296 | g_osc_fpga_reg_mem->chb_filt_aa = chb_filt.aa; |
||
297 | g_osc_fpga_reg_mem->chb_filt_bb = chb_filt.bb; |
||
298 | g_osc_fpga_reg_mem->chb_filt_pp = chb_filt.pp; |
||
299 | g_osc_fpga_reg_mem->chb_filt_kk = chb_filt.kk; |
||
300 | |||
301 | return 0; |
||
302 | } |
||
303 | |||
304 | /** @brief OSC FPGA reset |
||
305 | * |
||
306 | * Triggers internal oscilloscope FPGA state machine reset. |
||
307 | * |
||
308 | * @retval 0 Always returns 0. |
||
309 | */ |
||
310 | int osc_fpga_reset(void) |
||
311 | { |
||
312 | g_osc_fpga_reg_mem->conf |= OSC_FPGA_CONF_RST_BIT; |
||
313 | return 0; |
||
314 | } |
||
315 | |||
316 | /** @brief OSC FPGA ARM |
||
317 | * |
||
318 | * ARM internal oscilloscope FPGA state machine to start writting input buffers. |
||
319 | |||
320 | * @retval 0 Always returns 0. |
||
321 | */ |
||
322 | int osc_fpga_arm_trigger(void) |
||
323 | { |
||
324 | g_osc_fpga_reg_mem->conf |= OSC_FPGA_CONF_ARM_BIT; |
||
325 | |||
326 | return 0; |
||
327 | } |
||
328 | |||
329 | /** @brief Sets the trigger source in OSC FPGA register. |
||
330 | * |
||
331 | * Sets the trigger source in oscilloscope FPGA register. |
||
332 | * |
||
333 | * @param [in] trig_source Trigger source, as defined in FPGA register |
||
334 | * description. |
||
335 | */ |
||
336 | int osc_fpga_set_trigger(uint32_t trig_source) |
||
337 | { |
||
338 | g_osc_fpga_reg_mem->trig_source = trig_source; |
||
339 | return 0; |
||
340 | } |
||
341 | |||
342 | /** @brief Sets the trigger delay in OSC FPGA register. |
||
343 | * |
||
344 | * Sets the trigger delay in oscilloscope FPGA register. |
||
345 | * |
||
346 | * @param [in] trig_delay Trigger delay, as defined in FPGA register |
||
347 | * description. |
||
348 | * |
||
349 | * @retval 0 Always returns 0. |
||
350 | */ |
||
351 | int osc_fpga_set_trigger_delay(uint32_t trig_delay) |
||
352 | { |
||
353 | g_osc_fpga_reg_mem->trigger_delay = trig_delay; |
||
354 | return 0; |
||
355 | } |
||
356 | |||
357 | /** @brief Checks if FPGA detected trigger. |
||
358 | * |
||
359 | * This function checks if trigger was detected by the FPGA. |
||
360 | * |
||
361 | * @retval 0 Trigger not detected. |
||
362 | * @retval 1 Trigger detected. |
||
363 | */ |
||
364 | int osc_fpga_triggered(void) |
||
365 | { |
||
366 | return ((g_osc_fpga_reg_mem->trig_source & OSC_FPGA_TRIG_SRC_MASK)==0); |
||
367 | } |
||
368 | |||
369 | /** @brief Returns memory pointers for both input signal buffers. |
||
370 | * |
||
371 | * This function returns pointers for input signal buffers for both channels. |
||
372 | * |
||
373 | * @param [out] cha_signal Output pointer for Channel A buffer |
||
374 | * @param [out] cha_signal Output pointer for Channel B buffer |
||
375 | * |
||
376 | * @retval 0 Always returns 0. |
||
377 | */ |
||
378 | int osc_fpga_get_sig_ptr(int **cha_signal, int **chb_signal) |
||
379 | { |
||
380 | *cha_signal = (int *)g_osc_fpga_cha_mem; |
||
381 | *chb_signal = (int *)g_osc_fpga_chb_mem; |
||
382 | return 0; |
||
383 | } |
||
384 | |||
385 | /** @brief Returns values for current and trigger write FPGA pointers. |
||
386 | * |
||
387 | * This functions returns values for current and trigger write pointers. They |
||
388 | * are an address of the input signal buffer and are the same for both channels. |
||
389 | * |
||
390 | * @param [out] wr_ptr_curr Current FPGA input buffer address. |
||
391 | * @param [out] wr_ptr_trig Trigger FPGA input buffer address. |
||
392 | * |
||
393 | * @retval 0 Always returns 0. |
||
394 | */ |
||
395 | int osc_fpga_get_wr_ptr(int *wr_ptr_curr, int *wr_ptr_trig) |
||
396 | { |
||
397 | if(wr_ptr_curr) |
||
398 | *wr_ptr_curr = g_osc_fpga_reg_mem->wr_ptr_cur; |
||
399 | if(wr_ptr_trig) |
||
400 | *wr_ptr_trig = g_osc_fpga_reg_mem->wr_ptr_trigger; |
||
401 | return 0; |
||
402 | } |
||
403 | |||
404 | /** @brief Convert trigger parameters to FPGA trigger source value. |
||
405 | * |
||
406 | * This function takes as an argument trigger parameters and converts it to |
||
407 | * trigger source value used by the FPGA trigger source reigster. |
||
408 | * |
||
409 | * @param [in] trig_imm Trigger immediately, if set to 1 other trigger parameters |
||
410 | * are ignored. |
||
411 | * @param [in] trig_source Trigger source as defined in rp_main_params |
||
412 | * @param [in] trig_edge Trigger edge as defined in rp_main_params |
||
413 | * |
||
414 | * @retval -1 Error |
||
415 | * @retval otherwise Trigger source FPGA value |
||
416 | */ |
||
417 | int osc_fpga_cnv_trig_source(int trig_imm, int trig_source, int trig_edge) |
||
418 | { |
||
419 | int fpga_trig_source = 0; |
||
420 | |||
421 | /* Trigger immediately */ |
||
422 | if(trig_imm) |
||
423 | return 1; |
||
424 | |||
425 | switch(trig_source) { |
||
426 | case 0: /* ChA*/ |
||
427 | if(trig_edge == 0) |
||
428 | fpga_trig_source = 2; |
||
429 | else |
||
430 | fpga_trig_source = 3; |
||
431 | break; |
||
432 | case 1: /* ChB*/ |
||
433 | if(trig_edge == 0) |
||
434 | fpga_trig_source = 4; |
||
435 | else |
||
436 | fpga_trig_source = 5; |
||
437 | break; |
||
438 | case 2: /* External */ |
||
439 | if(trig_edge == 0) |
||
440 | fpga_trig_source = 6; |
||
441 | else |
||
442 | fpga_trig_source = 7; |
||
443 | |||
444 | break; |
||
445 | default: |
||
446 | /* Error */ |
||
447 | return -1; |
||
448 | } |
||
449 | |||
450 | return fpga_trig_source; |
||
451 | } |
||
452 | |||
453 | /** @brief Converts time range to decimation value. |
||
454 | * |
||
455 | * This function converts time range value defined by rp_main_params to |
||
456 | * decimation factor value. |
||
457 | * |
||
458 | * @param [in] time_range Time range, integer between 0 and 5, as defined by |
||
459 | * rp_main_params. |
||
460 | * |
||
461 | * @retval -1 Error |
||
462 | * |
||
463 | * @retval otherwise Decimation factor. |
||
464 | */ |
||
465 | int osc_fpga_cnv_time_range_to_dec(int time_range) |
||
466 | { |
||
467 | /* Input: 0, 1, 2, 3, 4, 5 translates to: |
||
468 | * Output: 1x, 8x, 64x, 1kx, 8kx, 65kx */ |
||
469 | switch(time_range) { |
||
470 | case 0: |
||
471 | return 1; |
||
472 | break; |
||
473 | case 1: |
||
474 | return 8; |
||
475 | break; |
||
476 | case 2: |
||
477 | return 64; |
||
478 | break; |
||
479 | case 3: |
||
480 | return 1024; |
||
481 | break; |
||
482 | case 4: |
||
483 | return 8*1024; |
||
484 | break; |
||
485 | case 5: |
||
486 | return 64*1024; |
||
487 | break; |
||
488 | default: |
||
489 | return -1; |
||
490 | } |
||
491 | |||
492 | return -1; |
||
493 | } |
||
494 | |||
495 | /** @brief Converts time to number of samples. |
||
496 | * |
||
497 | * This function converts time in [s], based on current decimation factor to |
||
498 | * number of samples at ADC sampling frequency. |
||
499 | * |
||
500 | * @param [in] time Time in [s] |
||
501 | * @param [in] dec_factor Decimation factor |
||
502 | * |
||
503 | * @retval Number of ADC samples define dby input parameters. |
||
504 | */ |
||
505 | int osc_fpga_cnv_time_to_smpls(float time, int dec_factor) |
||
506 | { |
||
507 | /* Calculate sampling period (including decimation) */ |
||
508 | float smpl_p = (c_osc_fpga_smpl_period * dec_factor); |
||
509 | int fpga_smpls = (int)round(time / smpl_p); |
||
510 | |||
511 | return fpga_smpls; |
||
512 | } |
||
513 | |||
514 | /** @brief Converts voltage to ADC counts. |
||
515 | * |
||
516 | * This function converts voltage in [V] to ADC counts. |
||
517 | * |
||
518 | * @param [in] voltage Voltage in [V] |
||
519 | * |
||
520 | * @retval adc_cnts ADC counts |
||
521 | */ |
||
522 | int osc_fpga_cnv_v_to_cnt(float voltage) |
||
523 | { |
||
524 | int adc_cnts = 0; |
||
525 | |||
526 | if((voltage > c_osc_fpga_adc_max_v) || (voltage < -c_osc_fpga_adc_max_v)) |
||
527 | return -1; |
||
528 | |||
529 | adc_cnts = (int)round(voltage * (float)((int)(1<<c_osc_fpga_adc_bits)) / |
||
530 | (2*c_osc_fpga_adc_max_v)); |
||
531 | |||
532 | /* Clip highest value (+14 is calculated in int32_t to 0x2000, but we have |
||
533 | * only 14 bits |
||
534 | */ |
||
535 | if((voltage > 0) && (adc_cnts & (1<<(c_osc_fpga_adc_bits-1)))) |
||
536 | adc_cnts = (1<<(c_osc_fpga_adc_bits-1))-1; |
||
537 | else |
||
538 | adc_cnts = adc_cnts & ((1<<(c_osc_fpga_adc_bits))-1); |
||
539 | |||
540 | return adc_cnts; |
||
541 | } |
||
542 | |||
543 | /** @brief Converts ADC counts to voltage |
||
544 | * |
||
545 | * This function converts ADC counts to voltage (in [V]) |
||
546 | * |
||
547 | * @param [in] cnts ADC counts |
||
548 | * |
||
549 | * @retval voltage Voltage in [V] |
||
550 | */ |
||
551 | float osc_fpga_cnv_cnt_to_v(int cnts) |
||
552 | { |
||
553 | int m; |
||
554 | |||
555 | if(cnts & (1<<(c_osc_fpga_adc_bits-1))) { |
||
556 | /* negative number */ |
||
557 | m = -1 *((cnts ^ ((1<<c_osc_fpga_adc_bits)-1)) + 1); |
||
558 | } else { |
||
559 | m = cnts; |
||
560 | /* positive number */ |
||
561 | } |
||
562 | return m; |
||
563 | } |
||
564 |