SPI: More MR issues fixed, style fixup

This commit is contained in:
Jeroen Domburg 2017-04-27 11:24:44 +08:00
parent bf0c32364a
commit 04b901e629
5 changed files with 299 additions and 283 deletions

View File

@ -169,16 +169,6 @@ spi_dev_t *spicommon_hw_for_host(spi_host_device_t host);
int spicommon_irqsource_for_host(spi_host_device_t host); int spicommon_irqsource_for_host(spi_host_device_t host);
/**
* @note In some (well-defined) cases in the ESP32 (at least rev v.0 and v.1), a SPI DMA channel will get confused. This can be remedied
* by resetting the SPI DMA hardware in case this happens. Unfortunately, the reset knob used for thsi will reset _both_ DMA channels, and
* as such can only done safely when both DMA channels are idle. These functions coordinate this.
*
* Essentially, when a reset is needed, a driver can request this using spicommon_dmaworkaround_req_reset. This is supposed to be called
* with an user-supplied function as an argument. If both DMA channels are idle, this call will reset the DMA subsystem and return true.
* If the other DMA channel is still busy, it will return false; as soon as the other DMA channel is done, however, it will reset the
* DMA subsystem and call the callback. The callback is then supposed to be used to continue the SPI drivers activity.
*/
/** /**
@ -190,6 +180,15 @@ typedef void(*dmaworkaround_cb_t)(void *arg);
/** /**
* @brief Request a reset for a certain DMA channel * @brief Request a reset for a certain DMA channel
* *
* @note In some (well-defined) cases in the ESP32 (at least rev v.0 and v.1), a SPI DMA channel will get confused. This can be remedied
* by resetting the SPI DMA hardware in case this happens. Unfortunately, the reset knob used for thsi will reset _both_ DMA channels, and
* as such can only done safely when both DMA channels are idle. These functions coordinate this.
*
* Essentially, when a reset is needed, a driver can request this using spicommon_dmaworkaround_req_reset. This is supposed to be called
* with an user-supplied function as an argument. If both DMA channels are idle, this call will reset the DMA subsystem and return true.
* If the other DMA channel is still busy, it will return false; as soon as the other DMA channel is done, however, it will reset the
* DMA subsystem and call the callback. The callback is then supposed to be used to continue the SPI drivers activity.
*
* @param dmachan DMA channel associated with the SPI host that needs a reset * @param dmachan DMA channel associated with the SPI host that needs a reset
* @param cb Callback to call in case DMA channel cannot be reset immediately * @param cb Callback to call in case DMA channel cannot be reset immediately
* @param arg Argument to the callback * @param arg Argument to the callback

View File

@ -31,7 +31,7 @@ extern "C"
#define SPI_DEVICE_TXBIT_LSBFIRST (1<<0) ///< Transmit command/address/data LSB first instead of the default MSB first #define SPI_DEVICE_TXBIT_LSBFIRST (1<<0) ///< Transmit command/address/data LSB first instead of the default MSB first
#define SPI_DEVICE_RXBIT_LSBFIRST (1<<1) ///< Receive data LSB first instead of the default MSB first #define SPI_DEVICE_RXBIT_LSBFIRST (1<<1) ///< Receive data LSB first instead of the default MSB first
#define SPI_DEVICE_BIT_LSBFIRST (SPI_TXBIT_LSBFIRST|SPI_RXBIT_LSBFIRST); ///< Transmit and receive LSB first #define SPI_DEVICE_BIT_LSBFIRST (SPI_TXBIT_LSBFIRST|SPI_RXBIT_LSBFIRST); ///< Transmit and receive LSB first
#define SPI_DEVICE_3WIRE (1<<2) ///< Use spid for both sending and receiving data #define SPI_DEVICE_3WIRE (1<<2) ///< Use MOSI (=spid) for both sending and receiving data
#define SPI_DEVICE_POSITIVE_CS (1<<3) ///< Make CS positive during a transaction instead of negative #define SPI_DEVICE_POSITIVE_CS (1<<3) ///< Make CS positive during a transaction instead of negative
#define SPI_DEVICE_HALFDUPLEX (1<<4) ///< Transmit data before receiving it, instead of simultaneously #define SPI_DEVICE_HALFDUPLEX (1<<4) ///< Transmit data before receiving it, instead of simultaneously
#define SPI_DEVICE_CLK_AS_CS (1<<5) ///< Output clock on CS line if CS is active #define SPI_DEVICE_CLK_AS_CS (1<<5) ///< Output clock on CS line if CS is active

View File

@ -59,7 +59,7 @@ struct spi_slave_transaction_t {
}; };
/** /**
* @brief Initialize a SPI bus * @brief Initialize a SPI bus as a slave interface
* *
* @warning For now, only supports HSPI and VSPI. * @warning For now, only supports HSPI and VSPI.
* *
@ -92,10 +92,13 @@ esp_err_t spi_slave_free(spi_host_device_t host);
/** /**
* @brief Queue a SPI transaction for execution * @brief Queue a SPI transaction for execution
* *
* This will queue a transaction for the master to pick it up. If the queue (specified in ``spi_slave_initialize``) * Queues a SPI transaction to be executed by this slave device. (The transaction queue size was specified when the slave
* is not full, this function will return directly; the actual transaction will be done if there aren't any * device was initialised via spi_slave_initialize.) This function may block if the queue is full (depending on the
* unhandled transactions before it and the master initiates a SPI transaction by pulling down CS and sending out * ticks_to_wait parameter). No SPI operation is directly initiated by this function, the next queued transaction
* clock signals. * will happen when the master initiates a SPI transaction by pulling down CS and sending out clock signals.
*
* This function hands over ownership of the buffers in ``trans_desc`` to the SPI slave driver; the application is
* not to access this memory until ``spi_slave_queue_trans`` is called to hand ownership back to the application.
* *
* @param host SPI peripheral that is acting as a slave * @param host SPI peripheral that is acting as a slave
* @param trans_desc Description of transaction to execute. Not const because we may want to write status back * @param trans_desc Description of transaction to execute. Not const because we may want to write status back
@ -117,8 +120,10 @@ esp_err_t spi_slave_queue_trans(spi_host_device_t host, const spi_slave_transact
* completed transaction so software can inspect the result and e.g. free the memory or * completed transaction so software can inspect the result and e.g. free the memory or
* re-use the buffers. * re-use the buffers.
* *
* It is mandatory to eventually use this function for any transaction queued by ``spi_slave_queue_trans``.
*
* @param host SPI peripheral to that is acting as a slave * @param host SPI peripheral to that is acting as a slave
* @param trans_desc Pointer to variable able to contain a pointer to the description of the * @param[out] trans_desc Pointer to variable able to contain a pointer to the description of the
* transaction that is executed * transaction that is executed
* @param ticks_to_wait Ticks to wait until there's a returned item; use portMAX_DELAY to never time * @param ticks_to_wait Ticks to wait until there's a returned item; use portMAX_DELAY to never time
* out. * out.

View File

@ -154,25 +154,29 @@ static const spi_signal_conn_t io_signal[3]={
static bool spi_periph_claimed[3] = {true, false, false}; static bool spi_periph_claimed[3] = {true, false, false};
//Returns true if this peripheral is successfully claimed, false if otherwise. //Returns true if this peripheral is successfully claimed, false if otherwise.
bool spicommon_periph_claim(spi_host_device_t host) { bool spicommon_periph_claim(spi_host_device_t host)
{
bool ret = __sync_bool_compare_and_swap(&spi_periph_claimed[host], false, true); bool ret = __sync_bool_compare_and_swap(&spi_periph_claimed[host], false, true);
if (ret) periph_module_enable(io_signal[host].module); if (ret) periph_module_enable(io_signal[host].module);
return ret; return ret;
} }
//Returns true if this peripheral is successfully freed, false if otherwise. //Returns true if this peripheral is successfully freed, false if otherwise.
bool spicommon_periph_free(spi_host_device_t host) { bool spicommon_periph_free(spi_host_device_t host)
{
bool ret = __sync_bool_compare_and_swap(&spi_periph_claimed[host], true, false); bool ret = __sync_bool_compare_and_swap(&spi_periph_claimed[host], true, false);
if (ret) periph_module_disable(io_signal[host].module); if (ret) periph_module_disable(io_signal[host].module);
return ret; return ret;
} }
int spicommon_irqsource_for_host(spi_host_device_t host) { int spicommon_irqsource_for_host(spi_host_device_t host)
{
return io_signal[host].irq; return io_signal[host].irq;
} }
spi_dev_t *spicommon_hw_for_host(spi_host_device_t host) { spi_dev_t *spicommon_hw_for_host(spi_host_device_t host)
{
return io_signal[host].hw; return io_signal[host].hw;
} }
@ -184,7 +188,7 @@ config can be done using the IOMUX instead of using the GPIO matrix.
esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan, int flags, bool *is_native) esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan, int flags, bool *is_native)
{ {
bool native = true; bool native = true;
bool use_quad=(flags&SPICOMMON_BUSFLAG_QUAD)?true:false; bool use_quad = (flags & SPICOMMON_BUSFLAG_QUAD) != 0;
SPI_CHECK(bus_config->mosi_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->mosi_io_num), "spid pin invalid", ESP_ERR_INVALID_ARG); SPI_CHECK(bus_config->mosi_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->mosi_io_num), "spid pin invalid", ESP_ERR_INVALID_ARG);
SPI_CHECK(bus_config->sclk_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->sclk_io_num), "spiclk pin invalid", ESP_ERR_INVALID_ARG); SPI_CHECK(bus_config->sclk_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->sclk_io_num), "spiclk pin invalid", ESP_ERR_INVALID_ARG);
@ -255,7 +259,8 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
//Find any pin with output muxed to ``func`` and reset it to GPIO //Find any pin with output muxed to ``func`` and reset it to GPIO
static void reset_func_to_gpio(int func) { static void reset_func_to_gpio(int func)
{
for (int x = 0; x < GPIO_PIN_COUNT; x++) { for (int x = 0; x < GPIO_PIN_COUNT; x++) {
if (GPIO_IS_VALID_GPIO(x) && (READ_PERI_REG(GPIO_FUNC0_OUT_SEL_CFG_REG + (x * 4))&GPIO_FUNC0_OUT_SEL_M) == func) { if (GPIO_IS_VALID_GPIO(x) && (READ_PERI_REG(GPIO_FUNC0_OUT_SEL_CFG_REG + (x * 4))&GPIO_FUNC0_OUT_SEL_M) == func) {
gpio_matrix_out(x, SIG_GPIO_OUT_IDX, false, false); gpio_matrix_out(x, SIG_GPIO_OUT_IDX, false, false);
@ -279,7 +284,8 @@ esp_err_t spicommon_bus_free_io(spi_host_device_t host)
return ESP_OK; return ESP_OK;
} }
void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num, int force_gpio_matrix) { void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num, int force_gpio_matrix)
{
if (!force_gpio_matrix && cs_io_num == io_signal[host].spics0_native && cs_num == 0) { if (!force_gpio_matrix && cs_io_num == io_signal[host].spics0_native && cs_num == 0) {
//The cs0s for all SPI peripherals map to pin mux source 1, so we use that instead of a define. //The cs0s for all SPI peripherals map to pin mux source 1, so we use that instead of a define.
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[cs_io_num], 1); PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[cs_io_num], 1);
@ -291,7 +297,8 @@ void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num,
} }
} }
void spicommon_cs_free(spi_host_device_t host, int cs_io_num) { void spicommon_cs_free(spi_host_device_t host, int cs_io_num)
{
if (cs_io_num == 0 && REG_GET_FIELD(GPIO_PIN_MUX_REG[io_signal[host].spics0_native], MCU_SEL) == 1) { if (cs_io_num == 0 && REG_GET_FIELD(GPIO_PIN_MUX_REG[io_signal[host].spics0_native], MCU_SEL) == 1) {
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[io_signal[host].spics0_native], PIN_FUNC_GPIO); PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[io_signal[host].spics0_native], PIN_FUNC_GPIO);
} }
@ -299,7 +306,8 @@ void spicommon_cs_free(spi_host_device_t host, int cs_io_num) {
} }
//Set up a list of dma descriptors. dmadesc is an array of descriptors. Data is the buffer to point to. //Set up a list of dma descriptors. dmadesc is an array of descriptors. Data is the buffer to point to.
void spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx) { void spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx)
{
int n = 0; int n = 0;
while (len) { while (len) {
int dmachunklen = len; int dmachunklen = len;
@ -363,7 +371,8 @@ bool IRAM_ATTR spicommon_dmaworkaround_reset_in_progress()
return (dmaworkaround_waiting_for_chan != 0); return (dmaworkaround_waiting_for_chan != 0);
} }
void IRAM_ATTR spicommon_dmaworkaround_idle(int dmachan) { void IRAM_ATTR spicommon_dmaworkaround_idle(int dmachan)
{
portENTER_CRITICAL(&dmaworkaround_mux); portENTER_CRITICAL(&dmaworkaround_mux);
dmaworkaround_channels_busy[dmachan] = 0; dmaworkaround_channels_busy[dmachan] = 0;
if (dmaworkaround_waiting_for_chan == dmachan) { if (dmaworkaround_waiting_for_chan == dmachan) {
@ -378,7 +387,8 @@ void IRAM_ATTR spicommon_dmaworkaround_idle(int dmachan) {
portEXIT_CRITICAL(&dmaworkaround_mux); portEXIT_CRITICAL(&dmaworkaround_mux);
} }
void IRAM_ATTR spicommon_dmaworkaround_transfer_active(int dmachan) { void IRAM_ATTR spicommon_dmaworkaround_transfer_active(int dmachan)
{
portENTER_CRITICAL(&dmaworkaround_mux); portENTER_CRITICAL(&dmaworkaround_mux);
dmaworkaround_channels_busy[dmachan] = 1; dmaworkaround_channels_busy[dmachan] = 1;
portEXIT_CRITICAL(&dmaworkaround_mux); portEXIT_CRITICAL(&dmaworkaround_mux);

View File

@ -236,7 +236,8 @@ esp_err_t spi_slave_transmit(spi_host_device_t host, spi_slave_transaction_t *tr
} }
#ifdef DEBUG_SLAVE #ifdef DEBUG_SLAVE
static void dumpregs(spi_dev_t *hw) { static void dumpregs(spi_dev_t *hw)
{
ets_printf("***REG DUMP ***\n"); ets_printf("***REG DUMP ***\n");
ets_printf("mosi_dlen : %08X\n", hw->mosi_dlen.val); ets_printf("mosi_dlen : %08X\n", hw->mosi_dlen.val);
ets_printf("miso_dlen : %08X\n", hw->miso_dlen.val); ets_printf("miso_dlen : %08X\n", hw->miso_dlen.val);
@ -249,7 +250,8 @@ static void dumpregs(spi_dev_t *hw) {
} }
static void dumpll(lldesc_t *ll) { static void dumpll(lldesc_t *ll)
{
ets_printf("****LL DUMP****\n"); ets_printf("****LL DUMP****\n");
ets_printf("Size %d\n", ll->size); ets_printf("Size %d\n", ll->size);
ets_printf("Len: %d\n", ll->length); ets_printf("Len: %d\n", ll->length);