Перейти к содержанию
    

Старт -стоп условия 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; 
//-----------------------------------------------------------------------------------------------------------------------

 

Спасибо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Да делаю асикс, надо 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 перестает читать из памяти???

Спасибо!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо!!!

Продолжая 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

Изменено пользователем -=Vitaly=-

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...