From aac55f7038f985e3b7ce4cf7c3b048d5119a80fe Mon Sep 17 00:00:00 2001 From: "(Tim) Efthimis Kritikos" Date: Sat, 10 Feb 2024 22:35:33 +0000 Subject: [PATCH] I2C_BOOTLOADER: Added support for error handling --- boot_code/i2c_bootloader.asm | 21 +++-- .../fpga_config/OrangeCrab_r0.2.1/fpga_top.v | 14 +++- system/peripherals/CPU_to_I2C_driver_bridge.v | 6 +- system/peripherals/I2C_driver.v | 83 +++++++++---------- system/peripherals/I2C_driver_multiplexer.v | 7 +- 5 files changed, 76 insertions(+), 55 deletions(-) diff --git a/boot_code/i2c_bootloader.asm b/boot_code/i2c_bootloader.asm index 992ce62..57e8e99 100644 --- a/boot_code/i2c_bootloader.asm +++ b/boot_code/i2c_bootloader.asm @@ -20,15 +20,23 @@ mov al,#0x00 outb #0x60 -wait_send: inb #0x62 +wait_send: +inb #0x62 +test al,#0x02 +jnz rom_fail test al,#0x01 jnz wait_send mov bx,#OK_loading_txt call print +jmp read_code + +rom_fail: +call rom_fail_print ;############ READ CODE ################## +read_code: mov bx,#0xEFFF mov di,#0x0000 @@ -66,9 +74,6 @@ test al,#0x01 jnz wait_send2 inw #0x60 -;MOV CL,AH -;MOV AH,AL -;MOV AL,CL STOSW @@ -135,10 +140,13 @@ call print ret ;######################################### - - include LiteDram_init.asm +rom_fail_print: +mov bx,#rom_fail_txt +call print +hlt + print: mov al,[bx] cmp al,#0 @@ -155,6 +163,7 @@ STACK: ; brainfuck_mandelbrot depends on stack being at the end load_i2c_txt: .ASCII 'Read I2C EEPROM:\0' OK_loading_txt: .ASCII 'OK\nLoading rom 0%\r\0' loading_rom_txt: .ASCII 'Loading rom \0' +rom_fail_txt: .ASCII 'FAIL\nNo i2c rom at 0x50\0' ten_prc_txt: .ASCII '10%\r\0' twenty_prc_txt: .ASCII '20%\r\0' thirty_prc_txt: .ASCII '30%\r\0' diff --git a/system/fpga_config/OrangeCrab_r0.2.1/fpga_top.v b/system/fpga_config/OrangeCrab_r0.2.1/fpga_top.v index 8aa9cdc..3cc7347 100644 --- a/system/fpga_config/OrangeCrab_r0.2.1/fpga_top.v +++ b/system/fpga_config/OrangeCrab_r0.2.1/fpga_top.v @@ -441,6 +441,7 @@ wire [6:0] CPU_I2C_OUT_ADDRESS; wire CPU_I2C_OUT_BUSY,CPU_I2C_OUT_TRANSACT,CPU_I2C_DIR; wire [15:0]CPU_I2C_DATA_READ,CPU_I2C_DATA_WRITE; wire CPU_I2C_IGN_ACK; +wire CPU_I2C_ERROR; CPU_to_I2C_driver_bridge CPU_to_I2C_driver_bridge ( .clock(CPU_SPEED), @@ -463,7 +464,8 @@ CPU_to_I2C_driver_bridge CPU_to_I2C_driver_bridge ( .OUT_I2C_DATA_WRITE(CPU_I2C_DATA_WRITE), .TRANS_WIDTH(CPU_I2C_TRANS_WIDTH), - .OUT_IGN_ACK(CPU_I2C_IGN_ACK) + .OUT_IGN_ACK(CPU_I2C_IGN_ACK), + .IN_ERROR(CPU_I2C_ERROR) ); // Display driver @@ -539,6 +541,7 @@ I2C_driver_multiplexer I2C_driver_multiplexer( .IN1_I2C_DATA_WRITE({8'h0,DISP_I2C_DATA_WRITE}), .IN1_TRANS_WIDTH(1'b0), .IN1_IGN_ACK(1'b0), + //.IN2_ERROR(), ////// INPUT 2 /////// .IN2_ADDRESS(CPU_I2C_OUT_ADDRESS), @@ -549,6 +552,7 @@ I2C_driver_multiplexer I2C_driver_multiplexer( .IN2_I2C_DATA_WRITE(CPU_I2C_DATA_WRITE), .IN2_TRANS_WIDTH(CPU_I2C_TRANS_WIDTH), .IN2_IGN_ACK(CPU_I2C_IGN_ACK), + .IN2_ERROR(CPU_I2C_ERROR), ////// OUTPUT /////// .OUT_ADDRESS(MULT_TO_DRIV_I2C_ADDRESS), @@ -558,7 +562,8 @@ I2C_driver_multiplexer I2C_driver_multiplexer( .OUT_I2C_DATA_WRITE(MULT_TO_DRIV_DATA_WRITE), .OUT_I2C_DATA_READ(MULT_TO_DRIV_DATA_READ), .OUT_TRANS_WIDTH(MULT_TO_DRIV_TRANS_WIDTH), - .OUT_IGN_ACK(MULT_TO_DRIV_IGN_ACK) + .OUT_IGN_ACK(MULT_TO_DRIV_IGN_ACK), + .OUT_ERROR(MULT_TO_DRIV_ERROR) ); // I2C driver @@ -567,6 +572,7 @@ wire SDA_direction; wire SCL,SDA_input,SDA_output; wire MULT_TO_DRIV_TRANS_WIDTH; wire MULT_TO_DRIV_IGN_ACK; +wire MULT_TO_DRIV_ERROR; I2C_driver i2c_driver( .clock(I2C_SPEED), @@ -584,7 +590,9 @@ I2C_driver i2c_driver( .i2c_data_read(MULT_TO_DRIV_DATA_READ), .transact_width(MULT_TO_DRIV_TRANS_WIDTH), - .ignore_ack(MULT_TO_DRIV_IGN_ACK) + .ignore_ack(MULT_TO_DRIV_IGN_ACK), + + .error(MULT_TO_DRIV_ERROR) ); `ifdef SYNTHESIS diff --git a/system/peripherals/CPU_to_I2C_driver_bridge.v b/system/peripherals/CPU_to_I2C_driver_bridge.v index 8912266..de80e21 100644 --- a/system/peripherals/CPU_to_I2C_driver_bridge.v +++ b/system/peripherals/CPU_to_I2C_driver_bridge.v @@ -38,7 +38,9 @@ module CPU_to_I2C_driver_bridge ( output reg [15:0] OUT_I2C_DATA_WRITE, output reg TRANS_WIDTH, - output reg OUT_IGN_ACK + output reg OUT_IGN_ACK, + + input IN_ERROR ); //assign data_bus_out=((address==3'h0)&&chip_select_n==1'b0&&read_n==1'b0)? 16'h0043 : 16'h0000; @@ -67,7 +69,7 @@ always @( posedge clock )begin if ( chip_select_n==0 && read_n==0 )begin case (address) 3'h0: data_bus_out <= {OUT_I2C_DATA_READ}; - 3'h2: data_bus_out <= {15'd0,OUT_BUSY|WAIT}; + 3'h2: data_bus_out <= {14'd0,IN_ERROR,OUT_BUSY|WAIT}; default: data_bus_out <= 16'h0; endcase end diff --git a/system/peripherals/I2C_driver.v b/system/peripherals/I2C_driver.v index 3f72c9b..9a07c11 100644 --- a/system/peripherals/I2C_driver.v +++ b/system/peripherals/I2C_driver.v @@ -20,7 +20,7 @@ module I2C_driver ( input wire clock, input wire SDA_input, - output wire SDA_output, + output reg SDA_output, output reg SDA_direction, //1:output 0:input output reg SCL, @@ -31,17 +31,15 @@ module I2C_driver ( input wire [15:0] i2c_data_write, input wire transact_width, /* 0=byte 1=word */ input wire ignore_ack, - output reg [15:0] i2c_data_read=16'h4141 + output reg [15:0] i2c_data_read=16'h4141, + + output reg error=0, ); //assign i2c_data_read=16'h0042; reg DIR_latched; -reg SDA; // TODO make SDA_output a reg and rename everything - -assign SDA_output=SDA; - reg [5:0] i2c_state = 6'b100100; reg [3:0] data_bit_counter; @@ -55,17 +53,17 @@ always @(posedge clock) begin /***** start sequence ******/ 6'b000000:begin SDA_direction<=1; - SDA<=1; + SDA_output<=1; SCL<=1; i2c_state<=6'b000001; end 6'b000001:begin - SDA<=0; + SDA_output<=0; SCL<=1; i2c_state<=6'b000010; end 6'b000010:begin - SDA<=0; + SDA_output<=0; SCL<=0; i2c_state<=6'b000011; data_bit_counter<=0; @@ -77,7 +75,7 @@ always @(posedge clock) begin end 6'b000100:begin SCL<=0; - SDA<=address_internal[6:6]; + SDA_output<=address_internal[6:6]; address_internal[6:0]<={address_internal[5:0],1'b0}; data_bit_counter<=data_bit_counter+1; i2c_state<=6'b000101; @@ -100,7 +98,7 @@ always @(posedge clock) begin end 6'b001000:begin SCL<=0; - SDA<=DIR_latched;/*Write=0 Read=1*/ + SDA_output<=DIR_latched;/*Write=0 Read=1*/ i2c_state<=6'b001001; end 6'b001001:begin @@ -128,16 +126,16 @@ always @(posedge clock) begin 6'b001110:begin SCL<=1; if (SDA_input==1)begin - i2c_state<=6'b111111; //TODO: Don't freeze the entire driver if a single error occurs!! (here and on the second ack as well) - end else begin - i2c_state<=6'b001111; - data_bit_counter<=0; + error<=1'b1; + i2c_state<=6'b100100; end + i2c_state<=6'b001111; + data_bit_counter<=0; end /****** separator ********/ 6'b001111:begin SCL<=0; - SDA<=0; + SDA_output<=0; i2c_state<=6'b010000; end 6'b010000:begin @@ -146,17 +144,17 @@ always @(posedge clock) begin end 6'b010001:begin SCL<=0; - SDA<=1; + SDA_output<=1; i2c_state<=6'b010010; end 6'b010010:begin SCL<=0; - SDA<=1; + SDA_output<=1; i2c_state<=6'b010011; end 6'b010011:begin SCL<=0; - SDA<=0; + SDA_output<=0; i2c_state<=6'b010100; end /****** Send data ********/ @@ -172,7 +170,7 @@ always @(posedge clock) begin 6'b010101:begin SCL<=0; if(DIR_latched==1'b0)begin - SDA<=data_internal[7:7]; + SDA_output<=data_internal[7:7]; data_internal[7:0]<={data_internal[6:0],1'b0}; end data_bit_counter<=data_bit_counter+1; @@ -208,7 +206,7 @@ always @(posedge clock) begin 6'b011001:begin SCL<=0; if(DIR_latched==1'b1)begin - SDA<=1'b0; + SDA_output<=1'b0; end i2c_state<=6'b011010; end @@ -218,15 +216,14 @@ always @(posedge clock) begin end 6'b011011:begin SCL<=1; - if (SDA_input==0||DIR_latched==1'b1)begin - if(trans_width_latch==1'b1)begin - i2c_state<=6'b100101; - data_bit_counter<=4'd0; - end else - i2c_state<=6'b011100; - end else begin - i2c_state<=6'b111111; + if (SDA_input==1 && DIR_latched==1'b0)begin + error<=1'b1; end + if(trans_width_latch==1'b1)begin + i2c_state<=6'b100101; + data_bit_counter<=4'd0; + end else + i2c_state<=6'b011100; end /****** Send data (16bit) ********/ 6'b100101:begin @@ -241,7 +238,7 @@ always @(posedge clock) begin 6'b100110:begin SCL<=0; if(DIR_latched==1'b0)begin - SDA<=data_internal[15:15]; + SDA_output<=data_internal[15:15]; data_internal[15:8]<={data_internal[14:8],1'b0}; end data_bit_counter<=data_bit_counter+1; @@ -277,17 +274,16 @@ always @(posedge clock) begin end 6'b101100:begin SCL<=1; - if (SDA_input==0||ignore_ack==1'b1)begin - i2c_state<=6'b011100; - SDA_direction<=1; - end else begin - i2c_state<=6'b111111; + if ( SDA_input==1 && DIR_latched==1'b0 ) begin + error<=1'b1; end + i2c_state<=6'b011100; + SDA_direction<=1; end /****** separator ********/ 6'b011100:begin SCL<=0; - SDA<=0; + SDA_output<=0; i2c_state<=6'b011101; end 6'b011101:begin @@ -296,33 +292,33 @@ always @(posedge clock) begin end 6'b011110:begin SCL<=0; - SDA<=1; + SDA_output<=1; i2c_state<=6'b011111; end 6'b011111:begin SCL<=0; - SDA<=1; + SDA_output<=1; i2c_state<=6'b100000; end 6'b100000:begin SCL<=0; - SDA<=0; + SDA_output<=0; i2c_state<=6'b100001; end /****** stop bit *******/ 6'b100001:begin SCL<=1; - SDA<=0; + SDA_output<=0; i2c_state<=6'b100010; end 6'b100010:begin SCL<=1; - SDA<=1; + SDA_output<=1; i2c_state<=6'b100011; end 6'b100011:begin SCL<=1; - SDA<=1; + SDA_output<=1; i2c_state<=6'b100100; I2C_BUSY<=0; end @@ -334,11 +330,12 @@ always @(posedge clock) begin address_internal<=address; trans_width_latch<=transact_width; DIR_latched<=DIR; + error<=1'b0; end end default:begin SCL<=0; - SDA<=0; + SDA_output<=0; end endcase diff --git a/system/peripherals/I2C_driver_multiplexer.v b/system/peripherals/I2C_driver_multiplexer.v index 8be64ef..6ad7b10 100644 --- a/system/peripherals/I2C_driver_multiplexer.v +++ b/system/peripherals/I2C_driver_multiplexer.v @@ -30,6 +30,7 @@ module I2C_driver_multiplexer ( input wire [15:0] IN1_I2C_DATA_WRITE, input IN1_TRANS_WIDTH, input IN1_IGN_ACK, + output reg IN1_ERROR, ////// INPUT 2 /////// input wire [6:0] IN2_ADDRESS, @@ -40,6 +41,7 @@ module I2C_driver_multiplexer ( input wire [15:0] IN2_I2C_DATA_WRITE, input IN2_TRANS_WIDTH, input IN2_IGN_ACK, + output reg IN2_ERROR, ////// OUTPUT /////// output wire [6:0] OUT_ADDRESS, @@ -49,7 +51,8 @@ module I2C_driver_multiplexer ( input wire [15:0] OUT_I2C_DATA_READ, output wire [15:0] OUT_I2C_DATA_WRITE, output OUT_TRANS_WIDTH, - output wire OUT_IGN_ACK + output wire OUT_IGN_ACK, + input wire OUT_ERROR ); reg select; @@ -110,8 +113,10 @@ end always @(negedge OUT_BUSY)begin if(select)begin IN1_I2C_DATA_READ<=OUT_I2C_DATA_READ; + IN1_ERROR<=OUT_ERROR; end else begin IN2_I2C_DATA_READ<=OUT_I2C_DATA_READ; + IN2_ERROR<=OUT_ERROR; end end