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 test APIs for clock switching NDP120 PDM <-> I2S BCLK #6426

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
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
122 changes: 91 additions & 31 deletions os/drivers/ai-soc/ndp120/src/ndp120_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,7 @@
/* currently the max size of tank is limited to ~580ms */
#define AUDIO_BEFORE_MATCH_MS (1500)

/* when defined, the let the NDP use an external PDM clock */
#define USE_EXTERNAL_PDM_CLOCK
#define EXTERNAL_PDM_CLOCK_PDM_RATE 1536000
#define PDM_CLOCK_PDM_RATE 1536000

/* this is the higher bound of the keyword length, it will be rounded down to multiple of frame size */
#define KEYWORD_BUFFER_LEN (SYNTIANT_NDP120_AUDIO_SAMPLE_RATE * SYNTIANT_NDP120_AUDIO_SAMPLES_PER_WORD * AUDIO_BEFORE_MATCH_MS / 1000)
Expand Down Expand Up @@ -596,15 +594,39 @@ static int configure_audio(struct ndp120_dev_s *dev, unsigned int pdm_in_shift)
s = syntiant_ndp120_config_gain(dev->ndp, &config_gain);
check_status("syntiant_ndp120_config_gain", s);

#if defined(USE_EXTERNAL_PDM_CLOCK)
/* enable the PDM clock (for the default, pdm0 aka 'left' mic) */
/* Note: this test code always sets up for internal clock and then adds intermediate test apis to either;
1) switch to external clock - for use when buffer is in use (also allows for switching back again)
or
2) switch to using PCLK1 input as passthrough (also allows for switching back again)

The assumption in this code is that at NDP initialization time, the buffer on i2s bclk is set to disabled (OE=0) so NDP can take control of the PDM clock

To switch the clock in the two different cases:
1) with "buffer approach": Generally, this needs to be done in "break before make" fashion
A) Switching from internal -> external
I) Switch NDP to external using ndp120_test_internal_external_switch(dev, 0) API, this will stop the PDM clock from NDP without a hard reconfig of the rest of the PDM interface
II) Set buffer OE=1 to allow i2s clk to DMIC

B) Switching from external -> internal, assuming buffer is on = set to NOT tri-state output
I) Set buffer to OE=0, to enable the tri-state of i2s clk to DMIC
II) Switch NDP to external using ndp120_test_internal_external_switch(dev, 1) API, this will start the PDM clock from NDP

2) with "PDM passthrough" approach:
A) Switching from internal -> external:
Call ndp120_test_internal_passthrough_switch(dev, 0) API
A) Switching from external -> internal:
Call ndp120_test_internal_passthrough_switch(dev, 1) API

*/

/* enable the PDM clock */
memset(&pdm_config, 0, sizeof(pdm_config));
pdm_config.interface = 0;
pdm_config.clk = SYNTIANT_NDP120_CONFIG_VALUE_PDM_CLK_ON;
pdm_config.sample_rate = 16000;
pdm_config.clk_mode = SYNTIANT_NDP120_CONFIG_VALUE_PDM_CLK_MODE_EXTERNAL;
pdm_config.clk_mode = SYNTIANT_NDP120_CONFIG_VALUE_PDM_CLK_MODE_INTERNAL;
pdm_config.mode = SYNTIANT_NDP120_CONFIG_VALUE_PDM_MODE_STEREO;
pdm_config.pdm_rate = EXTERNAL_PDM_CLOCK_PDM_RATE;
pdm_config.pdm_rate = PDM_CLOCK_PDM_RATE;

pdm_config.set = SYNTIANT_NDP120_CONFIG_SET_PDM_CLK
| SYNTIANT_NDP120_CONFIG_SET_PDM_MODE
Expand All @@ -615,26 +637,7 @@ static int configure_audio(struct ndp120_dev_s *dev, unsigned int pdm_in_shift)
if (check_status("config pdm clock on", s)) {
goto errout_configure_audio;
}
printf("NDP120 is configured for external clock\n");
#else
/* enable the PDM clock (for the default, pdm0 aka 'left' mic) */
memset(&pdm_config, 0, sizeof(pdm_config));
pdm_config.interface = 0;
pdm_config.clk = SYNTIANT_NDP120_CONFIG_VALUE_PDM_CLK_ON;
pdm_config.sample_rate = 16000;
pdm_config.clk_mode = SYNTIANT_NDP120_CONFIG_VALUE_PDM_CLK_MODE_DUAL_INTERNAL;
pdm_config.mode = SYNTIANT_NDP120_CONFIG_VALUE_PDM_MODE_STEREO;
pdm_config.pdm_rate = 768000;
pdm_config.set = SYNTIANT_NDP120_CONFIG_SET_PDM_CLK
| SYNTIANT_NDP120_CONFIG_SET_PDM_MODE
| SYNTIANT_NDP120_CONFIG_SET_PDM_CLK_MODE
| SYNTIANT_NDP120_CONFIG_SET_PDM_PDM_RATE
| SYNTIANT_NDP120_CONFIG_SET_PDM_SAMPLE_RATE;
s = syntiant_ndp120_config_pdm(dev->ndp, &pdm_config);
if (check_status("config pdm clock on", s)) {
goto errout_configure_audio;
}
#endif
printf("NDP120 is configured to generate PDM clock\n");

/*
* get the current audio frame size which is governed by the audio
Expand Down Expand Up @@ -1005,11 +1008,7 @@ int ndp120_init(struct ndp120_dev_s *dev)
attach_algo_config_area(dev->ndp);
add_dsp_flow_rules(dev->ndp);

#if defined(USE_EXTERNAL_PDM_CLOCK)
s = configure_audio(dev, DMIC_1536KHZ_PDM_IN_SHIFT_FF);
#else
s = configure_audio(dev, DMIC_768KHZ_PDM_IN_SHIFT_FF);
#endif
if (s) {
auddbg("audio configure failed\n");
goto errout_ndp120_init;
Expand Down Expand Up @@ -1252,3 +1251,64 @@ int ndp120_stop_sample_ready(struct ndp120_dev_s *dev)

return s;
}


void ndp120_test_internal_external_switch(struct ndp120_dev_s *dev, int internal)
{
uint32_t audctrl = 0;
int intf = 0;

syntiant_ndp120_read(dev->ndp, 1, NDP120_CHIP_CONFIG_AUDCTRL(intf), &audctrl);
if (internal) {
/* set to internal */
audctrl = NDP120_CHIP_CONFIG_AUDCTRL_PDMCLKOUTNEEDED_MASK_INSERT(audctrl, 1);
audctrl = NDP120_CHIP_CONFIG_AUDCTRL_OE_MASK_INSERT(audctrl, 1);
audctrl = NDP120_CHIP_CONFIG_AUDCTRL_MODE_MASK_INSERT(audctrl, NDP120_CHIP_CONFIG_AUDCTRL_MODE_PDM_OUT);
} else {
/* set to external */
audctrl = NDP120_CHIP_CONFIG_AUDCTRL_PDMCLKOUTNEEDED_MASK_INSERT(audctrl, 0);
audctrl = NDP120_CHIP_CONFIG_AUDCTRL_OE_MASK_INSERT(audctrl, 0);
audctrl = NDP120_CHIP_CONFIG_AUDCTRL_MODE_MASK_INSERT(audctrl, NDP120_CHIP_CONFIG_AUDCTRL_MODE_PDM_IN);
}

syntiant_ndp120_write(dev->ndp, 1, NDP120_CHIP_CONFIG_AUDCTRL(intf), audctrl);
}


void ndp120_test_internal_passthrough_switch(struct ndp120_dev_s *dev, int internal)
{
uint32_t audctrl = 0;
int intf = 0;

syntiant_ndp120_read(dev->ndp, 1, NDP120_CHIP_CONFIG_AUDCTRL(intf), &audctrl);
if (internal) {
/* set to internal */
audctrl = NDP120_CHIP_CONFIG_AUDCTRL_PDMCLKOUTNEEDED_MASK_INSERT(audctrl, 1);
audctrl = NDP120_CHIP_CONFIG_AUDCTRL_IE_MASK_INSERT(audctrl, 5); /* pclk0, pdat */
audctrl = NDP120_CHIP_CONFIG_AUDCTRL_MODE_MASK_INSERT(audctrl, NDP120_CHIP_CONFIG_AUDCTRL_MODE_PDM_OUT);
} else {
/* set to pass-thru */
audctrl = NDP120_CHIP_CONFIG_AUDCTRL_PDMCLKOUTNEEDED_MASK_INSERT(audctrl, 0);
audctrl = NDP120_CHIP_CONFIG_AUDCTRL_IE_MASK_INSERT(audctrl, 7); /* pclk0, pclk1, pdat */
audctrl = NDP120_CHIP_CONFIG_AUDCTRL_MODE_MASK_INSERT(audctrl, NDP120_CHIP_CONFIG_AUDCTRL_MODE_PDM_THRU); /* pdm-thru */
}

syntiant_ndp120_write(dev->ndp, 1, NDP120_CHIP_CONFIG_AUDCTRL(intf), audctrl);
}

#if 0
/* Currently unclear from where the functionality will be called. If dev handle is not available,
* the following is a hack but can be used to configure without having an explicit dsevice handle available */
void _ndp120_test_internal_external_switch(int internal)
{
if (!_ndp_debug_handle) return;

ndp120_test_internal_external_switch(_ndp_debug_handle, internal);
}

void _ndp120_test_internal_passthrough_switch(int internal)
{
if (!_ndp_debug_handle) return;
ndp120_test_internal_passthrough_switch(internal);
}
#endif