From 58955a79a27d3c7331eaec6e464878df42615a36 Mon Sep 17 00:00:00 2001 From: michael Date: Mon, 25 Jun 2018 12:34:31 +0800 Subject: [PATCH] spi_slave: improve the timing configuration SPI Slave =========== - Correct the configuration of mode 0~3 using new config in the TRM - Split the workaround for DMA in mode 0/2 out of normal config, to make it clear. - Update timing and speed document for the SPI slave. Resolves https://github.com/espressif/esp-idf/issues/1346, https://github.com/espressif/esp-idf/issues/2393 --- components/driver/spi_slave.c | 64 +++++++-- components/driver/test/test_spi_slave.c | 4 +- .../miso_timing_waveform.rst | 0 .../miso_timing_waveform_async.rst | 0 .../spi_master_freq_tv.plt | 0 .../diagrams/spi/spi_slave_miso_dma.rst | 23 +++ .../{spi_master => spi}/spi_timing.pptx | Bin .../diagrams/{spi_master => spi}/tv.csv | 0 docs/_static/spi_slave_miso_dma.png | Bin 0 -> 25734 bytes .../api-reference/peripherals/spi_slave.rst | 132 +++++++++++++++++- 10 files changed, 206 insertions(+), 17 deletions(-) rename docs/_static/diagrams/{spi_master => spi}/miso_timing_waveform.rst (100%) rename docs/_static/diagrams/{spi_master => spi}/miso_timing_waveform_async.rst (100%) rename docs/_static/diagrams/{spi_master => spi}/spi_master_freq_tv.plt (100%) create mode 100644 docs/_static/diagrams/spi/spi_slave_miso_dma.rst rename docs/_static/diagrams/{spi_master => spi}/spi_timing.pptx (100%) rename docs/_static/diagrams/{spi_master => spi}/tv.csv (100%) create mode 100644 docs/_static/spi_slave_miso_dma.png diff --git a/components/driver/spi_slave.c b/components/driver/spi_slave.c index 31606ac2af..02dd587df9 100644 --- a/components/driver/spi_slave.c +++ b/components/driver/spi_slave.c @@ -202,26 +202,62 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b spihost[host]->hw->slave.sync_reset = 1; spihost[host]->hw->slave.sync_reset = 0; - - bool nodelay = true; spihost[host]->hw->ctrl.rd_bit_order = (slave_config->flags & SPI_SLAVE_RXBIT_LSBFIRST) ? 1 : 0; spihost[host]->hw->ctrl.wr_bit_order = (slave_config->flags & SPI_SLAVE_TXBIT_LSBFIRST) ? 1 : 0; - if (slave_config->mode == 0) { - spihost[host]->hw->pin.ck_idle_edge = 0; - spihost[host]->hw->user.ck_i_edge = 1; - spihost[host]->hw->ctrl2.miso_delay_mode = nodelay ? 0 : 2; - } else if (slave_config->mode == 1) { - spihost[host]->hw->pin.ck_idle_edge = 0; - spihost[host]->hw->user.ck_i_edge = 0; - spihost[host]->hw->ctrl2.miso_delay_mode = nodelay ? 0 : 1; - } else if (slave_config->mode == 2) { + + const int mode = slave_config->mode; + if (mode == 0) { + //The timing needs to be fixed to meet the requirements of DMA spihost[host]->hw->pin.ck_idle_edge = 1; spihost[host]->hw->user.ck_i_edge = 0; - spihost[host]->hw->ctrl2.miso_delay_mode = nodelay ? 0 : 1; - } else if (slave_config->mode == 3) { + spihost[host]->hw->ctrl2.miso_delay_mode = 0; + spihost[host]->hw->ctrl2.miso_delay_num = 0; + spihost[host]->hw->ctrl2.mosi_delay_mode = 2; + spihost[host]->hw->ctrl2.mosi_delay_num = 2; + } else if (mode == 1) { spihost[host]->hw->pin.ck_idle_edge = 1; spihost[host]->hw->user.ck_i_edge = 1; - spihost[host]->hw->ctrl2.miso_delay_mode = nodelay ? 0 : 2; + spihost[host]->hw->ctrl2.miso_delay_mode = 2; + spihost[host]->hw->ctrl2.miso_delay_num = 0; + spihost[host]->hw->ctrl2.mosi_delay_mode = 0; + spihost[host]->hw->ctrl2.mosi_delay_num = 0; + } else if (mode == 2) { + //The timing needs to be fixed to meet the requirements of DMA + spihost[host]->hw->pin.ck_idle_edge = 0; + spihost[host]->hw->user.ck_i_edge = 1; + spihost[host]->hw->ctrl2.miso_delay_mode = 0; + spihost[host]->hw->ctrl2.miso_delay_num = 0; + spihost[host]->hw->ctrl2.mosi_delay_mode = 1; + spihost[host]->hw->ctrl2.mosi_delay_num = 2; + } else if (mode == 3) { + spihost[host]->hw->pin.ck_idle_edge = 0; + spihost[host]->hw->user.ck_i_edge = 0; + spihost[host]->hw->ctrl2.miso_delay_mode = 1; + spihost[host]->hw->ctrl2.miso_delay_num = 0; + spihost[host]->hw->ctrl2.mosi_delay_mode = 0; + spihost[host]->hw->ctrl2.mosi_delay_num = 0; + } + + /* Silicon issues exists in mode 0 and 2 with DMA, change clock phase to + * avoid dma issue. This will cause slave output to appear at most half a + * spi clock before + */ + if (dma_chan != 0) { + if (mode == 0) { + spihost[host]->hw->pin.ck_idle_edge = 0; + spihost[host]->hw->user.ck_i_edge = 1; + spihost[host]->hw->ctrl2.miso_delay_mode = 0; + spihost[host]->hw->ctrl2.miso_delay_num = 2; + spihost[host]->hw->ctrl2.mosi_delay_mode = 0; + spihost[host]->hw->ctrl2.mosi_delay_num = 3; + } else if (mode == 2) { + spihost[host]->hw->pin.ck_idle_edge = 1; + spihost[host]->hw->user.ck_i_edge = 0; + spihost[host]->hw->ctrl2.miso_delay_mode = 0; + spihost[host]->hw->ctrl2.miso_delay_num = 2; + spihost[host]->hw->ctrl2.mosi_delay_mode = 0; + spihost[host]->hw->ctrl2.mosi_delay_num = 3; + } } //Reset DMA diff --git a/components/driver/test/test_spi_slave.c b/components/driver/test/test_spi_slave.c index c468973faf..bee3fada69 100644 --- a/components/driver/test/test_spi_slave.c +++ b/components/driver/test/test_spi_slave.c @@ -17,6 +17,7 @@ #define PIN_NUM_CLK 19 #define PIN_NUM_CS 22 + static const char MASTER_TAG[] = "test_master"; static const char SLAVE_TAG[] = "test_slave"; @@ -45,7 +46,8 @@ static void master_init_nodma( spi_device_handle_t* spi) .spics_io_num=PIN_NUM_CS, //CS pin .queue_size=7, //We want to be able to queue 7 transactions at a time .pre_cb=NULL, - .cs_ena_posttrans=1, + .cs_ena_posttrans=5, + .cs_ena_pretrans=1, }; //Initialize the SPI bus ret=spi_bus_initialize(HSPI_HOST, &buscfg, 0); diff --git a/docs/_static/diagrams/spi_master/miso_timing_waveform.rst b/docs/_static/diagrams/spi/miso_timing_waveform.rst similarity index 100% rename from docs/_static/diagrams/spi_master/miso_timing_waveform.rst rename to docs/_static/diagrams/spi/miso_timing_waveform.rst diff --git a/docs/_static/diagrams/spi_master/miso_timing_waveform_async.rst b/docs/_static/diagrams/spi/miso_timing_waveform_async.rst similarity index 100% rename from docs/_static/diagrams/spi_master/miso_timing_waveform_async.rst rename to docs/_static/diagrams/spi/miso_timing_waveform_async.rst diff --git a/docs/_static/diagrams/spi_master/spi_master_freq_tv.plt b/docs/_static/diagrams/spi/spi_master_freq_tv.plt similarity index 100% rename from docs/_static/diagrams/spi_master/spi_master_freq_tv.plt rename to docs/_static/diagrams/spi/spi_master_freq_tv.plt diff --git a/docs/_static/diagrams/spi/spi_slave_miso_dma.rst b/docs/_static/diagrams/spi/spi_slave_miso_dma.rst new file mode 100644 index 0000000000..afa2a69a4a --- /dev/null +++ b/docs/_static/diagrams/spi/spi_slave_miso_dma.rst @@ -0,0 +1,23 @@ +.. This is the source code to generate figure by https://wavedrom.com/. +.. We can use the sphinx plugin sphinxcontrib-wavedrom to generate the figure and put it in the html doc (by include this source code), but it is not supported by the pdf. Currently we generate the figure manually and include the stataic figure in the doc. + +.. wavedrom:: + + { signal: [ + { name:'CS', wave:'10........'}, + { name: 'SCLK', wave: '0.10101010', node: '...ab'}, + { name: 'MISO (normal)', wave: 'x3.3.3.3.3', node: '...c.d', data: ['7','6','5','4','3'], phase:-0.8}, + { name: 'SCLK', wave: '0.10101010', node: '..e.f'}, + { name: 'MISO (DMA)', wave: 'x33.3.3.3', node: '..g.h', data: ['7','6','5','4','3','2'], phase:-0.8}, + ], + edge: [ + 'a|->c delay', + 'b-|->c setup', + 'b-|->d hold', + 'e|->g delay', + 'f|->g setup', + 'f-|>h hold', + ], + config:{hscale: 2} + } + diff --git a/docs/_static/diagrams/spi_master/spi_timing.pptx b/docs/_static/diagrams/spi/spi_timing.pptx similarity index 100% rename from docs/_static/diagrams/spi_master/spi_timing.pptx rename to docs/_static/diagrams/spi/spi_timing.pptx diff --git a/docs/_static/diagrams/spi_master/tv.csv b/docs/_static/diagrams/spi/tv.csv similarity index 100% rename from docs/_static/diagrams/spi_master/tv.csv rename to docs/_static/diagrams/spi/tv.csv diff --git a/docs/_static/spi_slave_miso_dma.png b/docs/_static/spi_slave_miso_dma.png new file mode 100644 index 0000000000000000000000000000000000000000..c0e48cd0f89c9ea17dd964e72f2f20dca1ad003d GIT binary patch literal 25734 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 UzVESkJrgAA>FVdQ&MBb@04ZcJApigX literal 0 HcmV?d00001 diff --git a/docs/en/api-reference/peripherals/spi_slave.rst b/docs/en/api-reference/peripherals/spi_slave.rst index 494ed09991..7b5762f5de 100644 --- a/docs/en/api-reference/peripherals/spi_slave.rst +++ b/docs/en/api-reference/peripherals/spi_slave.rst @@ -13,8 +13,10 @@ connected SPI master. The spi_slave driver ^^^^^^^^^^^^^^^^^^^^^ -The spi_slave driver allows using the HSPI and/or VSPI peripheral as a full-duplex SPI slave. It can make -use of DMA to send/receive transactions of arbitrary length. +The spi_slave driver allows using the HSPI and/or VSPI peripheral as a +full-duplex SPI slave. It can send/receive transactions within 64 bytes, or +make use of DMA to send/receive transactions longer than that. However, there +are some `known issues `_ when the DMA is enabled. Terminology ^^^^^^^^^^^ @@ -47,6 +49,54 @@ starts sending out clock pulses on the CLK line: every clock pulse causes a data the master to the slave on the MOSI line and vice versa on the MISO line. At the end of the transaction, the master makes CS high again. +.. note:: The SPI slave peripheral relies on the control of software very + much. The master shouldn't start a transaction when the slave hasn't prepared + for it. Using one more GPIO as the handshake signal to sync is a good idea. + For more details, see :ref:`transaction_interval`. + +GPIO matrix and IOMUX +^^^^^^^^^^^^^^^^^^^^^ + +Most peripheral signals in ESP32 can connect directly to a specific GPIO, +which is called its IOMUX pin. When a peripheral signal is routed to a pin +other than its IOMUX pin, ESP32 uses the less direct GPIO matrix to make this +connection. + +If the driver is configured with all SPI signals set to their specific IOMUX +pins (or left unconnected), it will bypass the GPIO matrix. If any SPI signal +is configured to a pin other than its IOMUx pin, the driver will +automatically route all the signals via the GPIO Matrix. The GPIO matrix +samples all signals at 80MHz and sends them between the GPIO and the +peripheral. + +When the GPIO matrix is used, setup time of MISO is more easily violated, +since the output delay of MISO signal is increased. + +.. note:: More details about influence of output delay on the maximum clock + frequency, see :ref:`timing_considerations` below. + +IOMUX pins for SPI controllers are as below: + ++----------+------+------+ +| Pin Name | HSPI | VSPI | ++ +------+------+ +| | GPIO Number | ++==========+======+======+ +| CS0* | 15 | 5 | ++----------+------+------+ +| SCLK | 14 | 18 | ++----------+------+------+ +| MISO | 12 | 19 | ++----------+------+------+ +| MOSI | 13 | 23 | ++----------+------+------+ +| QUADWP | 2 | 22 | ++----------+------+------+ +| QUADHD | 4 | 21 | ++----------+------+------+ + +note * Only the first device attaching to the bus can use CS0 pin. + Using the spi_slave driver ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,6 +135,73 @@ Warning: Due to a design peculiarity in the ESP32, if the amount of bytes sent b of the transmission queues in the slave driver, in bytes, is not both larger than eight and dividable by four, the SPI hardware can fail to write the last one to seven bytes to the receive buffer. +Speed and Timing considerations +------------------------------- + +.. _transaction_interval: + +Transaction interval +^^^^^^^^^^^^^^^^^^^^ + +The SPI slave is designed as s general purpose device controlled by the CPU. +Different from dedicated devices, CPU-based SPI slave doesn't have too much +pre-defined registers. All transactions should be triggered by the CPU, which +means the response speed would not be real-time, and there'll always be +noticeable intervals between transfers. + +During the transaction intervals, the device is not prepared for +transactions, the response is not meaningful at all. It is suggested to use +:cpp:func:`spi_slave_queue_trans` with :cpp:func:`spi_slave_get_trans_result` +to shorten the interval to half the case when using +:cpp:func:`spi_slave_transmit`. + +The master should always wait for the slave to be ready to start new +transactions. Suggested way is to use a gpio by the slave to indicate whether +it's ready. The example is in :example:`peripherals/spi_slave`. + +SCLK frequency requirement +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The spi slave is designed to work under 10MHz or lower. The clock and data +cannot be recognized or received correctly if the clock is too fast or +doesn't have a 50% duty cycle. + +Moreover, there are more requirements if the data meets the timing +requirement: + +- Read (MOSI): + Given that the MOSI is valid right at the launch edge, the slave can + read data correctly. Luckily, it's usually the case for most masters. + +- Write (MISO): + To meet the requirement that MISO is stable before the next latch edge of + SPI clock, the output delay of MISO signal should be shorter than half a + clock. The output delay and frequency limitation (given that the clock is + balanced) of different cases are as below : + + +-------------+---------------------------+------------------------+ + | | Output delay of MISO (ns) | Freq. limit (MHZ) | + +=============+===========================+========================+ + | IOMUX | 43.75 | <11.4 | + +-------------+---------------------------+------------------------+ + | GPIO matrix | 68.75 | <7.2 | + +-------------+---------------------------+------------------------+ + + Note: + 1. Random error will happen if the frequency exactly equals the + limitation + 2. The clock uncertainty between master and slave (12.5ns) is + included. + 3. The output delay is measured under ideal case (free of load). When + the loading of MISO pin is too heavy, the output delay will be longer, + and the maximum allowed frequency will be lower. + + There is an exceptions: The frequency is allowed to be higher if the + master has more toleration for the MISO setup time, e.g. latch data at + the next edge than expected, or configurable latching time. + +.. _spi_dma_known_issues: + Restrictions and Known issues ------------------------------- @@ -96,6 +213,17 @@ Restrictions and Known issues Also, master should write lengths which are a multiple of 4 bytes. Data longer than that will be discarded. +2. Furthurmore, the DMA requires a spi mode 1/3 timing. When using spi mode + 0/2, the MISO signal has to output half a clock earlier to meet the timing. + The new timing is as below: + + .. image:: /../_static/spi_slave_miso_dma.png + + The hold time after the latch edge is 68.75ns (when GPIO matrix is + bypassed), no longer half a SPI clock. The master should sample immediately + at the latch edge, or communicate in mode 1/3. Or just initial the spi + slave without DMA. + Application Example -------------------