Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
F
FMC ADC 100M 14b 4cha - Software
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
FMC ADC 100M 14b 4cha - Software
Commits
cf9bcbc4
Commit
cf9bcbc4
authored
Feb 18, 2019
by
Federico Vaga
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature/calibration' into develop
parents
c8eccabe
1cf4b8e0
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
329 additions
and
14 deletions
+329
-14
fa-calibration.c
kernel/fa-calibration.c
+65
-0
fa-core.c
kernel/fa-core.c
+3
-2
fa-zio-drv.c
kernel/fa-zio-drv.c
+6
-0
fmc-adc-100m14b4cha.h
kernel/fmc-adc-100m14b4cha.h
+19
-12
.gitignore
tools/.gitignore
+1
-0
Makefile
tools/Makefile
+1
-0
fau-calibration.c
tools/fau-calibration.c
+234
-0
No files found.
kernel/fa-calibration.c
View file @
cf9bcbc4
...
...
@@ -91,3 +91,68 @@ void fa_read_eeprom_calib(struct fa_dev *fa)
fa_endian_calib
(
&
fa
->
calib
);
fa_verify_calib
(
&
fa
->
fmc
->
dev
,
&
fa
->
calib
,
&
fa_identity_calib
);
}
/**
* Calculate calibrated values for offset and range using current values
* @fa: FMC ADC device
* @chan: channel
*/
static
void
fa_apply_calib
(
struct
fa_dev
*
fa
,
struct
zio_channel
*
chan
)
{
int
reg
=
zfad_get_chx_index
(
ZFA_CHx_CTL_RANGE
,
chan
);
int
range
=
fa_readl
(
fa
,
fa
->
fa_adc_csr_base
,
&
zfad_regs
[
reg
]);
zfad_set_range
(
fa
,
chan
,
range
);
zfad_apply_offset
(
chan
);
}
static
ssize_t
fa_write_eeprom
(
struct
file
*
file
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
)
{
struct
device
*
dev
=
container_of
(
kobj
,
struct
device
,
kobj
);
struct
fa_dev
*
fa
=
get_zfadc
(
dev
);
struct
fa_calib
*
calib
=
(
struct
fa_calib
*
)
buf
;
int
i
;
if
(
off
!=
0
||
count
!=
sizeof
(
*
calib
))
return
-
EINVAL
;
fa_endian_calib
(
calib
);
fa_verify_calib
(
dev
,
calib
,
&
fa_identity_calib
);
/*
* The user should be careful enough to not change calibration
* values while running an acquisition
*/
memcpy
(
&
fa
->
calib
,
calib
,
sizeof
(
*
calib
));
for
(
i
=
0
;
i
<
FA100M14B4C_NCHAN
;
++
i
)
fa_apply_calib
(
fa
,
&
fa
->
zdev
->
cset
->
chan
[
i
]);
return
count
;
}
static
ssize_t
fa_read_eeprom
(
struct
file
*
file
,
struct
kobject
*
kobj
,
struct
bin_attribute
*
attr
,
char
*
buf
,
loff_t
off
,
size_t
count
)
{
struct
device
*
dev
=
container_of
(
kobj
,
struct
device
,
kobj
);
struct
fa_dev
*
fa
=
get_zfadc
(
dev
);
if
(
off
!=
0
||
count
<
sizeof
(
fa
->
calib
))
return
-
EINVAL
;
memcpy
(
buf
,
&
fa
->
calib
,
sizeof
(
fa
->
calib
));
return
count
;
}
struct
bin_attribute
dev_attr_calibration
=
{
.
attr
=
{
.
name
=
"calibration_data"
,
.
mode
=
0744
,
},
.
size
=
sizeof
(
struct
fa_calib
),
.
write
=
fa_write_eeprom
,
.
read
=
fa_read_eeprom
,
};
kernel/fa-core.c
View file @
cf9bcbc4
...
...
@@ -394,7 +394,7 @@ static int __fa_init(struct fa_dev *fa)
}
}
/*
Retrieve calibration from the eeprom and validate
*/
/*
Use identity calibration
*/
fa_read_eeprom_calib
(
fa
);
fa
->
mshot_max_samples
=
fa_readl
(
fa
,
fa
->
fa_adc_csr_base
,
&
zfad_regs
[
ZFA_MULT_MAX_SAMP
]);
...
...
@@ -557,7 +557,7 @@ int fa_probe(struct fmc_device *fmc)
err
=
fa_setup_irqs
(
fa
);
if
(
err
<
0
)
goto
out
;
goto
out
_irq
;
/* Pin the carrier */
if
(
!
try_module_get
(
fmc
->
owner
))
...
...
@@ -567,6 +567,7 @@ int fa_probe(struct fmc_device *fmc)
out_mod:
fa_free_irqs
(
fa
);
out_irq:
out:
while
(
--
m
,
--
i
>=
0
)
if
(
m
->
exit
)
...
...
kernel/fa-zio-drv.c
View file @
cf9bcbc4
...
...
@@ -544,6 +544,10 @@ static int zfad_zio_probe(struct zio_device *zdev)
if
(
err
)
return
err
;
err
=
device_create_bin_file
(
&
zdev
->
cset
->
head
.
dev
,
&
dev_attr_calibration
);
if
(
err
)
return
err
;
/* We don't have csets at this point, so don't do anything more */
return
0
;
}
...
...
@@ -556,6 +560,8 @@ static int zfad_zio_probe(struct zio_device *zdev)
*/
static
int
zfad_zio_remove
(
struct
zio_device
*
zdev
)
{
device_remove_bin_file
(
&
zdev
->
cset
->
head
.
dev
,
&
dev_attr_calibration
);
return
0
;
}
...
...
kernel/fmc-adc-100m14b4cha.h
View file @
cf9bcbc4
...
...
@@ -8,6 +8,12 @@
#ifndef FMC_ADC_100M14B4C_H_
#define FMC_ADC_100M14B4C_H_
#ifdef __KERNEL__
#include <linux/types.h>
#else
#include <stdint.h>
#endif
#ifndef BIT
#define BIT(nr) (1UL << (nr))
#endif
...
...
@@ -128,6 +134,17 @@ enum fa100m14b4c_fsm_state {
FA100M14B4C_STATE_DECR
,
};
/* ADC and DAC Calibration, from EEPROM */
struct
fa_calib_stanza
{
int16_t
offset
[
4
];
/* One per channel */
uint16_t
gain
[
4
];
/* One per channel */
uint16_t
temperature
;
};
struct
fa_calib
{
struct
fa_calib_stanza
adc
[
3
];
/* For input, one per range */
struct
fa_calib_stanza
dac
[
3
];
/* For user offset, one per range */
};
#ifdef __KERNEL__
/* All the rest is only of kernel users */
#include <linux/dma-mapping.h>
...
...
@@ -350,18 +367,6 @@ struct fa_carrier_op {
void
(
*
dma_error
)(
struct
zio_cset
*
cset
);
};
/* ADC and DAC Calibration, from EEPROM */
struct
fa_calib_stanza
{
int16_t
offset
[
4
];
/* One per channel */
uint16_t
gain
[
4
];
/* One per channel */
uint16_t
temperature
;
};
struct
fa_calib
{
struct
fa_calib_stanza
adc
[
3
];
/* For input, one per range */
struct
fa_calib_stanza
dac
[
3
];
/* For user offset, one per range */
};
/*
* fa_dev: is the descriptor of the FMC ADC mezzanine
*
...
...
@@ -540,6 +545,8 @@ static inline void fa_writel(struct fa_dev *fa,
fa_iowrite
(
fa
,
val
,
base_off
+
field
->
offset
);
}
extern
struct
bin_attribute
dev_attr_calibration
;
/* Global variable exported by fa-core.c */
extern
struct
workqueue_struct
*
fa_workqueue
;
...
...
tools/.gitignore
View file @
cf9bcbc4
fau-acq-time
fau-trg-config
fau-calibration
parport-burst
tools/Makefile
View file @
cf9bcbc4
...
...
@@ -18,6 +18,7 @@ CC ?= $(CROSS_COMPILE)gcc
progs
:=
fau-trg-config
progs
+=
fau-acq-time
progs
+=
fau-calibration
progs
+=
parport-burst
# we are not in the kernel, so we need to piggy-back on "make modules"
...
...
tools/fau-calibration.c
0 → 100644
View file @
cf9bcbc4
// SPDX-License-Identifier: GPL-3.0-or-later
/*
* It lists all VME devices
* Copyright (C) 2018 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <fmc-adc-100m14b4cha.h>
static
const
char
program_name
[]
=
"fau-calibration"
;
static
char
options
[]
=
"hf:o:D:b"
;
static
const
char
help_msg
[]
=
"Usage: fau-calibration [options]
\n
"
"
\n
"
"It reads calibration data from a file that contains it in binary
\n
"
"form and it shows it on STDOUT in binary form or in human readable
\n
"
"one (default).
\n
"
"This could be used to change the ADC calibration data at runtime
\n
"
"by redirectiong the binary output of this program to the proper
\n
"
"sysfs binary attribute
\n
"
"
\n
"
"General options:
\n
"
"-h Print this message
\n
"
"-b Show Calibration in binary form
\n
"
"
\n
"
"Read options:
\n
"
"-f Source file where to read calibration data from
\n
"
"-o Offset in bytes within the file (default 0)
\n
"
"Write options:
\n
"
"-D FMC ADC Target Device ID
\n
"
"
\n
"
;
/**
* Read calibration data from file
* @path: file path
* @data: data location
* @size: data size
* @offset: offset in file
*
* Return: number of bytes read
*/
static
int
fau_calibration_read
(
char
*
path
,
void
*
data
,
size_t
size
,
off_t
offset
)
{
int
fd
;
int
ret
=
0
;
fd
=
open
(
path
,
O_RDONLY
);
if
(
fd
<
0
)
return
-
1
;
ret
=
lseek
(
fd
,
offset
,
SEEK_SET
);
if
(
ret
>=
0
)
ret
=
read
(
fd
,
data
,
size
);
close
(
fd
);
return
ret
;
}
static
void
fau_calibration_dump_stanza
(
struct
fa_calib_stanza
*
stanza
)
{
fprintf
(
stdout
,
" temperature: 0x%x
\n
"
,
stanza
->
temperature
);
fprintf
(
stdout
,
" gain: [0x%04"
PRIx16
", 0x%04"
PRIx16
", 0x%04"
PRIx16
", 0x%04"
PRIx16
"]
\n
"
,
stanza
->
gain
[
0
],
stanza
->
gain
[
1
],
stanza
->
gain
[
2
],
stanza
->
gain
[
3
]);
fprintf
(
stdout
,
" offset: [0x%04"
PRIx16
", 0x%04"
PRIx16
", 0x%04"
PRIx16
", 0x%04"
PRIx16
"]
\n
"
,
stanza
->
offset
[
0
],
stanza
->
offset
[
1
],
stanza
->
offset
[
2
],
stanza
->
offset
[
3
]);
}
/**
* Print calibration data on stdout in humand readable format
* @calib: calibration data
*/
static
void
fau_calibration_dump_human
(
struct
fa_calib
*
calib
)
{
fputs
(
"ADC Range 10V
\n
"
,
stdout
);
fau_calibration_dump_stanza
(
&
calib
->
adc
[
FA100M14B4C_RANGE_10V
]);
fputs
(
"DAC Range 10V
\n
"
,
stdout
);
fau_calibration_dump_stanza
(
&
calib
->
dac
[
FA100M14B4C_RANGE_10V
]);
fputs
(
"ADC Range 1V
\n
"
,
stdout
);
fau_calibration_dump_stanza
(
&
calib
->
adc
[
FA100M14B4C_RANGE_1V
]);
fputs
(
"DAC Range 1V
\n
"
,
stdout
);
fau_calibration_dump_stanza
(
&
calib
->
dac
[
FA100M14B4C_RANGE_1V
]);
fputs
(
"ADC Range 100mV
\n
"
,
stdout
);
fau_calibration_dump_stanza
(
&
calib
->
adc
[
FA100M14B4C_RANGE_100mV
]);
fputs
(
"DAC Range 100mV
\n
"
,
stdout
);
fau_calibration_dump_stanza
(
&
calib
->
dac
[
FA100M14B4C_RANGE_100mV
]);
fputc
(
'\n'
,
stdout
);
}
/**
* Print binary calibration data on stdout
* @calib: calibration data
*/
static
void
fau_calibration_dump_machine
(
struct
fa_calib
*
calib
)
{
write
(
fileno
(
stdout
),
calib
,
sizeof
(
*
calib
));
}
/**
* Write calibration data to device
* @devid: Device ID
* @data: data location
* @size: data size
*
* Return: number of bytes wrote
*/
static
int
fau_calibration_write
(
unsigned
int
devid
,
void
*
data
,
size_t
size
)
{
char
path
[
128
];
int
fd
;
int
ret
;
sprintf
(
path
,
"/sys/bus/zio/devices/adc-100m14b-%04x/cset0/calibration_data"
,
devid
);
fd
=
open
(
path
,
O_WRONLY
);
if
(
fd
<
0
)
return
-
1
;
ret
=
write
(
fd
,
data
,
size
);
close
(
fd
);
return
ret
;
}
int
main
(
int
argc
,
char
*
argv
[])
{
char
c
;
int
ret
;
char
*
path
=
NULL
;
unsigned
int
offset
=
0
;
unsigned
int
devid
=
0
;
int
show_bin
=
0
,
write
=
0
;
struct
fa_calib
calib
;
while
((
c
=
getopt
(
argc
,
argv
,
options
))
!=
-
1
)
{
switch
(
c
)
{
default:
case
'h'
:
fprintf
(
stderr
,
help_msg
);
exit
(
EXIT_SUCCESS
);
case
'D'
:
ret
=
sscanf
(
optarg
,
"0x%x"
,
&
devid
);
if
(
ret
!=
1
)
{
fprintf
(
stderr
,
"Invalid devid %s
\n
"
,
optarg
);
exit
(
EXIT_FAILURE
);
}
write
=
1
;
break
;
case
'f'
:
path
=
optarg
;
break
;
case
'o'
:
ret
=
sscanf
(
optarg
,
"0x%x"
,
&
offset
);
if
(
ret
!=
1
)
{
ret
=
sscanf
(
optarg
,
"%u"
,
&
offset
);
if
(
ret
!=
1
)
{
fprintf
(
stderr
,
"Invalid offset %s
\n
"
,
optarg
);
exit
(
EXIT_FAILURE
);
}
}
break
;
case
'b'
:
show_bin
=
1
;
break
;
}
}
if
(
!
path
)
{
fputs
(
"Calibration file is mandatory
\n
"
,
stderr
);
exit
(
EXIT_FAILURE
);
}
/* Read EEPROM file */
ret
=
fau_calibration_read
(
path
,
&
calib
,
sizeof
(
calib
),
offset
);
if
(
ret
<
0
)
{
fprintf
(
stderr
,
"Can't read calibration data from '%s'. %s
\n
"
,
path
,
strerror
(
errno
));
exit
(
EXIT_FAILURE
);
}
if
(
ret
!=
sizeof
(
calib
))
{
fprintf
(
stderr
,
"Can't read all calibration data from '%s'. %s
\n
"
,
path
,
strerror
(
errno
));
exit
(
EXIT_FAILURE
);
}
/* Show calibration data*/
if
(
show_bin
)
fau_calibration_dump_machine
(
&
calib
);
else
if
(
!
write
)
fau_calibration_dump_human
(
&
calib
);
/* Write calibration data */
if
(
write
)
{
ret
=
fau_calibration_write
(
devid
,
&
calib
,
sizeof
(
calib
));
if
(
ret
<
0
)
{
fprintf
(
stderr
,
"Can't write calibration data to '0x%x'. %s
\n
"
,
devid
,
strerror
(
errno
));
exit
(
EXIT_FAILURE
);
}
if
(
ret
!=
sizeof
(
calib
))
{
fprintf
(
stderr
,
"Can't write all calibration data to '0x%x'. %s
\n
"
,
devid
,
strerror
(
errno
));
exit
(
EXIT_FAILURE
);
}
}
exit
(
EXIT_SUCCESS
);
}
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