Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
14c49a6
Make a copy of the basic mic array example for porting to xCore-400
mbanth Feb 17, 2026
e6b8534
This is a safety commit. These files do not build successfully. dev…
mbanth Feb 19, 2026
d74e279
Merge branch 'vx4' into feature/port-basic-example-to-xcore-400
mbanth Feb 19, 2026
525000c
Merge branch 'vx4' into feature/port-basic-example-to-xcore-400
mbanth Feb 20, 2026
249f053
Safety commit
mbanth Feb 20, 2026
ad5eae9
Safety commit
mbanth Feb 20, 2026
51b60b8
Merge branch 'vx4' into feature/port-basic-example-to-xcore-400
mbanth Feb 23, 2026
48aa6b7
Merge branch 'vx4' into feature/port-basic-example-to-xcore-400
mbanth Feb 24, 2026
d48735f
Safety commit; compiles clean with XTC v15.3.1; fails to compile with…
mbanth Feb 24, 2026
8014a85
Add definition of pdm_rx_isr_context for the VX4 implementation.
mbanth Feb 24, 2026
29b2d2b
Add directives to allow stack size calculation
mbanth Feb 24, 2026
03aaa2a
Merge branch 'vx4' into feature/port-basic-example-to-xcore-400
mbanth Feb 24, 2026
491c126
Ad :orphan: to Read Me files to resolve Sphinx warnings
mbanth Feb 24, 2026
f3b44ff
Remove :orphan: directives because they do not have the desired effec…
mbanth Feb 24, 2026
dd525d1
Merge branch 'vx4' into feature/port-basic-example-to-xcore-400
mbanth Feb 25, 2026
fb96228
Remove unused parameters and switch to LF line endings only
mbanth Feb 25, 2026
a24514d
Updates reference mips json and rst files
Feb 25, 2026
90f26b4
Update exclude_patterns.inc to exclude app_mic_array_basic_xcore_400/…
Feb 25, 2026
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
2 changes: 1 addition & 1 deletion doc/exclude_patterns.inc
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ LICENSE.rst
build.xcore
tests/**/.pytest_cache/*.md
tests/.pytest_cache/*.md
**/app_mic_array_basic/*.md
**/app_mic_array_basic*/*.md
24 changes: 24 additions & 0 deletions examples/app_mic_array_basic_xcore_400/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
cmake_minimum_required(VERSION 3.21)
include($ENV{XMOS_CMAKE_PATH}/xcommon.cmake)
project(app_mic_array)

set(XMOS_SANDBOX_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..)

set(APP_HW_TARGET XK-EVK-XU416)
set(APP_DEPENDENT_MODULES "lib_mic_array")
set(APP_INCLUDES src)

set(APP_COMPILER_FLAGS
-Os
-g
-report
-Wall
-fxscope
# -Wno-xcore-fptrgroup
# Mic array config
-DMIC_ARRAY_CONFIG_SAMPLES_PER_FRAME=320
-DMIC_ARRAY_CONFIG_MIC_COUNT=1
-DMIC_ARRAY_CONFIG_USE_PDM_ISR=0
)

XMOS_REGISTER_APP()
30 changes: 30 additions & 0 deletions examples/app_mic_array_basic_xcore_400/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Basic Mic Array Example

## Hardware Required

- **XMS0016**

## Compile

```sh
cmake -G "Unix Makefiles" -B build
xmake -C build
```

## Run

```sh
xrun --xscope bin/app_mic_array.xe
```

## Convert Binary Data to WAV

```sh
python convert.py
```

**Output:**

```
Converted mic_array_output.bin to output.wav with 1 channels, 16000 Hz sample rate, and 32 bits per sample.
```
27 changes: 27 additions & 0 deletions examples/app_mic_array_basic_xcore_400/convert.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 2026 XMOS LIMITED.
# This Software is subject to the terms of the XMOS Public Licence: Version 1.

import numpy as np
import wave
import soundfile as sf


def convert_to_wav(
input_file, output_file, num_channels=1, sample_rate=16000, bits_per_sample=32
):
with open(input_file, "rb") as inp_f:
data = inp_f.read()
data = np.frombuffer(data, dtype=np.int32)

sf.write(output_file, data, sample_rate, subtype='PCM_32')
print(f"Converted {input_file} to {output_file} with {num_channels} channels, {sample_rate} Hz sample rate, and {bits_per_sample} bits per sample.")


if __name__ == "__main__":
convert_to_wav(
input_file="mic_array_output.bin",
output_file="output.wav",
num_channels=1,
sample_rate=16000,
bits_per_sample=32
)
Binary file not shown.
Binary file not shown.
99 changes: 99 additions & 0 deletions examples/app_mic_array_basic_xcore_400/src/app.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright 2026 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#if defined (__XS3A__)
#include <platform.h>
#elif defined (__VX4B__)
#include <netmain.h>
#endif

#include <xcore/chanend.h>
#include <xcore/channel.h>
#include <xcore/parallel.h>

#include "mic_array.h"
#include "device_pll_ctrl.h"

// -------------------- Frecuency and Port definitions --------------------
#define MIC_ARRAY_CONFIG_MCLK_FREQ (24576000)
#define MIC_ARRAY_CONFIG_PDM_FREQ (3072000)
#define MIC_ARRAY_CONFIG_PORT_MCLK XS1_PORT_1D
#define MIC_ARRAY_CONFIG_PORT_PDM_CLK XS1_PORT_1G /* X1D22 */
#define MIC_ARRAY_CONFIG_PORT_PDM_DATA XS1_PORT_1F /* X1D13 */
#define MIC_ARRAY_CONFIG_CLOCK_BLOCK_A XS1_CLKBLK_2
// ------------------------------------------------------------

// App defines
#define APP_N_SAMPLES (320)
#define APP_OUT_FREQ_HZ (16000)
#define APP_SAMPLE_SECONDS (2)
#define APP_N_FRAMES (APP_OUT_FREQ_HZ * APP_SAMPLE_SECONDS / APP_N_SAMPLES)
#define APP_BUFF_SIZE (APP_N_FRAMES * APP_N_SAMPLES)
#define APP_FILENAME ("mic_array_output.bin")

DECLARE_JOB(user_mic, (chanend_t));
DECLARE_JOB(user_audio, (chanend_t));

static pdm_rx_resources_t pdm_res = PDM_RX_RESOURCES_SDR(
MIC_ARRAY_CONFIG_PORT_MCLK,
MIC_ARRAY_CONFIG_PORT_PDM_CLK,
MIC_ARRAY_CONFIG_PORT_PDM_DATA,
MIC_ARRAY_CONFIG_MCLK_FREQ,
MIC_ARRAY_CONFIG_PDM_FREQ,
MIC_ARRAY_CONFIG_CLOCK_BLOCK_A);

void user_mic(chanend_t c_mic_audio)
{
printf("Mic Init\n");
device_pll_init();
mic_array_init(&pdm_res, NULL, APP_OUT_FREQ_HZ);
mic_array_start(c_mic_audio);
}

void user_audio(chanend_t c_mic_audio)
{
int32_t WORD_ALIGNED tmp_buff[APP_BUFF_SIZE] = {0};
int32_t *buff_ptr = &tmp_buff[0];
unsigned frame_counter = APP_N_FRAMES;
while (frame_counter--)
{
ma_frame_rx(buff_ptr, (chanend_t)c_mic_audio, MIC_ARRAY_CONFIG_MIC_COUNT, APP_N_SAMPLES);
buff_ptr += APP_N_SAMPLES;
for (unsigned i = 0; i < APP_N_SAMPLES; i++)
{
tmp_buff[i] <<= 6;
}
}

// write samples to a binary file
printf("Writing output to %s\n", APP_FILENAME);
FILE *f = fopen(APP_FILENAME, "wb");
assert(f != NULL);
fwrite(tmp_buff, sizeof(int32_t), APP_BUFF_SIZE, f);
fclose(f);
ma_shutdown(c_mic_audio);
printf("Done\n");
}

void main_tile_1(){
channel_t c_mic_audio = chan_alloc();
// Parallel Jobs
PAR_JOBS(
PJOB(user_mic, (c_mic_audio.end_a)),
PJOB(user_audio, (c_mic_audio.end_b))
);
chan_free(c_mic_audio);
}

void main_tile_0(){
// intentionally left empty
return;
}

NETWORK_MAIN(
TILE_MAIN(main_tile_1, 1, ()),
TILE_MAIN(main_tile_0, 0, ())
)
18 changes: 18 additions & 0 deletions examples/app_mic_array_basic_xcore_400/src/config.xscope
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?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">
</xSCOPEconfig>
73 changes: 73 additions & 0 deletions examples/app_mic_array_basic_xcore_400/src/device_pll_ctrl.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2022-2026 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.

#if defined (__XS3A__)
#include <platform.h>
#include <xs1.h>
#elif defined (__VX4B__)
#include <vx4b_defines.h>
#include <xsystem/local_tile.h>
#include <xsystem/switch.h>
#endif

#include <xcore/hwtimer.h>
#include <xcore/assert.h>
#include "device_pll_ctrl.h"


void device_pll_init(void)
{
#if 0
unsigned tileid = get_local_tile_id();

#if defined (__XS3A__)
// SS_APP_PLL_BYPASS (29:29) = 0b0 = 0x0
// SS_APP_PLL_INPUT_FROM_SYS_PLL (28:28) = 0b0 = 0x0
// SS_APP_PLL_ENABLE (27:27) = 0b0 = 0x0
// Reserved (26:26) = 0b0 = 0x0
// SS_PLL_CTL_POST_DIVISOR (25:23) = 0b100 = 0x4
// Reserved (22:21) = 0b00 = 0x0
// SS_PLL_CTL_FEEDBACK_MUL (20:08) = 0b0000111111111 = 0x01FF
// Reserved (07:06) = 0b00 = 0x0
// SS_PLL_CTL_INPUT_DIVISOR (05:00) = 0b000100 = 0x04
const unsigned DEVICE_PLL_DISABLE = 0x0201FF04;

// SS_APP_CLK_FROM_APP_PLL (31:31) = 0b1 = 0x1
// Reserved (30:17) = 0b00000000000000 = 0x0
// SS_APP_CLK_DIV_DISABLE (16:16) = 0b0 = 0x0
// SS_APP_CLK_DIV (15:00) = 0b0000000000000100 = 0x0004
const unsigned DEVICE_PLL_DIV_0 = 0x80000004;
#elif defined (__VX4B__)
// Reserved (31:31) = 0b0 = 0x0
// NLOCK (30:30) = 0b0 = 0x0
// Reserved (29:29) = 0b0 = 0x0
// BYPASS (28:28) = 0b0 = 0x0
// Reserved (27:27) = 0b0 = 0x0
// DISABLE (26:26) = 0b1 = 0x1
// OD_DIVIDER (25:23) = 0b100 = 0x4
// Reserved (22:21) = 0b00 = 0x0
// F_MULTIPLIER (20:08) = 0b0000111111111 = 0x01FF
// Reserved (07:06) = 0b00 = 0x0
// R_DIVIDER (05:00) = 0b000100 = 0x04
const unsigned DEVICE_PLL_DISABLE = 0x0601FF04;
const unsigned DEVICE_PLL_DIV_0 = 0x80000004;
#else
#error "Unsupported architecture"
#endif

write_sswitch_reg(tileid, XS1_SSWITCH_SS_APP_PLL_CTL_NUM,
DEVICE_PLL_DISABLE);

hwtimer_t tmr = hwtimer_alloc();
{
xassert(tmr != 0);
hwtimer_delay(tmr, 100000); // 1ms with 100 MHz timer tick
}
hwtimer_free(tmr);

write_sswitch_reg(tileid, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, DEVICE_PLL_CTL_VAL);
write_sswitch_reg(tileid, XS1_SSWITCH_SS_APP_PLL_CTL_NUM, DEVICE_PLL_CTL_VAL);
write_sswitch_reg(tileid, XS1_SSWITCH_SS_APP_PLL_FRAC_N_DIVIDER_NUM, DEVICE_PLL_FRAC_NOM);
write_sswitch_reg(tileid, XS1_SSWITCH_SS_APP_CLK_DIVIDER_NUM, DEVICE_PLL_DIV_0);
#endif
}
9 changes: 9 additions & 0 deletions examples/app_mic_array_basic_xcore_400/src/device_pll_ctrl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright 2022-2026 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.

#pragma once

#define DEVICE_PLL_CTL_VAL 0x0A019803 // Valid for all fractional values
#define DEVICE_PLL_FRAC_NOM 0x800095F9 // 24.576000 MHz

void device_pll_init(void);
92 changes: 92 additions & 0 deletions lib_mic_array/src/mic_array_task.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright 2026 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.

#include <stdbool.h>
#include <xcore/assert.h>
#include <xcore/parallel.h>
#include <platform.h>

#include "mic_array.h"
#include "mic_array_task_internal.hpp"

////////////////////
// Mic array init //
////////////////////
void mic_array_init(pdm_rx_resources_t *pdm_res, const unsigned *channel_map, unsigned output_samp_freq)
{
unsigned stg2_decimation_factor = (pdm_res->pdm_freq/STAGE1_DEC_FACTOR)/output_samp_freq;
assert ((output_samp_freq*STAGE1_DEC_FACTOR*stg2_decimation_factor) == pdm_res->pdm_freq); // assert if it doesn't divide cleanly
// assert if unsupported decimation factor. (for example. when starting with a pdm_freq of 3.072MHz, supported
// output sampling freqs are [48000, 32000, 16000]
assert ((stg2_decimation_factor == 2) || (stg2_decimation_factor == 3) || (stg2_decimation_factor == 6));

bool use_3_stg_decimator = false;
init_mic_array_storage(use_3_stg_decimator);
init_mics_default_filter(pdm_res, channel_map, stg2_decimation_factor);
}

void mic_array_init_custom_filter(pdm_rx_resources_t* pdm_res, mic_array_conf_t* mic_array_conf)
{
assert(pdm_res);
assert(mic_array_conf);
assert(mic_array_conf->decimator_conf.num_filter_stages == 2 ||
mic_array_conf->decimator_conf.num_filter_stages == 3);

init_mic_array_storage(mic_array_conf->decimator_conf.num_filter_stages == 3);
init_mics_custom_filter(pdm_res, mic_array_conf);

// Configure and start clocks
const unsigned divide = pdm_res->mclk_freq / pdm_res->pdm_freq;
mic_array_resources_configure(pdm_res, divide);
mic_array_pdm_clock_start(pdm_res);
}

/////////////////////
// Mic array start //
/////////////////////

// Parallel jobs for when XUA_PDM_MIC_USE_PDM_ISR == 0, run separate decimator and pdm rx tasks
DECLARE_JOB(default_ma_task_start_pdm, (void));
void default_ma_task_start_pdm(void)
{
start_pdm_task();
}

DECLARE_JOB(default_ma_task_start_decimator, (void));
void default_ma_task_start_decimator(void)
{
start_decimator_task();
}

DECLARE_JOB(default_ma_task_start_pdm_3stg, (void));
void default_ma_task_start_pdm_3stg(void)
{
start_pdm_task_3stg();
}

DECLARE_JOB(default_ma_task_start_decimator_3stg, (void));
void default_ma_task_start_decimator_3stg(void)
{
start_decimator_task_3stg();
}

void mic_array_start(chanend_t c_frames_out)
{
#if MIC_ARRAY_CONFIG_USE_PDM_ISR
start_mic_array_pdm_isr(c_frames_out);
#else
set_output_channel(c_frames_out);
bool use_3_stg_decimator = get_decimator_stg_count();
if (use_3_stg_decimator) {
PAR_JOBS(
PJOB(default_ma_task_start_pdm_3stg, ()),
PJOB(default_ma_task_start_decimator_3stg, ()));
} else {
PAR_JOBS(
PJOB(default_ma_task_start_pdm, ()),
PJOB(default_ma_task_start_decimator, ()));
}
#endif // MIC_ARRAY_CONFIG_USE_PDM_ISR

shutdown_mic_array();
}
Loading