imu_spi393.v 18.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/*!
 * <b>Module:</b>imu_spi393
 * @file imu_spi393.v
 * @date 2015-07-06  
 * @author Andrey Filippov     
 *
 * @brief SPI interface for the IMU
 *
 * @copyright Copyright (c) 2015 Elphel, Inc.
 *
 * <b>License:</b>
12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * imu_spi393.v is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 *  imu_spi393.v is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/> .
25 26 27 28 29 30
 *
 * Additional permission under GNU GPL version 3 section 7:
 * If you modify this Program, or any covered work, by linking or combining it
 * with independent modules provided by the FPGA vendor only (this permission
 * does not extend to any 3-rd party modules, "soft cores" or macros) under
 * different license terms solely for the purpose of generating binary "bitstream"
31
 * files and/or simulating the code, the copyright holders of this Program give
32 33
 * you the right to distribute the covered work without those independent modules
 * as long as the source code for them is available from the FPGA vendor free of
Andrey Filippov's avatar
Andrey Filippov committed
34
 * charge, and there is no dependence on any encrypted modules for simulating of
35 36 37
 * the combined code. This permission applies to you if the distributed code
 * contains all the components and scripts required to completely simulate it
 * with at least one of the Free Software programs.
38
 */
39 40 41
`timescale 1ns/1ps

module  imu_spi393(
42
//    input                         rst,
43 44 45 46 47 48 49 50 51
    input                         mclk,         // system clock, negedge TODO:COnvert to posedge!
    input                         xclk,         // half frequency (80 MHz nominal)
    input                         we_ra,        // write enable for registers to log (@negedge clk)
    input                         we_div,       // write enable for clock dividing(@negedge clk)
    input                         we_period,    // write enable for IMU cycle period(@negedge clk) 0 - disable, 1 - single, >1 - half bit periods
    input                  [ 4:0] wa,           // write address for register (5 bits, @negedge clk)
    input                  [31:0] din,          //
    output                        mosi,         // to IMU, bit 2 in J9
    input                         miso,         // from IMU, bit 3 on J9
52
    input                  [ 3:0] config_debug, // bit 0 - long sda_en
53 54 55 56 57 58 59 60
    output                        sda,          // sda, shared with i2c, bit 1
    output                        sda_en,       // enable sda output (when sda==0 and 1 cycle after sda 0->1)
    output                        scl,          // scl, shared with i2c, bit 0
    output                        scl_en,       // enable scl output (when scl==0 and 1 cycle after sda 0->1)
    output                        ts,           // timestamp request
    output                        rdy,          // data ready
    input                         rd_stb,       // data read strobe (increment address)
    output                 [15:0] rdata);       // data out (16 bits)
61 62
 /*
  input         mclk;   // system clock, negedge
63
  input         xclk;  // half frequency (80 MHz nominal)
64 65
  input         we_ra; // write enable for registers to log (@negedge mclk)
  input         we_div;// write enable for clock dividing(@negedge mclk)
66
  input         we_period;// write enable for IMU cycle period(@negedge clk)
67
  input  [4:0]  wa;    // write address for register (5 bits, @negedge mclk)
68 69 70 71 72 73 74 75 76 77 78 79 80 81
  input  [15:0] di;    // 16-bit data in
  output        mosi;  // to IMU, bit 2 in J9
  input         miso;  // from IMU, bit 3 on J9 
  input [3:0]   config_debug;
  output        sda;   // sda, shared with i2c, bit 1
  output        sda_en; // enable sda output (when sda==0 and 1 cycle after sda 0->1)
  output        scl;   // scl, shared with i2c, bit 0
  output        scl_en; // enable scl output (when scl==0 and 1 cycle after sda 0->1)
  output        ts;    // timestamp request

  output        rdy;    // encoded nmea data ready
  input         rd_stb; // encoded nmea data read strobe (increment address)
  output [15:0] rdata;  // encoded data (16 bits)
//  output        sngl_wire; // combined clock/data
82 83 84 85 86 87 88 89 90 91 92 93 94 95
 */ 
    reg    [ 7:0] bit_duration_mclk=8'h0; 
    reg    [ 7:0] bit_duration; 
    reg    [ 7:0] bit_duration_cntr=8'h0; 
    reg           bit_duration_zero; // just for simulation

    reg    [ 3:0] clk_en=4'h0;
    reg    [ 1:0] clk_div;
    reg    [ 4:0] imu_in_word=   5'b0; // number of IMU output word in a sample (0..31), 0..3 - timestamp
    reg           pre_imu_wr_buf,imu_wr_buf;
    wire   [15:0] imu_in_buf;

    reg     [4:0] reg_seq_number; // number of register in a sequence
    wire    [6:1] imu_reg_number; // register numer to read 
96
  
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
    reg     [1:0] seq_state; // 0 - idle, 1 - prepare spi(4?), 2 - spi-comm(32*29), 3 - finish (2)
    reg     [9:0] seq_counter;
    reg           end_spi, end_prepare;
    reg           set_mosi_prepare, set_mosi_spi;
    reg           seq_counter_zero, pre_seq_counter_zero;
    reg    [15:0] mosi_reg;
//    wire          mosi;
    reg     [1:0] sda_r;
    reg     [1:0] scl_r;
//    wire          scl_en;
    reg           shift_miso;
    reg    [15:0] miso_reg;
    reg           last_bit; // last clk _/~ in spi word (but first one)
    reg           last_bit_ext=1'b0; // from last bit till buffer write
    reg           last_buf_wr;
    reg    [ 4:0] raddr;
    reg           rdy_r=1'b0;
    reg           imu_start;
    reg           ts_r; // delay imu_start by one cycle, so it will be after rdy is reset

117
    reg    [31:0] period=0; // 0 - disable, 1 - single, >1 - period in 50 ns steps
118 119
//  reg    [15:0] di_d;

120
    reg           imu_enabled_mclk = 0;
121
    reg     [1:0] imu_enabled=2'h0;
122
    reg           imu_run_mclk = 0;
123
    reg     [1:0] imu_run;
124
    reg           imu_when_ready_mclk = 0;
125
    reg     [1:0] imu_when_ready;
126
  
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
    reg           imu_run_confirmed;
    reg           imu_start_mclk;
    reg     [1:0] imu_start_grant;
    reg           imu_start_first;
    reg           imu_start_first_was;
    reg    [31:0] period_counter;
    wire          en;
    reg    [4:01] we_timer;
    reg           first_prepare;
    reg     [1:0] first_prepare_d;
    wire          config_long_sda_en;
    wire          config_late_clk;
    reg     [7:0] stall_dur_mclk;  
    reg     [7:0] stall_dur;
    reg           stall;       // stall between words to satisfy SPI stall time
    reg     [7:0] stall_cntr;  // stall counter (in half mclk periods)
    reg           set_stall;
    reg           skip_stall; // first word after CS -\_
    wire          shift_mosi;
146
  
147 148 149 150 151 152 153 154 155 156 157
    reg           imu_ready_reset; 
    reg     [6:0] imu_ready_denoise_count;
    reg     [2:0] imu_data_ready_d; 
    reg     [5:0] imu_data_ready;
    reg     [1:0] seq_state_zero;  

    reg           pre_scl;
    reg     [2:0] sngl_wire_stb;
    reg     [1:0] sngl_wire_r;
    wire          sngl_wire;
    wire          config_single_wire; // used in 103695 rev A
158
  
159
    assign sngl_wire =          ~|sngl_wire_r[1:0];
160
  
161
    assign shift_mosi =         (clk_en[3] && seq_counter[0] && !stall);
162
    assign mosi =               config_single_wire?sngl_wire: mosi_reg[15];
163
  
164 165 166
    assign config_long_sda_en = config_debug[0];
    assign config_late_clk =    config_debug[1];
    assign config_single_wire = config_debug[2];
167
  
168 169 170
    assign en=                  imu_enabled[1];
    assign sda_en=              !config_single_wire && (!sda_r[0] || !sda_r[1] || (config_long_sda_en && (seq_state[1:0]!=2'b0)));
    assign scl_en=              !config_single_wire && (!scl_r[0] || !scl_r[1]);
171
  
172 173 174 175
    assign sda =                sda_r[0];
    assign scl =                scl_r[0];
    assign rdy =                rdy_r;
    assign ts =                 ts_r;
176
  
177 178 179 180 181 182
  
    always @ (posedge mclk) begin
    //    di_d[15:0] <= di[15:0];
        if (we_div) bit_duration_mclk[7:0] <=    din[7:0];
        if (we_div) stall_dur_mclk[7:0] <=       din[15:8];
        we_timer[4:1] <= {we_timer[3:1], we_period};
183
    
184 185
        if (we_period)   period[31:0] <=        din[31:0];
        if (we_timer[2]) imu_run_mclk <=        (period[31:1]!=31'b0); // double-cycle
186
        if (we_timer[3]) imu_enabled_mclk <=    imu_run_mclk | period[0]; // NC393: Why period[0]?
187 188 189 190 191 192
        
        if (we_timer[2]) imu_when_ready_mclk <= &period[31:16]; // double-cycle
        
        if (!imu_enabled_mclk || imu_start_grant[1]) imu_start_mclk <= 1'b0;
        else if (we_timer[4])imu_start_mclk <= imu_enabled_mclk;
    end
193 194

// debounce imu_data_ready
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
    always @ (posedge xclk) begin
        seq_state_zero[1:0] <= {seq_state_zero[0], ~|seq_state[1:0]};
        imu_ready_reset <= !imu_enabled[1] || (seq_state[1:0]!=2'b0) || !imu_when_ready[1];
        if (imu_ready_reset) imu_data_ready_d[2:0] <=3'b0;
        else                 imu_data_ready_d[2:0] <= {imu_data_ready_d[1:0], miso};
        
        if (imu_ready_reset)                         imu_data_ready[0] <= 1'b0;
        else if (imu_ready_denoise_count[6:0]==7'h0) imu_data_ready[0] <= imu_data_ready_d[2];
        
        if (imu_data_ready_d[2]==imu_data_ready[0]) imu_ready_denoise_count[6:0] <= 7'h7f; // use period LSBs?
        else                                        imu_ready_denoise_count[6:0] <= imu_ready_denoise_count[6:0] - 1;
        
        if (imu_ready_reset)                              imu_data_ready[1] <= 1'b0;
        else if (imu_data_ready[0])                       imu_data_ready[1] <= 1'b1;
        
        if (imu_ready_reset)                              imu_data_ready[2] <= 1'b0;
        else if (imu_data_ready[1] && !imu_data_ready[0]) imu_data_ready[2] <= 1'b1;
        
        if (imu_ready_reset)                              imu_data_ready[3] <= 1'b0;
        else if (imu_data_ready[2] &&  imu_data_ready[0]) imu_data_ready[3] <= 1'b1;
        
        if (clk_en[1]) imu_data_ready[4] <= imu_data_ready[3] ;
        
        imu_data_ready[5] <=clk_en[1] && imu_data_ready[3] && !imu_data_ready[4]; // single pulse @clk_en[2]
    end

    always @ (posedge xclk) begin
        imu_enabled[1:0]     <= {imu_enabled[0],imu_enabled_mclk}; 
        imu_run[1:0]         <= {imu_run[0],imu_run_mclk};
224
    
225
        imu_when_ready[1:0]         <= {imu_when_ready[0],imu_when_ready_mclk};
226
    
227 228 229 230 231 232 233 234 235
        if        (~imu_run[1:0]) imu_run_confirmed <= 1'b0;
        else if (imu_start_first) imu_run_confirmed <= imu_run[1];
        imu_start_grant[1:0] <= {imu_enabled_mclk && (imu_start_grant[0] || (imu_start_grant[1] && !imu_start)),imu_start_mclk};
        imu_start_first_was <= imu_start_grant[1] && (imu_start_first || imu_start_first_was);
        
        imu_start_first<=clk_en[1] && imu_start_grant[1] && !imu_start_first_was; // single xclk at clk_en[2] time slot
        imu_start            <=(!imu_when_ready[1] && imu_start_first)||
                               (!imu_when_ready[1] && imu_run_confirmed && (period_counter[31:0]==32'h1) && clk_en[2]) ||
                               imu_data_ready[5]; // single pulses at clk_en[3]
236
    
237 238 239 240 241 242 243 244
        if (imu_start || imu_when_ready[1]) period_counter[31:0] <= period[31:0];
        else if (clk_en[3]) period_counter[31:0] <= period_counter[31:0] - 1;
    end


    always @ (posedge xclk) begin
        bit_duration[7:0] <= bit_duration_mclk[7:0];
        stall_dur[7:0]       <= stall_dur_mclk[7:0];
245
    
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
        bit_duration_zero <= (bit_duration[7:0] == 8'h0);
        clk_div[1:0] <=      en ? (clk_div[1:0] + 1) : 2'b0;
        clk_en[3:0] <=       {clk_en[2:0], clk_div[1:0] == 2'h3};
        if (bit_duration_zero || (bit_duration_cntr[7:0]==8'h0)) bit_duration_cntr[7:0]<=bit_duration[7:0];
        else bit_duration_cntr[7:0] <= bit_duration_cntr[7:0]-1;
        clk_en[3:0]  <=      {clk_en[2:0], bit_duration_cntr[7:0] == 8'h3 };  // change 9'h3 to enforce frequency limit
    end  
  
    always @ (posedge xclk) begin
        pre_seq_counter_zero  <= clk_en[1] && (seq_counter[9:0]==10'h0) && (seq_state[1:0]!=2'h0); // active at clk_en[2]
        seq_counter_zero      <= pre_seq_counter_zero; // active at clk_en[3]
        if (!en)       seq_state[1:0] <= 2'h0;
        else if (imu_start)                                  seq_state[1:0] <= 2'h1;
        else if (seq_counter_zero ) seq_state[1:0] <= seq_state[1:0] + 1; // will not count from 0 as seq_counter_zero will be disabled
        
        if            (!en) first_prepare <=1'b0;
        else if (imu_start) first_prepare <=1'b1;
        else if (clk_en[3]) first_prepare <=1'b0;
        
        if            (!en) first_prepare_d[1:0] <= 2'b0;
        else if (clk_en[3]) first_prepare_d[1:0] <= {first_prepare_d[0],first_prepare};
        
        end_prepare <= pre_seq_counter_zero && (seq_state[1:0]==2'h1);
        end_spi       <= pre_seq_counter_zero && (seq_state[1:0]==2'h2);
        
        if      (!en)                                           seq_counter[9:0] <= 10'h000;
        else if (imu_start)                                     seq_counter[9:0] <= config_late_clk?10'h005:10'h003; // should be odd
        else if (end_prepare)                                   seq_counter[9:0] <= 10'h39f;
        else if (end_spi)                                       seq_counter[9:0] <= 10'h001;
        else if (clk_en[3] && (seq_state[1:0]!=2'h0) && !stall) seq_counter[9:0] <= seq_counter[9:0] - 1;
        set_mosi_prepare <= clk_en[2] && first_prepare;
//        set_mosi_spi       <= clk_en[2] && (seq_state[1:0]==2'h2) && (seq_counter[4:0]==5'h1f) && (seq_counter[9:5]!=6'h0) && !stall; // last word use zero
        set_mosi_spi       <= clk_en[2] && (seq_state[1:0]==2'h2) && (seq_counter[4:0]==5'h1f) && (seq_counter[9:5] != 0) && !stall; // last word use zero
        
    // no stall before the first word
        if      (!en)                          skip_stall <= 1'b0;
        else if (end_prepare)                  skip_stall <= 1'b1;
        else if (clk_en[3])                    skip_stall <= 1'b0;
         
        set_stall          <= clk_en[0] && (seq_state[1:0]==2'h2) && (seq_counter[4:0]==5'h1f) && !skip_stall && !stall; // @ clk_en[1]
286
    
287 288 289 290
        if      (!en)               mosi_reg[15:0] <= 16'h0;
        else if (set_mosi_prepare)  mosi_reg[15:0] <= 16'h7fff;
        else if (set_mosi_spi)      mosi_reg[15:0] <= {1'b0,imu_reg_number[6:1],9'b0};
        else if (shift_mosi)        mosi_reg[15:0] <= {mosi_reg[14:0],1'b0};
291
    
292 293 294 295 296
    // stall switches at clk_en[2]
    // stall switches at clk_en[1]
        if      (!en)                         stall_cntr[7:0] <= 8'h0;
        else if (set_stall)                   stall_cntr[7:0] <= stall_dur[7:0];
        else if (clk_en[1])                   stall_cntr[7:0] <= stall?(stall_cntr[7:0]-1):8'h0;
297 298
    
    
299 300 301 302
        if      (!en)                               stall <= 1'b0;
        else if (set_stall)                         stall <= (stall_dur[7:0]!=0);
        else if (clk_en[1] && (stall_cntr[7:1]==0)) stall <= 1'b0;
        
303 304
    
    
305 306
        if      (!en)        sda_r <=2'b11;
        else if (clk_en[3])  sda_r <= {sda_r[0], !(first_prepare_d[1] || (seq_counter[0] && (seq_state[1:0]==2'h3)))} ;
307 308
    
    
309 310 311 312 313 314
        if      (!en) pre_scl <=1'b1;
        else if (clk_en[2])       pre_scl <= (seq_state[1:0]!=2'h2) || !seq_counter[0] || stall;
        
        scl_r[0] <= pre_scl;
        if      (!en) scl_r[1] <=1'b1;
        else if (clk_en[3])       scl_r[1] <= scl_r[0];
315
    
316 317
        
        sngl_wire_stb[2:0] <={sngl_wire_stb[1:0], en & ((scl_r[0] ^ pre_scl) | end_prepare)};
318
    
319 320
        if      (!en)                                           sngl_wire_r[0]<=1'b0;
        else if ((pre_scl ^scl_r[0]) | end_prepare)             sngl_wire_r[0]<=1'b1;
321 322 323 324 325 326
        else if (!mosi_reg[15] || sngl_wire_stb[2] || scl_r[0]) sngl_wire_r[0]<=1'b0;
        
       
        
        if      (imu_start)     reg_seq_number[4:0] <= 5'h04;
        else if (set_mosi_spi)  reg_seq_number[4:0] <= reg_seq_number[4:0] + 1;
327
    
328
        shift_miso <= !scl_r[1] && clk_en[2]; // active at clk_en[3]
329
    
330
        if (shift_miso)     miso_reg[15:0] <= {miso_reg[14:0], miso};
331
    
332 333
        last_bit <= clk_en[2] && (seq_state[1:0]==2'h2) && (seq_counter[4:0]==5'h0) && (seq_counter[9:5]!=5'h1c);
        last_bit_ext <= en && (last_bit || (last_bit_ext && !(clk_en[2] && !seq_counter[0])));
334
    
335 336 337 338 339 340
        pre_imu_wr_buf <=clk_en[1] && last_bit_ext && !seq_counter[0]; 
        imu_wr_buf <= pre_imu_wr_buf;
        if    (imu_start) imu_in_word[4:0] <= 5'h0;
        else if (imu_wr_buf) imu_in_word[4:0] <= imu_in_word[4:0] + 1;
    
        last_buf_wr <= (pre_imu_wr_buf && (seq_state[1:0]==2'h3));
341
    
342
    end  
343

344 345 346
    always @ (negedge xclk) begin
        sngl_wire_r[1] <= sngl_wire_stb[0];
    end
347

348
    always @ (posedge xclk) begin
349

350 351
        if (!en || imu_start) raddr[4:0] <= 5'h0;
        else if (rd_stb)      raddr[4:0] <= raddr[4:0] + 1;
352

353 354
        if      (imu_start || (rd_stb && (raddr[4:0]==5'h1b)) || !en) rdy_r <= 1'b0; // only 28 words, not 32
        else if (last_buf_wr)                                         rdy_r <= 1'b1;
355

356
        ts_r <=imu_start;
357

358
    end  
359
  
360 361 362
    assign imu_in_buf[15:0]= miso_reg[15:0];
   
/*   
363 364 365
  myRAM_WxD_D #( .DATA_WIDTH(6),.DATA_DEPTH(5))
            i_registers2log   (.D(di_d[6:1]),
                             .WE(we_ra),
366
                             .clk(!mclk),
367 368 369 370
                             .AW(wa[4:0]),
                             .AR(reg_seq_number[4:0]),
                             .QW(),
                             .QR(imu_reg_number[6:1]));
371 372 373 374 375 376 377
*/
    reg     [5:0] registers2log_ram[0:31];
    always @ (posedge mclk) if (we_ra) begin
        registers2log_ram[wa[4:0]] <= din[6:1];
    end
    assign imu_reg_number[6:1] = registers2log_ram[reg_seq_number[4:0]];
/*
378 379 380 381 382 383 384 385
  myRAM_WxD_D #( .DATA_WIDTH(16),.DATA_DEPTH(5))
            i_odbuf0    (.D(imu_in_buf[15:0]),
                        .WE(imu_wr_buf),
                        .clk(xclk),
                        .AW(imu_in_word[4:0]),
                        .AR(raddr[4:0]),
                        .QW(),
                        .QR(rdata[15:0]));
386 387 388 389 390 391
*/
    reg     [15:0] odbuf0_ram[0:31];
    always @ (posedge xclk) if (imu_wr_buf) begin
        odbuf0_ram[imu_in_word[4:0]] <= imu_in_buf[15:0];
    end
    assign rdata[15:0] = odbuf0_ram[raddr[4:0]];
392 393 394 395


endmodule