I use a sliceKIT Starter Kit with the Audio Slice Card (XA-SK-AUDIO). I use the "I2S Master sliceKIT Loopback Demo" to read Audio in (e.g. by an mp3 player) and to give it back out as well (e.g. boxes or headphones). This is working fine. What I want to do now is to use that ADC values and send them to another thread to be able to display their values (in future spectrum) on the colour display. This would be the "app_display_spectrum_demo".
I display now the most important program parts from the two demos I mentioned above, which I combined in one program. If you want to have a look at the full program you can easily look at the mentioned demos in the XSOFTip. If someone is interested to look into the full program I could also upload it. The problem is mentioned at the bottom of this post in bold.
the main looks like this:
Code: Select all
int main(){
chan c_dc, c_lcd, c_sdram;
streaming chan c_sig1;
streaming chan c_con; // , c_data, c_sig2;
par {
on tile[0]: app(c_dc, c_sig1, c_con); //++ on tile[0]: app(c_dc, c_sig1, c_sig2);
on tile[0]: display_controller(c_dc,c_lcd,c_sdram);
on tile[0]: lcd_server(c_lcd,lcdports);
on tile[0]: sdram_server(c_sdram,sdramports);
// on tile[1]: sine_wave(c_sig1, FFT_POINTS); //simulated sine wave running parallel to the input
// on tile[1]: sine_wave(c_sig2, FFT_POINTS/4);
on tile[1] :
{
unsigned mclk_bclk_div = MCLK_FREQ/(AUSAMP_FREQ * 64); // (512*48000)/48000 *64= 32768
audio_hw_init(mclk_bclk_div);
audio_hw_config(AUSAMP_FREQ);
i2s_master(i2s_resources, c_sig1, mclk_bclk_div);
}
}return 0;
}
The sine_wave() function outputs a value every 20us over the streaming channel and looks like this:
Code: Select all
void sine_wave(streaming chanend c_sine, short maxSampPerCyc)
{
timer t;
unsigned time;
int data,data1;
t :> time;
while (1){
for (int i=1; i<=maxSampPerCyc; i++){
data = 2048*sin(2*PI*i/maxSampPerCyc);
data1 = data;
t when timerafter(time+(XS1_TIMER_HZ/SAMP_FREQ)):> void; //:> time; SAMP_FREQ 1sec/50000=20us/// 100000 timer ticks = 1ms
c_sine <: data1;
}
}
}
Code: Select all
void app(chanend c_dc, streaming chanend c_sig1, streaming chanend c_sig2)
{
unsigned frBufIndex=0, frBuf[2];
unsigned magSpec[FFT_POINTS], maxSpec;
// Create frame buffers
frBuf[0] = display_controller_register_image(c_dc, LCD_ROW_WORDS, LCD_HEIGHT);
frBuf[1] = display_controller_register_image(c_dc, LCD_ROW_WORDS, LCD_HEIGHT);
display_controller_frame_buffer_init(c_dc, frBuf[0]);
// Display spectrum periodically
while (1){
frBufIndex = 1-frBufIndex;
magnitude_spectrum(c_sig1, c_sig2, magSpec);
maxSpec = 0;
for (int i=0; i<FFT_POINTS/2; i++)
maxSpec = (magSpec[i]>maxSpec)? magSpec[i]:maxSpec;
level_meter(c_dc, frBuf[frBufIndex], magSpec, FFT_POINTS/2, maxSpec);
display_controller_frame_buffer_commit(c_dc,frBuf[frBufIndex]);
}
}
Code: Select all
void magnitude_spectrum( streaming chanend c_sig1, streaming chanend c_sig2, unsigned magSpectrum[])
{
int sig_re[FFT_POINTS] = { 0 }, im[FFT_POINTS] = { 0 }, temp = 0; // int sig_re[FFT_POINTS], im[FFT_POINTS], temp;
for (int i=0; i<FFT_POINTS; i++){
// buffering
c_sig1 :> sig_re[i];
c_sig2 :> temp;
// Mixing
sig_re[i] += temp;
im[i] = 0;
}
// fft
fftTwiddle(sig_re, im, FFT_POINTS);
fftForward(sig_re, im, FFT_POINTS, FFT_SINE);
// magnitude spectrum
for (int i=0; i<FFT_POINTS; i++)
magSpectrum[i] = sig_re[i]*sig_re[i] + im[i]*im[i];
}
Now to the second part where the audio input is captured (ADC) and right away sent to output it again over the DAC. This happens in the above already displayed main program on tile[1] in the function i2s_master(), which looks like this:
Code: Select all
void i2s_master(r_i2s &r_i2s, streaming chanend c_data, unsigned mclk_bclk_div)//streaming
{
if(mclk_bclk_div == 1)
{
// TODO
}
else
{
// clock block 1 clocked off MCK
set_clock_src(r_i2s.cb1, r_i2s.mck);
// clock block 2 clocked off BCK (which is generated on-chip)
set_clock_src(r_i2s.cb2, r_i2s.bck);
// BCK port clocked off clock block 1
set_port_clock(r_i2s.bck, r_i2s.cb1);
// WCK and all data ports clocked off clock block 2
set_port_clock(r_i2s.wck, r_i2s.cb2);
for (int i = 0; i < I2S_MASTER_NUM_PORTS_ADC; i++)
{
set_port_clock(r_i2s.din[i], r_i2s.cb2);
}
for (int i = 0; i < I2S_MASTER_NUM_PORTS_DAC; i++)
{
set_port_clock(r_i2s.dout[i], r_i2s.cb2);
}
// Start clock blocks after configuration
start_clock(r_i2s.cb1);
start_clock(r_i2s.cb2);
}
// Run I2S i/o loop
i2s_master_loop(r_i2s.din, r_i2s.dout, c_data, r_i2s.wck, r_i2s.bck, mclk_bclk_div);
// Client must have killed us, so die..
}
Code: Select all
void i2s_master_loop(in buffered port:32 p_i2s_adc[], out buffered port:32 p_i2s_dac[], streaming chanend c, out buffered port:32 p_lrclk, out buffered port:32 p_bclk, int divide)
{
unsigned sampsAdc[I2S_MASTER_NUM_CHANS_ADC];
unsigned sampsDac[I2S_MASTER_NUM_CHANS_DAC];
unsigned int data1,data2;
/* Init sample buffers */
for (int i = 0; i < I2S_MASTER_NUM_CHANS_ADC; i++)
{
sampsAdc[i] = 0;
}
for (int i = 0; i < I2S_MASTER_NUM_CHANS_DAC; i++)
{
sampsDac[i] = 0;
}
/* Lets do some I2S.. */
// inputs and outputs are 32 bits at a time
// assuming clock block is reset - initial time is 0
// split SETPT from IN using asm - basically a split transaction with BCK generation in between
// input is always "up to" given time, output is always "starting from" given time
// outputs will be aligned to WCK + 1 (first output at time 32, WCK at time 31)
// inputs will also be aligned to WCK + 1 (first input up to time 63, WCK up to time 62)
for (int i = 0; i < I2S_MASTER_NUM_PORTS_DAC; i++)
{
p_i2s_dac[i] @ 64 <: 0;
}
for (int i = 0; i < I2S_MASTER_NUM_PORTS_ADC; i++)
{
asm("setpt res[%0], %1" :: "r"(p_i2s_adc[i]), "r"(63));
}
p_lrclk @ 31 <: 0;
// clocks for previous outputs / inputs
bck_32_ticks(p_bclk, divide);
p_lrclk <: 0;
bck_32_ticks(p_bclk, divide);
#pragma unsafe arrays
while (1)
{
int p = 0;
/* Send ADC samples over channel... */
[b]#pragma loop unroll
for (int i = 0; i < I2S_MASTER_NUM_CHANS_ADC; i++){ //SOURCE
sampsDac[i] = sampsAdc[i];
// c <: sampsAdc[i];
data1 = sampsAdc[0];
data2 = ((data1)/2097152);
c <: data2;
}[/b]
/* Receive DAC samples from channel... */
/*++#pragma loop unroll
for (int i = 0; i < I2S_MASTER_NUM_CHANS_DAC; i++)
c :> sampsDac[i];
// input audio data
// will be output to channel end as left-aligned
// compiler would insert SETC FULL on DIN input, because it doesn't know about inline SETPT above
// hence we need inline IN too
p = 0;
++*/
#pragma loop unroll
for (int i = 0; i < I2S_MASTER_NUM_CHANS_ADC; i+=2)
{
int x;
asm("in %0, res[%1]" : "=r"(x) : "r"(p_i2s_adc[p++]));
sampsAdc[i] = bitrev(x);
}
/* Output LR clock to port */
p_lrclk <: 0;
/* drive bit clock */
bck_32_ticks(p_bclk, divide);
/* Output next DAC audio data for "Left" or "even" channels to I2S data ports.
* Samples expected to come from channel end as left-aligned
*/
p = 0;
#pragma loop unroll
for (int i = 0; i < I2S_MASTER_NUM_CHANS_DAC; i+=2)
{
p_i2s_dac[p++] <: bitrev(sampsDac[i]);
}
/* Input previous ADC audio data
* Will be output to channel end as left-aligned
* compiler would insert SETC FULL on DIN input, because it doesn't know about inline SETPT above
* hence we need inline IN too
*/
p = 0;
#pragma loop unroll
for (int i = 1; i < I2S_MASTER_NUM_CHANS_ADC; i+=2)
{
int x;
asm("in %0, res[%1]" : "=r"(x) : "r"(p_i2s_adc[p++]));
sampsAdc[i] = bitrev(x);
}
/* Output LR clock value to port */
p_lrclk <: 0xffffffff;
/* drive bit clock. This will clock out LRClk and DAC data from ports and clock in next
* ADC data into ports
*/
bck_32_ticks(p_bclk, divide);
/* Output "right" (or "odd") channel DAC data to DAC ports */
p = 0;
#pragma loop unroll
for (int i = 1; i < I2S_MASTER_NUM_CHANS_DAC; i+=2)
{
p_i2s_dac[p++] <: bitrev(sampsDac[i]);
}
}
}
Code: Select all
#pragma loop unroll
for (int i = 0; i < I2S_MASTER_NUM_CHANS_ADC; i++){ //SOURCE
sampsDac[i] = sampsAdc[i];
// c <: sampsAdc[i];
data1 = sampsAdc[0];
data2 = ((data1)/2097152);
c <: data2;
}
This works also fine.
I'm sorry this is so long, but I decided when I post it that I rather post the whole thing so it might help someone who really wants to try and help me.
A short summary and then finally the problem: We can give values over app() to the display and we can input and output audio files.
The problem: I would now like to send the ADC values from sampsAdc over a streaming channel to app() so they are displayed on the display. But so far whatever I tried, that moment when I send the ADC values (over e.g. c_sig1)
Code: Select all
i2s_master(i2s_resources, c_sig1, mclk_bclk_div);
Code: Select all
on tile[0]: app(c_dc, c_sig1, c_con);
I think this might be a timing problem since the app() function takes a while to accept the next value. The sampling from the audio values is set to 48000 what should provide a value every 20,3us.
Any sort of help, tip or thought on that problem would be appreciated. Thanks.