Skip to content
Open
Show file tree
Hide file tree
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
4 changes: 3 additions & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This file relates to internal XMOS infrastructure and should be ignored by external users

@Library('xmos_jenkins_shared_library@v0.49.0') _
@Library('xmos_jenkins_shared_library@v0.52.0') _

getApproval()
pipeline {
Expand Down Expand Up @@ -169,6 +169,8 @@ pipeline {
// This ensures a project for XS2 can be built and runs OK
sh "xsim test_xs2_benign/bin/xs2.xe"

sh "xrun -l"

// Run this first to ensure the XTAG is up and running for subsequent tests
timeout(time: 2, unit: 'MINUTES') {
sh "xrun --xscope --id 0 unit/bin/tests-unit.xe"
Expand Down
35 changes: 35 additions & 0 deletions lib_mic_array/api/mic_array/cpp/PdmRx.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,41 @@ void mic_array::StandardPdmRxService<CHANNELS_IN, CHANNELS_OUT>::SetPort(port_t
template <unsigned CHANNELS_IN, unsigned CHANNELS_OUT>
void mic_array::StandardPdmRxService<CHANNELS_IN, CHANNELS_OUT>::ThreadEntry()
{

// The boot pattern is interleaved silence on each channel, so 0101.. for 1 mic
// 00110011 for 2 mics etc. After deinterleaving, each channel ends up with the
// 0x55555555 (0101..) silence pattern. The pre-deinterleave pattern is
// CHANNELS_IN zeros followed by CHANNELS_IN ones, repeated.
uint32_t boot_pattern = (CHANNELS_IN == 1) ? 0x55555555 :
(CHANNELS_IN == 2) ? 0x33333333 :
(CHANNELS_IN == 4) ? 0x0F0F0F0F :
(CHANNELS_IN == 8) ? 0x00FF00FF :
0x0000FFFF; // 16 mics

uint32_t good_frames = 0;
while(1){
// During boot, the PDM port may read all 0s or all 1s.
// Output 0x55 (zero) to the buffer until we get a valid frame.
uint32_t data = port_in(this->p_pdm_mics);
this->blocks[0][--phase] = boot_pattern;

if(!phase){
this->phase = this->num_phases;
uint32_t* ready_block = this->blocks[0];
this->blocks[0] = this->blocks[1];
this->blocks[1] = ready_block;

s_chan_out_word(this->c_pdm_blocks.end_a, reinterpret_cast<uint32_t>(ready_block));
}
// During boot the pin can toggle between all-0s and all-1s, so wait for a
// couple of consecutive valid frames before using the data
bool bad_frame = (data == 0x00000000) || (data == 0xFFFFFFFF);
good_frames = bad_frame ? 0 : (good_frames + 1);
if (good_frames > 1) {
break;
}
}

while(1){
this->blocks[0][--phase] = port_in(this->p_pdm_mics);

Expand Down
26 changes: 26 additions & 0 deletions python/mic_array/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,39 @@ def _pad_input(self, sig_in):
S[:,P:] = sig_in
return S

def boot_logic(self, pdm_signal: np.ndarray) -> np.ndarray:
# Simulate the PdmRx thread boot loop (StandardPdmRxService::ThreadEntry,
# PdmRx.hpp): words are received one at a time; 0x55555555 is written to
# the buffer (discarding real data) until good_frames > 1, i.e. 2
# consecutive words that are neither all-0 nor all-1

good_frames = 0

for start in range(0, pdm_signal.shape[1], 32):
if np.all(pdm_signal[:,start:start+32] == 1) or np.all(pdm_signal[:,start:start+32] == -1):
good_frames = 0
pdm_signal[:,start:start+32] = np.tile([-1, 1], 16).T # write 0x55555555 to buffer
continue

# signal gets modified either way
pdm_signal[:,start:start+32] = np.tile([-1, 1], 16).T # write 0x55555555 to buffer

good_frames += 1
if good_frames > 1:
break

return pdm_signal


def FilterInt16(self, pdm_signal: np.ndarray) -> np.ndarray:
if pdm_signal.ndim == 1:
pdm_signal = pdm_signal[np.newaxis,:]
CHANS, SAMPS_IN = pdm_signal.shape
Q = self.DecimationFactor
N_pcm = SAMPS_IN // self.DecimationFactor

pdm_signal = self.boot_logic(pdm_signal)

S = self._pad_input(pdm_signal)
coefs = self.Coef.astype(np.int32)[:,np.newaxis]
res = np.empty((CHANS, N_pcm), dtype=np.int32)
Expand Down