From becc035ba95dea31d1f02e8c36673e7ec27aba8d Mon Sep 17 00:00:00 2001 From: LBFFilho Date: Mon, 30 Oct 2023 09:52:04 -0300 Subject: [PATCH] SPI Engine: Fixed delay behaviour on Chip-Select and Sleep instructions (#1200) Fixed wrong behaviour on chip select instruction: - previously, a sleep time happened before the chip select change - the intended behaviour was for another sleep time, of equal amount, to happen after the chip select change as well - additionally, the counter logic implementation was creating an additional factor of 2 on the sleep time All of the above points were fixed. The changes introduced also fix another issue where the sleep instruction was likewise happening with a duration larger than intended by a factor of 2 Signed-off-by: Laez Barbosa --- .../library/spi_engine/instruction-format.rst | 10 +++--- .../spi_engine_execution.v | 32 +++++++++++++++---- 2 files changed, 31 insertions(+), 11 deletions(-) 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