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:
Jeroen Domburg 2018-08-21 16:53:37 +08:00
commit 9de884f586
3 changed files with 35 additions and 15 deletions

View file

@ -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;
} }
} }

View file

@ -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,

View file

@ -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