mirror of
https://github.com/stnolting/neorv32.git
synced 2025-04-24 22:27:21 -04:00
[twd] add hide read option
Add hide read option to only ACK own Device-Address when the TX Fifo is not empty
This commit is contained in:
parent
b78531bb2d
commit
7fbac0f441
5 changed files with 28 additions and 12 deletions
|
@ -139,6 +139,7 @@ or **read** (leaving the SDA line high). If the transferred address matches the
|
|||
control register bits the TWD module will response with an **ACK** (acknowledge) by pulling the SDA bus line actively
|
||||
low during the 9th SCL clock pulse. If there is no address match the TWD will not interfere with the bus and move back
|
||||
to idle state.
|
||||
If the `hide_read` option is enabled, the address gets not acknowledged if the tx fifo is empty.
|
||||
|
||||
For a **write transaction** (upper timing diagram) the host can now transfer an arbitrary number of bytes (blue signals
|
||||
`D7` to `D0`, MSB-first) to the TWD module. Each byte is acknowledged by the TWD by pulling SDA low during the 9th SCL
|
||||
|
|
|
@ -54,6 +54,8 @@ architecture neorv32_twd_rtl of neorv32_twd is
|
|||
constant ctrl_tx_fifo_size0_c : natural := 19; -- r/-: log2(TX_FIFO size), bit 0 (LSB)
|
||||
constant ctrl_tx_fifo_size3_c : natural := 22; -- r/-: log2(TX_FIFO size), bit 3 (MSB)
|
||||
--
|
||||
constant ctrl_hide_read_c : natural := 23; -- r/w: generate NACK ony READ-access when TX FIFO is empty
|
||||
--
|
||||
constant ctrl_rx_avail_c : natural := 25; -- r/-: RX FIFO data available
|
||||
constant ctrl_rx_full_c : natural := 26; -- r/-: RX FIFO full
|
||||
constant ctrl_tx_empty_c : natural := 27; -- r/-: TX FIFO empty
|
||||
|
@ -77,6 +79,7 @@ architecture neorv32_twd_rtl of neorv32_twd is
|
|||
irq_rx_full : std_ulogic;
|
||||
irq_tx_empty : std_ulogic;
|
||||
tx_dummy_en : std_ulogic;
|
||||
hide_read : std_ulogic;
|
||||
end record;
|
||||
signal ctrl : ctrl_t;
|
||||
|
||||
|
@ -143,6 +146,7 @@ begin
|
|||
ctrl.irq_rx_full <= '0';
|
||||
ctrl.irq_tx_empty <= '0';
|
||||
ctrl.tx_dummy_en <= '0';
|
||||
ctrl.hide_read <= '0';
|
||||
elsif rising_edge(clk_i) then
|
||||
-- bus handshake defaults --
|
||||
bus_rsp_o.ack <= bus_req_i.stb;
|
||||
|
@ -163,6 +167,7 @@ begin
|
|||
ctrl.irq_rx_full <= bus_req_i.data(ctrl_irq_rx_full_c);
|
||||
ctrl.irq_tx_empty <= bus_req_i.data(ctrl_irq_tx_empty_c);
|
||||
ctrl.tx_dummy_en <= bus_req_i.data(ctrl_tx_dummy_en_c);
|
||||
ctrl.hide_read <= bus_req_i.data(ctrl_hide_read_c);
|
||||
end if;
|
||||
else -- read access
|
||||
if (bus_req_i.addr(2) = '0') then -- control register
|
||||
|
@ -177,6 +182,8 @@ begin
|
|||
bus_rsp_o.data(ctrl_rx_fifo_size3_c downto ctrl_rx_fifo_size0_c) <= std_ulogic_vector(to_unsigned(log2_rx_fifo_size_c, 4));
|
||||
bus_rsp_o.data(ctrl_tx_fifo_size3_c downto ctrl_tx_fifo_size0_c) <= std_ulogic_vector(to_unsigned(log2_tx_fifo_size_c, 4));
|
||||
--
|
||||
bus_rsp_o.data(ctrl_hide_read_c) <= ctrl.hide_read;
|
||||
--
|
||||
bus_rsp_o.data(ctrl_rx_avail_c) <= rx_fifo.avail;
|
||||
bus_rsp_o.data(ctrl_rx_full_c) <= not rx_fifo.free;
|
||||
bus_rsp_o.data(ctrl_tx_empty_c) <= not tx_fifo.avail;
|
||||
|
@ -391,7 +398,7 @@ begin
|
|||
engine.state <= S_ADDR;
|
||||
end if;
|
||||
|
||||
when S_ADDR => -- sample address + R/W bit and check if address match
|
||||
when S_ADDR => -- sample address + R/W bit and check if address match and data is available
|
||||
-- ------------------------------------------------------------
|
||||
if (ctrl.enable = '0') or (smp.stop = '1') then -- disabled or stop-condition received?
|
||||
engine.state <= S_IDLE;
|
||||
|
@ -399,9 +406,13 @@ begin
|
|||
engine.state <= S_INIT;
|
||||
elsif (engine.cnt(3) = '1') and (smp.scl_fall = '1') then -- 8 bits received?
|
||||
if (ctrl.device_addr = engine.sreg(7 downto 1)) then -- address match?
|
||||
engine.state <= S_RESP; -- access device
|
||||
else
|
||||
engine.state <= S_IDLE; -- no match, go back to idle
|
||||
-- ------------------------------------------------------------
|
||||
if (engine.sreg(0) = '1' and (ctrl.hide_read = '1' and (tx_fifo.free = '0'))) then -- READ but tx fifo is empty and hide_read is enabled
|
||||
engine.state <= S_IDLE;
|
||||
else
|
||||
engine.state <= S_RESP; -- access device
|
||||
end if;
|
||||
-- ------------------------------------------------------------
|
||||
end if;
|
||||
end if;
|
||||
-- sample bus on rising edge --
|
||||
|
@ -437,8 +448,8 @@ begin
|
|||
engine.wr_we <= '0'; -- Don't write into RX FIFO
|
||||
engine.state <= S_IDLE; -- Don't acknowledge (NACK)
|
||||
else
|
||||
engine.wr_we <= not engine.cmd; -- write byte to RX FIFO (only if WRITE command)
|
||||
engine.state <= S_ACK;
|
||||
engine.wr_we <= not engine.cmd; -- write byte to RX FIFO (only if WRITE command)
|
||||
engine.state <= S_ACK;
|
||||
end if;
|
||||
end if;
|
||||
-- sample bus on rising edge --
|
||||
|
|
|
@ -1058,7 +1058,7 @@ int main() {
|
|||
cnt_test++;
|
||||
|
||||
// configure TWD and enable RX-available interrupt
|
||||
neorv32_twd_setup(0b1101001, 0, 1, 0, 0);
|
||||
neorv32_twd_setup(0b1101001, 0, 1, 0, 0, 0);
|
||||
|
||||
// configure TWI with third-fastest clock, no clock stretching
|
||||
neorv32_twi_setup(CLK_PRSC_8, 1, 0);
|
||||
|
@ -1339,7 +1339,7 @@ int main() {
|
|||
neorv32_twi_setup(CLK_PRSC_8, 1, 0);
|
||||
|
||||
// configure TWD, no interrupts
|
||||
neorv32_twd_setup(0b0010110, 0, 0, 0, 0);
|
||||
neorv32_twd_setup(0b0010110, 0, 0, 0, 0, 0);
|
||||
neorv32_twd_put(0x8e);
|
||||
|
||||
// program sequence: read data via TWI
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
/**@{*/
|
||||
/** TWD module prototype */
|
||||
typedef volatile struct __attribute__((packed,aligned(4))) {
|
||||
uint32_t CTRL; /**< offset 0: control register (#NEORV32_TWD_CTRL_enum) */
|
||||
uint32_t DATA; /**< offset 4: data register (#NEORV32_TWD_DATA_enum) */
|
||||
uint32_t CTRL; /**< offset 0: control register (#NEORV32_TWD_CTRL_enum) */
|
||||
uint32_t DATA; /**< offset 4: data register (#NEORV32_TWD_DATA_enum) */
|
||||
} neorv32_twd_t;
|
||||
|
||||
/** TWD module hardware access (#neorv32_twd_t) */
|
||||
|
@ -49,6 +49,8 @@ enum NEORV32_TWD_CTRL_enum {
|
|||
TWD_CTRL_TX_FIFO_LSB = 19, /**< TWD control register(19) (r/-): log2(TX_FIFO size), LSB */
|
||||
TWD_CTRL_TX_FIFO_MSB = 22, /**< TWD control register(22) (r/-): log2(TX_FIFO size), MSB */
|
||||
|
||||
TWD_CTRL_HIDE_READ = 23, /**< TWD control register(14) (r/w): Generate NACK ony READ-access when TX FIFO is empty */
|
||||
|
||||
TWD_CTRL_RX_AVAIL = 25, /**< TWD control register(25) (r/-): RX FIFO data available */
|
||||
TWD_CTRL_RX_FULL = 26, /**< TWD control register(26) (r/-): RX FIFO full */
|
||||
TWD_CTRL_TX_EMPTY = 27, /**< TWD control register(27) (r/-): TX FIFO empty */
|
||||
|
|
|
@ -43,8 +43,9 @@ int neorv32_twd_available(void) {
|
|||
* @param[in] irq_rx_full IRQ if RX FIFO full.
|
||||
* @param[in] irq_tx_empty IRQ if TX FIFO empty.
|
||||
* @param[in] tx_dummy_en enable sending tx_dummy (last sent byte) when fifo is empty
|
||||
* @param[in] hide_read generate NACK ony READ-access when TX FIFO is empty
|
||||
**************************************************************************/
|
||||
void neorv32_twd_setup(int device_addr, int fsel, int irq_rx_avail, int irq_rx_full, int irq_tx_empty, int tx_dummy_en) {
|
||||
void neorv32_twd_setup(int device_addr, int fsel, int irq_rx_avail, int irq_rx_full, int irq_tx_empty, int tx_dummy_en, int hide_read) {
|
||||
|
||||
NEORV32_TWD->CTRL = 0; // reset
|
||||
|
||||
|
@ -56,6 +57,7 @@ void neorv32_twd_setup(int device_addr, int fsel, int irq_rx_avail, int irq_rx_f
|
|||
ctrl |= ((uint32_t)(irq_rx_full & 0x01) << TWD_CTRL_IRQ_RX_FULL);
|
||||
ctrl |= ((uint32_t)(irq_tx_empty & 0x01) << TWD_CTRL_IRQ_TX_EMPTY);
|
||||
ctrl |= ((uint32_t)(tx_dummy_en & 0x01) << TWD_CTRL_TX_DUMMY_EN);
|
||||
ctrl |= ((uint32_t)(hide_read & 0x01) << TWD_CTRL_HIDE_READ);
|
||||
NEORV32_TWD->CTRL = ctrl;
|
||||
}
|
||||
|
||||
|
@ -286,4 +288,4 @@ uint8_t neorv32_twd_get(void) {
|
|||
void neorv32_twd_set_dummy(uint8_t data) {
|
||||
neorv32_twd_clear_tx();
|
||||
neorv32_twd_put(data);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue