Jump to content
    

Старт -стоп условия I2C

Здравствуйте Уважаемые!

 

Подскажите как правильно определять старт - стоп условия в I2C.

Я сделал вот так, но носом чую, что где-то лажа :)

 

//------------------------------------------------------------------------------------------------------------------------
// generate shift register
    always @(posedge SCL)
      sr <= {sr[6:0],SDA};    
         
    assign my_adr = (sr[7:1] == I2C_ADR);       //??????????????????????????????????
    
    //generate bit-counter
    always @(posedge SCL)
        if(ld)
        bit_cnt <=  3'b111;
      else
        bit_cnt <=  bit_cnt - 3'h1;
        
        //generate access done signal
    assign acc_done = !(|bit_cnt);
    
    //detect start condition
    always @(negedge SDA)
            sta<=SCL;
    
    
      //-------------------------------------------------------------------------------------------------------------------
   always @(posedge SCL or posedge sto)
       if(sto)
         d_sta<=1'b0;
           else
         d_sta <= sta;

    // detect stop condition
    always @(posedge SDA or posedge sta)
        if(sta)
            sto <=  1'b0;
     else if(SCL)
        sto <= 1'b1;
                  

    //generate i2c_reset signal
    assign i2c_reset = sta || sto; 
//-----------------------------------------------------------------------------------------------------------------------

 

Спасибо.

Share this post


Link to post
Share on other sites

а почему бы не взять готовый XAPP с исходниками на Верилог?

(кстати, логики там немного - поскольку писали они под CPLD)

 

или тут посмотрите:

http://electronix.ru/forum/index.php?showtopic=9079

http://electronix.ru/forum/index.php?showtopic=16152

Share this post


Link to post
Share on other sites

Ну старт-стоп условия вы првильно определили. А в чем проблема-то конкретно? =)

Share this post


Link to post
Share on other sites

Ну старт-стоп условия вы првильно определили. А в чем проблема-то конкретно? =)

Да делаю асикс, надо i2c/spi слейв сделать, вот я и пытаюсь с минимальными ресурсами это сделать.

Нашел на опенкорес модель памяти мне в самый раз и по ресурсам классно, но в ней есть один недостаток она не совсем хорошо синтезится. В частности старт-стоп несинтезился вот я передлал и попросил посмотреть знающих или все ок.

Щас посмотрю ХАРР может там меня спасут :biggrin: Вот код кому интересно.

 

reg [7:0] mem [0:15]; // initiate memory       //GENERATE!!
    reg [7:0] mem_adr;   // memory address
    reg [7:0] mem_do;    // memory data output    
    
    // statemachine declaration
    parameter idle        = 3'b000;
    parameter slave_ack   = 3'b001;
    parameter get_mem_adr = 3'b010;
    parameter gma_ack     = 3'b011;
    parameter data        = 3'b100;
    parameter data_ack    = 3'b101;
      genvar i;
    
initial
    begin
    SDA_o =1;
    state = idle;
    end      
//--------------------------------------------------------------------------------------------------------
assign st_reset=sto || (sta && !d_sta);
//------------------------------------------------------------------------------------------------------------------------
// generate shift register
    always @(posedge SCL)
      sr <= {sr[6:0],SDA};    
         
    assign my_adr = (sr[7:1] == I2C_ADR);       //??????????????????????????????????
    
    //generate bit-counter
    always @(posedge SCL)
        if(ld)
        bit_cnt <=  3'b111;
      else
        bit_cnt <=  bit_cnt - 3'h1;
        
        //generate access done signal
    assign acc_done = !(|bit_cnt);
    
    //detect start condition
    always @(negedge SDA)
            sta<=SCL;
    
    
    
      //-------------------------------------------------------------------------------------------------------------------
   always @(posedge SCL or posedge sto)
       if(sto)
         d_sta<=1'b0;
           else
         d_sta <= sta;

    // detect stop condition
    always @(posedge SDA or posedge sta)
        if(sta)
            sto <=  1'b0;
     else if(SCL)
        sto <= 1'b1;
                  

    //generate i2c_reset signal
    assign i2c_reset = sta || sto; 
//-----------------------------------------------------------------------------------------------------------------------    
       // generate statemachine
    always @(negedge SCL or posedge st_reset)
      if(st_reset )
        begin
            state <= idle; // reset statemachine
            SDA_o <=  1'b1;
            ld    <= 1'b1;
        end
      else
        begin
            // initial settings
            SDA_o <= 1'b1;
            ld    <= 1'b0;

            case(state) // synopsys full_case parallel_case
                idle: // idle state
                  if (acc_done && my_adr)
                    begin
                        state <= slave_ack;
                        rw <= sr[0];
                        SDA_o <= 1'b0; // generate i2c_ack

                        #1;
                        if(rw)
                         begin
                              mem_do <= mem[mem_adr];
                         end
                       end

                slave_ack:
                  begin
                      if(rw)
                        begin
                            state <= data;
                            SDA_o <= mem_do[7];
                        end
                      else
                        state <= get_mem_adr;

                      ld    <= 1'b1;
                  end

                get_mem_adr: // wait for memory address
                  if(acc_done)
                    begin
                        state <=  gma_ack;
                        mem_adr <=  sr; // store memory address
                        SDA_o <= !(sr <= 15); // generate i2c_ack, for valid address
                    end

                gma_ack:
                  begin
                      state <= data;
                      ld    <=  1'b1;
                  end

                data: // receive or drive data
                  begin
                      if(rw)
                        SDA_o <= mem_do[7];

                      if(acc_done)
                        begin
                            state <= data_ack;
                            mem_adr <=  mem_adr + 8'h1;
                            SDA_o <= (rw && (mem_adr <= 15) ); // send ack on write, receive ack on read
                             if(rw)
                              mem_do <= mem[mem_adr];
                             if(!rw)
                             //  mem[ mem_adr[3:0] ] <= sr; // store data in memory        
                              mem[ mem_adr[3:0] ] <= sr;
                        end      
                     
                          if(!acc_done && rw)
                          mem_do <= {mem_do[6:0], 1'b1}; // insert 1'b1 for host ack generation     
                  end
                

                data_ack:
                  begin
                      ld <= 1'b1;

                      if(rw)
                        if(sr[0]) // read operation && master send NACK
                          begin
                              state <= idle;
                              SDA_o <= 1'b1;
                          end
                        else
                          begin
                              state <= data;
                              SDA_o <= mem_do[7];
                          end
                      else
                        begin
                            state <= data;
                            SDA_o <= 1'b1;
                        end
                  end

            endcase
        end

// generate tri-states
    assign SDA = SDA_o ? 1'bz : 1'b0;

    
    assign DATA_OUT=mem[4'd3];

 

Вот эту стейт машину надо под SPI постраться прикрутить. И чтобы автоинкремент адреса был :maniac:

Да может кто-то глянет в state==data я не могу понять в чем проблема, почему когда убераешь #1 перестает читать из памяти???

Спасибо!

Share this post


Link to post
Share on other sites

Что касается старта. Наверно недостаточно одной строчки

always @(negedge sda or negedge scl)

begin

if(scl == 1'b0) start <= 1'b0;

else start <= 1'b1;

end

 

always @(posedge sda or posedge start)

begin

if(start) stop <= 1'b0;

else if(scl) stop <= 1'b1;

end

Share this post


Link to post
Share on other sites

Спасибо!!!

Продолжая SPI/I2C эпопею. Запутался совсем. С записью проблем нету ни в SPI ни в I2C режиме, но в режиме чтения появляется 1 лишний бит. Как его убрать??

В SPI режиме 9 бит пустой и нужен только для экономии места, чтобы максимум использовать регистры I2C

 

module i2c_vim (nRESET, SCL ,SDA,SSB,MODE,DATA_OUT);
    
    input SCL;
    wire SCL;
    input nRESET;
    inout SDA;     
    input MODE;        //1=I2C mode, 0=SPI mode;
    input SSB;
    output [7:0] DATA_OUT;

//---------------------------------------------------------------------------------------------------
    reg [7:0] mem [0:15]; // initiate memory       //GENERATE!!
    reg [7:0] mem_adr;   // memory address
    reg [7:0] mem_do;    // memory data output    
    
    //I2C statemachine declaration
    parameter idle        = 3'b000;
    parameter slave_ack   = 3'b001;
    parameter get_mem_adr = 3'b010;
    parameter gma_ack     = 3'b011;
    parameter data        = 3'b100;
    parameter data_ack    = 3'b101;
    
    //--------------------------------------------------------------------------------------------------------      
    assign sto=(MODE) ? sto_int: SSB;
    //-------------------------------------------------------------------------------------------------------
    assign st_reset=sto || sta || !nRESET;
    //------------------------------------------------------------------------------------------------------------------------
    always @(posedge SCL or posedge st_reset)
        if(st_reset)
            sr<=8'b00000000;
        else
            sr <= {sr[6:0],SDA};    
    
    assign my_adr = (sr[7:1] == I2C_ADR);      
    
    //generate bit-counter
    always @(posedge SCL or posedge st_reset)
        if(st_reset)
            bit_cnt<=3'b000;
        else if(ld) //|!!!!!!!!!!!
            bit_cnt <=  3'b111;
        else
            bit_cnt <=  bit_cnt - 3'h1;
    
    //generate access done signal  
    always@(posedge SCL or posedge st_reset)
        if(st_reset)
            acc_done<=1'b1;
        else if(bit_cnt==3'b001)
            acc_done<=1'b1;
        else acc_done<=1'b0;     
    
    
    //detect start condition
    
    always@(negedge SDA or negedge SCL)
        if(SCL==1'b0)
            sta<=1'b0;
        else
            sta<=1'b1;
    // detect stop condition    
    always@(posedge SDA or posedge sta)
        if(sta) 
            sto_int<=1'b0;
        else if (SCL)            
            sto_int<=1'b1;
    //-----------------------------------------------------------------------------------------------------------------------    
    // generate statemachine
    always @(negedge SCL or posedge st_reset)
        if (st_reset )
            begin
                if(MODE)
                    begin    
                        state <= idle; // reset statemachine in I2C mode
                        SDA_o <=  1'b1;
                        ld    <= 1'b1;
                    end
                else     
                    begin    
                        state <= get_mem_adr; // reset statemachine in I2C mode
                        SDA_o <=  1'b1;
                        ld    <= 1'b1;
                    end
                
            end
        else
            begin
                SDA_o<=1'b1;
                case(state) // synopsys full_case parallel_case
                idle: // idle state    
                    begin
                        ld<=1'b0;
                        if (acc_done && my_adr)
                            begin
                                state <= slave_ack;
                                rw <= sr[0];
                                SDA_o <= 1'b0; // generate i2c_ack
                            end     
                    end
                slave_ack:
                    begin
                        if(rw)
                            state <= data;
                        else
                            state <= get_mem_adr;
                        ld    <= 1'b1;
                    end
                
                get_mem_adr: // wait for memory address    
                    begin 
                        ld<=1'b0;
                        if(acc_done)
                            begin
                                state <=  gma_ack;
                                mem_adr <=  sr; // store memory address       
                                if(MODE)
                                    SDA_o <= !(sr <= 15); // generate i2c_ack, for valid address  
                                else
                                    SDA_o <=1'b1;    
                            end                                                                   
                    end    
                
                gma_ack: 
                    begin
                        state <= data;
                        ld    <=  1'b1;
                        mem_do<=mem[mem_adr];
                        if (!MODE) 
                            rw<=SDA;
                    end
                
                data: // receive or drive data
                    begin      
                        // read data from memory 
                        if(!acc_done && rw)
                            begin
                                mem_do <= {mem_do[6:0], 1'b1}; 
                                SDA_o <= mem_do[7];      
                            end    
                        ld<=1'b0;
                        if(acc_done)
                            begin
                                //---------------------------------------------------------    
                                if(MODE)
                                    SDA_o <= (rw && (mem_adr <= 15)); // send ack on write, receive ack on read
                                else
                                    SDA_o<=1'b1;
                                //----------------------------------    
                                state <= data_ack; 
                                mem_adr<=mem_adr+8'h1;
                                if(!rw)    
                                    begin
                                    mem[ mem_adr[3:0] ] <= sr;
                                    end
                                else
                                  begin     
                                      mem_do<=mem[mem_adr];
                                      end    
                            end    
                    end
                                                            
                data_ack:
                    begin
                        ld <= 1'b1;      
                              mem_do<=mem[mem_adr];
                            if(rw)
                                if(sr[0] && MODE) // read operation && master send NACK I2C
                                        begin
                                            state <= idle;
                                            SDA_o <= 1'b1;
                                        end
                                    else
                                        begin
                                            state <= data;
                                            SDA_o <= mem_do[7];    
                                        end
                                else
                                    begin
                                        state <= data;
                                        SDA_o <= 1'b1;
                                    end
                            end      
                    
            
                
                endcase
            end      
    
    
    // generate tri-states
    assign SDA = SDA_o ? 1'bz : 1'b0;
    assign DATA_OUT=mem[4'd3];    
    
    pullup(SDA);
    
endmodule

 

На рисунке место с ошибкой там где курсор.

Спасибо!!

 

Еще вопросик, что такое Feedback mux ?? Чем это чревато??

post-19991-1175873070_thumb.jpg

Edited by -=Vitaly=-

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...