I need to manage HSPI directly through the hardware registers, without calling the API.
My configuration is:
* Half duplex (Mosi and Miso on a single wire)
* Slave mode
* NO DMA, no interrupt...
Typically, I need to send one byte, then (in another transaction) to receive 6 bytes. I managed to have the right signals on a scope, but I am not able to read the received data.
Mostly, I am confused with the different 'length' registers. I thought that I need for transmission to initialize slv_wrbuf_dlen.bit_len and possibly miso_dlen. And for reception slv_rdbuf_dlen.bit_len and mosi_dlen. But it does not work and I find:
* slv_rd_bit.slv_rdata_bit = 9 bit (instead of 48)...
* and the only read byte (first 8 bits of the 9) is the byte previously transmitted.
I also find a quite strange behaviour for miso_dlen and mosi_dlen : when I write one of these registers, I can read itsvalue in the other register. It seems that the hardware 'read and write' registers are inverted (silicon bug?). This would not be a real issue but it is quite confusing.
My main problem is that I don't see at all how to configure the peripheral to read my 6 bytes... Here is my code:
Code: Select all
/* ============================================
Same function is used to send trans_desc->tx_buffer
or to receive trans_desc->rx_buffer.
One of them must be NULL.
============================================ */
esp_err_t SPI_SLAVE_ATTR spi_slave_simple_transmit (spi_host_device_t host, spi_slave_transaction_t *trans_desc )
{
void S3P_PulseEnd(), S3P_PulseStart();
SPI_CHECK(trans_desc->length <= spihost[host]->max_transfer_sz * 8, "data transfer > host maximum", ESP_ERR_INVALID_ARG);
S3P_PulseStart();
spihost[host]->hw->cmd.usr = 0;
spihost[host]->hw->slave.trans_done = 0;
spihost[host]->cur_trans = trans_desc;
spihost[host]->hw->slave.sync_reset = 1;
spihost[host]->hw->slave.sync_reset = 0;
spihost[host]->hw->user.usr_miso_highpart = 0;
spihost[host]->hw->user.usr_mosi_highpart = 0;
if (trans_desc->tx_buffer)
{
const uint32_t *data = spihost[host]->cur_trans->tx_buffer;
for (int x = 0; x < trans_desc->length; x += 32)
{
uint32_t word;
memcpy(&word, &data[x / 32], 4);
spihost[host]->hw->data_buf[(x / 32)] = word;
}
spihost[host]->hw->slv_rd_bit.slv_rdata_bit = 0;
spihost[host]->hw->slv_wrbuf_dlen.bit_len = trans_desc->length - 1;
spihost[host]->hw->slv_rdbuf_dlen.bit_len = 0;
spihost[host]->hw->mosi_dlen.val = 0;
spihost[host]->hw->miso_dlen.val = trans_desc->length - 1;
ESP_LOGI(TAG, "1. Mosi_len = %X and Miso_len = %x", spihost[host]->hw->mosi_dlen.val, spihost[host]->hw->miso_dlen.val ); // <<< INVERTED!!!
spihost[host]->hw->user.usr_mosi = 0;
spihost[host]->hw->user.usr_miso = 1;
}
else //receive
{
spihost[host]->hw->slv_rd_bit.slv_rdata_bit = 0;
spihost[host]->hw->slv_wrbuf_dlen.bit_len = 0;
spihost[host]->hw->slv_rdbuf_dlen.bit_len = trans_desc->length - 1;
spihost[host]->hw->mosi_dlen.val = trans_desc->length - 1;
spihost[host]->hw->miso_dlen.val = 0;
ESP_LOGI(TAG, "2. Mosi_len = %X and Miso_len = %x", spihost[host]->hw->mosi_dlen.val, spihost[host]->hw->miso_dlen.val ); // <<< INVERTED!!!
spihost[host]->hw->user.usr_mosi = 1;
spihost[host]->hw->user.usr_miso = 0;
}
ESP_LOGI(TAG, "Registers before %s %d bits \n=====================================",
trans_desc->rx_buffer ? "receiving" :"transmitting", trans_desc->length);
dumpregs(spihost[host]->hw);
//The two lines below SHOULD be protected (critical section without interrupt).
S3P_PulseEnd(); // Everything is ready to launch the transaction.
spihost[host]->hw->cmd.usr = 1; //Kick off transfer
return ESP_OK;
}
Below is the output log with the registers dump:
To summarize:I (332722) spi_slave: In>>spi_slave_transmit
I (332730) spi_slave: 1. Mosi_len = 7 and Miso_len = 0
I (332734) spi_slave: Registers before transmitting 8 bits
=====================================
***REG DUMP ***
mosi_dlen : 00000007
miso_dlen : 00000000
slv_wrbuf_dlen : 00000007
slv_rdbuf_dlen : 00000000
slave : 607E0200
rd_buf_done : 00000000
wr_buf_done : 00000000
rd_sta_done : 00000000
wr_sta_done : 00000000
trans_done : 00000000
rd_buf_inten : 00000000
wr_buf_inten : 00000000
rd_sta_inten : 00000000
wr_sta_inten : 00000000
cs_i_mode : 00000000
last_command : 00000007
last_state : 00000007
trans_cnt : 00000000
cmd_define : 00000000
wr_rd_sta_en : 00000000
wr_rd_buf_en : 00000001
slave_mode : 00000001
sync_reset : 00000000
slave1 : 02000000
slave2 : 00000000
slave3 : 00000000
slv_rdata_bit : 0
I (332826) spi_slave: Registers after transmitting 8 bits
=====================================
***REG DUMP ***
mosi_dlen : 00000007
miso_dlen : 00000000
slv_wrbuf_dlen : 00000007
slv_rdbuf_dlen : 00000000
slave : 627E0210
rd_buf_done : 00000000
wr_buf_done : 00000000
rd_sta_done : 00000000
wr_sta_done : 00000000
trans_done : 00000001
rd_buf_inten : 00000000
wr_buf_inten : 00000000
rd_sta_inten : 00000000
wr_sta_inten : 00000000
cs_i_mode : 00000000
last_command : 00000007
last_state : 00000007
trans_cnt : 00000007
cmd_define : 00000000
wr_rd_sta_en : 00000000
wr_rd_buf_en : 00000001
slave_mode : 00000001
sync_reset : 00000000
slave1 : 02000000
slave2 : 00000000
slave3 : 00000000
slv_rdata_bit : 0
I (332910) spi_slave: In>>spi_slave_transmit
I (332914) spi_slave: 2. Mosi_len = 0 and Miso_len = 2f
I (332922) spi_slave: Registers before receiving 48 bits
=====================================
***REG DUMP ***
mosi_dlen : 00000000
miso_dlen : 0000002F
slv_wrbuf_dlen : 00000000
slv_rdbuf_dlen : 0000002F
slave : 607E0210
rd_buf_done : 00000000
wr_buf_done : 00000000
rd_sta_done : 00000000
wr_sta_done : 00000000
trans_done : 00000001
rd_buf_inten : 00000000
wr_buf_inten : 00000000
rd_sta_inten : 00000000
wr_sta_inten : 00000000
cs_i_mode : 00000000
last_command : 00000007
last_state : 00000007
trans_cnt : 00000000
cmd_define : 00000000
wr_rd_sta_en : 00000000
wr_rd_buf_en : 00000001
slave_mode : 00000001
sync_reset : 00000000
slave1 : 02000000
slave2 : 00000000
slave3 : 00000000
slv_rdata_bit : 0
I (333014) spi_slave: Registers after receiving 48 bits
=====================================
***REG DUMP ***
mosi_dlen : 00000000
miso_dlen : 0000002F
slv_wrbuf_dlen : 00000000
slv_rdbuf_dlen : 0000002F
slave : 607E0210
rd_buf_done : 00000000
wr_buf_done : 00000000
rd_sta_done : 00000000
wr_sta_done : 00000000
trans_done : 00000001
rd_buf_inten : 00000000
wr_buf_inten : 00000000
rd_sta_inten : 00000000
wr_sta_inten : 00000000
cs_i_mode : 00000000
last_command : 00000007
last_state : 00000007
trans_cnt : 00000000
cmd_define : 00000000
wr_rd_sta_en : 00000000
wr_rd_buf_en : 00000001
slave_mode : 00000001
sync_reset : 00000000
slave1 : 02000000
slave2 : 00000000
slave3 : 00000000
slv_rdata_bit : 9
I (333098) S3P: S3P_SPI_Transmit_Receive RX part (4f 00)
1. mosi_dlen contains what I wrote into miso_dlen (and vice versa)
2. I would like to get 48 bits in slv_rdata_bit (and I got only 9...)
3. The only byte received (4F) is what I sent before...
I hope someone could help...
Thanks,
Francis