Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SDM C code and example #46

Merged
merged 54 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
1f0289f
Initial copy of simple example and separate out pfd
ed-xmos Nov 15, 2023
4eafeeb
WIP SDM C
ed-xmos Nov 15, 2023
e0df4c1
Very basic working SDM loop
ed-xmos Nov 16, 2023
828d6fb
Add double integral term
ed-xmos Nov 16, 2023
83e4f8f
Add missing version bump
ed-xmos Nov 16, 2023
0577d8f
Another bump missing
ed-xmos Nov 16, 2023
0e35d3f
Fix check for zero Kii
ed-xmos Nov 16, 2023
4af5649
Typo Ki -> Kii
ed-xmos Nov 16, 2023
d74b857
Add missing register setup file
ed-xmos Nov 16, 2023
8041d8a
Copyright
ed-xmos Nov 16, 2023
0fa6f32
Remove repeated fn
ed-xmos Nov 16, 2023
d3742f7
WIP make HW setup generic
ed-xmos Nov 20, 2023
e9b0edf
Refactor with struct of structs
ed-xmos Nov 20, 2023
dba71af
Fix build error in i2s example
ed-xmos Nov 20, 2023
7604f86
Make pfd init common
ed-xmos Nov 20, 2023
969427c
Fix tests
ed-xmos Nov 20, 2023
bc6b983
Test fix
ed-xmos Nov 20, 2023
a6a2295
Add IIR to C SDM
ed-xmos Nov 21, 2023
ae246d9
Separate out low level equiv test
ed-xmos Nov 21, 2023
c092c5a
Merge branch 'feature/sdm' into feature/sdm_c
ed-xmos Nov 21, 2023
56a31a5
Tidy test separation
ed-xmos Nov 21, 2023
c2e4899
Move SDM code from example to lib
ed-xmos Nov 21, 2023
7c82e6f
Add initial SDM DCO test app
ed-xmos Nov 21, 2023
0d261ac
Keep param inside object in DCO
ed-xmos Nov 21, 2023
9bd2532
WIP SDM DCO test
ed-xmos Nov 21, 2023
5213860
Basic working SDM DCO test
ed-xmos Nov 22, 2023
589d5b5
Finished DCO SDM test but fails after 20 iters
ed-xmos Nov 22, 2023
d500641
SDM ctrl test firmware
ed-xmos Nov 22, 2023
9b05864
Fix mask op
ed-xmos Nov 22, 2023
ecd77c8
Fix SDM DCO equiv test
ed-xmos Nov 22, 2023
67729a5
Add SDM tests to build
ed-xmos Nov 23, 2023
b944eb0
Refactor and tidy
ed-xmos Nov 23, 2023
85f5370
Add failing SDM ctrl test
ed-xmos Nov 23, 2023
a446b23
Passing SDM ctrl app
ed-xmos Nov 23, 2023
c35f689
add exclude for autgen files
ed-xmos Nov 23, 2023
088d884
Fix exclude
ed-xmos Nov 23, 2023
1a614e9
remove unnecessary inheritance
ed-xmos Nov 23, 2023
2c71246
Merge commit '69e67bd53c113b903acc0e1dabc79d1f2f98254d' into feature/…
ed-xmos Nov 23, 2023
ef3e62a
Tidy example and add lock detect for SDM
ed-xmos Nov 23, 2023
c0f5969
Refactor lock status in model
ed-xmos Nov 27, 2023
20cedc9
SDM C API tidy and doxy
ed-xmos Nov 27, 2023
4992035
Os in test apps
ed-xmos Nov 27, 2023
80bd5a9
Improve model comments
ed-xmos Nov 27, 2023
55b5ca5
Run python model examples and archive
ed-xmos Nov 27, 2023
a844de2
Run through all SDM profiles for test and improve artefact store
ed-xmos Nov 27, 2023
9685467
Merge branch 'feature/add_ii' into feature/sdm_c
ed-xmos Nov 27, 2023
db99260
Finish adding II term and fix example run
ed-xmos Nov 27, 2023
8d01815
Changelog and typo fix
ed-xmos Nov 27, 2023
fcccf6e
Missing version bump
ed-xmos Nov 27, 2023
781d70a
Add Kii into tests
ed-xmos Nov 27, 2023
4efa998
Fix missing handling of Kii
ed-xmos Nov 27, 2023
b6d69eb
II clipping now tested and equivalent
ed-xmos Nov 27, 2023
ae58cb9
Var typo
ed-xmos Nov 27, 2023
1fe88c9
Remove some copy pasta test comments
ed-xmos Nov 28, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .xmos_ignore_source_check
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
python/sw_pll/pll_calc.py
register_setup.h
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
lib_sw_pll library change log
=============================

2.0.0
-----

* ADDED: Double integral term to controller
* ADDED: Sigma Delta Modulator option for PLL
* CHANGED: Refactored Python model into analogous objects

1.1.0
-----

Expand Down
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ if(PROJECT_IS_TOP_LEVEL)
add_subdirectory(modules/fwk_io)
add_subdirectory(tests/test_app)
add_subdirectory(tests/test_app_low_level_api)
add_subdirectory(tests/test_app_sdm_dco)
add_subdirectory(tests/test_app_sdm_ctrl)
endif()
14 changes: 13 additions & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,26 @@ pipeline {
}
zip archive: true, zipFile: "build.zip", dir: "build"
zip archive: true, zipFile: "tests.zip", dir: "tests/bin"
archiveArtifacts artifacts: "tests/bin/timing-report.txt", allowEmptyArchive: false
archiveArtifacts artifacts: "tests/bin/timing-report*.txt", allowEmptyArchive: false

junit 'tests/results.xml'
}
}
}
}
}
stage('Python examples'){
steps {
dir('lib_sw_pll') {
withVenv {
catchError {
sh './tools/ci/do-model-examples.sh'
}
archiveArtifacts artifacts: "python/sw_pll/*.png,python/sw_pll/*.wav", allowEmptyArchive: false
}
}
}
}
}
post {
cleanup {
Expand Down
2 changes: 1 addition & 1 deletion doc/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"title": "XMOS SW PLL",
"project": "SW PLL",
"version": "1.1.0",
"version": "2.0.0",
"architectures": {
"xcore.ai": ["15.2.x"]
}
Expand Down
4 changes: 2 additions & 2 deletions doc/substitutions.rst-inc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.. |full_version_str| replace:: v1.1.0
.. |tools_version| replace:: 15.2.x
.. |full_version_str| replace:: v2.0.0
.. |tools_version| replace:: 15.2.1
.. |I2S| replace:: I\ :sup:`2`\ S
.. |I2C| replace:: I\ :sup:`2`\ C
.. |trademark| replace:: :sup:`TM`
Expand Down
1 change: 1 addition & 0 deletions examples/examples.cmake
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
include(${CMAKE_CURRENT_LIST_DIR}/simple/simple.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/simple_sdm/simple_sdm.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/i2s_slave/i2s_slave.cmake)
3 changes: 2 additions & 1 deletion examples/i2s_slave/src/i2s_slave_sw_pll.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ void sw_pll_test(void){
sw_pll_init(&sw_pll,
SW_PLL_15Q16(0.0),
SW_PLL_15Q16(1.0),
SW_PLL_15Q16(0.0),
CONTROL_LOOP_COUNT,
PLL_RATIO,
BCLKS_PER_LRCLK,
Expand All @@ -189,7 +190,7 @@ void sw_pll_test(void){
PPM_RANGE);


printf("i_windup_limit: %ld\n", sw_pll.i_windup_limit);
printf("i_windup_limit: %ld\n", sw_pll.pi_state.i_windup_limit);


// Initialise app_data
Expand Down
60 changes: 60 additions & 0 deletions examples/shared/src/clock_gen.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.

#include <xs1.h>
#include <stdio.h>
#include <xcore/hwtimer.h>
#include <xcore/port.h>

#include "sw_pll_common.h"

#define DO_CLOCKS \
printf("Ref Hz: %d\n", clock_rate >> 1); \
\
unsigned cycle_ticks_int = XS1_TIMER_HZ / clock_rate; \
unsigned cycle_ticks_remaidner = XS1_TIMER_HZ % clock_rate; \
unsigned carry = 0; \
\
period_trig += XS1_TIMER_HZ * 1; \
unsigned time_now = hwtimer_get_time(period_tmr); \
while(TIMER_TIMEAFTER(period_trig, time_now)) \
{ \
port_out(p_clock_gen, port_val); \
hwtimer_wait_until(clock_tmr, time_trig); \
time_trig += cycle_ticks_int; \
carry += cycle_ticks_remaidner; \
if(carry >= clock_rate){ \
time_trig++; \
carry -= clock_rate; \
} \
port_val ^= 1; \
time_now = hwtimer_get_time(period_tmr); \
}

void clock_gen(unsigned ref_frequency, unsigned ppm_range) // Step from - to + this
{
unsigned clock_rate = ref_frequency * 2; // Note double because we generate edges at this rate

unsigned clock_rate_low = (unsigned)(clock_rate * (1.0 - (float)ppm_range / 1000000.0));
unsigned clock_rate_high = (unsigned)(clock_rate * (1.0 + (float)ppm_range / 1000000.0));
unsigned step_size = (clock_rate_high - clock_rate_low) / 20;

printf("Sweep range: %d %d %d, step size: %d\n", clock_rate_low / 2, clock_rate / 2, clock_rate_high / 2, step_size);

hwtimer_t period_tmr = hwtimer_alloc();
unsigned period_trig = hwtimer_get_time(period_tmr);

hwtimer_t clock_tmr = hwtimer_alloc();
unsigned time_trig = hwtimer_get_time(clock_tmr);

port_t p_clock_gen = PORT_I2S_BCLK;
port_enable(p_clock_gen);
unsigned port_val = 1;

for(unsigned clock_rate = clock_rate_low; clock_rate <= clock_rate_high; clock_rate += 2 * step_size){
DO_CLOCKS
}
for(unsigned clock_rate = clock_rate_high; clock_rate > clock_rate_low; clock_rate -= 2 * step_size){
DO_CLOCKS
}
}
6 changes: 6 additions & 0 deletions examples/shared/src/clock_gen.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright 2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.

// Runs a task in a thread that produces a clock that sweeps a reference clock
// between + and - the ppm value specified.
void clock_gen(unsigned ref_frequency, unsigned ppm_range);
43 changes: 43 additions & 0 deletions examples/shared/src/resource_setup.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.

#include <stdio.h>
#include "resource_setup.h"

void setup_ref_and_mclk_ports_and_clocks(port_t p_mclk, xclock_t clk_mclk, port_t p_ref_clk_in, xclock_t clk_word_clk, port_t p_ref_clk_count)
{
// Create clock from mclk port and use it to clock the p_ref_clk port.
clock_enable(clk_mclk);
port_enable(p_mclk);
clock_set_source_port(clk_mclk, p_mclk);

// Clock p_ref_clk from MCLK
port_enable(p_ref_clk_in);
port_set_clock(p_ref_clk_in, clk_mclk);

clock_start(clk_mclk);

// Create clock from ref_clock_port and use it to clock the p_ref_clk_count port.
clock_enable(clk_word_clk);
clock_set_source_port(clk_word_clk, p_ref_clk_in);
port_enable(p_ref_clk_count);
port_set_clock(p_ref_clk_count, clk_word_clk);

clock_start(clk_word_clk);
}


void setup_recovered_ref_clock_output(port_t p_recovered_ref_clk, xclock_t clk_recovered_ref_clk, port_t p_mclk, unsigned divider)
{
// Connect clock block with divide to mclk
clock_enable(clk_recovered_ref_clk);
clock_set_source_port(clk_recovered_ref_clk, p_mclk);
clock_set_divide(clk_recovered_ref_clk, divider / 2);
printf("Divider: %u\n", divider);

// Output the divided mclk on a port
port_enable(p_recovered_ref_clk);
port_set_clock(p_recovered_ref_clk, clk_recovered_ref_clk);
port_set_out_clock(p_recovered_ref_clk);
clock_start(clk_recovered_ref_clk);
}
17 changes: 17 additions & 0 deletions examples/shared/src/resource_setup.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.

#include <xcore/port.h>

#pragma once

// Sets up the provided resources so that we can count PLL output clocks.
// We do this by clocking the input reference clock port with the output from the PLL
// and its internal counter is used to count the PLL clock cycles(normal timers cannot count custom clocks)
// It also sets up a dummy port clocked by the input reference to act as a timing barrier so that
// the output clock count can be precisely sampled.
void setup_ref_and_mclk_ports_and_clocks(port_t p_mclk, xclock_t clk_mclk, port_t p_ref_clk_in, xclock_t clk_word_clk, port_t p_ref_clk_count);

// Sets up a divided version of the PLL output so it can visually be compared (eg. on a DSO)
// with the input reference clock to the PLL
void setup_recovered_ref_clock_output(port_t p_recovered_ref_clk, xclock_t clk_recovered_ref_clk, port_t p_mclk, unsigned divider);
8 changes: 5 additions & 3 deletions examples/simple/simple.cmake
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#**********************
# Gather Sources
#**********************
file(GLOB_RECURSE APP_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/*.c ${CMAKE_CURRENT_LIST_DIR}/src/*.xc)
set(APP_INCLUDES
${CMAKE_CURRENT_LIST_DIR}/src
file(GLOB_RECURSE APP_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/*.c
${CMAKE_CURRENT_LIST_DIR}/src/*.xc
${CMAKE_CURRENT_LIST_DIR}/../shared/src/*.c )
set(APP_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/src
${CMAKE_CURRENT_LIST_DIR}/../shared/src
)

#**********************
Expand Down
25 changes: 16 additions & 9 deletions examples/simple/src/main.xc
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,27 @@

#include <platform.h>
#include <xs1.h>
#include <stdlib.h>

extern void sw_pll_test(void);
extern void clock_gen(void);
extern "C" {
#include "clock_gen.h"
}


int main(void)
{
par
{
on tile[0]: par {
}
on tile[1]: par {
sw_pll_test();
clock_gen();
par
{
on tile[0]: par {
}
on tile[1]: par {
sw_pll_test();
{
clock_gen(48000, 150);
exit(0);
}
}
}
}
return 0;
}
93 changes: 2 additions & 91 deletions examples/simple/src/simple_sw_pll.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <xs1.h>

#include "sw_pll.h"
#include "resource_setup.h"

#define MCLK_FREQUENCY 12288000
#define REF_FREQUENCY 48000
Expand All @@ -21,44 +22,6 @@
//Found solution: IN 24.000MHz, OUT 12.288018MHz, VCO 3047.43MHz, RD 4, FD 507.905 (m = 19, n = 21), OD 2, FOD 31, ERR +1.50ppm
#include "fractions.h"

void setup_ref_and_mclk_ports_and_clocks(port_t p_mclk, xclock_t clk_mclk, port_t p_ref_clk_in, xclock_t clk_word_clk, port_t p_ref_clk_count)
{
// Create clock from mclk port and use it to clock the p_ref_clk port.
clock_enable(clk_mclk);
port_enable(p_mclk);
clock_set_source_port(clk_mclk, p_mclk);

// Clock p_ref_clk from MCLK
port_enable(p_ref_clk_in);
port_set_clock(p_ref_clk_in, clk_mclk);

clock_start(clk_mclk);

// Create clock from ref_clock_port and use it to clock the p_ref_clk_count port.
clock_enable(clk_word_clk);
clock_set_source_port(clk_word_clk, p_ref_clk_in);
port_enable(p_ref_clk_count);
port_set_clock(p_ref_clk_count, clk_word_clk);

clock_start(clk_word_clk);
}


void setup_recovered_ref_clock_output(port_t p_recovered_ref_clk, xclock_t clk_recovered_ref_clk, port_t p_mclk, unsigned divider)
{
// Connect clock block with divide to mclk
clock_enable(clk_recovered_ref_clk);
clock_set_source_port(clk_recovered_ref_clk, p_mclk);
clock_set_divide(clk_recovered_ref_clk, divider / 2);
printf("Divider: %u\n", divider);

// Output the divided mclk on a port
port_enable(p_recovered_ref_clk);
port_set_clock(p_recovered_ref_clk, clk_recovered_ref_clk);
port_set_out_clock(p_recovered_ref_clk);
clock_start(clk_recovered_ref_clk);
}

void sw_pll_test(void){

// Declare mclk and refclk resources and connect up
Expand All @@ -78,6 +41,7 @@ void sw_pll_test(void){
sw_pll_init(&sw_pll,
SW_PLL_15Q16(0.0),
SW_PLL_15Q16(1.0),
SW_PLL_15Q16(0.0),
CONTROL_LOOP_COUNT,
PLL_RATIO,
0,
Expand Down Expand Up @@ -111,56 +75,3 @@ void sw_pll_test(void){
}
}
}

#define DO_CLOCKS \
printf("Ref Hz: %d\n", clock_rate >> 1); \
\
unsigned cycle_ticks_int = XS1_TIMER_HZ / clock_rate; \
unsigned cycle_ticks_remaidner = XS1_TIMER_HZ % clock_rate; \
unsigned carry = 0; \
\
period_trig += XS1_TIMER_HZ * 1; \
unsigned time_now = hwtimer_get_time(period_tmr); \
while(TIMER_TIMEAFTER(period_trig, time_now)) \
{ \
port_out(p_clock_gen, port_val); \
hwtimer_wait_until(clock_tmr, time_trig); \
time_trig += cycle_ticks_int; \
carry += cycle_ticks_remaidner; \
if(carry >= clock_rate){ \
time_trig++; \
carry -= clock_rate; \
} \
port_val ^= 1; \
time_now = hwtimer_get_time(period_tmr); \
}

void clock_gen(void)
{
unsigned clock_rate = REF_FREQUENCY * 2; // Note double because we generate edges at this rate
unsigned ppm_range = 150; // Step from - to + this

unsigned clock_rate_low = (unsigned)(clock_rate * (1.0 - (float)ppm_range / 1000000.0));
unsigned clock_rate_high = (unsigned)(clock_rate * (1.0 + (float)ppm_range / 1000000.0));
unsigned step_size = (clock_rate_high - clock_rate_low) / 20;

printf("Sweep range: %d %d %d, step size: %d\n", clock_rate_low / 2, clock_rate / 2, clock_rate_high / 2, step_size);

hwtimer_t period_tmr = hwtimer_alloc();
unsigned period_trig = hwtimer_get_time(period_tmr);

hwtimer_t clock_tmr = hwtimer_alloc();
unsigned time_trig = hwtimer_get_time(clock_tmr);

port_t p_clock_gen = PORT_I2S_BCLK;
port_enable(p_clock_gen);
unsigned port_val = 1;

for(unsigned clock_rate = clock_rate_low; clock_rate <= clock_rate_high; clock_rate += 2 * step_size){
DO_CLOCKS
}
for(unsigned clock_rate = clock_rate_high; clock_rate > clock_rate_low; clock_rate -= 2 * step_size){
DO_CLOCKS
}
exit(0);
}
Loading