Issues with HSPI (slave, half duplex)

FrancisL
Posts: 21
Joined: Wed Jul 25, 2018 3:34 pm

Issues with HSPI (slave, half duplex)

Postby FrancisL » Fri Aug 09, 2019 1:32 pm

Hi,
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;
}
I also tried to invert both mosi_dlen and miso_dlen (when writing them), but it does not change anything.
Below is the output log with the registers dump:
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)
To summarize:
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

FrancisL
Posts: 21
Joined: Wed Jul 25, 2018 3:34 pm

Re: Issues with HSPI (slave, half duplex)

Postby FrancisL » Fri Aug 09, 2019 2:35 pm

I believe that I understand why "9 bit are received" :
When I sent my data (one byte), the reception was active and the signal was also read in MOSI (that is on the same pin as MISO). Then, the receiver ignored my "48 bits", but found that I have to send '0+1 bit'. I see also a conflict on the scope...
Conclusion: It seems that my SPI is always transmitting (either 7+1 or 0+1 bits), never receiving.
And I don't know how to disable transmission (and enable reception).
Francis

FrancisL
Posts: 21
Joined: Wed Jul 25, 2018 3:34 pm

Re: Issues with HSPI (slave, half duplex)

Postby FrancisL » Tue Aug 13, 2019 11:48 am

I found out why the values I transmit were shifted. It seems that, beside the "data_buf" register, there is a single shift-register that is not modified when I just write to data_buf.
I solved the problem by applying a SPI reset (hw->slave.sync_reset = 1;hw->slave.sync_reset = 0;) AFTER filling the data_buf register (I used to reset only once before writing data_buf).

Now I am still stuck on the receive stage: everything seems to be correct and I see the expected value (x2f) for slv_rdata_bit. But the data_buf registers do not contain any value but the initialized contents (I previously wrote xAAAAAAAAAA for all of them). I checked N times my source code, but don't see why I don't get any received value. At a first step, I discarded the 3 lines mode, but even with 4 lines, data_buf is still unmodified.

FrancisL
Posts: 21
Joined: Wed Jul 25, 2018 3:34 pm

Re: Issues with HSPI (slave, half duplex)

Postby FrancisL » Wed Aug 14, 2019 11:46 am

Good news:
I just got my very first exchange:

[*] I gave up the 'data_buf'... I tried will possible combinations with flags, but it never works. I never saw any of the data_buf register modified by reception. I guess the issue could be with the timing configuration, but without a decent documentation, it is quite difficult to go further...
[*] I decided to keep the original management of the DMA (without FreeRTOS in my case), and it works fine.

In my case, I have a single data signal (MOSI = MISO), but I selected the two signals mode and I switch between MOSI and MISO routing when I want to receive/send. I discarded 'Half Duplex' and deal with Full Duplex only. Half Duplex looks so complicated...
I thought that the direct register mode would be simpler, but either it does not work, or I missed some information to enable reception.

Who is online

Users browsing this forum: No registered users and 55 guests