Skip to content

Commit e09a34c

Browse files
authored
Merge pull request #125 from shuchitak/save_producer_timestamp
Fix bug due to overwriting of asrc_io->input_timestamp
2 parents 54d83c2 + b95a46d commit e09a34c

12 files changed

Lines changed: 95 additions & 96 deletions

File tree

CHANGELOG.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
lib_src change log
22
==================
33

4+
3.0.0
5+
-----
6+
7+
* FIXED: Double buffer asrc_io.input_timestamp to prevent producer timestamp
8+
getting overwritten during asrc processing
9+
* REMOVED: xscope_used argument from the asynchronous_fifo_producer_put() API
10+
411
2.5.0
512
-----
613

doc/asrc_task/asrc_task.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ The ASRC Task supports the following nominal sample rates for input and output:
2525
- 88.2 kHz
2626
- 96 kHz
2727
- 176.4 kHz
28-
- 192 kHz
28+
- 192 kHz
2929

3030
Because the required compute for multi-channel systems may exceed the performance limit of a single thread, the ASRC subsystem is able to make use of multiple threads in parallel to achieve the required conversion within the sample time period. It uses a dynamic fork and join architecture to share the ASRC workload across multiple threads each time a batch of samples is processed. The threads must all reside on the same tile as the ASRC task due to them sharing input and output buffers. The workload and buffer partitioning is dynamically computed by the ASRC task at stream startup and is constrained by the user at compile time to set maximum limits of both channel count and worker threads.
3131

@@ -40,7 +40,7 @@ The difference between the performance requirement between the two architectures
4040

4141
- An eight channel system consisting of either 44.1kHz or 48kHz input with maximum output rate of 192kHz will require about (0.15 * (48 + 192) * 8) ~= 288 thread MHz. This can adequately be provided by four threads (assuming up to 8 active threads on an xcore.ai device with a 600MHz clock).
4242

43-
In reality the amount of thread MHz needed will be lower than the above formulae suggest since subsequent ASRC channels after the first can share some of the calculations. This results in about at 10% performance requirement reduction per additional channel per worker thread. Increasing the input frame size in the ASRC task may also reduce the MHz requirement a few % at the cost of larger buffers and a slight latency increase.
43+
In reality the amount of thread MHz needed will be lower than the above formulae suggest since subsequent ASRC channels after the first can share some of the calculations. This results in about at 10% performance requirement reduction per additional channel per worker thread. Increasing the input frame size in the ASRC task may also reduce the MHz requirement a few % at the cost of larger buffers and a slight latency increase.
4444

4545
.. warning::
4646
Exceeding the processing time available by specifying a channel count, input/output rates, number of worker threads or device clock speed may result in at best choppy audio or a blocked ASRC task if the overrun is persistent.
@@ -102,7 +102,7 @@ An example of the user-defined `C` function for receiving the input samples is s
102102

103103
// Receive stream info from producer
104104
*new_input_rate = chanend_in_word(c_producer);
105-
asrc_io->input_timestamp = chanend_in_word(c_producer);
105+
asrc_io->input_timestamp[asrc_io->input_write_idx] = chanend_in_word(c_producer);
106106
asrc_io->input_channel_count = chanend_in_word(c_producer);
107107

108108
// Pack into array properly LRLRLRLR or 123412341234 etc.

lib_src/api/asynchronous_fifo.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ typedef struct asynchronous_fifo_t_ {
5959
* The ``state`` argument should be an int64_t array of
6060
* ``ASYNCHRONOUS_FIFO_INT64_ELEMENTS`` elements that is cast to
6161
* ``asynchronous_fifo_t*``.
62-
*
62+
*
6363
* That pointer should also be used for all other operations, including operations
6464
* both the consumer and producer sides.
6565
*
@@ -177,8 +177,6 @@ void asynchronous_fifo_exit(asynchronous_fifo_t * UNSAFE state);
177177
*
178178
* @param timestamp The number of ticks when this sample was input.
179179
*
180-
* @param xscope_used Set to 1 if the PID values should be output over
181-
* xscope. Used for debugging. This parameter is subject to be removed in future revisions.
182180
*
183181
* @returns The current estimate of the mismatch of input and output frequencies.
184182
* This is represented as a 32-bit signed number. Zero means no mismatch,
@@ -193,8 +191,7 @@ void asynchronous_fifo_exit(asynchronous_fifo_t * UNSAFE state);
193191
int32_t asynchronous_fifo_producer_put(asynchronous_fifo_t * UNSAFE state,
194192
int32_t * UNSAFE samples,
195193
int n,
196-
int32_t timestamp,
197-
int xscope_used);
194+
int32_t timestamp);
198195

199196

200197
/**

lib_src/lib_build_info.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
set(LIB_NAME lib_src)
2-
set(LIB_VERSION 2.5.0)
2+
set(LIB_VERSION 3.0.0)
33

44
set(LIB_DEPENDENT_MODULES "lib_logging(3.2.0)")
55

lib_src/module_build_info

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION = 2.5.0
1+
VERSION = 3.0.0
22

33
DEPENDENT_MODULES = lib_logging(>=3.2.0)
44

lib_src/src/asrc_task/asrc_task.c

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ void do_asrc_group(schedule_info_t *schedule, uint64_t fs_ratio, asrc_in_out_t *
8282
// Pack into the frame this instance of ASRC expects
8383
int input_samples[ASRC_N_IN_SAMPLES * MAX_ASRC_CHANNELS_TOTAL];
8484
for(int i = 0; i < ASRC_N_IN_SAMPLES * num_worker_channels; i++){
85-
// int rd_idx = i % num_worker_channels + (i / num_worker_channels) * asrc_io->asrc_channel_count + worker_channel_start_idx;
85+
// int rd_idx = i % num_worker_channels + (i / num_worker_channels) * asrc_io->asrc_channel_count + worker_channel_start_idx;
8686
int rd_idx = i + (asrc_io->asrc_channel_count - num_worker_channels) * (i / num_worker_channels) + worker_channel_start_idx; // Optimisation of above
8787
input_samples[i] = asrc_io->input_samples[input_write_idx][rd_idx];
8888
}
@@ -193,13 +193,13 @@ void reset_asrc_fifo_consumer(asynchronous_fifo_t * fifo){
193193
}
194194

195195
// Default implementation of receive (called from ASRC) which receives samples and config over a channel. This is overridable.
196-
ASRC_TASK_ISR_CALLBACK_ATTR
196+
ASRC_TASK_ISR_CALLBACK_ATTR
197197
unsigned receive_asrc_input_samples_cb_default(chanend_t c_asrc_input, asrc_in_out_t *asrc_io, unsigned *new_input_rate){
198198
static unsigned asrc_in_counter = 0;
199199

200200
// Get format and timing data from channel
201201
*new_input_rate = chanend_in_word(c_asrc_input);
202-
asrc_io->input_timestamp = chanend_in_word(c_asrc_input);
202+
asrc_io->input_timestamp[asrc_io->input_write_idx] = chanend_in_word(c_asrc_input);
203203
asrc_io->input_channel_count = chanend_in_word(c_asrc_input);
204204

205205
// Pack into array properly LRLRLRLR for 2ch or 123412341234 for 4ch etc.
@@ -232,7 +232,7 @@ DEFINE_INTERRUPT_CALLBACK(ASRC_ISR_GRP, asrc_samples_rx_isr_handler, app_data){
232232
chanend_t c_buff_idx = asrc_receive_samples_ctx->c_buff_idx;
233233
asrc_in_out_t *asrc_io = asrc_receive_samples_ctx->asrc_io;
234234
ASRC_TASK_ISR_CALLBACK_ATTR asrc_task_produce_isr_cb_t receive_asrc_input_samples_cb = asrc_io->asrc_task_produce_cb;
235-
235+
236236
// Always consume samples so we don't apply backpressure to the producer
237237
// Call the user defined receive samples callback.
238238
ASRC_TASK_ISR_CALLBACK_ATTR
@@ -242,7 +242,7 @@ DEFINE_INTERRUPT_CALLBACK(ASRC_ISR_GRP, asrc_samples_rx_isr_handler, app_data){
242242
if(asrc_in_counter == 0 && asrc_io->ready_flag_to_receive){
243243
// Note if you ever find the code has stopped here then this is due to the time required to ASRC process the input frame
244244
// is longer than the period of the frames coming in. To remedy this you need to increase ASRC processing resources or reduce
245-
// the processing requirement. If you are using XCORE-200, consider using xcore.ai for more than 2x the ASRC performance.
245+
// the processing requirement. If you are using XCORE-200, consider using xcore.ai for more than 2x the ASRC performance.
246246
// Notify ASRC main loop of new frame
247247
chanend_out_byte(c_buff_idx, (uint8_t)asrc_io->input_write_idx);
248248
asrc_io->input_write_idx ^= 1; // Swap buffers
@@ -274,7 +274,7 @@ static inline void asrc_wait_for_valid_config(chanend_t c_buff_idx, uint32_t *in
274274

275275
// Check to see if input params have changed since last process
276276
static inline bool asrc_detect_format_change(uint32_t input_frequency, uint32_t output_frequency, asrc_in_out_t *asrc_io){
277-
if( asrc_io->input_frequency != input_frequency ||
277+
if( asrc_io->input_frequency != input_frequency ||
278278
asrc_io->input_channel_count != asrc_io->asrc_channel_count ||
279279
asrc_io->output_frequency != output_frequency){
280280

@@ -291,7 +291,7 @@ DEFINE_INTERRUPT_PERMITTED(ASRC_ISR_GRP, void, asrc_processor,
291291
asrc_in_out_t *asrc_io,
292292
chanend_t c_buff_idx,
293293
asynchronous_fifo_t * fifo){
294-
294+
295295
uint32_t input_frequency = 0; // Set to invalid for now. We will get rates supplied by producer and consumer.
296296
uint32_t output_frequency = 0;
297297

@@ -304,7 +304,7 @@ DEFINE_INTERRUPT_PERMITTED(ASRC_ISR_GRP, void, asrc_processor,
304304
{ 2268, 2268, 1134, 1134, 567, 567},
305305
{ 2083, 2083, 1042, 1042, 521, 521}
306306
};
307-
307+
308308
// Setup a pointer to a struct so the ISR can access these elements
309309
asrc_receive_samples_ctx_t asrc_receive_samples_ctx = {c_asrc_input, c_buff_idx, asrc_io};
310310

@@ -322,7 +322,7 @@ DEFINE_INTERRUPT_PERMITTED(ASRC_ISR_GRP, void, asrc_processor,
322322
int inputFsCode = frequency_to_fs_code(input_frequency);
323323
int outputFsCode = frequency_to_fs_code(output_frequency);
324324
int interpolation_ticks = interpolation_ticks_2D[inputFsCode][outputFsCode];
325-
325+
326326
//// FIFO init
327327
dprintf("FIFO init channels: %d length: %ld\n", asrc_io->asrc_channel_count, fifo->max_fifo_depth);
328328
asynchronous_fifo_init(fifo, asrc_io->asrc_channel_count, fifo->max_fifo_depth);
@@ -367,8 +367,6 @@ DEFINE_INTERRUPT_PERMITTED(ASRC_ISR_GRP, void, asrc_processor,
367367
ideal_fs_ratio = (fs_ratio + (1<<31)) >> 32;
368368
dprintf("ideal_fs_ratio: %d\n", ideal_fs_ratio);
369369

370-
const int xscope_used = 0; // Vestige of ASRC API. TODO - cleanup in future when lib_src is tidied
371-
372370
asrc_io->ready_flag_to_receive = 1; // Signal we are ready to consume a frame of input samples
373371
asrc_io->ready_flag_configured = 1; // SIgnal we are ready to produce
374372

@@ -385,10 +383,10 @@ DEFINE_INTERRUPT_PERMITTED(ASRC_ISR_GRP, void, asrc_processor,
385383

386384
int32_t t0 = get_reference_time();
387385
int num_output_samples = par_asrc(num_jobs, schedule, fs_ratio, asrc_io, input_write_idx, sASRCCtrl);
388-
int ts = asrc_timestamp_interpolation(asrc_io->input_timestamp, sASRCCtrl[0], interpolation_ticks);
386+
int ts = asrc_timestamp_interpolation(asrc_io->input_timestamp[input_write_idx], sASRCCtrl[0], interpolation_ticks);
389387
// Only push to FIFO if we have samples (FIFO has a bug) otherwise hold last error value
390388
if(num_output_samples){
391-
error = asynchronous_fifo_producer_put(fifo, &asrc_io->output_samples[0], num_output_samples, ts, xscope_used);
389+
error = asynchronous_fifo_producer_put(fifo, &asrc_io->output_samples[0], num_output_samples, ts);
392390
}
393391

394392
fs_ratio = (((int64_t)ideal_fs_ratio) << 32) + (error * (int64_t) ideal_fs_ratio);
@@ -409,7 +407,7 @@ DEFINE_INTERRUPT_PERMITTED(ASRC_ISR_GRP, void, asrc_processor,
409407
}
410408

411409

412-
// Wrapper to setup ISR->task signalling chanend and use ISR friendly call to function
410+
// Wrapper to setup ISR->task signalling chanend and use ISR friendly call to function
413411
void asrc_task(chanend_t c_asrc_input, asrc_in_out_t *asrc_io, asynchronous_fifo_t *fifo, unsigned fifo_length){
414412
// Check callback is init'd. If not, use default implementation.
415413
if (asrc_io->asrc_task_produce_cb == NULL){

lib_src/src/asrc_task/asrc_task.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
#define SRC_DITHER_SETTING 0
2828

2929
#else
30-
// Check for required static defines
30+
// Check for required static defines
3131
#include "asrc_task_config.h"
3232

3333
#ifndef MAX_ASRC_CHANNELS_TOTAL
@@ -53,7 +53,7 @@
5353
#endif
5454

5555
/** @brief Decorator for user ASRC producer receive callback. Must be used to allow stack usage calculation. */
56-
#define ASRC_TASK_ISR_CALLBACK_ATTR __attribute__((fptrgroup("asrc_callback_isr_fptr_grp")))
56+
#define ASRC_TASK_ISR_CALLBACK_ATTR __attribute__((fptrgroup("asrc_callback_isr_fptr_grp")))
5757

5858
#ifndef __DOXYGEN__
5959

@@ -90,11 +90,11 @@ typedef struct asrc_in_out_t_{
9090
int32_t input_samples[2][ASRC_N_IN_SAMPLES * MAX_ASRC_CHANNELS_TOTAL];
9191
/** Double buffer idx */
9292
unsigned input_write_idx;
93-
/** Timestamp of last received input sample */
94-
int32_t input_timestamp;
95-
/** Nominal input sample rate 44100..192000 (set by producer) */
93+
/** Timestamp of last received input sample. Double buffered */
94+
int32_t input_timestamp[2];
95+
/** Nominal input sample rate 44100..192000 (set by producer) */
9696
unsigned input_frequency;
97-
/** This is set by the producer and can change dynamically */
97+
/** This is set by the producer and can change dynamically */
9898
unsigned input_channel_count;
9999
/** The function pointer of the ASRC_TASK producer receive callback. Must be defined by user to receive samples from producer over channel. */
100100
void * UNSAFE asrc_task_produce_cb;
@@ -111,7 +111,7 @@ typedef struct asrc_in_out_t_{
111111
unsigned asrc_channel_count;
112112
/** Flag to indicate ASRC ready to accept samples */
113113
int ready_flag_to_receive;
114-
/** Flag to indicate ASRC is configured and OK to pull from FIFO */
114+
/** Flag to indicate ASRC is configured and OK to pull from FIFO */
115115
int ready_flag_configured;
116116

117117
}asrc_in_out_t;
@@ -161,9 +161,9 @@ void reset_asrc_fifo_consumer(asynchronous_fifo_t * UNSAFE fifo);
161161
* Prototype that can optionally be defined by the user to initialise the function pointer for the ASRC receive produced samples ISR.
162162
* If this is not called then receive_asrc_input_samples_cb_default() is used and the you may call send_asrc_input_samples_default()
163163
* from the application to send samples to the ASRC task.
164-
*
164+
*
165165
* Must be called before running asrc_task()
166-
*
166+
*
167167
* \param asrc_io A pointer to the structure used for holding ASRC IO and state.
168168
* \param asrc_rx_fp A pointer to the user asrc_receive_samples function. NOTE - This MUST be decorated by ASRC_TASK_ISR_CALLBACK_ATTR
169169
* to allow proper stack calculation by the compiler. See receive_asrc_input_samples_cb_default() in asrc_task.c
@@ -176,7 +176,7 @@ void init_asrc_io_callback(asrc_in_out_t * UNSAFE asrc_io, asrc_task_produce_isr
176176
/**
177177
* If the init_asrc_io_callback() function is not called then a default implementation of the ASRC receive will be used.
178178
* This send function (called by the user producer side) mirrors the receive and can be used to push samples into the ASRC.
179-
*
179+
*
180180
* \param c_asrc_input The chan end on the application producer side connecting to the ASRC task.
181181
* \param input_frequency The sample rate of the input stream (44100, 48000, ...).
182182
* \param input_timestamp The ref clock timestamp of latest received input sample.

lib_src/src/asynchronous_fifo.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,7 @@ void asynchronous_fifo_reset_consumer(asynchronous_fifo_t *state) {
110110

111111
int32_t asynchronous_fifo_producer_put(asynchronous_fifo_t *state, int32_t *samples,
112112
int n,
113-
int32_t timestamp,
114-
int xscope_used) {
113+
int32_t timestamp) {
115114
int read_ptr = state->read_ptr;
116115
int write_ptr = state->write_ptr;
117116
int max_fifo_depth = state->max_fifo_depth;
@@ -160,21 +159,17 @@ int32_t asynchronous_fifo_producer_put(asynchronous_fifo_t *state, int32_t *samp
160159
state->frequency_ratio +=
161160
(diff_error * (int64_t) (state->Kp / n)) + // TODO: make this lookup table
162161
(phase_error * (int64_t) state->Ki);
163-
if (xscope_used) {
164-
#if defined(ASYNC_FIFO_XSCOPE_INSTRUMENTATION)
162+
#if defined(ASYNC_FIFO_XSCOPE_INSTRUMENTATION)
165163
xscope_int(1, phase_error);
166164
xscope_int(2, diff_error);
167165
#endif
168-
}
169166
}
170167
state->last_phase_error = phase_error;
171168
}
172-
if (xscope_used) {
173-
#if defined(ASYNC_FIFO_XSCOPE_INSTRUMENTATION)
169+
#if defined(ASYNC_FIFO_XSCOPE_INSTRUMENTATION)
174170
xscope_int(3, len);
175171
xscope_int(4, state->frequency_ratio >> K_SHIFT);
176172
#endif
177-
}
178173
return (state->frequency_ratio + (1<<(K_SHIFT-1))) >> K_SHIFT;
179174
}
180175

settings.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
project: lib_src
33
title: SAMPLE RATE CONVERSION
4-
version: 2.5.0
4+
version: 3.0.0
55

66
documentation:
77
exclude_patterns_path: doc/exclude_patterns.inc

tests/asrc_task_test/asrc_task_receive_samples.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ unsigned receive_asrc_input_samples(chanend_t c_producer, asrc_in_out_t *asrc_io
99

1010
// Receive stream info from producer
1111
*new_input_rate = chanend_in_word(c_producer);
12-
asrc_io->input_timestamp = chanend_in_word(c_producer);
12+
asrc_io->input_timestamp[asrc_io->input_write_idx] = chanend_in_word(c_producer);
1313
asrc_io->input_channel_count = chanend_in_word(c_producer);
1414

1515
// Pack into array properly LRLRLRLR or 123412341234 etc.
@@ -29,4 +29,4 @@ unsigned receive_asrc_input_samples(chanend_t c_producer, asrc_in_out_t *asrc_io
2929
// Register the above function for ASRC task
3030
void setup_asrc_io_custom_callback(asrc_in_out_t *asrc_io){
3131
init_asrc_io_callback(asrc_io, receive_asrc_input_samples);
32-
}
32+
}

0 commit comments

Comments
 (0)