init
This commit is contained in:
50
lib_sw_pll/examples/simple_sdm/simple_sdm.cmake
Normal file
50
lib_sw_pll/examples/simple_sdm/simple_sdm.cmake
Normal file
@@ -0,0 +1,50 @@
|
||||
#**********************
|
||||
# Gather Sources
|
||||
#**********************
|
||||
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
|
||||
)
|
||||
|
||||
#**********************
|
||||
# Flags
|
||||
#**********************
|
||||
set(APP_COMPILER_FLAGS
|
||||
-Os
|
||||
-g
|
||||
-report
|
||||
-fxscope
|
||||
-mcmodel=large
|
||||
-Wno-xcore-fptrgroup
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/config.xscope
|
||||
-target=XCORE-AI-EXPLORER
|
||||
)
|
||||
|
||||
set(APP_COMPILE_DEFINITIONS
|
||||
DEBUG_PRINT_ENABLE=1
|
||||
PLATFORM_SUPPORTS_TILE_0=1
|
||||
PLATFORM_SUPPORTS_TILE_1=1
|
||||
PLATFORM_SUPPORTS_TILE_2=0
|
||||
PLATFORM_SUPPORTS_TILE_3=0
|
||||
PLATFORM_USES_TILE_0=1
|
||||
PLATFORM_USES_TILE_1=1
|
||||
)
|
||||
|
||||
set(APP_LINK_OPTIONS
|
||||
-report
|
||||
-target=XCORE-AI-EXPLORER
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/config.xscope
|
||||
)
|
||||
|
||||
#**********************
|
||||
# Tile Targets
|
||||
#**********************
|
||||
add_executable(simple_sdm)
|
||||
target_sources(simple_sdm PUBLIC ${APP_SOURCES})
|
||||
target_include_directories(simple_sdm PUBLIC ${APP_INCLUDES})
|
||||
target_compile_definitions(simple_sdm PRIVATE ${APP_COMPILE_DEFINITIONS})
|
||||
target_compile_options(simple_sdm PRIVATE ${APP_COMPILER_FLAGS})
|
||||
target_link_options(simple_sdm PRIVATE ${APP_LINK_OPTIONS})
|
||||
target_link_libraries(simple_sdm PUBLIC lib_sw_pll)
|
||||
24
lib_sw_pll/examples/simple_sdm/src/config.xscope
Normal file
24
lib_sw_pll/examples/simple_sdm/src/config.xscope
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- ======================================================= -->
|
||||
<!-- The 'ioMode' attribute on the xSCOPEconfig -->
|
||||
<!-- element can take the following values: -->
|
||||
<!-- "none", "basic", "timed" -->
|
||||
<!-- -->
|
||||
<!-- The 'type' attribute on Probe -->
|
||||
<!-- elements can take the following values: -->
|
||||
<!-- "STARTSTOP", "CONTINUOUS", "DISCRETE", "STATEMACHINE" -->
|
||||
<!-- -->
|
||||
<!-- The 'datatype' attribute on Probe -->
|
||||
<!-- elements can take the following values: -->
|
||||
<!-- "NONE", "UINT", "INT", "FLOAT" -->
|
||||
<!-- ======================================================= -->
|
||||
|
||||
<xSCOPEconfig ioMode="basic" enabled="true">
|
||||
|
||||
<!-- For example: -->
|
||||
<!-- <Probe name="I2S_RX_0" type="CONTINUOUS" datatype="INT" units="Value" enabled="true"/> -->
|
||||
|
||||
|
||||
<!-- From the target code, call: xscope_int(PROBE_NAME, value); -->
|
||||
</xSCOPEconfig>
|
||||
33
lib_sw_pll/examples/simple_sdm/src/main.xc
Normal file
33
lib_sw_pll/examples/simple_sdm/src/main.xc
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#include <platform.h>
|
||||
#include <xs1.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern void sw_pll_sdm_test(chanend c_sdm_control);
|
||||
extern void sdm_task(chanend c_sdm_control);
|
||||
extern "C" {
|
||||
#include "clock_gen.h"
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
chan c_sdm_control;
|
||||
|
||||
par
|
||||
{
|
||||
on tile[0]: par {
|
||||
}
|
||||
|
||||
on tile[1]: par {
|
||||
sw_pll_sdm_test(c_sdm_control);
|
||||
sdm_task(c_sdm_control);
|
||||
{
|
||||
clock_gen(96000, 300);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
15
lib_sw_pll/examples/simple_sdm/src/register_setup.h
Normal file
15
lib_sw_pll/examples/simple_sdm/src/register_setup.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/* Autogenerated SDM App PLL setup by dco_model.py using 24.576_1M profile */
|
||||
/* Input freq: 24000000
|
||||
F: 146
|
||||
R: 0
|
||||
f: 4
|
||||
p: 10
|
||||
OD: 5
|
||||
ACD: 5
|
||||
*/
|
||||
|
||||
#define APP_PLL_CTL_REG 0x0A809200
|
||||
#define APP_PLL_DIV_REG 0x80000005
|
||||
#define APP_PLL_FRAC_REG 0x8000040A
|
||||
#define SW_PLL_SDM_CTRL_MID 478151
|
||||
#define SW_PLL_SDM_RATE 1000000
|
||||
137
lib_sw_pll/examples/simple_sdm/src/simple_sw_pll_sdm.c
Normal file
137
lib_sw_pll/examples/simple_sdm/src/simple_sw_pll_sdm.c
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright 2022-2023 XMOS LIMITED.
|
||||
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <xscope.h>
|
||||
#include <xs1.h>
|
||||
#include <platform.h>
|
||||
|
||||
#include <xcore/select.h>
|
||||
|
||||
#include "sw_pll.h"
|
||||
#include "resource_setup.h"
|
||||
|
||||
#define MCLK_FREQUENCY 24576000
|
||||
#define REF_FREQUENCY 96000
|
||||
#define PLL_RATIO (MCLK_FREQUENCY / REF_FREQUENCY)
|
||||
#define CONTROL_LOOP_COUNT 512
|
||||
|
||||
#include "register_setup.h"
|
||||
|
||||
void sdm_task(chanend_t c_sdm_control){
|
||||
printf("sdm_task\n");
|
||||
|
||||
const uint32_t sdm_interval = XS1_TIMER_HZ / SW_PLL_SDM_RATE; // in 10ns ticks = 1MHz
|
||||
|
||||
sw_pll_sdm_state_t sdm_state;
|
||||
sw_pll_init_sigma_delta(&sdm_state);
|
||||
|
||||
tileref_t this_tile = get_local_tile_id();
|
||||
|
||||
hwtimer_t tmr = hwtimer_alloc();
|
||||
int32_t trigger_time = hwtimer_get_time(tmr) + sdm_interval;
|
||||
bool running = true;
|
||||
int32_t sdm_in = 0; // Zero is an invalid number and the SDM will not write the frac reg until
|
||||
// the first control value has been received. This avoids issues with
|
||||
// channel lockup if two tasks (eg. init and SDM) try to write at the same
|
||||
// time.
|
||||
|
||||
while(running){
|
||||
// Poll for new SDM control value
|
||||
SELECT_RES(
|
||||
CASE_THEN(c_sdm_control, ctrl_update),
|
||||
DEFAULT_THEN(default_handler)
|
||||
)
|
||||
{
|
||||
ctrl_update:
|
||||
{
|
||||
sdm_in = chan_in_word(c_sdm_control);
|
||||
}
|
||||
break;
|
||||
|
||||
default_handler:
|
||||
{
|
||||
// Do nothing & fall-through
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Wait until the timer value has been reached
|
||||
// This implements a timing barrier and keeps
|
||||
// the loop rate constant.
|
||||
hwtimer_wait_until(tmr, trigger_time);
|
||||
trigger_time += sdm_interval;
|
||||
|
||||
// Do not write to the frac reg until we get out first
|
||||
// control value. This will avoid the writing of the
|
||||
// frac reg from two different threads which may cause
|
||||
// a channel deadlock.
|
||||
if(sdm_in){
|
||||
sw_pll_do_sigma_delta(&sdm_state, this_tile, sdm_in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sw_pll_send_ctrl_to_sdm_task(chanend_t c_sdm_control, int32_t dco_ctl){
|
||||
chan_out_word(c_sdm_control, dco_ctl);
|
||||
}
|
||||
|
||||
void sw_pll_sdm_test(chanend_t c_sdm_control){
|
||||
|
||||
// Declare mclk and refclk resources and connect up
|
||||
port_t p_mclk = PORT_MCLK_IN;
|
||||
xclock_t clk_mclk = XS1_CLKBLK_1;
|
||||
port_t p_clock_counter = PORT_I2S_LRCLK;
|
||||
xclock_t clk_ref_clk = XS1_CLKBLK_2;
|
||||
port_t p_ref_clk_timing = XS1_PORT_32A;
|
||||
setup_ref_and_mclk_ports_and_clocks(p_mclk, clk_mclk, p_clock_counter, clk_ref_clk, p_ref_clk_timing);
|
||||
|
||||
// Make a test output to observe the recovered mclk divided down to the refclk frequency
|
||||
xclock_t clk_recovered_ref_clk = XS1_CLKBLK_3;
|
||||
port_t p_recovered_ref_clk = PORT_I2S_DAC_DATA;
|
||||
setup_recovered_ref_clock_output(p_recovered_ref_clk, clk_recovered_ref_clk, p_mclk, PLL_RATIO);
|
||||
|
||||
sw_pll_state_t sw_pll;
|
||||
sw_pll_sdm_init(&sw_pll,
|
||||
SW_PLL_15Q16(0.0),
|
||||
SW_PLL_15Q16(32.0),
|
||||
SW_PLL_15Q16(0.25),
|
||||
CONTROL_LOOP_COUNT,
|
||||
PLL_RATIO,
|
||||
0, /* No jitter compensation needed */
|
||||
APP_PLL_CTL_REG,
|
||||
APP_PLL_DIV_REG,
|
||||
APP_PLL_FRAC_REG,
|
||||
SW_PLL_SDM_CTRL_MID,
|
||||
3000 /*PPM_RANGE FOR PFD*/);
|
||||
|
||||
sw_pll_lock_status_t lock_status = SW_PLL_LOCKED;
|
||||
|
||||
uint32_t max_time = 0;
|
||||
while(1)
|
||||
{
|
||||
port_in(p_ref_clk_timing); // This blocks each time round the loop until it can sample input (rising edges of word clock). So we know the count will be +1 each time.
|
||||
uint16_t mclk_pt = port_get_trigger_time(p_clock_counter);// Get the port timer val from p_clock_counter (which is running from MCLK). So this is basically a 16 bit free running counter running from MCLK.
|
||||
|
||||
uint32_t t0 = get_reference_time();
|
||||
bool ctrl_done = sw_pll_sdm_do_control(&sw_pll, mclk_pt, 0);
|
||||
uint32_t t1 = get_reference_time();
|
||||
|
||||
if(ctrl_done){
|
||||
sw_pll_send_ctrl_to_sdm_task(c_sdm_control, sw_pll.sdm_state.current_ctrl_val);
|
||||
}
|
||||
|
||||
if(t1 - t0 > max_time){
|
||||
max_time = t1 - t0;
|
||||
printf("Max ticks taken: %lu\n", max_time);
|
||||
}
|
||||
|
||||
if(sw_pll.lock_status != lock_status){
|
||||
lock_status = sw_pll.lock_status;
|
||||
const char msg[3][16] = {"UNLOCKED LOW\0", "LOCKED\0", "UNLOCKED HIGH\0"};
|
||||
printf("%s\n", msg[lock_status+1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user