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 <laez.barbosa@analog.com>
main
LBFFilho 2023-10-30 09:52:04 -03:00 committed by GitHub
parent 365933542d
commit becc035ba9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 11 deletions

View File

@ -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. 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, This delay is inserted before and after the update of the chip-select signal,
so the total execution time of the chip-select 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:: .. math::
delay = t * \frac{div + 1}{f_{clk}} delay = t * \frac{(div + 1)*2}{f_{clk}}
.. list-table:: .. list-table::
:widths: 10 15 75 :widths: 10 15 75
@ -152,11 +153,12 @@ Sleep Instruction
The sleep instruction stops the execution of the command stream for the 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 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 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:: .. math::
sleep\_time = \frac{(t + 1) * ((div + 1) * 2)}{f_{clk}} sleep\_time = \frac{2+(t) * ((div + 1) * 2)}{f_{clk}}
.. list-table:: .. list-table::
:widths: 10 15 75 :widths: 10 15 75

View File

@ -157,6 +157,8 @@ module spi_engine_execution #(
wire sleep_counter_compare; wire sleep_counter_compare;
wire cs_sleep_counter_compare; wire cs_sleep_counter_compare;
wire cs_sleep_early_exit;
reg cs_sleep_repeat;
wire io_ready1; wire io_ready1;
wire io_ready2; wire io_ready2;
@ -167,7 +169,10 @@ module spi_engine_execution #(
(* direct_enable = "yes" *) wire cs_gen; (* 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; assign cmd_ready = idle;
always @(posedge clk) begin always @(posedge clk) begin
@ -239,17 +244,30 @@ module spi_engine_execution #(
assign trigger_tx = trigger == 1'b1 && ntx_rx == 1'b0; assign trigger_tx = trigger == 1'b1 && ntx_rx == 1'b0;
assign trigger_rx = trigger == 1'b1 && ntx_rx == 1'b1; 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 sleep_counter_compare = sleep_counter == cmd_d1[7:0];
assign cs_sleep_counter_compare = cs_sleep_counter == cmd_d1[9:8] && clk_div_last == 1'b1; 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 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; counter <= 'h00;
end else if (clk_div_last == 1'b1 && wait_for_io == 1'b0) begin end else if (clk_div_last == 1'b1 && wait_for_io == 1'b0) begin
if (bit_counter == word_length) 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 end else begin
counter <= counter + (transfer_active ? 'h1 : 'h10); counter <= counter + (transfer_active ? 'h1 : (2**BIT_COUNTER_WIDTH));
end end
end end
end end
@ -267,7 +285,7 @@ module spi_engine_execution #(
idle <= 1'b1; idle <= 1'b1;
end end
CMD_CHIPSELECT: begin CMD_CHIPSELECT: begin
if (cs_sleep_counter_compare) if ((cs_sleep_counter_compare && cs_sleep_repeat) || cs_sleep_early_exit)
idle <= 1'b1; idle <= 1'b1;
end end
CMD_MISC: begin CMD_MISC: begin