Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
S
Software for White Rabbit PTP Core
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
32
Issues
32
List
Board
Labels
Milestones
Merge Requests
6
Merge Requests
6
CI / CD
CI / CD
Pipelines
Schedules
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
Software for White Rabbit PTP Core
Commits
abf90c8b
Commit
abf90c8b
authored
Sep 03, 2019
by
José López Jiménez
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Adaptations for low jitter switch in Grandmaster and Boundary clock mode
parent
02f04ab1
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
219 additions
and
121 deletions
+219
-121
ad9516.c
dev/ad9516.c
+22
-21
ad9516_config.h
dev/ad9516_config.h
+122
-32
spll_defs.h
include/spll_defs.h
+1
-1
softpll_ng.c
softpll/softpll_ng.c
+4
-4
spll_common.c
softpll/spll_common.c
+2
-2
spll_external.c
softpll/spll_external.c
+34
-29
spll_helper.c
softpll/spll_helper.c
+8
-8
spll_main.c
softpll/spll_main.c
+25
-15
spll_main.h
softpll/spll_main.h
+1
-1
wrs_main.c
wrs_main.c
+0
-8
No files found.
dev/ad9516.c
View file @
abf90c8b
...
@@ -231,12 +231,10 @@ static void ad9516_sync_outputs(void *spi_base)
...
@@ -231,12 +231,10 @@ static void ad9516_sync_outputs(void *spi_base)
}
}
// This function is related to a not very well documented bug in the external softpll init code.
int
ext_ad9516_locked
(
void
)
int
ext_ad9516_locked
(
void
)
{
{
if
((
ad9516_read_reg
((
void
*
)
BASE_SPI_EXT_BOARD
,
0x1f
)
&
1
))
if
((
ad9516_read_reg
((
void
*
)
BASE_SPI_EXT_BOARD
,
0x1f
)
&
1
))
return
1
;
return
1
;
return
0
;
return
0
;
}
}
...
@@ -266,10 +264,12 @@ int ad9516_init(int scb_version)
...
@@ -266,10 +264,12 @@ int ad9516_init(int scb_version)
return
-
1
;
return
-
1
;
}
}
pp_printf
(
"PLL Responding
\n
"
);
// During the development of the WRS LJ, several OXCOs were checked, with different input freqs.
// This implies that every oscillator requires a different register set for the AD9516 config.
// In ad9516_config.h there is a register set for 20, 50 and 125 MHz.
if
(
scb_version
>=
34
){
//New SCB v3.4. 10MHz Output.
if
(
scb_version
>=
34
){
//New SCB v3.4. 10MHz Output.
ad9516_load_regset
(
spi_base
,
ad9516_base_config_34
,
ARRAY_SIZE
(
ad9516_base_config_34
),
0
);
ad9516_load_regset
(
spi_base
,
ad9516_base_config_34
_20
,
ARRAY_SIZE
(
ad9516_base_config_34_20
),
0
);
pp_printf
(
"loaded for 34
\n
"
);
pp_printf
(
"loaded for 34
\n
"
);
}
}
else
{
//Old one
else
{
//Old one
...
@@ -277,19 +277,26 @@ int ad9516_init(int scb_version)
...
@@ -277,19 +277,26 @@ int ad9516_init(int scb_version)
pp_printf
(
"loaded for 33
\n
"
);
pp_printf
(
"loaded for 33
\n
"
);
}
}
ad9516_load_regset
(
spi_base
,
ad9516_ref_tcxo
,
ARRAY_SIZE
(
ad9516_ref_tcxo
),
1
);
ad9516_load_regset
(
spi_base
,
ad9516_ref_tcxo_20
,
ARRAY_SIZE
(
ad9516_ref_tcxo_20
),
1
);
pp_printf
(
"Did the weird rewrite
\n
"
);
ad9516_wait_lock
(
spi_base
);
ad9516_wait_lock
(
spi_base
);
ad9516_sync_outputs
(
spi_base
);
ad9516_sync_outputs
(
spi_base
);
if
(
scb_version
>=
34
)
{
//New SCB v3.4. 10MHz Output.
if
(
scb_version
>=
34
)
{
//New SCB v3.4. 10MHz Output.
// ad9516_set_output_divider(spi_base, 2, 4, 0); // OUT2. 187.5 MHz. - not anymore
ad9516_set_output_divider
(
spi_base
,
0
,
4
,
0
);
// ad9516_set_output_divider(spi_base, 3, 4, 0); // OUT3. 187.5 MHz. - not anymore
ad9516_set_output_divider
(
spi_base
,
1
,
4
,
0
);
ad9516_set_output_divider
(
spi_base
,
2
,
4
,
0
);
ad9516_set_output_divider
(
spi_base
,
3
,
4
,
0
);
ad9516_set_output_divider
(
spi_base
,
4
,
4
,
0
);
ad9516_set_output_divider
(
spi_base
,
5
,
4
,
0
);
// ad9516_set_output_divider(spi_base, 4, 1, 0); // OUT4. 500 MHz.
ad9516_set_output_divider
(
spi_base
,
6
,
1
,
0
);
// ad9516_set_output_divider(spi_base,
9, 20,
0);
// ad9516_set_output_divider(spi_base,
7, 3,
0);
ad9516_set_output_divider
(
spi_base
,
8
,
4
,
0
);
ad9516_set_output_divider
(
spi_base
,
9
,
4
,
0
);
/*The following PLL outputs have been configured through the ad9516_base_config_34 register,
/*The following PLL outputs have been configured through the ad9516_base_config_34 register,
* so it doesn't need to replicate the configuration:
* so it doesn't need to replicate the configuration:
*
*
...
@@ -309,7 +316,6 @@ int ad9516_init(int scb_version)
...
@@ -309,7 +316,6 @@ int ad9516_init(int scb_version)
ad9516_sync_outputs
(
spi_base
);
ad9516_sync_outputs
(
spi_base
);
ad9516_set_vco_divider
(
spi_base
,
6
);
ad9516_set_vco_divider
(
spi_base
,
6
);
pp_printf
(
"Reg for clk8 has value %d
\n
"
,
ad9516_read_reg
(
spi_base
,
0x142
));
pp_printf
(
"AD9516 locked.
\n
"
);
pp_printf
(
"AD9516 locked.
\n
"
);
gpio_out
(
GPIO_SYS_CLK_SEL
,
1
);
/* switch the system clock to the PLL reference */
gpio_out
(
GPIO_SYS_CLK_SEL
,
1
);
/* switch the system clock to the PLL reference */
...
@@ -344,20 +350,15 @@ int ext_ad9516_init (void) {
...
@@ -344,20 +350,15 @@ int ext_ad9516_init (void) {
ad9516_write_reg
(
spi_base
,
0x232
,
0x1
);
ad9516_write_reg
(
spi_base
,
0x232
,
0x1
);
ad9516_write_reg
(
spi_base
,
0x232
,
0x0
);
ad9516_write_reg
(
spi_base
,
0x232
,
0x0
);
ad9516_set_vco_divider
(
spi_base
,
3
);
ad9516_load_regset
(
spi_base
,
ad9516_ext_base_config
,
ARRAY_SIZE
(
ad9516_ext_base_config
),
1
);
ad9516_load_regset
(
spi_base
,
ad9516_ext_base_config
,
ARRAY_SIZE
(
ad9516_ext_base_config
),
1
);
// while ((ad9516_read_reg(spi_base, 0x1f) & (1 << 6)) == 0);
// pp_printf("Calibration done\n");
ad9516_set_output_divider
(
spi_base
,
6
,
8
,
0
);
// OUT6. 62.5MHz
ad9516_set_output_divider
(
spi_base
,
8
,
20
,
0
);
// OUT6. 62.5MHz
ad9516_write_reg
(
spi_base
,
0x018
,
0x0
);
// reset VCO calibration
ad9516_write_reg
(
spi_base
,
0x232
,
0x0
);
ad9516_write_reg
(
spi_base
,
0x232
,
0x1
);
ad9516_write_reg
(
spi_base
,
0x232
,
0x0
);
return
0
;
return
0
;
}
}
...
...
dev/ad9516_config.h
View file @
abf90c8b
...
@@ -69,18 +69,19 @@ const struct ad9516_reg ad9516_base_config_33[] = {
...
@@ -69,18 +69,19 @@ const struct ad9516_reg ad9516_base_config_33[] = {
{
0x0230
,
0x00
},
{
0x0230
,
0x00
},
{
0x0231
,
0x00
},
{
0x0231
,
0x00
},
};
};
/* Configuration for the SCB version greater than or equal 3.4: Base + 6, 7, 8, 9 outputs*/
/* Configuration for the SCB version greater than or equal 3.4: Base + 6, 7, 8, 9 outputs*/
const
struct
ad9516_reg
ad9516_base_config_34
[]
=
{
const
struct
ad9516_reg
ad9516_base_config_34
_20
[]
=
{
{
0x0000
,
0x99
},
{
0x0000
,
0x99
},
{
0x0001
,
0x00
},
{
0x0001
,
0x00
},
{
0x0002
,
0x10
},
{
0x0002
,
0x10
},
{
0x0003
,
0xC3
},
{
0x0003
,
0xC3
},
{
0x0004
,
0x00
},
{
0x0004
,
0x00
},
{
0x0010
,
0x7C
},
{
0x0010
,
0x7C
},
{
0x0011
,
0x0
5
},
{
0x0011
,
0x0
2
},
{
0x0012
,
0x00
},
{
0x0012
,
0x00
},
{
0x0013
,
0x0
C
},
{
0x0013
,
0x0
6
},
{
0x0014
,
0x
12
},
{
0x0014
,
0x
09
},
{
0x0015
,
0x00
},
{
0x0015
,
0x00
},
{
0x0016
,
0x05
},
{
0x0016
,
0x05
},
{
0x0017
,
0x88
},
{
0x0017
,
0x88
},
...
@@ -111,7 +112,7 @@ const struct ad9516_reg ad9516_base_config_34[] = {
...
@@ -111,7 +112,7 @@ const struct ad9516_reg ad9516_base_config_34[] = {
{
0x00F4
,
0x08
},
{
0x00F4
,
0x08
},
{
0x00F5
,
0x08
},
{
0x00F5
,
0x08
},
// The following registers configure the PLL outputs from 6 to 9.
// The following registers configure the PLL outputs from 6 to 9.
{
0x0140
,
0x
4
2
},
{
0x0140
,
0x
5
2
},
{
0x0141
,
0x42
},
{
0x0141
,
0x42
},
{
0x0142
,
0x42
},
{
0x0142
,
0x42
},
{
0x0143
,
0x4E
},
{
0x0143
,
0x4E
},
...
@@ -124,9 +125,9 @@ const struct ad9516_reg ad9516_base_config_34[] = {
...
@@ -124,9 +125,9 @@ const struct ad9516_reg ad9516_base_config_34[] = {
{
0x0196
,
0x11
},
{
0x0196
,
0x11
},
{
0x0197
,
0x00
},
{
0x0197
,
0x00
},
{
0x0198
,
0x00
},
{
0x0198
,
0x00
},
{
0x0199
,
0x
11
},
{
0x0199
,
0x
00
},
{
0x019A
,
0x00
},
{
0x019A
,
0x00
},
{
0x019B
,
0x
1
1
},
{
0x019B
,
0x
2
1
},
{
0x019C
,
0x20
},
{
0x019C
,
0x20
},
{
0x019D
,
0x00
},
{
0x019D
,
0x00
},
{
0x019E
,
0x11
},
{
0x019E
,
0x11
},
...
@@ -142,21 +143,22 @@ const struct ad9516_reg ad9516_base_config_34[] = {
...
@@ -142,21 +143,22 @@ const struct ad9516_reg ad9516_base_config_34[] = {
{
0x0231
,
0x00
},
{
0x0231
,
0x00
},
};
};
/* Configuration for the SCB version greater than or equal 3.4: Base + 6, 7, 8, 9 outputs*/
/* Configuration for the SCB version greater than or equal 3.4: Base + 6, 7, 8, 9 outputs*/
const
struct
ad9516_reg
ad9516_base_config_34_
new
[]
=
{
const
struct
ad9516_reg
ad9516_base_config_34_
50
[]
=
{
{
0x0000
,
0x
18
},
{
0x0000
,
0x
99
},
{
0x0001
,
0x00
},
{
0x0001
,
0x00
},
{
0x0002
,
0x10
},
{
0x0002
,
0x10
},
{
0x0003
,
0xC3
},
{
0x0003
,
0xC3
},
{
0x0004
,
0x00
},
{
0x0004
,
0x00
},
{
0x0010
,
0x7C
},
{
0x0010
,
0x7C
},
{
0x0011
,
0x0
5
},
{
0x0011
,
0x0
A
},
{
0x0012
,
0x00
},
{
0x0012
,
0x00
},
{
0x0013
,
0x0
0
},
{
0x0013
,
0x0
C
},
{
0x0014
,
0x
0B
},
{
0x0014
,
0x
12
},
{
0x0015
,
0x00
},
{
0x0015
,
0x00
},
{
0x0016
,
0x05
},
{
0x0016
,
0x05
},
{
0x0017
,
0x
00
},
{
0x0017
,
0x
88
},
{
0x0018
,
0x07
},
{
0x0018
,
0x07
},
{
0x0019
,
0x00
},
{
0x0019
,
0x00
},
{
0x001A
,
0x00
},
{
0x001A
,
0x00
},
...
@@ -184,10 +186,10 @@ const struct ad9516_reg ad9516_base_config_34_new[] = {
...
@@ -184,10 +186,10 @@ const struct ad9516_reg ad9516_base_config_34_new[] = {
{
0x00F4
,
0x08
},
{
0x00F4
,
0x08
},
{
0x00F5
,
0x08
},
{
0x00F5
,
0x08
},
// The following registers configure the PLL outputs from 6 to 9.
// The following registers configure the PLL outputs from 6 to 9.
{
0x0140
,
0x
4
2
},
{
0x0140
,
0x
5
2
},
{
0x0141
,
0x42
},
{
0x0141
,
0x42
},
{
0x0142
,
0x42
},
{
0x0142
,
0x42
},
{
0x0143
,
0x4
A
},
{
0x0143
,
0x4
E
},
{
0x0190
,
0x11
},
{
0x0190
,
0x11
},
{
0x0191
,
0x00
},
{
0x0191
,
0x00
},
{
0x0192
,
0x00
},
{
0x0192
,
0x00
},
...
@@ -197,9 +199,9 @@ const struct ad9516_reg ad9516_base_config_34_new[] = {
...
@@ -197,9 +199,9 @@ const struct ad9516_reg ad9516_base_config_34_new[] = {
{
0x0196
,
0x11
},
{
0x0196
,
0x11
},
{
0x0197
,
0x00
},
{
0x0197
,
0x00
},
{
0x0198
,
0x00
},
{
0x0198
,
0x00
},
{
0x0199
,
0x
11
},
{
0x0199
,
0x
00
},
{
0x019A
,
0x00
},
{
0x019A
,
0x00
},
{
0x019B
,
0x
1
1
},
{
0x019B
,
0x
2
1
},
{
0x019C
,
0x20
},
{
0x019C
,
0x20
},
{
0x019D
,
0x00
},
{
0x019D
,
0x00
},
{
0x019E
,
0x11
},
{
0x019E
,
0x11
},
...
@@ -217,20 +219,20 @@ const struct ad9516_reg ad9516_base_config_34_new[] = {
...
@@ -217,20 +219,20 @@ const struct ad9516_reg ad9516_base_config_34_new[] = {
/* Configuration for the SCB version greater than or equal 3.4: Base + 6, 7, 8, 9 outputs*/
/* Configuration for the SCB version greater than or equal 3.4: Base + 6, 7, 8, 9 outputs*/
const
struct
ad9516_reg
ad9516_
ext_base_config
[]
=
{
const
struct
ad9516_reg
ad9516_
base_config_34_125
[]
=
{
{
0x0000
,
0x
18
},
{
0x0000
,
0x
99
},
{
0x0001
,
0x00
},
{
0x0001
,
0x00
},
{
0x0002
,
0x10
},
{
0x0002
,
0x10
},
{
0x0003
,
0xC3
},
{
0x0003
,
0xC3
},
{
0x0004
,
0x00
},
{
0x0004
,
0x00
},
{
0x0010
,
0x7C
},
{
0x0010
,
0x7C
},
{
0x0011
,
0x0
5
},
{
0x0011
,
0x0
A
},
{
0x0012
,
0x00
},
{
0x0012
,
0x00
},
{
0x0013
,
0x0
0
},
{
0x0013
,
0x0
8
},
{
0x0014
,
0x0
B
},
{
0x0014
,
0x0
E
},
{
0x0015
,
0x00
},
{
0x0015
,
0x00
},
{
0x0016
,
0x0
5
},
{
0x0016
,
0x0
4
},
{
0x0017
,
0x
00
},
{
0x0017
,
0x
B4
},
{
0x0018
,
0x07
},
{
0x0018
,
0x07
},
{
0x0019
,
0x00
},
{
0x0019
,
0x00
},
{
0x001A
,
0x00
},
{
0x001A
,
0x00
},
...
@@ -258,10 +260,10 @@ const struct ad9516_reg ad9516_ext_base_config[] = {
...
@@ -258,10 +260,10 @@ const struct ad9516_reg ad9516_ext_base_config[] = {
{
0x00F4
,
0x08
},
{
0x00F4
,
0x08
},
{
0x00F5
,
0x08
},
{
0x00F5
,
0x08
},
// The following registers configure the PLL outputs from 6 to 9.
// The following registers configure the PLL outputs from 6 to 9.
{
0x0140
,
0x
4
2
},
{
0x0140
,
0x
5
2
},
{
0x0141
,
0x42
},
{
0x0141
,
0x42
},
{
0x0142
,
0x42
},
{
0x0142
,
0x42
},
{
0x0143
,
0x4
A
},
{
0x0143
,
0x4
E
},
{
0x0190
,
0x11
},
{
0x0190
,
0x11
},
{
0x0191
,
0x00
},
{
0x0191
,
0x00
},
{
0x0192
,
0x00
},
{
0x0192
,
0x00
},
...
@@ -271,9 +273,9 @@ const struct ad9516_reg ad9516_ext_base_config[] = {
...
@@ -271,9 +273,9 @@ const struct ad9516_reg ad9516_ext_base_config[] = {
{
0x0196
,
0x11
},
{
0x0196
,
0x11
},
{
0x0197
,
0x00
},
{
0x0197
,
0x00
},
{
0x0198
,
0x00
},
{
0x0198
,
0x00
},
{
0x0199
,
0x
11
},
{
0x0199
,
0x
00
},
{
0x019A
,
0x00
},
{
0x019A
,
0x00
},
{
0x019B
,
0x
1
1
},
{
0x019B
,
0x
2
1
},
{
0x019C
,
0x20
},
{
0x019C
,
0x20
},
{
0x019D
,
0x00
},
{
0x019D
,
0x00
},
{
0x019E
,
0x11
},
{
0x019E
,
0x11
},
...
@@ -283,18 +285,106 @@ const struct ad9516_reg ad9516_ext_base_config[] = {
...
@@ -283,18 +285,106 @@ const struct ad9516_reg ad9516_ext_base_config[] = {
{
0x01A2
,
0x00
},
{
0x01A2
,
0x00
},
{
0x01A3
,
0x00
},
{
0x01A3
,
0x00
},
//
//
{
0x01E0
,
0x0
2
},
{
0x01E0
,
0x0
4
},
{
0x01E1
,
0x02
},
{
0x01E1
,
0x02
},
{
0x0230
,
0x00
},
{
0x0230
,
0x00
},
{
0x0231
,
0x00
},
{
0x0231
,
0x00
},
};
};
/* Configuration for the SCB version greater than or equal 3.4: Base + 6, 7, 8, 9 outputs*/
const
struct
ad9516_reg
ad9516_ext_base_config
[]
=
{
{
0x0000
,
0x99
},
{
0x0001
,
0x00
},
{
0x0002
,
0x10
},
{
0x0003
,
0xC3
},
{
0x0004
,
0x01
},
{
0x0010
,
0x4C
},
{
0x0011
,
0x00
},
{
0x0012
,
0x00
},
{
0x0013
,
0x06
},
{
0x0014
,
0x12
},
{
0x0015
,
0x00
},
{
0x0016
,
0x04
},
{
0x0017
,
0x00
},
{
0x0018
,
0x07
},
{
0x0019
,
0x00
},
{
0x001A
,
0x00
},
{
0x001B
,
0x00
},
{
0x001C
,
0x01
},
{
0x001D
,
0x00
},
{
0x001E
,
0x00
},
{
0x001F
,
0x0E
},
{
0x00A0
,
0x01
},
{
0x00A1
,
0x00
},
{
0x00A2
,
0x00
},
{
0x00A3
,
0x01
},
{
0x00A4
,
0x00
},
{
0x00A5
,
0x00
},
{
0x00A6
,
0x01
},
{
0x00A7
,
0x00
},
{
0x00A8
,
0x00
},
{
0x00A9
,
0x01
},
{
0x00AA
,
0x00
},
{
0x00AB
,
0x00
},
{
0x00F0
,
0x0A
},
{
0x00F1
,
0x0A
},
{
0x00F2
,
0x0A
},
{
0x00F3
,
0x0A
},
{
0x00F4
,
0x0A
},
{
0x00F5
,
0x0A
},
// The following registers configure the PLL outputs from 6 to 9.
{
0x0140
,
0x42
},
{
0x0141
,
0x43
},
{
0x0142
,
0x42
},
{
0x0143
,
0x43
},
{
0x0190
,
0x55
},
{
0x0191
,
0x00
},
{
0x0192
,
0x00
},
{
0x0193
,
0x11
},
{
0x0194
,
0x00
},
{
0x0195
,
0x00
},
{
0x0196
,
0x11
},
{
0x0197
,
0x00
},
{
0x0198
,
0x00
},
{
0x0199
,
0x33
},
{
0x019A
,
0x00
},
{
0x019B
,
0x11
},
{
0x019C
,
0x20
},
{
0x019D
,
0x00
},
{
0x019E
,
0x33
},
{
0x019F
,
0x00
},
{
0x01A0
,
0x11
},
{
0x01A1
,
0x20
},
{
0x01A2
,
0x00
},
{
0x01A3
,
0x00
},
//
{
0x01E0
,
0x01
},
{
0x01E1
,
0x02
},
{
0x0230
,
0x00
},
{
0x0231
,
0x01
},
};
/* Config for 125 MHz VCTCXO reference (RDiv = 5, use REF1) */
const
struct
ad9516_reg
ad9516_ref_tcxo_125
[]
=
{
{
0x0011
,
0x0A
},
{
0x0012
,
0x00
},
/* RDiv = 4 */
{
0x001C
,
0x02
}
/* Use REF1 */
};
/* Config for 25 MHz VCTCXO reference (RDiv = 5, use REF1) */
/* Config for
1
25 MHz VCTCXO reference (RDiv = 5, use REF1) */
const
struct
ad9516_reg
ad9516_ref_tcxo
[]
=
{
const
struct
ad9516_reg
ad9516_ref_tcxo
_50
[]
=
{
{
0x0011
,
0x0A
},
{
0x0011
,
0x0A
},
{
0x0012
,
0x00
},
/* RDiv = 4 */
{
0x0012
,
0x00
},
/* RDiv = 4 */
{
0x001C
,
0x06
}
/* Use REF1 */
{
0x001C
,
0x02
}
/* Use REF1 */
};
/* Config for 20 MHz VCTCXO reference (RDiv = 5, use REF1) */
const
struct
ad9516_reg
ad9516_ref_tcxo_20
[]
=
{
{
0x0011
,
0x02
},
{
0x0012
,
0x00
},
/* RDiv = 4 */
{
0x001C
,
0x02
}
/* Use REF1 */
};
};
/* Config for 10 MHz external reference (RDiv = 2, use REF2) */
/* Config for 10 MHz external reference (RDiv = 2, use REF2) */
...
...
include/spll_defs.h
View file @
abf90c8b
...
@@ -32,7 +32,7 @@ WARNING: These parameters must be in sync with the generics of the HDL instantia
...
@@ -32,7 +32,7 @@ WARNING: These parameters must be in sync with the generics of the HDL instantia
/* Helper PLL N divider (2**(-N) is the frequency offset). Must be big enough
/* Helper PLL N divider (2**(-N) is the frequency offset). Must be big enough
to offer reasonable PLL bandwidth, and small enough so the offset frequency fits
to offer reasonable PLL bandwidth, and small enough so the offset frequency fits
within the tuning range of the helper oscillator. */
within the tuning range of the helper oscillator. */
#define HPLL_N 1
4
#define HPLL_N 1
5
/* Fractional bits in PI controller coefficients */
/* Fractional bits in PI controller coefficients */
#define PI_FRACBITS 12
#define PI_FRACBITS 12
...
...
softpll/softpll_ng.c
View file @
abf90c8b
...
@@ -314,10 +314,10 @@ void spll_init(int mode, int slave_ref_channel, int align_pps)
...
@@ -314,10 +314,10 @@ void spll_init(int mode, int slave_ref_channel, int align_pps)
helper_init
(
&
s
->
helper
,
helper_ref
);
helper_init
(
&
s
->
helper
,
helper_ref
);
if
(
mode
!=
SPLL_MODE_GRAND_MASTER
)
if
(
mode
!=
SPLL_MODE_GRAND_MASTER
)
mpll_init
(
&
s
->
mpll
,
slave_ref_channel
,
spll_n_chan_ref
);
mpll_init
(
&
s
->
mpll
,
slave_ref_channel
,
spll_n_chan_ref
,
mode
);
for
(
i
=
0
;
i
<
spll_n_chan_out
-
1
;
i
++
)
{
for
(
i
=
0
;
i
<
spll_n_chan_out
-
1
;
i
++
)
{
mpll_init
(
&
s
->
aux
[
i
].
pll
.
dmtd
,
slave_ref_channel
,
spll_n_chan_ref
+
i
+
1
);
mpll_init
(
&
s
->
aux
[
i
].
pll
.
dmtd
,
slave_ref_channel
,
spll_n_chan_ref
+
i
+
1
,
mode
);
s
->
aux
[
i
].
seq_state
=
AUX_DISABLED
;
s
->
aux
[
i
].
seq_state
=
AUX_DISABLED
;
}
}
...
@@ -465,12 +465,12 @@ void spll_show_stats()
...
@@ -465,12 +465,12 @@ void spll_show_stats()
if
(
softpll
.
mode
>
0
)
if
(
softpll
.
mode
>
0
)
pp_printf
(
"softpll: irqs %d seq %s mode %d "
pp_printf
(
"softpll: irqs %d seq %s mode %d "
"alignment_state %d HL%d ML%d HY=%d MY=%d E
M=%d setpoint:
%d
\n
"
,
"alignment_state %d HL%d ML%d HY=%d MY=%d E
H=%d EM=%d sp:%d tar=
%d
\n
"
,
s
->
irq_count
,
stringlist_lookup
(
seq_states
,
s
->
seq_state
),
s
->
irq_count
,
stringlist_lookup
(
seq_states
,
s
->
seq_state
),
s
->
mode
,
s
->
ext
.
align_state
,
s
->
mode
,
s
->
ext
.
align_state
,
s
->
helper
.
ld
.
locked
,
s
->
mpll
.
ld
.
locked
,
s
->
helper
.
ld
.
locked
,
s
->
mpll
.
ld
.
locked
,
s
->
helper
.
pi
.
y
,
s
->
mpll
.
pi
.
y
,
s
->
helper
.
pi
.
y
,
s
->
mpll
.
pi
.
y
,
s
->
mpll
.
pi
.
x
,
s
->
mpll
.
phase_shift_curren
t
);
s
->
helper
.
pi
.
x
,
s
->
mpll
.
pi
.
x
,
s
->
mpll
.
phase_shift_current
,
s
->
mpll
.
phase_shift_targe
t
);
}
}
int
spll_shifter_busy
(
int
channel
)
int
spll_shifter_busy
(
int
channel
)
...
...
softpll/spll_common.c
View file @
abf90c8b
...
@@ -31,12 +31,12 @@ int pi_update(spll_pi_t *pi, int x)
...
@@ -31,12 +31,12 @@ int pi_update(spll_pi_t *pi, int x)
out of range and the output is going further away from
out of range and the output is going further away from
y_min/y_max. */
y_min/y_max. */
if
(
y
<
pi
->
y_min
)
{
if
(
y
<
pi
->
y_min
)
{
//
y = pi->y_min;
y
=
pi
->
y_min
;
if
((
pi
->
anti_windup
&&
(
i_new
>
pi
->
integrator
))
if
((
pi
->
anti_windup
&&
(
i_new
>
pi
->
integrator
))
||
!
pi
->
anti_windup
)
||
!
pi
->
anti_windup
)
pi
->
integrator
=
i_new
;
pi
->
integrator
=
i_new
;
}
else
if
(
y
>
pi
->
y_max
)
{
}
else
if
(
y
>
pi
->
y_max
)
{
//
y = pi->y_max;
y
=
pi
->
y_max
;
if
((
pi
->
anti_windup
&&
(
i_new
<
pi
->
integrator
))
if
((
pi
->
anti_windup
&&
(
i_new
<
pi
->
integrator
))
||
!
pi
->
anti_windup
)
||
!
pi
->
anti_windup
)
pi
->
integrator
=
i_new
;
pi
->
integrator
=
i_new
;
...
...
softpll/spll_external.c
View file @
abf90c8b
...
@@ -21,7 +21,7 @@
...
@@ -21,7 +21,7 @@
#define EXT_PERIOD_NS 100
#define EXT_PERIOD_NS 100
#define EXT_FREQ_HZ 10000000
#define EXT_FREQ_HZ 10000000
#define EXT_PPS_LATENCY_PS
63000 // fixme: make configurable
#define EXT_PPS_LATENCY_PS
16000 // def 30000 please verify
void
external_init
(
volatile
struct
spll_external_state
*
s
,
int
ext_ref
,
void
external_init
(
volatile
struct
spll_external_state
*
s
,
int
ext_ref
,
...
@@ -29,11 +29,13 @@ void external_init(volatile struct spll_external_state *s, int ext_ref,
...
@@ -29,11 +29,13 @@ void external_init(volatile struct spll_external_state *s, int ext_ref,
{
{
int
idx
=
spll_n_chan_ref
+
spll_n_chan_out
;
int
idx
=
spll_n_chan_ref
+
spll_n_chan_out
;
if
(
gpio_in
(
GPIO_EXT_BOARD_DETECT
))
idx
++
;
/* Legacy from LJD */
// if (gpio_in(GPIO_EXT_BOARD_DETECT))
// idx++;
helper_init
(
s
->
helper
,
idx
);
helper_init
(
s
->
helper
,
idx
);
mpll_init
(
s
->
main
,
idx
,
spll_n_chan_ref
);
mpll_init
(
s
->
main
,
idx
,
spll_n_chan_ref
,
SPLL_MODE_GRAND_MASTER
);
s
->
align_state
=
ALIGN_STATE_EXT_OFF
;
s
->
align_state
=
ALIGN_STATE_EXT_OFF
;
s
->
enabled
=
0
;
s
->
enabled
=
0
;
...
@@ -55,17 +57,10 @@ int external_locked(volatile struct spll_external_state *s)
...
@@ -55,17 +57,10 @@ int external_locked(volatile struct spll_external_state *s)
if
(
!
s
->
helper
->
ld
.
locked
||
!
s
->
main
->
ld
.
locked
)
if
(
!
s
->
helper
->
ld
.
locked
||
!
s
->
main
->
ld
.
locked
)
return
0
;
return
0
;
if
(
!
gpio_in
(
GPIO_EXT_BOARD_DETECT
)
&&
(
!
(
SPLL
->
ECCR
&
SPLL_ECCR_EXT_REF_LOCKED
)
||
// ext PLL became unlocked
if
(
(
!
(
SPLL
->
ECCR
&
SPLL_ECCR_EXT_REF_LOCKED
)
||
// ext PLL became unlocked
(
SPLL
->
ECCR
&
SPLL_ECCR_EXT_REF_STOPPED
)))
// 10MHz unplugged (only SPEC)
(
SPLL
->
ECCR
&
SPLL_ECCR_EXT_REF_STOPPED
)))
// 10MHz unplugged (only SPEC)
return
0
;
return
0
;
if
(
!
(
gpio_in
(
GPIO_EXT_BOARD_DETECT
)
&&
(
SPLL
->
ECCR
&
SPLL_ECCR_EXT_REF_PLLLOCK
)))
return
0
;
//FIXME A bug prevents the correct locking if the external lock check is executed
// Correct way to solve it: export the LOCK signal from the gateware and check it
// if (gpio_in(GPIO_EXT_BOARD_DETECT) && ext_ad9516_locked())
// return 1;
switch
(
s
->
align_state
)
{
switch
(
s
->
align_state
)
{
case
ALIGN_STATE_EXT_OFF
:
case
ALIGN_STATE_EXT_OFF
:
case
ALIGN_STATE_WAIT_CLKIN
:
case
ALIGN_STATE_WAIT_CLKIN
:
...
@@ -99,34 +94,46 @@ int external_align_fsm(volatile struct spll_external_state *s)
...
@@ -99,34 +94,46 @@ int external_align_fsm(volatile struct spll_external_state *s)
{
{
int
v
,
done_sth
=
0
;
int
v
,
done_sth
=
0
;
uint32_t
f_ext
=
0
;
uint32_t
f_ext
=
0
;
uint32_t
f_vco
=
0
;
switch
(
s
->
align_state
)
{
switch
(
s
->
align_state
)
{
case
ALIGN_STATE_EXT_OFF
:
case
ALIGN_STATE_EXT_OFF
:
break
;
break
;
case
ALIGN_STATE_WAIT_CLKIN
:
case
ALIGN_STATE_WAIT_CLKIN
:
if
(
!
gpio_in
(
GPIO_EXT_BOARD_DETECT
)
&&
!
(
SPLL
->
ECCR
&
SPLL_ECCR_EXT_REF_STOPPED
)
)
{
if
(
!
(
SPLL
->
ECCR
&
SPLL_ECCR_EXT_REF_STOPPED
)
)
{
SPLL
->
ECCR
|=
SPLL_ECCR_EXT_REF_PLLRST
;
SPLL
->
ECCR
|=
SPLL_ECCR_EXT_REF_PLLRST
;
s
->
align_state
=
ALIGN_STATE_WAIT_PLOCK
;
s
->
align_state
=
ALIGN_STATE_WAIT_PLOCK
;
done_sth
++
;
done_sth
++
;
}
}
f_ext
=
spll_measure_frequency
(
SPLL_OSC_EXT
);
f_ext
=
spll_measure_frequency
(
SPLL_OSC_EXT
);
if
(
gpio_in
(
GPIO_EXT_BOARD_DETECT
)
&&
(
f_ext
>
9999000
)
&&
(
f_ext
<
10001000
))
pp_printf
(
"Meas ext freq: %d
\n
"
,
f_ext
);
if
(
!
ext_ad9516_init
())
{
f_vco
=
spll_measure_frequency
(
SPLL_OSC_REF
);
s
->
align_state
=
ALIGN_STATE_WAIT_PLOCK
;
pp_printf
(
"Meas vco freq: %d
\n
"
,
f_vco
);
pp_printf
(
"External AD9516 locked
\n
"
);
}
if
((
f_ext
>
9999000
)
&&
(
f_ext
<
10001000
))
{
if
(
!
ext_ad9516_init
())
{
s
->
align_state
=
ALIGN_STATE_WAIT_PLOCK
;
pp_printf
(
"External AD9516 programmed
\n
"
);
}
else
{
pp_printf
(
"Something went wrong programming the GM PLL
\n
"
);
}
}
break
;
break
;
case
ALIGN_STATE_WAIT_PLOCK
:
case
ALIGN_STATE_WAIT_PLOCK
:
SPLL
->
ECCR
&=
(
~
SPLL_ECCR_EXT_REF_PLLRST
);
SPLL
->
ECCR
&=
(
~
SPLL_ECCR_EXT_REF_PLLRST
);
if
(
!
gpio_in
(
GPIO_EXT_BOARD_DETECT
)
&&
SPLL
->
ECCR
&
SPLL_ECCR_EXT_REF_STOPPED
)
if
(
/* !gpio_in(GPIO_EXT_BOARD_DETECT) && */
SPLL
->
ECCR
&
SPLL_ECCR_EXT_REF_STOPPED
)
s
->
align_state
=
ALIGN_STATE_WAIT_CLKIN
;
s
->
align_state
=
ALIGN_STATE_WAIT_CLKIN
;
else
if
((
!
gpio_in
(
GPIO_EXT_BOARD_DETECT
)
&&
SPLL
->
ECCR
&
SPLL_ECCR_EXT_REF_LOCKED
)
||
else
if
(
ext_ad9516_locked
())
gpio_in
(
GPIO_EXT_BOARD_DETECT
)
&&
SPLL
->
ECCR
&
SPLL_ECCR_EXT_REF_PLLLOCK
)
{
s
->
align_state
=
ALIGN_STATE_START
;
pp_printf
(
"External AD9516 locked.
\n
"
);
done_sth
++
;
s
->
align_state
=
ALIGN_STATE_START
;
}
done_sth
++
;
break
;
break
;
case
ALIGN_STATE_START
:
case
ALIGN_STATE_START
:
...
@@ -143,7 +150,7 @@ int external_align_fsm(volatile struct spll_external_state *s)
...
@@ -143,7 +150,7 @@ int external_align_fsm(volatile struct spll_external_state *s)
SPLL
->
AL_CR
=
2
;
SPLL
->
AL_CR
=
2
;
if
(
s
->
helper
->
ld
.
locked
&&
s
->
main
->
ld
.
locked
)
{
if
(
s
->
helper
->
ld
.
locked
&&
s
->
main
->
ld
.
locked
)
{
PPSG
->
CR
=
PPSG_CR_CNT_EN
|
PPSG_CR_PWIDTH_W
(
10
);
PPSG
->
CR
=
PPSG_CR_CNT_EN
|
PPSG_CR_PWIDTH_W
(
10
);
PPSG
->
ADJ_NSEC
=
3
;
PPSG
->
ADJ_NSEC
=
5
;
PPSG
->
ESCR
=
PPSG_ESCR_SYNC
;
PPSG
->
ESCR
=
PPSG_ESCR_SYNC
;
s
->
align_state
=
ALIGN_STATE_INIT_CSYNC
;
s
->
align_state
=
ALIGN_STATE_INIT_CSYNC
;
pll_verbose
(
"EXT: DMTD locked.
\n
"
);
pll_verbose
(
"EXT: DMTD locked.
\n
"
);
...
@@ -166,20 +173,18 @@ int external_align_fsm(volatile struct spll_external_state *s)
...
@@ -166,20 +173,18 @@ int external_align_fsm(volatile struct spll_external_state *s)
s
->
align_shift
=
0
;
s
->
align_shift
=
0
;
pll_verbose
(
"EXT: CSync complete.
\n
"
);
pll_verbose
(
"EXT: CSync complete.
\n
"
);
done_sth
++
;
done_sth
++
;
//REMOVE
//mpll_set_phase_shift(s->main, +9000);
//s->align_state = ALIGN_STATE_COMPENSATE_DELAY;
}
}
break
;
break
;
case
ALIGN_STATE_START_ALIGNMENT
:
case
ALIGN_STATE_START_ALIGNMENT
:
if
(
align_sample
(
1
,
&
v
))
{
if
(
align_sample
(
1
,
&
v
))
{
v
%=
ALIGN_SAMPLE_PERIOD
;
v
%=
ALIGN_SAMPLE_PERIOD
;
pp_printf
(
"1st v: %d
\n
"
,
v
);
if
(
v
==
0
||
v
>=
ALIGN_SAMPLE_PERIOD
/
2
)
{
if
(
v
==
0
||
v
>=
ALIGN_SAMPLE_PERIOD
/
2
)
{
s
->
align_target
=
EXT_PERIOD_NS
;
s
->
align_target
=
0
;
s
->
align_step
=
-
100
;
s
->
align_step
=
-
100
;
}
else
if
(
s
>
0
)
{
}
else
if
(
s
>
0
)
{
s
->
align_target
=
0
;
s
->
align_target
=
ALIGN_SAMPLE_PERIOD
-
EXT_PERIOD_NS
;
s
->
align_step
=
100
;
s
->
align_step
=
100
;
}
}
...
...
softpll/spll_helper.c
View file @
abf90c8b
...
@@ -28,8 +28,8 @@ void helper_init(struct spll_helper_state *s, int ref_channel)
...
@@ -28,8 +28,8 @@ void helper_init(struct spll_helper_state *s, int ref_channel)
s
->
pi
.
kp
=
-
150
;
//(int)(0.3 * 32.0 * 16.0); // / 2;
s
->
pi
.
kp
=
-
150
;
//(int)(0.3 * 32.0 * 16.0); // / 2;
s
->
pi
.
ki
=
-
2
;
//(int)(0.03 * 32.0 * 3.0); // / 2;
s
->
pi
.
ki
=
-
2
;
//(int)(0.03 * 32.0 * 3.0); // / 2;
#else
#else
s
->
pi
.
kp
=
150
;
s
->
pi
.
kp
=
150
;
// default 150;
s
->
pi
.
ki
=
2
;
s
->
pi
.
ki
=
2
;
// default 2
#endif
#endif
s
->
pi
.
anti_windup
=
1
;
s
->
pi
.
anti_windup
=
1
;
...
@@ -62,12 +62,12 @@ int helper_update(struct spll_helper_state *s, int tag,
...
@@ -62,12 +62,12 @@ int helper_update(struct spll_helper_state *s, int tag,
err
=
(
tag
+
s
->
p_adder
)
-
s
->
p_setpoint
;
err
=
(
tag
+
s
->
p_adder
)
-
s
->
p_setpoint
;
if
(
HELPER_ERROR_CLAMP
)
{
if
(
HELPER_ERROR_CLAMP
)
{
if
(
err
<
-
HELPER_ERROR_CLAMP
)
if
(
err
<
-
HELPER_ERROR_CLAMP
)
err
=
-
HELPER_ERROR_CLAMP
;
err
=
-
HELPER_ERROR_CLAMP
;
if
(
err
>
HELPER_ERROR_CLAMP
)
if
(
err
>
HELPER_ERROR_CLAMP
)
err
=
HELPER_ERROR_CLAMP
;
err
=
HELPER_ERROR_CLAMP
;
}
}
if
((
tag
+
s
->
p_adder
)
>
HELPER_TAG_WRAPAROUND
if
((
tag
+
s
->
p_adder
)
>
HELPER_TAG_WRAPAROUND
...
...
softpll/spll_main.c
View file @
abf90c8b
...
@@ -22,22 +22,36 @@
...
@@ -22,22 +22,36 @@
void
mpll_init
(
struct
spll_main_state
*
s
,
int
id_ref
,
void
mpll_init
(
struct
spll_main_state
*
s
,
int
id_ref
,
int
id_out
)
int
id_out
,
int
mode
)
{
{
/* Frequency branch PI controller */
/* Frequency branch PI controller */
s
->
pi
.
y_min
=
5
;
s
->
pi
.
y_min
=
5
;
s
->
pi
.
y_max
=
65530
;
s
->
pi
.
y_max
=
65530
;
s
->
pi
.
anti_windup
=
1
;
s
->
pi
.
anti_windup
=
1
;
s
->
pi
.
bias
=
30000
;
s
->
pi
.
bias
=
30000
;
#if defined(CONFIG_WR_SWITCH)
s
->
pi
.
kp
=
1000
;
// / 2;
if
(
mode
==
SPLL_MODE_GRAND_MASTER
)
s
->
pi
.
ki
=
5
;
// / 2;
{
#elif defined(CONFIG_WR_NODE)
#if defined(CONFIG_WR_SWITCH)
s
->
pi
.
kp
=
-
1100
;
// / 2;
s
->
pi
.
kp
=
1100
;
s
->
pi
.
ki
=
-
30
;
// / 2;
s
->
pi
.
ki
=
30
;
#else
#elif defined(CONFIG_WR_NODE)
#error "Please set CONFIG for wr switch or wr node"
s
->
pi
.
kp
=
-
1100
;
#endif
s
->
pi
.
ki
=
-
30
;
#else
#error "Please set CONFIG wr wr switch or wr node"
#endif
}
else
{
#if defined(CONFIG_WR_SWITCH)
s
->
pi
.
kp
=
600
;
s
->
pi
.
ki
=
2
;
#elif defined(CONFIG_WR_NODE)
s
->
pi
.
kp
=
-
600
;
s
->
pi
.
ki
=
-
2
;
#else
#error "Please set CONFIG wr wr switch or wr node"
#endif
}
s
->
delock_count
=
0
;
s
->
delock_count
=
0
;
s
->
enabled
=
0
;
s
->
enabled
=
0
;
...
@@ -49,7 +63,7 @@ void mpll_init(struct spll_main_state *s, int id_ref,
...
@@ -49,7 +63,7 @@ void mpll_init(struct spll_main_state *s, int id_ref,
s
->
id_out
=
id_out
;
s
->
id_out
=
id_out
;
s
->
dac_index
=
id_out
-
spll_n_chan_ref
;
s
->
dac_index
=
id_out
-
spll_n_chan_ref
;
pll_verbose
(
"ref %d out %d idx %x
\n
"
,
s
->
id_ref
,
s
->
id_out
,
s
->
dac_index
);
pll_verbose
(
"
mpll_init:
ref %d out %d idx %x
\n
"
,
s
->
id_ref
,
s
->
id_out
,
s
->
dac_index
);
pi_init
((
spll_pi_t
*
)
&
s
->
pi
);
pi_init
((
spll_pi_t
*
)
&
s
->
pi
);
ld_init
((
spll_lock_det_t
*
)
&
s
->
ld
);
ld_init
((
spll_lock_det_t
*
)
&
s
->
ld
);
...
@@ -120,10 +134,6 @@ int mpll_update(struct spll_main_state *s, int tag, int source)
...
@@ -120,10 +134,6 @@ int mpll_update(struct spll_main_state *s, int tag, int source)
if
(
s
->
tag_ref
>=
0
&&
s
->
tag_out
>=
0
)
{
if
(
s
->
tag_ref
>=
0
&&
s
->
tag_out
>=
0
)
{
err
=
s
->
adder_ref
+
s
->
tag_ref
-
s
->
adder_out
-
s
->
tag_out
;
err
=
s
->
adder_ref
+
s
->
tag_ref
-
s
->
adder_out
-
s
->
tag_out
;
// if (!(count++ % 1000))
// {
// pll_verbose("%d %d %d %d %d %d\n",count,s->tag_ref,s->tag_out,s->adder_ref,s->adder_out,err);
// }
#ifndef WITH_SEQUENCING
#ifndef WITH_SEQUENCING
...
...
softpll/spll_main.h
View file @
abf90c8b
...
@@ -37,7 +37,7 @@ struct spll_main_state {
...
@@ -37,7 +37,7 @@ struct spll_main_state {
};
};
void
mpll_init
(
struct
spll_main_state
*
s
,
int
id_ref
,
void
mpll_init
(
struct
spll_main_state
*
s
,
int
id_ref
,
int
id_out
);
int
id_out
,
int
mode
);
void
mpll_stop
(
struct
spll_main_state
*
s
);
void
mpll_stop
(
struct
spll_main_state
*
s
);
...
...
wrs_main.c
View file @
abf90c8b
...
@@ -42,9 +42,6 @@ int main(void)
...
@@ -42,9 +42,6 @@ int main(void)
build_revision
,
build_date
,
build_time
);
build_revision
,
build_date
,
build_time
);
pp_printf
(
"SCB version: %d. %s
\n
"
,
scb_ver
,(
scb_ver
>=
34
)
?
"10 MHz SMC Output."
:
""
);
pp_printf
(
"SCB version: %d. %s
\n
"
,
scb_ver
,(
scb_ver
>=
34
)
?
"10 MHz SMC Output."
:
""
);
pp_printf
(
"Start counter %d
\n
"
,
stats
.
start_cnt
);
pp_printf
(
"Start counter %d
\n
"
,
stats
.
start_cnt
);
//if (gpio_in(GPIO_EXT_BOARD_DETECT))
// pp_printf("\n--- WRS Low jitter board detected. ---\nAllow 1 hour of warming up before starting measurements\n");
//pp_printf("--\n");
if
(
stats
.
start_cnt
>
1
)
{
if
(
stats
.
start_cnt
>
1
)
{
pp_printf
(
"!!spll does not work after restart!!
\n
"
);
pp_printf
(
"!!spll does not work after restart!!
\n
"
);
...
@@ -65,11 +62,6 @@ int main(void)
...
@@ -65,11 +62,6 @@ int main(void)
start_tics
=
tics
;
start_tics
=
tics
;
}
}
/* if (time_after(tics, start_tics + TICS_PER_SECOND*10)){
if
}
*/
rts_update
();
rts_update
();
rtipc_action
();
rtipc_action
();
spll_update
();
spll_update
();
...
...
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