Search code examples
vhdlfpgaintel-fpga

Clock configuration - VHDL coding Altera DE1 audio codec chip


I am working on a project where I am required to code the WM8731 audio codec chip on the Altera DE1 board. The project is very basic. It does not need to process the input audio signals. The signal from the input should be directly relayed to the output.

The main task is to set up the codec chip via the I2C protocol. I am new to VHDL and I am having some issues understanding the concept.

Prior to use the codec chip needs to be initialised. This consists of passing sets of data via the I2C. The data to be passed is given below along with the description.

    constant sdin_load : std_logic_vector (11*24-1 downto 0) 
    --this contains codec configuration data

Problem - The main clock frequency is 50MHz, and the I2C bus frequency is 100KHz. So the projects ask to have:
1) declare the bit counter; -- bit counter, runs at 100kHz,
2) declare the word counter; -- word counter, runs at about 5kHz
3) declare the counter for the bit length; -- frequency divider counter which runs at 50MHz

What I understand is that since the main clock and the I2C clock are of different frequency we need to have a counter to keep track of event. My understanding:
1) The bit counter can count from 1 to 500 which is 50MHz/100KHz. So whenever the counter goes to 500 next bit of information is transferred.
2) This is the part which I do not understand. If the word counter runs at 5KHz then it will only count 20 pulses of the I2C clock (100KHz/5KHz) not the 29 bit of information that it is sending.
3) Finally, why do we need to declare a counter to bit length that runs at 50MHz? We already have the clock running at that frequency.

We have been given a sample code. for the implementation of the counter. I am attaching the complete architecture for reference.

library ieee;
use ieee.std_logic_1164.all;

entity codec_init is
    port 
    (
        CLOCK_50    : in  std_logic;    -- master clock
        RES_N       : in  std_logic;    -- reset, active 0
        SCLK        : out std_logic;    -- serial clock
        SDIN        : out std_logic     -- serial data
    );

end entity;

architecture rtl of codec_init is

    constant sdin_load : std_logic_vector (11*24-1 downto 0)
    --this contains codec configuration data

begin

    process (CLOCK_50)
    begin
        if (rising_edge(CLOCK_50)) then
        -- reset actions
            if (RES_N = '0') then
            -- reset the counters to an appropriate state
                ...;    -- load the frequency divider,
                    -- 50MHz/500=100kHz bus speed
                ...;    -- load the shift register
                ...;    -- load the bit counter,
                    -- 29 bits in the word protocol
                ...;    -- load the word counter, 11 words
            -- reset the outputs to an appropriate state
                ...;
                ...;

            elsif (...) then -- deadlock in the end
                -- do nothing, wait for the next reset

        -- modify reference counters
        -- for frequency divider, bits and words
            elsif (...) then -- at the end of each bit 
                ...; -- reload the frequency divider counter

                if (bcnt = 0) then -- at the end of each word
                    ...;    -- reset the bit counter
                    ...;    --modify the word counter
                else    -- the bit is not the end of a word
                    ...;    --modify the bit counter
                end if;

            else    -- if not the end of the bit
                ...; -- modify the frequency divider
            end if;

        -- generating SCLK, it is going up and then down inside each bit
            if (...) then   -- condition when SCLK goes up
                ...;
            elsif (...) then    -- condition when SCLK goes down
                ...;
            end if;

        -- generating serial data output
            if (...) then -- start transition condition
                ...;
            elsif (...) then -- ack bit condition
                ...;
            elsif (...) then -- stop transition condition
                ...;
            elsif(...) then -- condition for the non-special bits
                ...; -- shifting
                ...;
            end if;

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

    -- forming the output with high impedance states for ack-s
    SDIN <= 'Z' when (...condition for ack bits...) 
                    else (sdout);

end rtl;

Thanks.


Solution

  • This may not be the answer that you are looking for, but I will post it as it may be useful.

    If your main goal is to just program your audio chip, and not necessarily fight with I2C protocol, you may use I2C block from for example OpenCores. You can find there quite good projects. I can't recommend particular one for I2C, but there are many I2C projects, that you can try.

    Another place there you can try looking for IPs is Altera's IP library. I don't know if there is one for I2C there, because I work with Xilinx devices, but you can try.

    EDIT: Ok, I will also refer more to actual question, as probably your task to really implement i2c. As far as I can see, you are asked to have counters, not clocks. This is not the same. And for this 5KHz - it is said that it will be about 5KHz, probably because of the reason you already pointed out. And if you ask about what do you need this counters for, I guess for:

    1. Clock for sending data
    2. You have to count words to know when to stop transmission.
    3. This is for bit length, so maybe this 50MHz should be 50KHz? It would be more reasonable.

    Read carefully what it is given to you in comments of this code.