Merge branch 'feat/spi_non_dma_64byte' into 'master'
spi_master: change high part config to allow transactions of 64 bytes See merge request idf/esp-idf!3025
This commit is contained in:
commit
9de884f586
3 changed files with 35 additions and 15 deletions
|
@ -177,7 +177,7 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus
|
||||||
|
|
||||||
spihost[host]->dma_chan=dma_chan;
|
spihost[host]->dma_chan=dma_chan;
|
||||||
if (dma_chan == 0) {
|
if (dma_chan == 0) {
|
||||||
spihost[host]->max_transfer_sz = 32;
|
spihost[host]->max_transfer_sz = 64;
|
||||||
} else {
|
} else {
|
||||||
//See how many dma descriptors we need and allocate them
|
//See how many dma descriptors we need and allocate them
|
||||||
int dma_desc_ct=(bus_config->max_transfer_sz+SPI_MAX_DMA_LEN-1)/SPI_MAX_DMA_LEN;
|
int dma_desc_ct=(bus_config->max_transfer_sz+SPI_MAX_DMA_LEN-1)/SPI_MAX_DMA_LEN;
|
||||||
|
@ -213,6 +213,10 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus
|
||||||
//Reset timing
|
//Reset timing
|
||||||
spihost[host]->hw->ctrl2.val=0;
|
spihost[host]->hw->ctrl2.val=0;
|
||||||
|
|
||||||
|
//master use all 64 bytes of the buffer
|
||||||
|
spihost[host]->hw->user.usr_miso_highpart=0;
|
||||||
|
spihost[host]->hw->user.usr_mosi_highpart=0;
|
||||||
|
|
||||||
//Disable unneeded ints
|
//Disable unneeded ints
|
||||||
spihost[host]->hw->slave.rd_buf_done=0;
|
spihost[host]->hw->slave.rd_buf_done=0;
|
||||||
spihost[host]->hw->slave.wr_buf_done=0;
|
spihost[host]->hw->slave.wr_buf_done=0;
|
||||||
|
@ -633,7 +637,6 @@ static void SPI_MASTER_ISR_ATTR spi_intr(void *arg)
|
||||||
//Fill DMA descriptors
|
//Fill DMA descriptors
|
||||||
int extra_dummy=0;
|
int extra_dummy=0;
|
||||||
if (trans_buf->buffer_to_rcv) {
|
if (trans_buf->buffer_to_rcv) {
|
||||||
host->hw->user.usr_miso_highpart=0;
|
|
||||||
if (host->dma_chan == 0) {
|
if (host->dma_chan == 0) {
|
||||||
//No need to setup anything; we'll copy the result out of the work registers directly later.
|
//No need to setup anything; we'll copy the result out of the work registers directly later.
|
||||||
} else {
|
} else {
|
||||||
|
@ -662,16 +665,13 @@ static void SPI_MASTER_ISR_ATTR spi_intr(void *arg)
|
||||||
//Use memcpy to get around alignment issues for txdata
|
//Use memcpy to get around alignment issues for txdata
|
||||||
uint32_t word;
|
uint32_t word;
|
||||||
memcpy(&word, &trans_buf->buffer_to_send[x/32], 4);
|
memcpy(&word, &trans_buf->buffer_to_send[x/32], 4);
|
||||||
host->hw->data_buf[(x/32)+8]=word;
|
host->hw->data_buf[(x/32)]=word;
|
||||||
}
|
}
|
||||||
host->hw->user.usr_mosi_highpart=1;
|
|
||||||
} else {
|
} else {
|
||||||
spicommon_dmaworkaround_transfer_active(host->dma_chan); //mark channel as active
|
spicommon_dmaworkaround_transfer_active(host->dma_chan); //mark channel as active
|
||||||
spicommon_setup_dma_desc_links(host->dmadesc_tx, (trans->length+7)/8, (uint8_t*)trans_buf->buffer_to_send, false);
|
spicommon_setup_dma_desc_links(host->dmadesc_tx, (trans->length+7)/8, (uint8_t*)trans_buf->buffer_to_send, false);
|
||||||
host->hw->user.usr_mosi_highpart=0;
|
|
||||||
host->hw->dma_out_link.addr=(int)(&host->dmadesc_tx[0]) & 0xFFFFF;
|
host->hw->dma_out_link.addr=(int)(&host->dmadesc_tx[0]) & 0xFFFFF;
|
||||||
host->hw->dma_out_link.start=1;
|
host->hw->dma_out_link.start=1;
|
||||||
host->hw->user.usr_mosi_highpart=0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -234,6 +234,10 @@ TEST_CASE("SPI Master test", "[spi]")
|
||||||
success &= spi_test(handle, 4); //aligned
|
success &= spi_test(handle, 4); //aligned
|
||||||
success &= spi_test(handle, 16); //small
|
success &= spi_test(handle, 16); //small
|
||||||
success &= spi_test(handle, 21); //small, unaligned
|
success &= spi_test(handle, 21); //small, unaligned
|
||||||
|
success &= spi_test(handle, 32); //small
|
||||||
|
success &= spi_test(handle, 47); //small, unaligned
|
||||||
|
success &= spi_test(handle, 63); //small
|
||||||
|
success &= spi_test(handle, 64); //small, unaligned
|
||||||
|
|
||||||
destroy_spi_bus(handle);
|
destroy_spi_bus(handle);
|
||||||
|
|
||||||
|
@ -693,8 +697,22 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
|
||||||
|
|
||||||
static const char MASTER_TAG[] = "test_master";
|
static const char MASTER_TAG[] = "test_master";
|
||||||
static const char SLAVE_TAG[] = "test_slave";
|
static const char SLAVE_TAG[] = "test_slave";
|
||||||
DRAM_ATTR static uint8_t master_send[] = {0x93, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43};
|
DRAM_ATTR static uint8_t master_send[] = {
|
||||||
DRAM_ATTR static uint8_t slave_send[] = { 0xaa, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x13, 0x57, 0x9b, 0xdf, 0x24, 0x68, 0xac, 0xe0 };
|
0x93, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43,
|
||||||
|
0x74,
|
||||||
|
0x93, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43,
|
||||||
|
0x74,
|
||||||
|
0x93, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43,
|
||||||
|
0x74,
|
||||||
|
};
|
||||||
|
DRAM_ATTR static uint8_t slave_send[] = {
|
||||||
|
0xaa, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x13, 0x57, 0x9b, 0xdf, 0x24, 0x68, 0xac, 0xe0,
|
||||||
|
0xda,
|
||||||
|
0xaa, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x13, 0x57, 0x9b, 0xdf, 0x24, 0x68, 0xac, 0xe0,
|
||||||
|
0xda,
|
||||||
|
0xaa, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x13, 0x57, 0x9b, 0xdf, 0x24, 0x68, 0xac, 0xe0,
|
||||||
|
0xda,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static void master_deinit(spi_device_handle_t spi)
|
static void master_deinit(spi_device_handle_t spi)
|
||||||
|
@ -1006,6 +1024,8 @@ esp_err_t check_data(spi_transaction_t *t, spi_dup_t dup, slave_rxdata_t *slave_
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int test_len[] = {1, 3, 5, 7, 9, 11, 33, 64};
|
||||||
|
|
||||||
static void timing_init_transactions(spi_dup_t dup, timing_context_t* context)
|
static void timing_init_transactions(spi_dup_t dup, timing_context_t* context)
|
||||||
{
|
{
|
||||||
spi_transaction_t* trans = context->master_trans;
|
spi_transaction_t* trans = context->master_trans;
|
||||||
|
@ -1014,7 +1034,7 @@ static void timing_init_transactions(spi_dup_t dup, timing_context_t* context)
|
||||||
for (int i = 0; i < 8; i++ ) {
|
for (int i = 0; i < 8; i++ ) {
|
||||||
trans[i] = (spi_transaction_t) {
|
trans[i] = (spi_transaction_t) {
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.rxlength = 8*(i*2+1),
|
.rxlength = 8*test_len[i],
|
||||||
.rx_buffer = rx_buf_ptr,
|
.rx_buffer = rx_buf_ptr,
|
||||||
};
|
};
|
||||||
rx_buf_ptr += ((context->master_trans[i].rxlength + 31)/8)&(~3);
|
rx_buf_ptr += ((context->master_trans[i].rxlength + 31)/8)&(~3);
|
||||||
|
@ -1023,7 +1043,7 @@ static void timing_init_transactions(spi_dup_t dup, timing_context_t* context)
|
||||||
for (int i = 0; i < 8; i++ ) {
|
for (int i = 0; i < 8; i++ ) {
|
||||||
trans[i] = (spi_transaction_t) {
|
trans[i] = (spi_transaction_t) {
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.length = 8*(i*2+1),
|
.length = 8*test_len[i],
|
||||||
.tx_buffer = master_send+i,
|
.tx_buffer = master_send+i,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1031,7 +1051,7 @@ static void timing_init_transactions(spi_dup_t dup, timing_context_t* context)
|
||||||
for (int i = 0; i < 8; i++ ) {
|
for (int i = 0; i < 8; i++ ) {
|
||||||
trans[i] = (spi_transaction_t) {
|
trans[i] = (spi_transaction_t) {
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.length = 8*(i*2+1),
|
.length = 8*test_len[i],
|
||||||
.tx_buffer = master_send+i,
|
.tx_buffer = master_send+i,
|
||||||
.rx_buffer = rx_buf_ptr,
|
.rx_buffer = rx_buf_ptr,
|
||||||
};
|
};
|
||||||
|
@ -1042,7 +1062,7 @@ static void timing_init_transactions(spi_dup_t dup, timing_context_t* context)
|
||||||
for (int i = 0; i < 8; i ++) {
|
for (int i = 0; i < 8; i ++) {
|
||||||
context->slave_trans[i] = (slave_txdata_t) {
|
context->slave_trans[i] = (slave_txdata_t) {
|
||||||
.start = slave_send + 4*(i%3),
|
.start = slave_send + 4*(i%3),
|
||||||
.len = 256,
|
.len = 512,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1073,7 +1093,7 @@ typedef struct {
|
||||||
#define ESP_SPI_SLAVE_MAX_FREQ_SYNC SPI_MASTER_FREQ_40M
|
#define ESP_SPI_SLAVE_MAX_FREQ_SYNC SPI_MASTER_FREQ_40M
|
||||||
|
|
||||||
|
|
||||||
static test_timing_config_t timing_master_conf_t[] = {/**/
|
static test_timing_config_t timing_master_conf_t[] = {
|
||||||
{ .cfg_name = "FULL_DUP, MASTER IOMUX",
|
{ .cfg_name = "FULL_DUP, MASTER IOMUX",
|
||||||
.freq_limit = SPI_MASTER_FREQ_13M,
|
.freq_limit = SPI_MASTER_FREQ_13M,
|
||||||
.dup = FULL_DUPLEX,
|
.dup = FULL_DUPLEX,
|
||||||
|
|
|
@ -217,7 +217,7 @@ speed a lot if small transactions are used.
|
||||||
2. When the DMA is enabled, it needs about 2us per transaction to setup the linked list. When the master is
|
2. When the DMA is enabled, it needs about 2us per transaction to setup the linked list. When the master is
|
||||||
transferring, it automatically read data from the linked list. If the DMA is not enabled,
|
transferring, it automatically read data from the linked list. If the DMA is not enabled,
|
||||||
CPU has to write/read each byte to/from the FIFO by itself. Usually this is faster than 2us, but the
|
CPU has to write/read each byte to/from the FIFO by itself. Usually this is faster than 2us, but the
|
||||||
transaction length is limited to 32 bytes for both write and read.
|
transaction length is limited to 64 bytes for both write and read.
|
||||||
|
|
||||||
Typical transaction interval with one byte data is as below:
|
Typical transaction interval with one byte data is as below:
|
||||||
|
|
||||||
|
@ -401,7 +401,7 @@ Known Issues
|
||||||
2. disable the DMA by setting the last parameter to 0 in bus initialization function just as below:
|
2. disable the DMA by setting the last parameter to 0 in bus initialization function just as below:
|
||||||
``ret=spi_bus_initialize(VSPI_HOST, &buscfg, 0);``
|
``ret=spi_bus_initialize(VSPI_HOST, &buscfg, 0);``
|
||||||
|
|
||||||
this may prohibit you from transmitting and receiving data longer than 32 bytes.
|
this may prohibit you from transmitting and receiving data longer than 64 bytes.
|
||||||
3. try to use command and address field to replace the write phase.
|
3. try to use command and address field to replace the write phase.
|
||||||
|
|
||||||
2. Full duplex mode is not compatible with the *dummy bit workaround*, hence the frequency is limited. See :ref:`dummy
|
2. Full duplex mode is not compatible with the *dummy bit workaround*, hence the frequency is limited. See :ref:`dummy
|
||||||
|
|
Loading…
Reference in a new issue