diff --git a/examples/xua_lite_example/src/fifo_impl.h b/examples/xua_lite_example/src/fifo_impl.h new file mode 100644 index 00000000..315b199f --- /dev/null +++ b/examples/xua_lite_example/src/fifo_impl.h @@ -0,0 +1,72 @@ +#ifndef __FIFO__ +#define __FIFO__ +#include //memcpy +#include "fifo_types.h" + +//Asynch FIFO implementaion +//Note these are in the include file to allow the compiler to inline for performance + +/////////////////////////////////////// +//Shared memory FIFO (sample by sample) +//Can be any size +/////////////////////////////////////// + + +static inline unsigned fifo_get_fill(volatile mem_fifo_t * unsafe fifo) { + unsafe{ + unsigned fifo_fill = 0; + if (fifo->write_idx >= fifo->read_idx){ + fifo_fill = fifo->write_idx - fifo->read_idx; + } + else{ + fifo_fill = (fifo->size + fifo->write_idx) - fifo->read_idx; + } + return fifo_fill; + } +} + +#pragma unsafe arrays +static inline fifo_ret_t fifo_block_push(volatile mem_fifo_t * unsafe fifo, int data[], unsigned n) { + unsafe{ + //check there is a block of space large enough + unsigned space_remaining = fifo->size - fifo_get_fill(fifo) - 1; + if (n > space_remaining) { + return FIFO_FULL; + } + for (int i = 0; i < n; i++){ + unsigned next_idx = fifo->write_idx + 1; + if (next_idx == fifo->size) next_idx = 0; //Check for wrap + fifo->data_base_ptr[fifo->write_idx] = data[i]; + fifo->write_idx = next_idx; + } + return FIFO_SUCCESS; + } +} + +#pragma unsafe arrays +static inline fifo_ret_t fifo_block_pop(volatile mem_fifo_t * unsafe fifo, int data[], unsigned n) { + unsafe{ + //Check we have a block big enough to send + if (n > fifo_get_fill(fifo)){ + return FIFO_EMPTY; + } + for (int i = 0; i < n; i++){ + data[i] = fifo->data_base_ptr[fifo->read_idx]; + fifo->read_idx++; + if (fifo->read_idx == fifo->size) fifo->read_idx = 0; //Check for wrap + } + return FIFO_SUCCESS; + } +} + + +//Version of above that returns fill level relative to half full +static inline int fifo_get_fill_relative_half(volatile mem_fifo_t * unsafe fifo){ + unsafe{ + int fifo_fill = (int)fifo_get_fill(fifo); + fifo_fill -= (fifo->size / 2); + return fifo_fill; + } +} + +#endif \ No newline at end of file diff --git a/examples/xua_lite_example/src/fifo_types.h b/examples/xua_lite_example/src/fifo_types.h new file mode 100644 index 00000000..159a95ae --- /dev/null +++ b/examples/xua_lite_example/src/fifo_types.h @@ -0,0 +1,30 @@ +#ifndef __ASRC_FIFO_TYPES__ +#define __ASRC_FIFO_TYPES__ +#include + +//Shared FIFO return types +typedef enum fifo_ret_t { + FIFO_SUCCESS = 0, + FIFO_FULL, + FIFO_EMPTY +} fifo_ret_t; + +///////////////////////////////////////////////////////////////////////// +//Shared memory FIFO (sample by sample or block) +//Can be any size +// +//Note that the actual storage for the FIFO is declared externally +//and a reference to the base address of the storage is passed in along +//with the size of the storage. This way, multiple instances may be +//different sizes. +// +///////////////////////////////////////////////////////////////////////// + +typedef struct mem_fifo_t { + const unsigned size; //Size in INTs + int * const unsafe data_base_ptr; //Base of the data array - declared externally so we can have differnt sized FIFOs + unsigned write_idx; + unsigned read_idx; +} mem_fifo_t; + +#endif \ No newline at end of file diff --git a/examples/xua_lite_example/src/xua_buffer.xc b/examples/xua_lite_example/src/xua_buffer.xc index ac363331..3d4a17fd 100644 --- a/examples/xua_lite_example/src/xua_buffer.xc +++ b/examples/xua_lite_example/src/xua_buffer.xc @@ -9,7 +9,7 @@ #define DEBUG_PRINT_ENABLE_XUA_LITE_BUFFER 1 #include "debug_print.h" #include "xua.h" -//#include "fifo_impl.h" //xua_conf.h must be included before hand so that we have FIFO sizes +#include "fifo_impl.h" //Currently only single frequency supported #define NOMINAL_SR_DEVICE DEFAULT_FREQ @@ -93,7 +93,7 @@ static inline void pack_samples_to_buff(int input[], const unsigned n_samples, c } -void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, chanend c_aud_ctl, in port p_for_mclk_count, chanend c_audio_hub){ +void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, chanend c_sof, chanend c_aud_ctl, in port p_for_mclk_count, chanend c_audio_hub) { debug_printf("%d\n", MAX_OUT_SAMPLES_PER_SOF_PERIOD); @@ -134,167 +134,177 @@ void XUA_Buffer_lite(chanend c_aud_out, chanend c_feedback, chanend c_aud_in, ch XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, num_samples_to_send_to_host); XUD_SetReady_InPtr(ep_feedback, (unsigned)buffer_feedback, FEEDBACK_BUFF_SIZE); - // printintln(OUT_AUDIO_BUFFER_SIZE_BYTES); - // printintln(MAX_OUT_SAMPLES_PER_SOF_PERIOD); - int loopback_samples[MAX_OUT_SAMPLES_PER_SOF_PERIOD] = {0}; int32_t samples_out[NUM_USB_CHAN_OUT] = {0}; int32_t samples_in[NUM_USB_CHAN_IN] = {0}; - while(1){ + unsafe{ + + int host_to_device_fifo_storage[MAX_OUT_SAMPLES_PER_SOF_PERIOD * 2]; + mem_fifo_t host_to_device_fifo = {sizeof(host_to_device_fifo_storage)/sizeof(host_to_device_fifo_storage[0]) + , host_to_device_fifo_storage, 0, 0}; + volatile mem_fifo_t * unsafe host_to_device_fifo_ptr = &host_to_device_fifo; + XUD_Result_t result; unsigned length = 0; + while(1){ + select{ + //Handle control path from EP0 + case testct_byref(c_aud_ctl, tmp): + //ignore tmp as is used for reboot signalling only + unsigned cmd = inuint(c_aud_ctl); + + debug_printf("c_aud_ctl cmd: %d\n", cmd); + if(cmd == SET_SAMPLE_FREQ){ + unsigned receivedSampleFreq = inuint(c_aud_ctl); + debug_printf("SET_SAMPLE_FREQ: %d\n", receivedSampleFreq); + sampleFreq = receivedSampleFreq; + } - select{ - //Handle control path from EP0 - case testct_byref(c_aud_ctl, tmp): - //ignore tmp as is used for reboot signalling only - unsigned cmd = inuint(c_aud_ctl); - - debug_printf("c_aud_ctl cmd: %d\n", cmd); - if(cmd == SET_SAMPLE_FREQ){ - unsigned receivedSampleFreq = inuint(c_aud_ctl); - debug_printf("SET_SAMPLE_FREQ: %d\n", receivedSampleFreq); - sampleFreq = receivedSampleFreq; - } - - else if(cmd == SET_STREAM_FORMAT_IN){ - unsigned formatChange_DataFormat = inuint(c_aud_ctl); - unsigned formatChange_NumChans = inuint(c_aud_ctl); - unsigned formatChange_SubSlot = inuint(c_aud_ctl); - unsigned formatChange_SampRes = inuint(c_aud_ctl); - debug_printf("SET_STREAM_FORMAT_IN: %d %d %d %d\n", formatChange_DataFormat, formatChange_NumChans, formatChange_SubSlot, formatChange_SampRes); - in_subslot_size = formatChange_SubSlot; - in_num_chan = formatChange_NumChans; - } - - else if (cmd == SET_STREAM_FORMAT_OUT) - { - XUD_BusSpeed_t busSpeed; + else if(cmd == SET_STREAM_FORMAT_IN){ unsigned formatChange_DataFormat = inuint(c_aud_ctl); unsigned formatChange_NumChans = inuint(c_aud_ctl); unsigned formatChange_SubSlot = inuint(c_aud_ctl); unsigned formatChange_SampRes = inuint(c_aud_ctl); - debug_printf("SET_STREAM_FORMAT_OUT: %d %d %d %d\n", formatChange_DataFormat, formatChange_NumChans, formatChange_SubSlot, formatChange_SampRes); - out_subslot_size = formatChange_SubSlot; - out_num_chan = formatChange_NumChans; - } + debug_printf("SET_STREAM_FORMAT_IN: %d %d %d %d\n", formatChange_DataFormat, formatChange_NumChans, formatChange_SubSlot, formatChange_SampRes); + in_subslot_size = formatChange_SubSlot; + in_num_chan = formatChange_NumChans; + } - else{ - debug_printf("Unhandled command\n"); - } - outct(c_aud_ctl, XS1_CT_END); - break; + else if (cmd == SET_STREAM_FORMAT_OUT) + { + XUD_BusSpeed_t busSpeed; + unsigned formatChange_DataFormat = inuint(c_aud_ctl); + unsigned formatChange_NumChans = inuint(c_aud_ctl); + unsigned formatChange_SubSlot = inuint(c_aud_ctl); + unsigned formatChange_SampRes = inuint(c_aud_ctl); + debug_printf("SET_STREAM_FORMAT_OUT: %d %d %d %d\n", formatChange_DataFormat, formatChange_NumChans, formatChange_SubSlot, formatChange_SampRes); + out_subslot_size = formatChange_SubSlot; + out_num_chan = formatChange_NumChans; + } - //SOF - case inuint_byref(c_sof, tmp): - unsigned mclk_port_count = 0; - asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_count) : "r" (p_for_mclk_count)); + else{ + debug_printf("Unhandled command\n"); + } + outct(c_aud_ctl, XS1_CT_END); + break; - /* Assuming 48kHz from a 24.576 master clock (0.0407uS period) - * MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF. - * expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format. - * Average over 128 SOFs - 128 x 3072 = 0x60000. - */ + //SOF + case inuint_byref(c_sof, tmp): + unsigned mclk_port_count = 0; + asm volatile(" getts %0, res[%1]" : "=r" (mclk_port_count) : "r" (p_for_mclk_count)); - unsigned long long feedbackMul = 64ULL; - if(AUDIO_CLASS == 1) - feedbackMul = 8ULL; /* TODO Use 4 instead of 8 to avoid windows LSB issues? */ + /* Assuming 48kHz from a 24.576 master clock (0.0407uS period) + * MCLK ticks per SOF = 125uS / 0.0407 = 3072 MCLK ticks per SOF. + * expected Feedback is 48000/8000 = 6 samples. so 0x60000 in 16:16 format. + * Average over 128 SOFs - 128 x 3072 = 0x60000. + */ - /* Number of MCLK ticks in this SOF period (E.g = 125 * 24.576 = 3072) */ - int count = (int) ((short)(mclk_port_count - lastClock)); + unsigned long long feedbackMul = 64ULL; + if(AUDIO_CLASS == 1) + feedbackMul = 8ULL; /* TODO Use 4 instead of 8 to avoid windows LSB issues? */ - unsigned long long full_result = count * feedbackMul * DEFAULT_FREQ; + /* Number of MCLK ticks in this SOF period (E.g = 125 * 24.576 = 3072) */ + int count = (int) ((short)(mclk_port_count - lastClock)); - clockcounter += full_result; + unsigned long long full_result = count * feedbackMul * DEFAULT_FREQ; - /* Store MCLK for next time around... */ - lastClock = mclk_port_count; + clockcounter += full_result; - /* Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll - * We always count 128 SOFs, so 16ms @ HS, 128ms @ FS */ - if(sof_count == 128) - { - debug_printf("fb\n"); - sof_count = 0; + /* Store MCLK for next time around... */ + lastClock = mclk_port_count; - clockcounter += mod_from_last_time; - clocks = clockcounter / MCLK_48; - mod_from_last_time = clockcounter % MCLK_48; + /* Reset counts based on SOF counting. Expect 16ms (128 HS SOFs/16 FS SOFS) per feedback poll + * We always count 128 SOFs, so 16ms @ HS, 128ms @ FS */ + if(sof_count == 128) + { + //debug_printf("fb\n"); + sof_count = 0; - //Scale for working out number of samps to take from device for input - if(AUDIO_CLASS == 2) - { - clocks <<= 3; - } - else - { - clocks <<= 6; - } - asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks + clockcounter += mod_from_last_time; + clocks = clockcounter / MCLK_48; + mod_from_last_time = clockcounter % MCLK_48; - //Write to feedback EP buffer - if (AUDIO_CLASS == 2) - { - fb_clocks[0] = clocks; - } - else - { - fb_clocks[0] = clocks >> 2; - } - clockcounter = 0; - } - sof_count++; - break; + //Scale for working out number of samps to take from device for input + if(AUDIO_CLASS == 2) + { + clocks <<= 3; + } + else + { + clocks <<= 6; + } + asm volatile("stw %0, dp[g_speed]"::"r"(clocks)); // g_speed = clocks - //Receive samples from host - case XUD_GetData_Select(c_aud_out, ep_aud_out, length, result): - num_samples_received_from_host = length / out_subslot_size; - //debug_printf("out samps: %d\n", num_samples_received_from_host); - outstanding_samples_to_host += num_samples_received_from_host; + //Write to feedback EP buffer + if (AUDIO_CLASS == 2) + { + fb_clocks[0] = clocks; + } + else + { + fb_clocks[0] = clocks >> 2; + } + clockcounter = 0; + } + sof_count++; + break; - unpack_buff_to_samples(buffer_aud_out, num_samples_received_from_host, out_subslot_size, loopback_samples); + //Receive samples from host + case XUD_GetData_Select(c_aud_out, ep_aud_out, length, result): + num_samples_received_from_host = length / out_subslot_size; + //debug_printf("out samps: %d\n", num_samples_received_from_host); + outstanding_samples_to_host += num_samples_received_from_host; - num_samples_to_send_to_host = num_samples_received_from_host; - - //Mark EP as ready for next frame from host - XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); - break; + unpack_buff_to_samples(buffer_aud_out, num_samples_received_from_host, out_subslot_size, loopback_samples); - //Send feedback - case XUD_SetData_Select(c_feedback, ep_feedback, result): - //debug_printf("ep_feedback\n"); - //XUD_SetReady_InPtr(ep_feedback, (unsigned)buffer_feedback, FEEDBACK_BUFF_SIZE); - if (AUDIO_CLASS == 2) - { - XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), 4); - } - else - { - XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), 3); - } + fifo_ret_t ret = fifo_block_push(host_to_device_fifo_ptr, loopback_samples, num_samples_received_from_host); + if (ret != FIFO_SUCCESS) debug_printf("full\n"); - break; + num_samples_to_send_to_host = num_samples_received_from_host; + + //Mark EP as ready for next frame from host + XUD_SetReady_OutPtr(ep_aud_out, (unsigned)buffer_aud_out); + break; - //Send samples to host - case XUD_SetData_Select(c_aud_in, ep_aud_in, result): - //debug_printf("sent data\n"); + //Send feedback + case XUD_SetData_Select(c_feedback, ep_feedback, result): + //debug_printf("ep_feedback\n"); + //XUD_SetReady_InPtr(ep_feedback, (unsigned)buffer_feedback, FEEDBACK_BUFF_SIZE); + if (AUDIO_CLASS == 2) + { + XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), 4); + } + else + { + XUD_SetReady_In(ep_feedback, (fb_clocks, unsigned char[]), 3); + } - //Populate the input buffer ready for the next read - pack_samples_to_buff(loopback_samples, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); - //Use the number of samples we received last time so we are always balanced (assumes same in/out count) - - unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; - XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, input_buffer_size); //loopback - num_samples_to_send_to_host = 0; - break; + break; - case c_audio_hub :> samples_in[0]: - for (int i = 1; i < NUM_USB_CHAN_IN; i++) c_audio_hub :> samples_in[i]; - // for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: samples_out[1]; - for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: loopback_samples[i]; - break; + //Send samples to host + case XUD_SetData_Select(c_aud_in, ep_aud_in, result): + //debug_printf("sent data\n"); + + //Populate the input buffer ready for the next read + pack_samples_to_buff(loopback_samples, num_samples_to_send_to_host, in_subslot_size, buffer_aud_in); + //Use the number of samples we received last time so we are always balanced (assumes same in/out count) + + unsigned input_buffer_size = num_samples_to_send_to_host * in_subslot_size; + XUD_SetReady_InPtr(ep_aud_in, (unsigned)buffer_aud_in, input_buffer_size); //loopback + num_samples_to_send_to_host = 0; + break; + + case c_audio_hub :> samples_in[0]: + for (int i = 1; i < NUM_USB_CHAN_IN; i++) c_audio_hub :> samples_in[i]; + // for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: samples_out[1]; + int out_samps[NUM_USB_CHAN_OUT]; + fifo_ret_t ret = fifo_block_pop(host_to_device_fifo_ptr, out_samps, NUM_USB_CHAN_OUT); + if (ret != FIFO_SUCCESS) debug_printf("empty\n"); + for (int i = 0; i < NUM_USB_CHAN_OUT; i++) c_audio_hub <: out_samps[i]; + break; + } } } } \ No newline at end of file