Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
A
adc-lib
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
misc
adc-lib
Commits
d3b68357
Commit
d3b68357
authored
Oct 22, 2018
by
Federico Vaga
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature/zero-offset' into develop
parents
8ba919e1
443e1442
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
666 additions
and
5 deletions
+666
-5
library-user.rst
doc/library-user.rst
+31
-0
Makefile
lib/Makefile
+1
-0
adc-lib-100m14b4cha.h
lib/adc-lib-100m14b4cha.h
+10
-0
adc-lib-int.h
lib/adc-lib-int.h
+7
-0
adc-lib.h
lib/adc-lib.h
+37
-0
fmc-adc-100m14b4cha.c
lib/fmc-adc-100m14b4cha.c
+294
-0
lib-math.c
lib/lib-math.c
+62
-0
lib.c
lib/lib.c
+76
-0
route.c
lib/route.c
+49
-1
adc-acq.c
tools/adc-acq.c
+99
-4
No files found.
doc/library-user.rst
View file @
d3b68357
...
...
@@ -207,7 +207,34 @@ and get values with :cpp:func:`adc_get_param()`
err = adc_set_param(adc, "identifier", NULL, &v_int);
err = adc_get_param(adc, "identifier", NULL, &v_int);
Offset Auto Clear
'''''''''''''''''
It may happen that due to temperature or other external factors there are
constant offsets on channels. This library, through function
:cpp:func:`adc_offset_auto_clear()` offers a mechanism to be able
to compensate these offsets.::
err = adc_offset_auto_clear(adc, 2, 0x0);
During this procedure, by default, the library will disconnect any input
signal and connect the channel to the local ground level. By using the flag
:cpp:any:`ADC_OFFSET_AC_F_MANUAL` it is possible to use the current input signal
and compensate it.
During this process, the library may change the ADC configuration.
It is possible to ask the library to restore any previous configuration by
using the flag :cpp:any:`ADC_OFFSET_AC_F_RESTORE`.
If this feature is not supported in hardware or in the driver, it is possible
to ask for a software implementation by using the flag
:cpp:any:`ADC_OFFSET_AC_F_SOFTWARE`. In this case the idea is to run some
acquisitions, compute the average and apply this value as offset compensation.
If on a particular board the offset auto-clear needs extra parameters, you
have to set them using :ref:`board specific configurations<lib:usr:cfg:cus>`.
.. _`lib:usr:cfg:cus`:
Board Specific Configuration
''''''''''''''''''''''''''''
...
...
@@ -255,6 +282,10 @@ since the specifc parameters for this card are global, so there is no need for
any routing mechanism.
Following some special values defined for this board.
.. doxygenenum:: adc_configuration_100m14b4cha_channel_range
Acquisition
-----------
...
...
lib/Makefile
View file @
d3b68357
...
...
@@ -23,6 +23,7 @@ LOBJ += init.o
LOBJ
+=
config-zio.o
LOBJ
+=
buffer-zio.o
LOBJ
+=
lib.o
LOBJ
+=
lib-math.o
LOBJ
+=
adc-ziofake.o
LOBJ
+=
adc-genericfake.o
LOBJ
+=
adc-zio.o
...
...
lib/adc-lib-100m14b4cha.h
View file @
d3b68357
...
...
@@ -23,6 +23,16 @@ extern "C" {
#include "adc-lib.h"
/**
* List of known voltage ranges to be used with the configuration option
* ADC_CONF_CHN_RANGE
*/
enum
adc_configuration_100m14b4cha_channel_range
{
ADC_CONF_100M14B4CHA_CHN_RANGE_OPEN_DRAIN
=
0
,
ADC_CONF_100M14B4CHA_CHN_RANGE_100mV
=
0x23
,
ADC_CONF_100M14B4CHA_CHN_RANGE_1V
=
0x11
,
ADC_CONF_100M14B4CHA_CHN_RANGE_10V
=
0x45
,
};
/**
* List of possible buffer types (options for ADC_CONF_100M14B4CHA_BUF_TYPE)
...
...
lib/adc-lib-int.h
View file @
d3b68357
...
...
@@ -47,6 +47,7 @@ struct adc_operations {
typeof
(
adc_trigger_fire
)
*
trigger_fire
;
/**< @related adc_trigger_fire */
typeof
(
adc_buffer_get_sample
)
*
buffer_get_sample
;
/**< @related adc_buffer_get_sample */
typeof
(
adc_buffer_fixup
)
*
buffer_fixup
;
/**< @related adc_buffer_fixup*/
typeof
(
adc_offset_auto_clear
)
*
offset_auto_clear
;
/**< @related adc_offset_auto_clear */
};
...
...
@@ -183,6 +184,12 @@ int adc_zio_get_param(struct adc_dev *dev, char *name,
int
adc_zio_sysfs_set
(
struct
__adc_dev_zio
*
fa
,
char
*
name
,
uint32_t
*
value
);
int
adc_offset_auto_clear_sw_avg
(
struct
adc_dev
*
dev
,
unsigned
int
chan
,
unsigned
int
nsamples
,
unsigned
long
flags
,
int32_t
*
offset
);
/*adc-genericfake*/
...
...
lib/adc-lib.h
View file @
d3b68357
...
...
@@ -26,6 +26,12 @@ extern "C" {
#define ADC_ENOMASK 1030
#define ADC_EDISABLED 1031
#define ADC_EROUTE 1032
#define ADC_ENOP_SWTRG 1033
#define ADC_ENOP_OFFCLR 1034
#define ADC_ENOP_OFFCLRHW 1035
#define ADC_ENOP_OFFCLRSW 1036
#define ADC_OFF_AC_RESTORE_S 1037
#define ADC_OFF_AC_RESTORE_R 1038
/**
* Opaque type. any instance of this should be used as token
...
...
@@ -269,6 +275,24 @@ struct adc_conf {
#define ADC_F_FIXUP 0x00400000
/**< Flag used to fixup a buffer when
filling it (usable by adc_fill_buffer) */
/**
* Enumeration of all possible flags to driver the auto-clear offset
*/
enum
adc_offset_auto_clear_flags
{
ADC_OFFSET_AC_F_MANUAL
=
0x00000001
,
/**< the signal will be acquired with
the last configuration set */
ADC_OFFSET_AC_F_RESTORE
=
0x00000002
,
/**< restore previous
configuration when done. It
does not have any effect when
MANUAL is active*/
ADC_OFFSET_AC_F_SOFTWARE
=
0x00000004
,
/**< use software mechanism,
it implies manual
configuration */
__ADC_OFFSET_AC_F_MASK
=
(
ADC_OFFSET_AC_F_MANUAL
|
ADC_OFFSET_AC_F_RESTORE
|
ADC_OFFSET_AC_F_SOFTWARE
),
/**< used internally */
};
/**
* @defgroup dev Basic
* Basic library functions
...
...
@@ -290,6 +314,9 @@ extern struct adc_dev *adc_open_by_lun(char *name, int lun,
extern
int
adc_close
(
struct
adc_dev
*
dev
);
extern
int
adc_trigger_fire
(
struct
adc_dev
*
dev
);
extern
int
adc_has_trigger_fire
(
struct
adc_dev
*
dev
);
extern
int
adc_offset_auto_clear
(
struct
adc_dev
*
dev
,
unsigned
int
chan
,
unsigned
long
flags
);
/**@}*/
...
...
@@ -406,6 +433,16 @@ extern int adc_buffer_get_sample(struct adc_buffer *buf,
extern
int
adc_buffer_fixup
(
struct
adc_buffer
*
buf
);
/**@}*/
/**
* @defgroup buf_math Buffer Math
* Mathematical operations on buffers
* @{
*/
extern
int
adc_buffer_math_avg
(
struct
adc_buffer
*
buf
,
unsigned
int
chan
,
int32_t
*
avg
);
/**@}*/
/* libfmcadc version string */
extern
const
char
*
const
libadc_version_s
;
...
...
lib/fmc-adc-100m14b4cha.c
View file @
d3b68357
...
...
@@ -36,6 +36,8 @@
#define ADC_CONF_GET 0
#define ADC_CONF_SET 1
#define __ADC_CONF_CHN_OFFSET_ZERO 200
static
typeof
(
adc_get_param
)
*
adc_param
[]
=
{
[
ADC_CONF_GET
]
=
adc_get_param
,
[
ADC_CONF_SET
]
=
adc_set_param
,
...
...
@@ -335,6 +337,9 @@ static int adc_100m14b4cha_config_chn(struct adc_dev *adc,
case
ADC_CONF_CHN_OFFSET
:
sprintf
(
path
,
"cset%d/ch%d-offset"
,
fa
->
cset
,
source
);
break
;
case
__ADC_CONF_CHN_OFFSET_ZERO
:
sprintf
(
path
,
"cset%d/ch%d-offset-zero"
,
fa
->
cset
,
source
);
break
;
case
ADC_CONF_CHN_SATURATION
:
sprintf
(
path
,
"cset%d/ch%d-saturation"
,
fa
->
cset
,
source
);
break
;
...
...
@@ -734,6 +739,294 @@ static int adc_100m14b4cha_buffer_get_sample(struct adc_buffer *buf,
return
0
;
}
struct
tmp_cfg_store
{
uint32_t
trg_source
;
uint32_t
pre
;
uint32_t
post
;
uint32_t
nshots
;
uint32_t
undersample
;
uint32_t
chan
;
uint32_t
range
;
uint32_t
termination
;
uint32_t
saturation
;
uint32_t
offset
;
};
static
int
__cfg_offac_save
(
struct
adc_dev
*
dev
,
unsigned
int
chan
,
struct
tmp_cfg_store
*
cfg
,
unsigned
long
flags
)
{
int
err
;
if
((
flags
&
ADC_OFFSET_AC_F_MANUAL
)
||
!
(
flags
&
ADC_OFFSET_AC_F_RESTORE
))
return
0
;
cfg
->
chan
=
chan
;
err
=
adc_100m14b4cha_config_acq
(
dev
,
ADC_CONF_ACQ_PRE_SAMP
,
&
cfg
->
pre
,
ADC_CONF_GET
);
if
(
err
)
goto
err
;
err
=
adc_100m14b4cha_config_acq
(
dev
,
ADC_CONF_ACQ_POST_SAMP
,
&
cfg
->
post
,
ADC_CONF_GET
);
if
(
err
)
goto
err
;
err
=
adc_100m14b4cha_config_acq
(
dev
,
ADC_CONF_ACQ_N_SHOTS
,
&
cfg
->
nshots
,
ADC_CONF_GET
);
if
(
err
)
goto
err
;
err
=
adc_100m14b4cha_config_acq
(
dev
,
ADC_CONF_ACQ_UNDERSAMPLE
,
&
cfg
->
undersample
,
ADC_CONF_GET
);
if
(
err
)
goto
err
;
err
=
adc_100m14b4cha_config_chn
(
dev
,
cfg
->
chan
,
ADC_CONF_CHN_RANGE
,
&
cfg
->
range
,
ADC_CONF_GET
);
if
(
err
)
goto
err
;
err
=
adc_100m14b4cha_config_chn
(
dev
,
cfg
->
chan
,
ADC_CONF_CHN_TERMINATION
,
&
cfg
->
termination
,
ADC_CONF_GET
);
if
(
err
)
goto
err
;
err
=
adc_100m14b4cha_config_chn
(
dev
,
cfg
->
chan
,
ADC_CONF_CHN_SATURATION
,
&
cfg
->
saturation
,
ADC_CONF_GET
);
if
(
err
)
goto
err
;
err
=
adc_100m14b4cha_config_chn
(
dev
,
cfg
->
chan
,
ADC_CONF_CHN_OFFSET
,
&
cfg
->
offset
,
ADC_CONF_GET
);
if
(
err
)
goto
err
;
err
=
adc_get_param
(
dev
,
"cset0/trigger/source"
,
NULL
,
(
int
*
)
&
cfg
->
trg_source
);
if
(
err
)
goto
err
;
return
0
;
err:
errno
=
ADC_OFF_AC_RESTORE_S
;
return
err
;
}
static
int
__cfg_offac_restore
(
struct
adc_dev
*
dev
,
struct
tmp_cfg_store
*
cfg
,
unsigned
long
flags
)
{
int
err
=
0
;
if
((
flags
&
ADC_OFFSET_AC_F_MANUAL
)
||
!
(
flags
&
ADC_OFFSET_AC_F_RESTORE
))
return
0
;
err
|=
adc_100m14b4cha_config_acq
(
dev
,
ADC_CONF_ACQ_PRE_SAMP
,
&
cfg
->
pre
,
ADC_CONF_SET
);
err
|=
adc_100m14b4cha_config_acq
(
dev
,
ADC_CONF_ACQ_POST_SAMP
,
&
cfg
->
post
,
ADC_CONF_SET
);
err
|=
adc_100m14b4cha_config_acq
(
dev
,
ADC_CONF_ACQ_N_SHOTS
,
&
cfg
->
nshots
,
ADC_CONF_SET
);
err
|=
adc_100m14b4cha_config_acq
(
dev
,
ADC_CONF_ACQ_UNDERSAMPLE
,
&
cfg
->
undersample
,
ADC_CONF_SET
);
err
|=
adc_100m14b4cha_config_chn
(
dev
,
cfg
->
chan
,
ADC_CONF_CHN_RANGE
,
&
cfg
->
range
,
ADC_CONF_SET
);
err
|=
adc_100m14b4cha_config_chn
(
dev
,
cfg
->
chan
,
ADC_CONF_CHN_TERMINATION
,
&
cfg
->
termination
,
ADC_CONF_SET
);
err
|=
adc_100m14b4cha_config_chn
(
dev
,
cfg
->
chan
,
ADC_CONF_CHN_SATURATION
,
&
cfg
->
saturation
,
ADC_CONF_SET
);
err
|=
adc_100m14b4cha_config_chn
(
dev
,
cfg
->
chan
,
ADC_CONF_CHN_OFFSET
,
&
cfg
->
offset
,
ADC_CONF_SET
);
err
|=
adc_set_param
(
dev
,
"cset0/trigger/source"
,
NULL
,
(
int
*
)
&
cfg
->
trg_source
);
if
(
err
)
errno
=
ADC_OFF_AC_RESTORE_R
;
return
err
;
}
#define CFG_OFFAC_NSAMPLES 100000
static
struct
adc_conf
cfg_off_acq
=
{
.
type
=
ADC_CONF_TYPE_ACQ
,
.
mask
=
(
1ULL
<<
ADC_CONF_ACQ_N_SHOTS
)
|
(
1ULL
<<
ADC_CONF_ACQ_PRE_SAMP
)
|
(
1ULL
<<
ADC_CONF_ACQ_POST_SAMP
)
|
(
1ULL
<<
ADC_CONF_ACQ_UNDERSAMPLE
),
.
value
=
{
[
ADC_CONF_ACQ_N_SHOTS
]
=
1
,
[
ADC_CONF_ACQ_PRE_SAMP
]
=
0
,
[
ADC_CONF_ACQ_POST_SAMP
]
=
CFG_OFFAC_NSAMPLES
,
[
ADC_CONF_ACQ_UNDERSAMPLE
]
=
0
,
},
};
static
struct
adc_conf
cfg_off_cus
=
{
.
type
=
ADC_CONF_TYPE_CUS
,
.
mask
=
(
1ULL
<<
ADC_CONF_100M14B4CHA_TRG_SW_EN
)
|
(
1ULL
<<
ADC_CONF_100M14B4CHA_BUF_SIZE_KB
),
.
value
=
{
[
ADC_CONF_100M14B4CHA_TRG_SW_EN
]
=
1
,
[
ADC_CONF_100M14B4CHA_BUF_SIZE_KB
]
=
2048
,
},
};
/**
* It configures the ADC for the offset auto-clear
* @param[in] dev ADC token
* @param[in] chan channel number [0, 4]
* @param[in] flags options
*
* @return 0 on success, otherwise -1 and errno is appropriately set
*
* pre-sample: 0
* post-sample: 100000
* undersample: 0
* nshots: 1
* offset: 0
* range: open-drain
* sw-trg: enable
* buf-size: 2MiB
*/
static
int
__cfg_offac_apply
(
struct
adc_dev
*
dev
,
unsigned
int
chan
,
unsigned
long
flags
)
{
int
err
,
trgsrc
=
FA100M14B4C_TRG_SRC_SW
;
uint32_t
range
=
0
,
offset
=
0
;
if
(
flags
&
ADC_OFFSET_AC_F_MANUAL
)
return
0
;
err
=
adc_set_param
(
dev
,
"cset0/trigger/source"
,
NULL
,
&
trgsrc
);
if
(
err
)
return
-
1
;
err
=
adc_apply_config
(
dev
,
0
,
&
cfg_off_acq
);
if
(
err
)
return
-
1
;
err
=
adc_apply_config
(
dev
,
0
,
&
cfg_off_cus
);
if
(
err
)
return
-
1
;
err
=
adc_100m14b4cha_config_chn
(
dev
,
chan
,
ADC_CONF_CHN_RANGE
,
&
range
,
ADC_CONF_SET
);
if
(
err
)
return
-
1
;
err
=
adc_100m14b4cha_config_chn
(
dev
,
chan
,
ADC_CONF_CHN_OFFSET
,
&
offset
,
ADC_CONF_SET
);
if
(
err
)
return
-
1
;
err
=
adc_100m14b4cha_config_chn
(
dev
,
chan
,
__ADC_CONF_CHN_OFFSET_ZERO
,
&
offset
,
ADC_CONF_SET
);
if
(
err
)
return
-
1
;
return
0
;
}
/**
* It converts an hardware value to uV
* @param[in] val value to be converted (hardware format)
* @param[in] range switch configuration read from the hardware
*
* @return uV value
*/
static
int32_t
__convert_hw_to_uv
(
int32_t
val
,
unsigned
int
range
)
{
int32_t
result_int
,
result_frac
,
range_uV
,
factor
;
switch
(
range
)
{
case
0x45
:
range_uV
=
10000000
;
break
;
case
0x23
:
range_uV
=
100000
;
break
;
case
0x11
:
case
0x00
:
range_uV
=
1000000
;
break
;
default:
fprintf
(
stderr
,
"Invalid switch configuration 0x%x
\n
"
,
range
);
return
0
;
}
factor
=
(
range_uV
/
BIT
(
14
));
result_int
=
((
val
>>
2
)
*
factor
);
result_frac
=
((
val
&
0x3
)
*
10
)
*
(
factor
/
1000
);
return
result_int
+
result_frac
;
}
static
int
adc_100m14b4cha_offset_auto_clear
(
struct
adc_dev
*
dev
,
unsigned
int
chan
,
unsigned
long
flags
)
{
struct
tmp_cfg_store
tmpcfg
;
int32_t
offset
;
int
err
,
err_rst
;
uint32_t
range
;
flags
|=
ADC_OFFSET_AC_F_SOFTWARE
;
err
=
__cfg_offac_save
(
dev
,
chan
,
&
tmpcfg
,
flags
);
if
(
err
)
return
err
;
err
=
__cfg_offac_apply
(
dev
,
chan
,
flags
);
if
(
err
)
goto
err
;
err
=
adc_offset_auto_clear_sw_avg
(
dev
,
chan
,
CFG_OFFAC_NSAMPLES
,
flags
,
&
offset
);
if
(
err
)
goto
err
;
err
=
adc_100m14b4cha_config_chn
(
dev
,
chan
,
ADC_CONF_CHN_RANGE
,
&
range
,
ADC_CONF_GET
);
if
(
err
)
goto
err
;
err_rst
=
__cfg_offac_restore
(
dev
,
&
tmpcfg
,
flags
);
if
(
err_rst
)
{
errno
=
ADC_OFF_AC_RESTORE_R
;
return
err_rst
;
}
/*
* Since the Hw does (Vin - Vdac), to compensate a positive offset
* we need to apply a positive value to the DAC. For this reason
* we do not need to revert that value: the offset sign measured it
* is fine
*/
offset
=
__convert_hw_to_uv
(
offset
,
range
);
return
adc_100m14b4cha_config_chn
(
dev
,
chan
,
__ADC_CONF_CHN_OFFSET_ZERO
,
(
uint32_t
*
)
&
offset
,
ADC_CONF_SET
);
err:
err_rst
=
__cfg_offac_restore
(
dev
,
&
tmpcfg
,
flags
);
if
(
err_rst
)
{
errno
=
ADC_OFF_AC_RESTORE_R
;
return
err_rst
;
}
return
err
;
}
#define ADC_100M_4CH_14BIT_ACQ_MASK (1LL << ADC_CONF_ACQ_N_SHOTS) | \
(1LL << ADC_CONF_ACQ_POST_SAMP) | \
(1LL << ADC_CONF_ACQ_PRE_SAMP) | \
...
...
@@ -785,6 +1078,7 @@ static struct adc_operations fa_100ms_4ch_14bit_op = {
.
buffer_get_sample
=
adc_100m14b4cha_buffer_get_sample
,
.
buffer_fixup
=
NULL
,
.
offset_auto_clear
=
adc_100m14b4cha_offset_auto_clear
,
};
struct
adc_board_type
fmcadc_100ms_4ch_14bit
=
{
...
...
lib/lib-math.c
0 → 100644
View file @
d3b68357
/*
* Routing public functions to device-specific code
*
* Copyright (C) 2018 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2 as published by the Free Software Foundation or, at your
* option, any later version.
*/
#include <errno.h>
#include <string.h>
#include "adc-lib.h"
#include "adc-lib-int.h"
/**
* It computes the avarege voltage within the given buffer
* @param[in] buf data set to use
* @param[in] chan channel number [0, NCHAN]
* @param[out] avg the computer avarage. The scale depends on the
* configuration,
* @return 0 on success, -1 on error and errno is set appropriately
* EINVAL: if the buffer is invalid, or channel is invalid
*/
int
adc_buffer_math_avg
(
struct
adc_buffer
*
buf
,
unsigned
int
chan
,
int32_t
*
avg
)
{
struct
adc_conf
cfg_brd
;
uint32_t
nchan
=
0
;
int
i
,
err
;
int64_t
total
=
0
;
memset
(
&
cfg_brd
,
0
,
sizeof
(
struct
adc_conf
));
cfg_brd
.
type
=
ADC_CONF_TYPE_BRD
;
adc_set_conf_mask_all
(
&
cfg_brd
,
buf
->
dev
);
err
=
adc_retrieve_config
(
buf
->
dev
,
&
cfg_brd
);
if
(
err
)
return
err
;
adc_get_conf
(
&
cfg_brd
,
ADC_CONF_BRD_N_CHAN
,
&
nchan
);
if
(
chan
>=
nchan
)
{
errno
=
EINVAL
;
return
-
1
;
}
for
(
i
=
0
;
i
<
buf
->
nsamples
;
++
i
)
{
int32_t
val
;
err
=
adc_buffer_get_sample
(
buf
,
chan
,
i
,
&
val
);
if
(
err
)
return
err
;
total
+=
val
;
}
*
avg
=
total
/
buf
->
nsamples
;
return
0
;
}
lib/lib.c
View file @
d3b68357
...
...
@@ -9,6 +9,7 @@
* version 2 as published by the Free Software Foundation or, at your
* option, any later version.
*/
#include <errno.h>
#include <string.h>
#include "adc-lib.h"
#include "adc-lib-int.h"
...
...
@@ -31,6 +32,12 @@ static struct adc_errors {
{
ADC_ENOMASK
,
"Missing configuration mask"
},
{
ADC_EDISABLED
,
"Trigger is disabled: I/O aborted"
},
{
ADC_EROUTE
,
"Cannot route correctly the configuration"
},
{
ADC_ENOP_SWTRG
,
"Operation not supported: software trigger"
},
{
ADC_ENOP_OFFCLR
,
"Operation not supported: offset auto-clear"
},
{
ADC_ENOP_OFFCLRHW
,
"Operation not supported: offset auto-clear hardware"
},
{
ADC_ENOP_OFFCLRSW
,
"Operation not supported: offset auto-clear software"
},
{
ADC_OFF_AC_RESTORE_S
,
"Offset auto-clear: cannot store configuration"
},
{
ADC_OFF_AC_RESTORE_R
,
"Offset auto-clear: cannot restore configuration"
},
{
0
,
}
};
...
...
@@ -86,3 +93,72 @@ uint64_t adc_get_capabilities(struct adc_dev *dev,
return
b
->
board
->
capabilities
[
type
];
}
/**
* It computes what is the necessary offset to apply on a given channel
* in order to clear a constant offset on a channel
* approach.
* @param[in] dev ADC device token
* @param[in] chan channel number
* @param[in] flags options @see adc_offset_auto_clear_flags
* @param[out] offset compensation offset
* @return 0 on success, -1 on error and errno is set appropriately
* EINVAL: invalid flags value
* ADC_ENOP_SWTRG: when software trigger is missing
*
* The configuration is board dependent, so here we just run and apply
* the compensation offset. The configuration is left to the user.
*
* Since this function uses software trigger, the user should disable
* all trigger sources except the software one.
*/
int
adc_offset_auto_clear_sw_avg
(
struct
adc_dev
*
dev
,
unsigned
int
chan
,
unsigned
int
nsamples
,
unsigned
long
flags
,
int32_t
*
offset
)
{
struct
adc_buffer
*
buf
;
struct
timeval
tv
=
{
0
,
0
};
int
err
,
err_stop
;
if
(
!
(
flags
&
ADC_OFFSET_AC_F_SOFTWARE
))
{
errno
=
EINVAL
;
return
-
1
;
}
if
(
!
adc_has_trigger_fire
(
dev
))
{
errno
=
ADC_ENOP_SWTRG
;
return
-
1
;
}
buf
=
adc_request_buffer
(
dev
,
nsamples
,
NULL
,
0
);
if
(
!
buf
)
return
-
1
;
err
=
adc_acq_start
(
dev
,
ADC_F_FLUSH
,
&
tv
);
if
(
err
)
goto
out
;
err
=
adc_trigger_fire
(
dev
);
if
(
err
)
goto
out
;
tv
.
tv_sec
=
10
;
err
=
adc_fill_buffer
(
dev
,
buf
,
0
,
&
tv
);
if
(
err
)
goto
out
;
err
=
adc_buffer_math_avg
(
buf
,
chan
,
offset
);
if
(
err
)
goto
out
;
out:
adc_release_buffer
(
dev
,
buf
,
NULL
);
err_stop
=
adc_acq_stop
(
dev
,
0
);
if
(
err_stop
)
return
err_stop
;
return
err
;
}
lib/route.c
View file @
d3b68357
...
...
@@ -508,6 +508,7 @@ int adc_has_trigger_fire(struct adc_dev *dev)
* It forces the board to trigger the acquisition
* @param[in] dev ADC device token
* @return 0 on success, -1 on error and errno is set appropriately
* ADC_ENOP_SWTRG: when software trigger is not supported
*/
int
adc_trigger_fire
(
struct
adc_dev
*
dev
)
{
...
...
@@ -515,7 +516,7 @@ int adc_trigger_fire(struct adc_dev *dev)
const
struct
adc_board_type
*
b
=
g
->
board
;
if
(
!
b
->
adc_op
->
trigger_fire
)
{
errno
=
ADC_ENOP
;
errno
=
ADC_ENOP
_SWTRG
;
return
-
1
;
}
return
b
->
adc_op
->
trigger_fire
(
dev
);
...
...
@@ -568,3 +569,50 @@ int adc_buffer_fixup(struct adc_buffer *buf)
return
b
->
adc_op
->
buffer_fixup
(
buf
);
return
0
;
}
/**
* It checks if the board support offset auto-clear
* @param[in] dev ADC device token
* @return 1 when it does support offset auto clear; 0 when it does not
*/
int
adc_has_offset_auto_clear
(
struct
adc_dev
*
dev
)
{
struct
adc_gid
*
g
=
(
struct
adc_gid
*
)
dev
;
const
struct
adc_board_type
*
b
=
g
->
board
;
return
!!
b
->
adc_op
->
offset_auto_clear
;
}
/**
* It clears aventual offsets on a given channel
* @param[in] dev ADC device token
* @param[in] chan channel number
* @param[in] flags options @see adc_offset_auto_clear_flags
* @return 0 on success, -1 on error and errno is set appropriately
* EINVAL: invalid flags value
* ADC_ENOP_OFFCLR: when offset auto-clear is not supported
*
* NOTE: The function may overwrite your current configuration (unless
* you use a flag) and it may remove any trace of previous acquisitions.
*
* Offset configuration is always overwritten (no matter what flag you use)
*/
int
adc_offset_auto_clear
(
struct
adc_dev
*
dev
,
unsigned
int
chan
,
unsigned
long
flags
)
{
struct
adc_gid
*
g
=
(
struct
adc_gid
*
)
dev
;
const
struct
adc_board_type
*
b
=
g
->
board
;
if
(
!
adc_has_offset_auto_clear
(
dev
))
{
errno
=
ADC_ENOP_OFFCLR
;
return
-
1
;
}
if
(
flags
&
~
__ADC_OFFSET_AC_F_MASK
)
{
errno
=
EINVAL
;
return
-
1
;
}
return
b
->
adc_op
->
offset_auto_clear
(
dev
,
chan
,
flags
);
}
tools/adc-acq.c
View file @
d3b68357
...
...
@@ -22,6 +22,7 @@
#include <unistd.h>
#include <inttypes.h>
#include <adc-lib.h>
#include <adc-lib-100m14b4cha.h>
static
int
arg_show_config
=
0
;
static
int
arg_no_read
=
0
;
...
...
@@ -29,6 +30,8 @@ static int arg_plot = 0;
static
int
arg_x_display
=
0
;
static
int
arg_trgsw_delay
=
0
;
static
int
arg_trgsw
=
0
;
static
int
fixup
=
0
;
static
int
statistics
=
0
;
static
char
git_version
[]
=
"version: "
GIT_VERSION
;
...
...
@@ -51,6 +54,7 @@ static void fald_help()
printf
(
" <NOT IMPLEMENTED YET>
\n
"
);
printf
(
" --trg-sw <parameters> configure a software trigger
\n
"
);
printf
(
" <delay_seconds>
\n
"
);
printf
(
" --off-clr <mode>,<idx> run offset-clear on a given channel (mode: {a: automatic, m: manual})
\n
"
);
printf
(
" --channel| -c <parameters> configure an acquisition channel
\n
"
);
printf
(
" <channel>,<termination>,<range>,<offset>,<saturation>
\n
"
);
printf
(
" --timeout|-T <millisec> timeout for acquisition
\n
"
);
...
...
@@ -64,6 +68,7 @@ static void fald_help()
">0 from head, <0 from tail
\n
"
);
printf
(
" --graph|-g <chnum> plot the desired channel
\n
"
);
printf
(
" --X11|-X Gnuplot will use X connection
\n
"
);
printf
(
" --stats It prints some statistics
\n
"
);
printf
(
" --version|-V print version information
\n
"
);
printf
(
" --help|-h show this help
\n\n
"
);
}
...
...
@@ -74,6 +79,7 @@ enum fald_acq_options {
FALD_ACQ_OPT_TRG_THR
,
FALD_ACQ_OPT_TRG_TIM
,
FALD_ACQ_OPT_TRG_SW
,
FALD_ACQ_OPT_OFF_CLR
,
};
static
struct
option
options
[]
=
{
...
...
@@ -85,6 +91,9 @@ static struct option options[] = {
{
"trg-sw"
,
required_argument
,
0
,
FALD_ACQ_OPT_TRG_SW
},
{
"channel"
,
required_argument
,
0
,
'c'
},
{
"timeout"
,
required_argument
,
0
,
'T'
},
{
"off-clr"
,
required_argument
,
0
,
FALD_ACQ_OPT_OFF_CLR
},
{
"fixup"
,
no_argument
,
&
fixup
,
1
},
{
"stats"
,
no_argument
,
&
statistics
,
1
},
/* new options, to help stress-test */
...
...
@@ -448,15 +457,15 @@ static int fald_acq_channel_configuration(struct adc_dev *adc, char *param)
*/
switch
(
range
)
{
case
100
:
range
=
0x23
;
range
=
ADC_CONF_100M14B4CHA_CHN_RANGE_100mV
;
bit_scale
=
0
.
05
/
(
1
<<
15
);
break
;
case
1
:
range
=
0x11
;
range
=
ADC_CONF_100M14B4CHA_CHN_RANGE_1V
;
bit_scale
=
0
.
5
/
(
1
<<
15
);
break
;
case
10
:
range
=
0x45
;
range
=
ADC_CONF_100M14B4CHA_CHN_RANGE_10V
;
bit_scale
=
5
.
0
/
(
1
<<
15
);
break
;
}
...
...
@@ -626,6 +635,58 @@ static int fald_trg_timer_configuration(struct adc_dev *adc, char *param)
return
adc_apply_config
(
adc
,
0
,
&
cfg
);
}
/**
* It peforms the auto-clear offset according to the command line options
* @param[in] adc The ADC device token
* @param[in] argc number of arguments
* @param[in] argv arguments
* @return 0 on success, otherwise -1 and errno is appropriately set
*/
static
int
adc_acq_offset_auto_clear
(
struct
adc_dev
*
adc
,
int
argc
,
char
*
argv
[])
{
char
offclr_mode
;
unsigned
int
chan
;
unsigned
long
flags
;
int
c
,
opt_index
,
ret
;
optind
=
1
;
/* set to 1 to make getopt_long happy */
/* Parse options */
while
((
c
=
getopt_long
(
argc
,
argv
,
GETOPT_STRING
,
options
,
&
opt_index
))
>=
0
)
{
switch
(
c
)
{
case
FALD_ACQ_OPT_OFF_CLR
:
ret
=
sscanf
(
optarg
,
"%c,%d"
,
&
offclr_mode
,
&
chan
);
if
(
ret
<=
0
)
{
errno
=
EINVAL
;
return
-
1
;
}
flags
=
0
;
switch
(
offclr_mode
)
{
case
'm'
:
flags
|=
ADC_OFFSET_AC_F_MANUAL
;
break
;
case
'a'
:
flags
|=
ADC_OFFSET_AC_F_RESTORE
;
break
;
default:
fprintf
(
stderr
,
"%s: invalid offset auto-clear mode '%c' (valid modes: {a: automatic, m: manual})"
,
_argv
[
0
],
offclr_mode
);
return
-
1
;
}
ret
=
adc_offset_auto_clear
(
adc
,
chan
,
flags
);
if
(
ret
<
0
)
return
ret
;
break
;
default:
break
;
}
}
return
0
;
}
/**
* It parses command line arguments and consequential it configures the device
...
...
@@ -712,6 +773,10 @@ static int fald_acq_parse_args_and_configure(struct adc_dev *adc, int argc, char
}
}
err
=
adc_acq_offset_auto_clear
(
adc
,
argc
,
argv
);
if
(
err
)
return
-
1
;
fald_acq_print_config
(
adc
);
return
0
;
...
...
@@ -869,6 +934,31 @@ static void fald_acq_plot_data(struct adc_buffer *buf, unsigned int ch)
system
(
cmd
);
}
/**
* It prints data using json format
*/
static
void
adc_acq_statistics
(
struct
adc_buffer
*
buf
,
unsigned
int
max_chan
)
{
int32_t
avg
;
int
i
,
err
;
fprintf
(
stdout
,
"{
\"
statistics
\"
: ["
);
for
(
i
=
0
;
i
<
max_chan
;
++
i
)
{
fprintf
(
stdout
,
"{
\"
chan
\"
: %d"
,
i
);
err
=
adc_buffer_math_avg
(
buf
,
i
,
&
avg
);
if
(
err
)
{
fprintf
(
stdout
,
",
\"
average
\"
: -1"
);
}
else
{
fprintf
(
stdout
,
",
\"
average
\"
: %"
PRId32
,
avg
);
}
if
(
i
==
max_chan
-
1
)
fprintf
(
stdout
,
"}"
);
else
fprintf
(
stdout
,
"}, "
);
}
fprintf
(
stdout
,
"]}
\n
"
);
}
/**
* It process the buffer
...
...
@@ -894,6 +984,9 @@ static void fald_acq_process_buffer(struct adc_buffer *buf,
break
;
}
if
(
statistics
)
adc_acq_statistics
(
buf
,
nchan
);
if
(
arg_plot
)
for
(
w
=
0
;
w
<
nchan
;
++
w
)
fald_acq_plot_data
(
buf
,
w
+
1
);
...
...
@@ -1079,7 +1172,9 @@ int main(int argc, char *argv[])
break
;
}
err
=
adc_fill_buffer
(
adc
,
buf
,
0
,
NULL
);
err
=
adc_fill_buffer
(
adc
,
buf
,
fixup
?
ADC_F_FIXUP
:
0
,
NULL
);
if
(
err
)
{
fprintf
(
stderr
,
"Failed to retrieve for data: (%d) %s
\n
"
,
errno
,
adc_strerror
(
errno
));
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment