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.