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
parent
365933542d
commit
becc035ba9
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue