Why a bitrev() on an I2S in buffered:32 port?

If you have a simple question and just want an answer.
philwick
Member
Posts: 10
Joined: Tue Dec 08, 2015 1:20 pm

Why a bitrev() on an I2S in buffered:32 port?

Post by philwick »

Hello,

I've been digging in the USB AUDIO2 reference code and something is puzzling me. Each time a sample is read form an I2S ADC, the read value is bit reversed 3before being saved to memory. In the XS1-Port-Specification (1.0.2) document I can read:

"Bits are shifted in and out starting with the least significant bit. When you need to start with the most significant bit you can use a single cycle bit-reverse operation (BITREV) that can be called by invoking the bitrev() function. "

Assuming an "in bufferded:32 port", my understanding is that incoming bits from the ADC is shifted into the port from the LS position. Knowing that I2S always sends MSB first, the MSB is first shifted into the port register in the LSB position. When next bits are shifted, this MSB is shifted toward the MSB side of the register. So when 32 bits have been received the I2S MSB should be in the MSB position within the port register. But the code from the USB AUDIO2 ref design is something like the following (simplified, from module_usb_audio::audio.xc line 713):

                unsigned sample;

                asm volatile("in %0, res[%1]" : "=r"(sample)  : "r"(p_i2s_adc[index++]));

 

                samplesIn_1[some index] = bitrev(sample);

 
Could it be that "Bits are shifted in and out starting with the least significant bit" means that the 1st received bit is saved on position 0 (LSB), the next one on position 1, and so on (which would then need the bitrev)? 
 
Thank you


User avatar
infiniteimprobability
XCore Legend
Posts: 1126
Joined: Thu May 27, 2010 10:08 am

Post by infiniteimprobability »

"Bits are shifted in and out starting with the least significant bit" means that the 1st received bit is saved on position 0 (LSB), the next one on position 1, and so on (which would then need the bitrev)?
You are exactly right! for example, in doI2SClocks() in audio.xc,

Code: Select all

                p_bclk <: 0xff00ff00;
where p_blck is also a 1b buffered port clocked from BCLK, outputs two cycles of a square-wave, starting low with a high/low time of 16 BCLKs..
philwick
Member
Posts: 10
Joined: Tue Dec 08, 2015 1:20 pm

Post by philwick »

infiniteimprobability wrote:
You are exactly right! for example, in doI2SClocks() in audio.xc,

Code: Select all

                p_bclk <: 0xff00ff00;
where p_blck is also a 1b buffered port clocked from BCLK, outputs two cycles of a square-wave, starting low with a high/low time of 16 BCLKs..
Yes, I understand that bitrev() is needed when the word is output (which is the case in your code snippet). In that case if the port register behaves like a shift register, then the LSB is shifted into the gpio latch and the bit [1] becomes the bit [0] in the port register.

What I don’t understand is how the port register behaves when it is an *input* port like below:

Code: Select all

               buffered in port:32 p = SOME_1BIT_PORT;
               .....
               p :> tmp;  // external stream sends 0xff00ff00 starting with MSB 1st
If I assume that this port register behaves like a standard shift register, and that the IO pin is connected to the LSB of the port (shift) register, then at the 1st clock the data from the IO pin is shifted in bit pos [0], at second clock this data is shifted to position [1], and so on. So at the 32nd clock, the bit should be at position [31] which is the MSB of the port register. Therefore if bits received are ordered so that the MSB is entered first (which is the case for the I2S protocol), the MSB of a 32 bit sample in the I2S stream should be the MSB in the port register after the 32nd clock. In the example above, the MSB 1 is shifted into p::pos[0] at first clock, then shifted to p::pos[1] at 2nd clock, etc... At the 32nd clock the same data is shifted into p::pos[31] and the whole word is written into tmp. Then no need to bitrev(), but the USB AUDIO 2 SDK code do use a bitrev().

I’m puzzled...