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

XiaomaGee發表於2017-09-15

實驗現象:

1、先燒寫ARM程式,然後燒寫FPGA程式。

2、開啟串列埠精靈,通過串列埠精靈給ARM傳送資料從而給FPGA傳送資料 ,會接收到字元GINGKO。

3、通過串列埠精靈傳送命令可以控制ARM·LED和FPGA·LED。

命令格式
LEDR\CR\LF ARM·LED、FPGA·LED亮
LEDG\CR\LF ARM·LED、FPGA·LED亮
LEDB\CR\LF ARM·LED、FPGA·LED亮

核心程式碼:

int main(void)
{

  /* USER CODE BEGIN 1 */
    int i;
    char buffer[20];
    char i2c_buffer[20];
  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART6_UART_Init();

  /* USER CODE BEGIN 2 */
    i2c.initialize();
    usart6.initialize(115200);
    usart6.printf("Hello,I am iCore4!\r\n");
    LED_GREEN_ON;
    
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
        if(usart6.receive_ok_flag == 1){
            usart6.receive_ok_flag = 0;
            for(i = 0;i < 20;i ++){
                buffer[i] = tolower(usart6.receive_buffer[i]);
            }
            if(memcmp(buffer,"ledr",strlen("ledr")) == 0){        //±È½Ï½ÓÊÕÊý¾Ý
                LED_RED_ON;
                LED_GREEN_OFF;
                LED_BLUE_OFF;
                i2c.write_nbyte(0x03,0X8F,buffer,strlen(buffer));   //i2c×ÜÏß·¢ËÍÊý¾Ý
            }
            if(memcmp(buffer,"ledg",strlen("ledg")) == 0){
                LED_RED_OFF;
                LED_GREEN_ON;
                LED_BLUE_OFF;
                i2c.write_nbyte(0x03,0X8F,buffer,strlen(buffer));
            }
            if(memcmp(buffer,"ledb",strlen("ledb")) == 0){
                LED_RED_OFF;
                LED_GREEN_OFF;
                LED_BLUE_ON;
                i2c.write_nbyte(0x03,0X8F,buffer,strlen(buffer));
            }        
            for(i = 0; i < 1000; i ++);
            i2c.read_nbyte(0x02,0x0F,i2c_buffer,0x06);            //i2c×ÜÏß½ÓÊÕÊý¾Ý
            usart6.printf(i2c_buffer);            
        }
  }
  /* USER CODE END 3 */

}
module i2c_ctrl(
    input clk_25m,
    input rst_n,
    input scl,
    inout sda,
    output led_red,
    output led_green,
    output led_blue    
);

//---------------------------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},
             wide = 6'd40;

//-----------------------------address--------------------------//                                                                                    
reg[4:0]m;
reg[7:0]device_address,word_address;                           //接收地址先傳輸高位

always@(posedge scl or negedge rst_n)
    if(!rst_n)
        begin
            m <= 5'd0;
            device_address <= 8'd0;
            word_address <= 8'd0;
            tx_en <= 1'd0;
            tx_en <= 1'd0;
        end
    else case(m)
            5'd0,5'd1,5'd2,5'd3,5'd4,5'd5,5'd6,5'd7:                    //接收裝置地址
                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(rx_ack || tx_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;
                            word_address <= 8'd0;
                        end
                    else if(word_address == 8'h0f)                         //使能傳送資料
                        begin
                            tx_en <= 1'd1;
                            word_address <= 8'd0;
                        end
                    else if(rx_ack)
                        begin
                            rx_en <= 1'd0;
                            m <= 5'd0;
                        end
                    else if(tx_ack)
                        begin
                            tx_en <= 1'd0;
                            m <= 5'd18;
                        end
                    else m <= 5'd17;
                end
            5'd18:begin
                        m <= 5'd0;
                    end
            endcase        
    
//-------------------------------rx---------------------------//        
/*接收資料*/
reg[63:0]data_in;
reg[63:0]data;
reg[4:0]i;
reg tx_en,rx_en;
reg rx_ack;

always@(posedge scl or negedge rst_n)
    if(!rst_n)
        begin
            i <= 5'd0;
            data <= 64'd0;
            data_in <= 64'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:        //移位完成資料接收
                    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
                            begin
                                i <= 5'd0;
                            end
                    end
                5'd9:begin
                        rx_ack <= 1'd0;
                        i <= 5'd0;
                      end
                default:i <= 5'd0;
            endcase
        end    
    
//-----------------------------data-------------------------//        
/*比較接收資料*/
reg [2:0]led;    
always@(posedge clk_25m or negedge rst_n)
    if(!rst_n)
        begin
            led <= 3'b101;
        end
    else if (data[wide-1:0] == ledr)
            led <= 3'b011;
    else if (data[wide-1:0] == ledg)
            led <= 3'b101;
    else if (data[wide-1:0] == ledb)
            led <= 3'b110;    
            
assign {led_red,led_green,led_blue} = led;    
    
//----------------------------tx--------------------------//        //傳送資料   先傳輸高位
reg[47:0]data_out;
reg[3:0]j;
reg send_data;
reg tx_ack;
reg[2:0]tx_cnt;
always@(negedge scl or negedge rst_n)
    if(!rst_n)
        begin
            j <= 4'd0;
            send_data <= 1'd1;
            tx_ack <= 1'd0;
            tx_cnt <= 3'd0;
            data_out <= GINGKO;
        end
    else case(j)
                4'd0,4'd1,4'd2,4'd3,4'd4,4'd5,4'd6,4'd7:        //移位輸出資料
                    begin
                        if(tx_en)
                            begin
                                j <= j + 1'd1;
                                {send_data,data_out[47:1]} <= data_out;
                                tx_ack <= 1'd0;
                            end
                    end
                4'd8:begin
                        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_ack <= 1'd0;    
                                tx_cnt <= tx_cnt + 1'd1;
                            end
                    end 
                4'd9:begin
                            j <= 4'd0;
                            tx_ack <= 1'd0;
                            data_out <= GINGKO;
                    end
                4'd10:begin
                            j <= 4'd0;
                            tx_ack <= 1'd0;
                        end
            endcase    

assign sda = (j >= 4'd1 && j <= 4'd8) ? send_data : 1'dz;
            
endmodule

原始碼下載連結:

連結:http://pan.baidu.com/s/1geWgggF 密碼:an3s

iCore4連結:

相關文章