【iCore1S 雙核心板_FPGA】例程十五:基於I2C的ARM與FPGA通訊實驗

XiaomaGee發表於2017-09-25

實驗現象:

 

核心程式碼:

int main(void)
{
    int i,n;
    char buffer[20];
    char i2c_buffer[20];
    
  HAL_Init();
  system_clock.initialize();

    led.initialize();
  usart1.initialize(115200);
    i2c.initialize();
    

    usart1.printf("Hello! I am iCore1S!\r\n");        //´®¿Ú1Êä³ö
    while(1)
        {
        if(usart1.receive_ok_flag)
            {                                           //½ÓÊÕÍê³É
                usart1.receive_ok_flag = 0;
                for(i = 0;i < 20;i++)
                {
                    buffer[i] = tolower(usart1.receive_buffer[i]);
                }
            n = strlen(buffer);
            //±È½Ï½ÓÊÕÐÅÏ¢
            if(memcmp(buffer,"ledr",strlen("ledr")) == 0)
                {
                    //ºìÉ«LEDµãÁÁ
                    LED_RED_ON;
                    LED_GREEN_OFF;
                    LED_BLUE_OFF;
                }
            if(memcmp(buffer,"ledg",strlen("ledg")) == 0)
                {
                    //ÂÌÉ«LEDµãÁÁ
                    LED_RED_OFF;
                    LED_GREEN_ON;
                    LED_BLUE_OFF;
                }    
            if(memcmp(buffer,"ledb",strlen("ledb")) == 0)
                {
                    //À¶É«LEDµãÁÁ
                    LED_RED_OFF;
                    LED_GREEN_OFF;
                    LED_BLUE_ON;
                }    
            buffer[4]=13;//Ìí¼Ó½áÊøλ
            n=strlen(buffer);
            i2c.write_nbyte(0x03,0x8F,buffer,n);        //i2c·¢ËÍÊý¾Ý
            for(i=0;i<100;i++);
            i2c.read_nbyte(0x03,0x0F,i2c_buffer,0x06);
            usart1.printf("%s\n",i2c_buffer);//´®¿Ú1Êä³ö½ÓÊÕµ½µÄÊý¾Ý
        }
    }
}
module I2C(
    input CLK_12M,
    input SCL,
    inout SDA,
    output FPGA_LEDR,
    output FPGA_LEDG,
    output FPGA_LEDB    
);
//-------------------------rst_n----------------------------//
    reg rst_n;
    reg [3:0]cnt_rst;
    
    always@(posedge CLK_12M)
        begin
            if(cnt_rst==4'd10)
                begin
                    rst_n <= 1'd1;
                    cnt_rst <= 4'd10;
                end
            else cnt_rst <= cnt_rst + 1'd1;
        end
    
//-------------------------parameter------------------------//
    parameter ledr = {8'd108,8'd101,8'd100,8'd114,8'd13},
                 ledg = {8'd108,8'd101,8'd100,8'd103,8'd13},
                 ledb = {8'd108,8'd101,8'd100,8'd98, 8'd13},
                 GINGKO = {8'd71,8'd73,8'd78,8'd71,8'd75,8'd79};
                 
//---------------------------address------------------------//    
    reg [7:0]device_address,word_address;
    reg [4:0]m;
    
    always@(posedge SCL or negedge rst_n)
        begin
            if(!rst_n)
                begin
                    device_address <= 8'd0;
                    word_address <= 8'd0;
                    m <= 5'd0;
                    tx_en <= 1'd0;
                    rx_en <= 1'd0;
                end
            else 
                begin
                    case(m)
                        5'd0,5'd1,5'd2,5'd3,5'd4,5'd5,5'd6,5'd7:    //接收8位地址
                            begin
                                if(!rx_en || !tx_en)
                                    begin
                                        m <= m + 1'd1;
                                        device_address <= {device_address[6:0],SDA};
                                    end
                                else m <= 5'd0;
                            end
                        5'd8:
                            begin
                                if(device_address==8'd3 || device_address==8'd2)//識別地址
                                    begin
                                        m <= 5'd9;
                                        device_address <= 8'd0;
                                    end
                                else if(tx_ack || rx_ack)//識別應答應答
                                    begin
                                        m <= 5'd18;
                                        device_address <= 8'd0;
                                    end
                                else 
                                    begin
                                        m <= 5'd0;
                                    end
                            end
                        5'd9,5'd10,5'd11,5'd12,5'd13,5'd14,5'd15,5'd16://接收命令
                            begin
                                m <= m + 1'd1;
                                word_address <= {word_address[6:0],SDA};
                            end
                        5'd17:
                            begin
                                if(word_address == 8'h8f)//判斷接收命令
                                    begin
                                        rx_en <= 1'd1;
                                        device_address <= 8'hff;
                                        word_address <= 8'd0;
                                    end
                                else if(word_address == 8'h0f)//判斷髮送命令
                                    begin
                                        tx_en <= 1'd1;
                                        word_address <= 8'd0;
                                    end
                                else if(tx_ack)
                                    begin
                                        tx_en <= 1'd0;
                                        m <= 5'd0;
                                    end
                                else if(rx_ack)
                                    begin
                                        rx_en <= 1'd0;
                                        m <= 5'd0;
                                    end
                                else m <= 5'd17;
                            end
                        5'd18:
                            begin
                                m <= 5'd0;
                            end
                    endcase
                end            
        end
//-----------------------------rx---------------------------//
    //接收資料
    reg [63:0]data_in;
    reg [63:0]data;
    reg [4:0]i;
    reg rx_en;
    reg rx_ack;
    
    always@(posedge SCL or negedge rst_n)
        begin
            if(!rst_n)
                begin
                    data_in <= 64'd0;
                    data <= 64'd0;
                    i <= 5'd0;
                    rx_ack <= 1'd0;
                end
            else if(rx_en)
                begin
                    case(i)
                        5'd0,5'd1,5'd2,5'd3,5'd4,5'd5,5'd6,5'd7://接收8位資料
                            begin
                                i <= i + 1'd1;
                                rx_ack <= 1'd0;
                                data_in <= {data_in[62:0],SDA};
                            end
                        5'd8:
                            begin
                                if(data_in[7:0]==8'h0d)//判斷結束為
                                    begin
                                        i <= 5'd9;
                                        rx_ack <= 1'd1;
                                        data <= data_in;
                                    end
                                else i <= 5'd0;
                            end
                        5'd9:
                            begin
                                i <= 5'd0;
                                rx_ack <= 1'd0;
                            end
                        default:
                            begin
                                i <= 5'd0;
                            end
                    endcase
                end
        end
        
//----------------------------data--------------------------//
    //對比接收資料
    reg [2:0]led;
    
    always@(posedge CLK_12M or negedge rst_n)
        begin
            if(!rst_n)
                begin
                    led <= 3'b111;
                end
            else 
                begin
                    case(data[39:0])
                        ledr:    led <= 3'b011;//紅燈亮
                        ledg: led <= 3'b101;//綠燈亮
                        ledb: led <= 3'b110;//藍燈亮
                        default:led <= 3'b111;//都不亮    
                    endcase
                end
        end
    
    assign {FPGA_LEDR,FPGA_LEDG,FPGA_LEDB} = led;
    
//-----------------------------tx---------------------------//
    //傳送資料
    reg [47:0]data_out;
    reg [3:0]j;
    reg [2:0]tx_cnt;
    reg tx_ack;
    reg tx_en;
    reg sda;
    
    always@(posedge SCL or negedge rst_n)
        begin
            if(!rst_n)
                begin
                    data_out <= GINGKO;
                    j <= 4'd0;
                    tx_ack <= 1'd0;
                    tx_cnt <= 3'd0;
                    sda <= 1'd1;
                end
            else 
                begin
                    case(j)
                        4'd0,4'd1,4'd2,4'd3,4'd4,4'd5,4'd6,4'd7://傳送8位書籍
                            begin
                                if(tx_en)
                                    begin
                                        j <= j + 1'd1;
                                        {sda,data_out[47:1]} <= data_out;
                                        tx_ack <= 1'd0;
                                    end
                            end
                        4'd8:
                            begin //傳送6次,8位資料(GINGKO)
                                if(tx_cnt ==3'd5)
                                    begin
                                        j <= j + 1'd1;
                                        tx_ack <= 1'd1;
                                        tx_cnt <= 3'd0;
                                    end
                                else
                                    begin
                                        j <= 4'd0;
                                        tx_cnt <= tx_cnt + 1'd1;
                                        tx_ack <= 1'd0;
                                    end
                            end
                        4'd9:
                            begin
                                j <= 4'd0;
                                tx_ack <= 1'd0;
                                data_out <= GINGKO;
                            end
                        default:
                            begin
                                j <= 4'd0;
                                tx_ack <= 1'd0;
                                data_out <= GINGKO;
                            end
                    endcase
                end
        end
        
    assign SDA = (j>=4'd1 && j<=4'd8)? sda : 1'dz;
    
//--------------------------endmodule-----------------------//
endmodule 

實驗方法及指導書:

連結:http://pan.baidu.com/s/1hs8ErAW 密碼:wven

相關文章