diff --git a/docs/library/spi_engine/instruction-format.rst b/docs/library/spi_engine/instruction-format.rst index 152e6f955..fdf05340c 100644 --- a/docs/library/spi_engine/instruction-format.rst +++ b/docs/library/spi_engine/instruction-format.rst @@ -65,11 +65,12 @@ specified delay. The length of the delay depends on the module clock frequency, the setting of the prescaler register and the t parameter of the instruction. This delay is inserted before and after the update of the chip-select signal, so the total execution time of the chip-select -instruction is twice the delay. +instruction is twice the delay, plus a fixed 2 clock cycles (fast clock, not prescaled) +for the internal logic. .. math:: - delay = t * \frac{div + 1}{f_{clk}} + delay = t * \frac{(div + 1)*2}{f_{clk}} .. list-table:: :widths: 10 15 75 @@ -152,11 +153,12 @@ Sleep Instruction The sleep instruction stops the execution of the command stream for the specified amount of time. The time is based on the external clock frequency the configuration value of the prescaler register and the time parameter of the -instruction. +instruction. A fixed delay of two clock cycles (fast, not affected by the prescaler) +is the minimum, needed by the internal logic. .. math:: - sleep\_time = \frac{(t + 1) * ((div + 1) * 2)}{f_{clk}} + sleep\_time = \frac{2+(t) * ((div + 1) * 2)}{f_{clk}} .. list-table:: :widths: 10 15 75 diff --git a/library/spi_engine/spi_engine_execution/spi_engine_execution.v b/library/spi_engine/spi_engine_execution/spi_engine_execution.v index cb9ded906..418d2f01c 100644 --- a/library/spi_engine/spi_engine_execution/spi_engine_execution.v +++ b/library/spi_engine/spi_engine_execution/spi_engine_execution.v @@ -157,6 +157,8 @@ module spi_engine_execution #( wire sleep_counter_compare; wire cs_sleep_counter_compare; + wire cs_sleep_early_exit; + reg cs_sleep_repeat; wire io_ready1; wire io_ready2; @@ -167,7 +169,10 @@ module spi_engine_execution #( (* direct_enable = "yes" *) wire cs_gen; - assign cs_gen = inst_d1 == CMD_CHIPSELECT && cs_sleep_counter_compare == 1'b1; + assign cs_gen = inst_d1 == CMD_CHIPSELECT + && ((cs_sleep_counter_compare == 1'b1) || cs_sleep_early_exit) + && (cs_sleep_repeat == 1'b0) + && (idle == 1'b0); assign cmd_ready = idle; always @(posedge clk) begin @@ -239,17 +244,30 @@ module spi_engine_execution #( assign trigger_tx = trigger == 1'b1 && ntx_rx == 1'b0; assign trigger_rx = trigger == 1'b1 && ntx_rx == 1'b1; - assign sleep_counter_compare = sleep_counter == cmd_d1[7:0] && clk_div_last == 1'b1; - assign cs_sleep_counter_compare = cs_sleep_counter == cmd_d1[9:8] && clk_div_last == 1'b1; + assign sleep_counter_compare = sleep_counter == cmd_d1[7:0]; + assign cs_sleep_counter_compare = cs_sleep_counter == cmd_d1[9:8]; + assign cs_sleep_early_exit = (cmd_d1[9:8] == 2'b00); always @(posedge clk) begin - if (idle == 1'b1) begin + if (resetn == 1'b0) begin + cs_sleep_repeat <= 1'b0; + end else begin + if (idle) begin + cs_sleep_repeat <= 1'b0; + end else if (cs_sleep_counter_compare && (inst_d1 == CMD_CHIPSELECT)) begin + cs_sleep_repeat <= !cs_sleep_repeat; + end + end + end + + always @(posedge clk) begin + if (idle == 1'b1 || (cs_sleep_counter_compare && !cs_sleep_repeat && inst_d1 == CMD_CHIPSELECT)) begin counter <= 'h00; end else if (clk_div_last == 1'b1 && wait_for_io == 1'b0) begin if (bit_counter == word_length) begin - counter <= (counter & BIT_COUNTER_CLEAR) + (transfer_active ? 'h1 : 'h10) + BIT_COUNTER_CARRY; + counter <= (counter & BIT_COUNTER_CLEAR) + (transfer_active ? 'h1 : (2**BIT_COUNTER_WIDTH)) + BIT_COUNTER_CARRY; end else begin - counter <= counter + (transfer_active ? 'h1 : 'h10); + counter <= counter + (transfer_active ? 'h1 : (2**BIT_COUNTER_WIDTH)); end end end @@ -267,7 +285,7 @@ module spi_engine_execution #( idle <= 1'b1; end CMD_CHIPSELECT: begin - if (cs_sleep_counter_compare) + if ((cs_sleep_counter_compare && cs_sleep_repeat) || cs_sleep_early_exit) idle <= 1'b1; end CMD_MISC: begin