Search code examples
integerrangevhdlcounter

How is it possible to send out a bit every counter update (variable integer range)?


I've made a code for my I2S transceiver in VHDL (simple). I have to know how it's possible to send after each counter update 1,2,3 one of the 24 bits of the (24 bit) I2S word (with a short statement). for example:

if cnt = 2 => load bit 1 of left channel
if cnt = 3 => load bit 2
if cnt = 25 => load bit 24 of left channel
if cnt = 26 => load bit 1 of right channel
if cnt = 48 => load bit 24 of right channel

As you can see, the WS in my code selects the left or right channel. In my testbench I add the testword (2 x 24 bit word).

It's parallel data in and serial out (PISO), so it has to be something like a shift register.

I've been studying VHDL lately, because I'm a newbie in VHDL, but I don't know how to do this.

Here you can see my written code. Maybe it's a foolish question, but I already searched the whole Internet. Thanks in advance for answer my question.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity Simple_I2S_transceiver_V1 is
generic  (
    DATAWIDTH: integer := 24     
   );

port  
   (
    RST  : in std_logic;
    SCK  : in std_logic;             -- Serial Clock
    BCLK   : in std_logic;             -- Bit Clock
    WS   : inout std_logic;            -- Word Select or Left/Right channel select
    SD     : out std_logic;             -- Serial Data
    PDL  : in std_logic_vector(DATAWIDTH - 1 downto 0);   -- Parallel Data Left
    PDR  : in std_logic_vector(DATAWIDTH - 1 downto 0);   -- Parallel Data Right
    UPD  : inout std_logic;             -- Update data
    READY  : out std_logic;             -- check if data is ready to send (it depends on "VALID")
    VALID  : out std_logic             -- Check if data is valid (length) 
   );

end Simple_I2S_transceiver_V1;

architecture behavior of Simple_I2S_transceiver_V1 is
signal PDL_BUF : std_logic_vector(DATAWIDTH - 1 downto 0);
signal PDR_BUF : std_logic_vector(DATAWIDTH - 1 downto 0);
begin 

process(BCLK)

 -- Declaration of optional variables 
 variable bitcounter  : integer range 0 to 48;

 begin
  -------------------------------------------------
  -- RESET all     
  -------------------------------------------------

  if RST = '1' then
   WS  <= '0';
   SD  <= '0';
   READY <= '0';
   VALID <= '0';
   UPD   <= '0';
   PDL_BUF <= (OTHERS => '0');                                         -- Clear left channel buffer
   PDR_BUF <= (OTHERS => '0');                 -- Clear right channel buffer
      -------------------------------------------------
  -- Set WS / left/right-channel
      -------------------------------------------------

  elsif (BCLK'event and BCLK = '1') then
   PDL_BUF <= PDL;
   PDR_BUF <= PDR;

   bitcounter := bitcounter + 1;

   if bitcounter = 1 then
    UPD <= '1';
   else 
    UPD <= '0';

   if bitcounter >= 1 and bitcounter <= 24 then  
    WS <= '0';
   else
    WS <= '1';
    UPD <= '0'; 

   if WS = '0' then
    SD <= PDL(23);         <-- Parallel load -> it has to be serial load
   elsif WS = '1' then
    SD <= PDR(23);         <-- The same as PDL

   if bitcounter = 48 then
    bitcounter := 0;

   ----------------------------------------------
     -- transmitt data
   ---------------------------------------------- 
   -- add transmission 

     end if;
       end if;
      end if;
    end if;
   end if;
end process;

end behavior;


Solution

  • As I2S is MSB first, shift left and use the MSbit of PDx for SD out , something like.

    For left channel (transmit)

    SD <= PDL_BUF (23); -- use most significant bit
    PDL_BUF <= PDL_BUF (22 downto 0) & '0'; -- 22nd bit becomes 23 and puts a zero into unused bit 0
    

    Similar for right channel. For receive you'll still want to shift left too.

    Sorry I don't know much about I2S, but

    1. be careful of when loading PDL/PDR such that they can't be modified whilst sending (state machine perhaps?)
    2. be careful when sending data out when setting data clock out high at the same time, you might want to output the data on falling edge of data clock such that the data is latched correctly on the rising edge at the other side correctly. You could always state machine the clock - however this will slow down the data rate.
    3. know when to switch between WS 0 and 1 on transmit