OpenCores
URL https://opencores.org/ocsvn/ao486/ao486/trunk

Subversion Repositories ao486

[/] [ao486/] [trunk/] [rtl/] [soc/] [driver_sound/] [driver_sound.v] - Rev 2

Compare with Previous | Blame | View Log

/*
 * Copyright (c) 2014, Aleksander Osman
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 * 
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
module driver_sound(
    input           clk_12,
    input           rst_n,
 
    //sound interface slave
    input           avs_write,
    input   [31:0]  avs_writedata,
 
    //WM8731 audio codec
    output reg      ac_sclk,
    inout           ac_sdat,
 
    output          ac_xclk,
    output reg      ac_bclk,
    output          ac_dat,
    output reg      ac_lr
);
 
//------------------------------------------------------------------------------ audio codec output DSP/PCM mode B
 
assign ac_dat = sample[15];
assign ac_xclk = clk_12;
 
reg [15:0] sample_next;
always @(posedge clk_12 or negedge rst_n) begin
    if(rst_n == 1'b0)   sample_next <= 16'd0;
    else if(avs_write)  sample_next <= avs_writedata[15:0];
end
 
reg [6:0] sample_cnt;
always @(posedge clk_12 or negedge rst_n) begin
    if(rst_n == 1'b0)               sample_cnt <= 7'd0;
    else if(~(sound_ready))         sample_cnt <= 7'd0;
    else if(sample_cnt == 7'd124)   sample_cnt <= 7'd0;
    else                            sample_cnt <= sample_cnt + 7'd1;
end
 
always @(posedge clk_12 or negedge rst_n) begin
    if(rst_n == 1'b0)                                   ac_lr <= 1'b0;
    else if(sample_cnt == 7'd1 || sample_cnt == 7'd2)   ac_lr <= 1'b1;
    else                                                ac_lr <= 1'b0;
end
 
always @(posedge clk_12 or negedge rst_n) begin
    if(rst_n == 1'b0)                                   ac_bclk <= 1'b0;
    else if(sample_cnt >= 7'd2 && sample_cnt <= 7'd64)  ac_bclk <= ~(ac_bclk);
    else                                                ac_bclk <= 1'b0;
end
 
reg [15:0] sample;
always @(posedge clk_12 or negedge rst_n) begin
    if(rst_n == 1'b0)                                                           sample <= 16'd0;
    else if(sample_cnt == 7'd1)                                                 sample <= sample_next;
    else if(sample_cnt >= 7'd2 && sample_cnt <= 7'd64 && sample_cnt[0] == 1'b1) sample <= { sample[14:0], sample[15] };
end
 
//------------------------------------------------------------------------------
 
//------------------------------------------------------------------------------
 
localparam [3:0] CTRL_IDLE     = 4'd0;
localparam [3:0] CTRL_RESET    = 4'd1;
localparam [3:0] CTRL_POWER    = 4'd2;
localparam [3:0] CTRL_OUTPUT   = 4'd3;
localparam [3:0] CTRL_SIDE     = 4'd4;
localparam [3:0] CTRL_EMPH     = 4'd5;
localparam [3:0] CTRL_FORMAT   = 4'd6;
localparam [3:0] CTRL_SAMPLING = 4'd7;
localparam [3:0] CTRL_ACTIVATE = 4'd8;
localparam [3:0] CTRL_READY    = 4'd9;
 
reg [3:0]  control_state;
 
reg        control_start;
reg [15:0] control_data;
 
wire sound_ready = control_state == CTRL_READY;
 
always @(posedge clk_12 or negedge rst_n) begin
    if(rst_n == 1'b0) begin
        control_start   <= 1'b0;
        control_data    <= 16'd0;
        control_state   <= CTRL_IDLE;
    end
    else begin
        if(control_state == CTRL_IDLE) begin
            control_start   <= 1'b1;
            control_data    <= 16'b0001111_000000000; //reset
            control_state   <= CTRL_RESET;
        end
        else if(control_state == CTRL_RESET && i2c_ready == 1'b1) begin
            control_start   <= 1'b1;
            control_data    <= 16'b0000110_001100111; // power down unused parts
            control_state   <= CTRL_POWER;
        end
        else if(control_state == CTRL_POWER && i2c_ready == 1'b1) begin
            control_start   <= 1'b1;
            control_data    <= 16'b0000010_101111001; // 0dB headphone output
            control_state   <= CTRL_OUTPUT;
        end
        else if(control_state == CTRL_OUTPUT && i2c_ready == 1'b1) begin
            control_start   <= 1'b1;
            control_data    <= 16'b0000100_011010010; // DAC select
            control_state   <= CTRL_SIDE;
        end
        else if(control_state == CTRL_SIDE && i2c_ready == 1'b1) begin
            control_start   <= 1'b1;
            control_data    <= 16'b0000101_000000101; // disable mute, 41.1kHz de-emphasis
            control_state   <= CTRL_EMPH;
        end
        else if(control_state == CTRL_EMPH && i2c_ready == 1'b1) begin
            control_start   <= 1'b1;
            control_data    <= 16'b0000111_000000011; // DSP mode
            control_state   <= CTRL_FORMAT;
        end
        else if(control_state == CTRL_FORMAT && i2c_ready == 1'b1) begin
            control_start   <= 1'b1;
            control_data    <= 16'b0001000_000011101; // USB mode, 12MHz, 96 kHz
            control_state   <= CTRL_SAMPLING;
        end
        else if(control_state == CTRL_SAMPLING && i2c_ready == 1'b1) begin
            control_start   <= 1'b1;
            control_data    <= 16'b0001001_000000001; //activate
            control_state   <= CTRL_ACTIVATE;
        end
        else if(control_state == CTRL_ACTIVATE && i2c_ready == 1'b1) begin
            control_state   <= CTRL_READY;
        end
        else begin
            control_start <= 1'b0;
        end
    end
end
 
//------------------------------------------------------------------------------
 
wire i2c_ready = (i2c_state == S_IDLE && control_start == 1'b0);
assign ac_sdat = (sdat_oe == 1'b0)? 1'bZ : sdat_o;
 
reg         sdat_oe;
reg         sdat_o;
reg [7:0]   dat_byte;
reg [1:0]   part;
reg [2:0]   counter;
reg [3:0]   i2c_state;
 
localparam [3:0] S_IDLE     = 4'd0;
localparam [3:0] S_SEND_0   = 4'd1;
localparam [3:0] S_SEND_1   = 4'd2;
localparam [3:0] S_SEND_2   = 4'd3;
localparam [3:0] S_SEND_3   = 4'd4;
localparam [3:0] S_SEND_4   = 4'd5;
localparam [3:0] S_END_0    = 4'd6;
localparam [3:0] S_END_1    = 4'd7;
localparam [3:0] S_END_2    = 4'd8;
 
always @(posedge clk_12 or negedge rst_n) begin
    if(rst_n == 1'b0) begin
        ac_sclk   <= 1'b1;
        sdat_oe   <= 1'b0;
        sdat_o    <= 1'b1;
        dat_byte  <= 8'd0;
        part      <= 2'b0;
        counter   <= 3'd0;
        i2c_state <= S_IDLE;
    end
    else if(i2c_state == S_IDLE && control_start == 1'b1) begin
        // start
        sdat_oe   <= 1'b1;
        sdat_o    <= 1'b0;
        ac_sclk   <= 1'b1;
 
        part      <= 2'b0;
        dat_byte  <= 8'b0011010_0;
        counter   <= 3'd7;
        i2c_state <= S_SEND_0;
    end
    else if(i2c_state == S_SEND_0) begin
        sdat_oe   <= 1'b1;
        sdat_o    <= dat_byte[7];
        ac_sclk   <= 1'b0;
        i2c_state <= S_SEND_1;
    end
    else if(i2c_state == S_SEND_1) begin
        ac_sclk <= 1'b1;
 
        if(counter == 3'd0) i2c_state <= S_SEND_2;
        else begin
            dat_byte  <= { dat_byte[6:0], 1'b0 };
            counter   <= counter - 3'd1; 
            i2c_state <= S_SEND_0;
        end
    end
    else if(i2c_state == S_SEND_2) begin
        sdat_oe   <= 1'b0;
        ac_sclk   <= 1'b0;
        i2c_state <= S_SEND_3;
    end
    else if(i2c_state == S_SEND_3) begin
        ac_sclk   <= 1'b1;
        i2c_state <= S_SEND_4;
    end
    else if(i2c_state == S_SEND_4 && ac_sdat == 1'b0) begin
        ac_sclk   <= 1'b0;
        part      <= part + 2'b1;
        counter   <= 3'd7;
 
        if(part == 2'd0)      dat_byte <= control_data[15:8];
        else if(part == 2'd1) dat_byte <= control_data[7:0];
 
        if(part == 2'd0 || part == 2'd1) i2c_state <= S_SEND_0;
        else                             i2c_state <= S_END_0;
    end
    else if(i2c_state == S_END_0) begin
        sdat_oe   <= 1'b1;
        sdat_o    <= 1'b0;
        ac_sclk   <= 1'b0;
        i2c_state <= S_END_1;
    end
    else if(i2c_state == S_END_1) begin
        ac_sclk   <= 1'b1;
        i2c_state <= S_END_2;
    end
    else if(i2c_state == S_END_2) begin
        // end
        sdat_oe   <= 1'b0;
        i2c_state <= S_IDLE;
    end
end
 
//------------------------------------------------------------------------------
 
// synthesis translate_off
wire _unused_ok = &{ 1'b0, avs_writedata[31:16], 1'b0 };
// synthesis translate_on
 
//------------------------------------------------------------------------------
 
endmodule
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.