2018-06-08 07:32:43 +00:00
// Copyright 2010-2018 Espressif Systems (Shanghai) PTE LTD
2017-03-31 07:05:25 +00:00
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
# ifndef _DRIVER_SPI_COMMON_H_
# define _DRIVER_SPI_COMMON_H_
# include <stdint.h>
# include <stdbool.h>
# include "esp_err.h"
2019-03-14 09:29:32 +00:00
# include "esp32/rom/lldesc.h"
2018-06-08 07:32:43 +00:00
# include "soc/spi_periph.h"
2019-06-13 06:12:54 +00:00
# include "hal/spi_types.h"
2018-07-12 07:57:32 +00:00
# include "sdkconfig.h"
2017-03-31 07:05:25 +00:00
# ifdef __cplusplus
extern " C "
{
# endif
//Maximum amount of bytes that can be put in one DMA descriptor
# define SPI_MAX_DMA_LEN (4096-4)
2018-06-27 10:41:57 +00:00
/**
* Transform unsigned integer of length < = 32 bits to the format which can be
* sent by the SPI driver directly .
*
* E . g . to send 9 bits of data , you can :
*
* uint16_t data = SPI_SWAP_DATA_TX ( 0x145 , 9 ) ;
*
* Then points tx_buffer to ` ` & data ` ` .
*
* @ param data Data to be sent , can be uint8_t , uint16_t or uint32_t . @ param
* len Length of data to be sent , since the SPI peripheral sends from the MSB ,
* this helps to shift the data to the MSB .
*/
# define SPI_SWAP_DATA_TX(data, len) __builtin_bswap32((uint32_t)data<<(32-len))
/**
* Transform received data of length < = 32 bits to the format of an unsigned integer .
*
* E . g . to transform the data of 15 bits placed in a 4 - byte array to integer :
*
* uint16_t data = SPI_SWAP_DATA_RX ( * ( uint32_t * ) t - > rx_data , 15 ) ;
*
* @ param data Data to be rearranged , can be uint8_t , uint16_t or uint32_t .
* @ param len Length of data received , since the SPI peripheral writes from
* the MSB , this helps to shift the data to the LSB .
*/
# define SPI_SWAP_DATA_RX(data, len) (__builtin_bswap32(data)>>(32-len))
2017-03-31 07:05:25 +00:00
/**
* @ brief This is a configuration structure for a SPI bus .
*
* You can use this structure to specify the GPIO pins of the bus . Normally , the driver will use the
2018-06-27 10:41:57 +00:00
* GPIO matrix to route the signals . An exception is made when all signals either can be routed through
2017-03-31 07:05:25 +00:00
* the IO_MUX or are - 1. In that case , the IO_MUX is used , allowing for > 40 MHz speeds .
2017-05-02 08:36:01 +00:00
*
* @ note Be advised that the slave driver does not use the quadwp / quadhd lines and fields in spi_bus_config_t refering to these lines will be ignored and can thus safely be left uninitialized .
2017-03-31 07:05:25 +00:00
*/
typedef struct {
int mosi_io_num ; ///< GPIO pin for Master Out Slave In (=spi_d) signal, or -1 if not used.
int miso_io_num ; ///< GPIO pin for Master In Slave Out (=spi_q) signal, or -1 if not used.
int sclk_io_num ; ///< GPIO pin for Spi CLocK signal, or -1 if not used.
int quadwp_io_num ; ///< GPIO pin for WP (Write Protect) signal which is used as D2 in 4-bit communication modes, or -1 if not used.
int quadhd_io_num ; ///< GPIO pin for HD (HolD) signal which is used as D3 in 4-bit communication modes, or -1 if not used.
int max_transfer_sz ; ///< Maximum transfer size, in bytes. Defaults to 4094 if 0.
2018-03-21 12:42:45 +00:00
uint32_t flags ; ///< Abilities of bus to be checked by the driver. Or-ed value of ``SPICOMMON_BUSFLAG_*`` flags.
2018-10-23 08:57:32 +00:00
int intr_flags ; /**< Interrupt flag for the bus to set the priority, and IRAM attribute, see
* ` ` esp_intr_alloc . h ` ` . Note that the EDGE , INTRDISABLED attribute are ignored
* by the driver . Note that if ESP_INTR_FLAG_IRAM is set , ALL the callbacks of
* the driver , and their callee functions , should be put in the IRAM .
*/
2017-03-31 07:05:25 +00:00
} spi_bus_config_t ;
/**
* @ brief Try to claim a SPI peripheral
*
* Call this if your driver wants to manage a SPI peripheral .
*
* @ param host Peripheral to claim
2018-10-05 07:39:32 +00:00
* @ param source The caller indentification string .
*
2017-03-31 07:05:25 +00:00
* @ return True if peripheral is claimed successfully ; false if peripheral already is claimed .
*/
2018-10-05 07:39:32 +00:00
bool spicommon_periph_claim ( spi_host_device_t host , const char * source ) ;
// The macro is to keep the back-compatibility of IDF v3.2 and before
// In this way we can call spicommon_periph_claim with two arguments, or the host with the source set to the calling function name
// When two arguments (host, func) are given, __spicommon_periph_claim2 is called
// or if only one arguments (host) is given, __spicommon_periph_claim1 is called
# define spicommon_periph_claim(host...) __spicommon_periph_claim(host, 2, 1)
# define __spicommon_periph_claim(host, source, n, ...) __spicommon_periph_claim ## n(host, source)
# define __spicommon_periph_claim1(host, _) ({ \
char * warning_str = " calling spicommon_periph_claim without source string is deprecated. " ; \
spicommon_periph_claim ( host , __FUNCTION__ ) ; } )
# define __spicommon_periph_claim2(host, func) spicommon_periph_claim(host, func)
/**
* @ brief Check whether the spi periph is in use .
*
* @ param host Peripheral to check .
*
* @ return True if in use , otherwise false .
*/
bool spicommon_periph_in_use ( spi_host_device_t host ) ;
2017-03-31 07:05:25 +00:00
/**
* @ brief Return the SPI peripheral so another driver can claim it .
*
2017-08-31 11:59:30 +00:00
* @ param host Peripheral to return
2017-03-31 07:05:25 +00:00
* @ return True if peripheral is returned successfully ; false if peripheral was free to claim already .
*/
bool spicommon_periph_free ( spi_host_device_t host ) ;
2017-08-31 11:59:30 +00:00
/**
* @ brief Try to claim a SPI DMA channel
2018-06-27 10:41:57 +00:00
*
2017-08-31 11:59:30 +00:00
* Call this if your driver wants to use SPI with a DMA channnel .
2018-06-27 10:41:57 +00:00
*
2017-08-31 11:59:30 +00:00
* @ param dma_chan channel to claim
2018-06-27 10:41:57 +00:00
*
2017-08-31 11:59:30 +00:00
* @ return True if success ; false otherwise .
*/
bool spicommon_dma_chan_claim ( int dma_chan ) ;
2018-10-05 07:39:32 +00:00
/**
* @ brief Check whether the spi DMA channel is in use .
*
* @ param dma_chan DMA channel to check .
*
* @ return True if in use , otherwise false .
*/
bool spicommon_dma_chan_in_use ( int dma_chan ) ;
2017-08-31 11:59:30 +00:00
/**
* @ brief Return the SPI DMA channel so other driver can claim it , or just to power down DMA .
2018-06-27 10:41:57 +00:00
*
2017-08-31 11:59:30 +00:00
* @ param dma_chan channel to return
2018-06-27 10:41:57 +00:00
*
2017-08-31 11:59:30 +00:00
* @ return True if success ; false otherwise .
*/
bool spicommon_dma_chan_free ( int dma_chan ) ;
2017-03-31 07:05:25 +00:00
2018-03-21 12:42:45 +00:00
# define SPICOMMON_BUSFLAG_SLAVE 0 ///< Initialize I/O in slave mode
# define SPICOMMON_BUSFLAG_MASTER (1<<0) ///< Initialize I/O in master mode
2019-06-13 06:12:54 +00:00
# define SPICOMMON_BUSFLAG_IOMUX_PINS (1<<1) ///< Check using iomux pins. Or indicates the pins are configured through the IO mux rather than GPIO matrix.
2018-03-21 12:42:45 +00:00
# define SPICOMMON_BUSFLAG_SCLK (1<<2) ///< Check existing of SCLK pin. Or indicates CLK line initialized.
# define SPICOMMON_BUSFLAG_MISO (1<<3) ///< Check existing of MISO pin. Or indicates MISO line initialized.
# define SPICOMMON_BUSFLAG_MOSI (1<<4) ///< Check existing of MOSI pin. Or indicates CLK line initialized.
# define SPICOMMON_BUSFLAG_DUAL (1<<5) ///< Check MOSI and MISO pins can output. Or indicates bus able to work under DIO mode.
# define SPICOMMON_BUSFLAG_WPHD (1<<6) ///< Check existing of WP and HD pins. Or indicates WP & HD pins initialized.
# define SPICOMMON_BUSFLAG_QUAD (SPICOMMON_BUSFLAG_DUAL|SPICOMMON_BUSFLAG_WPHD) ///< Check existing of MOSI/MISO/WP/HD pins as output. Or indicates bus able to work under QIO mode.
2017-03-31 07:05:25 +00:00
2019-06-13 06:12:54 +00:00
# define SPICOMMON_BUSFLAG_NATIVE_PINS SPICOMMON_BUSFLAG_IOMUX_PINS
2017-03-31 07:05:25 +00:00
/**
* @ brief Connect a SPI peripheral to GPIO pins
*
* This routine is used to connect a SPI peripheral to the IO - pads and DMA channel given in
2018-06-27 10:41:57 +00:00
* the arguments . Depending on the IO - pads requested , the routing is done either using the
2017-03-31 07:05:25 +00:00
* IO_mux or using the GPIO matrix .
*
* @ param host SPI peripheral to be routed
* @ param bus_config Pointer to a spi_bus_config struct detailing the GPIO pins
* @ param dma_chan DMA - channel ( 1 or 2 ) to use , or 0 for no DMA .
2018-03-21 12:42:45 +00:00
* @ param flags Combination of SPICOMMON_BUSFLAG_ * flags , set to ensure the pins set are capable with some functions :
* - ` ` SPICOMMON_BUSFLAG_MASTER ` ` : Initialize I / O in master mode
* - ` ` SPICOMMON_BUSFLAG_SLAVE ` ` : Initialize I / O in slave mode
2019-06-13 06:12:54 +00:00
* - ` ` SPICOMMON_BUSFLAG_IOMUX_PINS ` ` : Pins set should match the iomux pins of the controller .
2018-06-27 10:41:57 +00:00
* - ` ` SPICOMMON_BUSFLAG_SCLK ` ` , ` ` SPICOMMON_BUSFLAG_MISO ` ` , ` ` SPICOMMON_BUSFLAG_MOSI ` ` :
2018-03-21 12:42:45 +00:00
* Make sure SCLK / MISO / MOSI is / are set to a valid GPIO . Also check output capability according to the mode .
* - ` ` SPICOMMON_BUSFLAG_DUAL ` ` : Make sure both MISO and MOSI are output capable so that DIO mode is capable .
* - ` ` SPICOMMON_BUSFLAG_WPHD ` ` Make sure WP and HD are set to valid output GPIOs .
* - ` ` SPICOMMON_BUSFLAG_QUAD ` ` : Combination of ` ` SPICOMMON_BUSFLAG_DUAL ` ` and ` ` SPICOMMON_BUSFLAG_WPHD ` ` .
* @ param [ out ] flags_o A SPICOMMON_BUSFLAG_ * flag combination of bus abilities will be written to this address .
* Leave to NULL if not needed .
2019-06-13 06:12:54 +00:00
* - ` ` SPICOMMON_BUSFLAG_IOMUX_PINS ` ` : The bus is connected to iomux pins .
2018-03-21 12:42:45 +00:00
* - ` ` SPICOMMON_BUSFLAG_SCLK ` ` , ` ` SPICOMMON_BUSFLAG_MISO ` ` , ` ` SPICOMMON_BUSFLAG_MOSI ` ` : The bus has
* CLK / MISO / MOSI connected .
* - ` ` SPICOMMON_BUSFLAG_DUAL ` ` : The bus is capable with DIO mode .
* - ` ` SPICOMMON_BUSFLAG_WPHD ` ` The bus has WP and HD connected .
* - ` ` SPICOMMON_BUSFLAG_QUAD ` ` : Combination of ` ` SPICOMMON_BUSFLAG_DUAL ` ` and ` ` SPICOMMON_BUSFLAG_WPHD ` ` .
2018-06-27 10:41:57 +00:00
* @ return
2017-03-31 07:05:25 +00:00
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
2018-03-21 12:42:45 +00:00
esp_err_t spicommon_bus_initialize_io ( spi_host_device_t host , const spi_bus_config_t * bus_config , int dma_chan , uint32_t flags , uint32_t * flags_o ) ;
2017-03-31 07:05:25 +00:00
/**
* @ brief Free the IO used by a SPI peripheral
2018-06-08 07:33:04 +00:00
* @ deprecated Use spicommon_bus_free_io_cfg instead .
2018-06-27 10:41:57 +00:00
*
2017-03-31 07:05:25 +00:00
* @ param host SPI peripheral to be freed
2018-06-27 10:41:57 +00:00
*
* @ return
2017-03-31 07:05:25 +00:00
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
2018-06-08 07:33:04 +00:00
esp_err_t spicommon_bus_free_io ( spi_host_device_t host ) __attribute__ ( ( deprecated ) ) ;
2017-03-31 07:05:25 +00:00
2018-06-08 07:33:04 +00:00
/**
* @ brief Free the IO used by a SPI peripheral
*
* @ param bus_cfg Bus config struct which defines which pins to be used .
2018-06-27 10:41:57 +00:00
*
* @ return
2018-06-08 07:33:04 +00:00
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t spicommon_bus_free_io_cfg ( const spi_bus_config_t * bus_cfg ) ;
2017-03-31 07:05:25 +00:00
/**
* @ brief Initialize a Chip Select pin for a specific SPI peripheral
*
*
* @ param host SPI peripheral
* @ param cs_io_num GPIO pin to route
* @ param cs_num CS id to route
* @ param force_gpio_matrix If true , CS will always be routed through the GPIO matrix . If false ,
* if the GPIO number allows it , the routing will happen through the IO_mux .
*/
void spicommon_cs_initialize ( spi_host_device_t host , int cs_io_num , int cs_num , int force_gpio_matrix ) ;
/**
* @ brief Free a chip select line
2018-06-08 07:33:04 +00:00
* @ deprecated Use spicommon_cs_io , which inputs the gpio num rather than the cs id instead .
2017-03-31 07:05:25 +00:00
*
* @ param host SPI peripheral
* @ param cs_num CS id to free
*/
2018-06-08 07:33:04 +00:00
void spicommon_cs_free ( spi_host_device_t host , int cs_num ) __attribute__ ( ( deprecated ) ) ;
2017-03-31 07:05:25 +00:00
2018-06-08 07:33:04 +00:00
/**
* @ brief Free a chip select line
*
* @ param cs_gpio_num CS gpio num to free
*/
void spicommon_cs_free_io ( int cs_gpio_num ) ;
2017-03-31 07:05:25 +00:00
/**
* @ brief Setup a DMA link chain
*
* This routine will set up a chain of linked DMA descriptors in the array pointed to by
* ` ` dmadesc ` ` . Enough DMA descriptors will be used to fit the buffer of ` ` len ` ` bytes in , and the
* descriptors will point to the corresponding positions in ` ` buffer ` ` and linked together . The
* end result is that feeding ` ` dmadesc [ 0 ] ` ` into DMA hardware results in the entirety ` ` len ` ` bytes
* of ` ` data ` ` being read or written .
*
* @ param dmadesc Pointer to array of DMA descriptors big enough to be able to convey ` ` len ` ` bytes
* @ param len Length of buffer
* @ param data Data buffer to use for DMA transfer
* @ param isrx True if data is to be written into ` ` data ` ` , false if it ' s to be read from ` ` data ` ` .
*/
void spicommon_setup_dma_desc_links ( lldesc_t * dmadesc , int len , const uint8_t * data , bool isrx ) ;
/**
* @ brief Get the position of the hardware registers for a specific SPI host
*
* @ param host The SPI host
*
* @ return A register descriptor stuct pointer , pointed at the hardware registers
*/
spi_dev_t * spicommon_hw_for_host ( spi_host_device_t host ) ;
/**
* @ brief Get the IRQ source for a specific SPI host
*
* @ param host The SPI host
*
* @ return The hosts IRQ source
*/
int spicommon_irqsource_for_host ( spi_host_device_t host ) ;
2019-06-13 06:12:54 +00:00
/**
* @ brief Get the IRQ source for a specific SPI DMA
*
* @ param host The SPI host
*
* @ return The hosts IRQ source
*/
int spicommon_irqdma_source_for_host ( spi_host_device_t host ) ;
2017-03-31 07:05:25 +00:00
/**
* Callback , to be called when a DMA engine reset is completed
*/
typedef void ( * dmaworkaround_cb_t ) ( void * arg ) ;
/**
* @ brief Request a reset for a certain DMA channel
*
2017-04-27 03:24:44 +00:00
* @ 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 .
2018-06-27 10:41:57 +00:00
*
2017-04-27 03:24:44 +00:00
* Essentially , when a reset is needed , a driver can request this using spicommon_dmaworkaround_req_reset . This is supposed to be called
2018-06-27 10:41:57 +00:00
* 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
2017-04-27 03:24:44 +00:00
* DMA subsystem and call the callback . The callback is then supposed to be used to continue the SPI drivers activity .
*
2017-04-13 03:14:35 +00:00
* @ param dmachan DMA channel associated with the SPI host that needs a reset
2017-03-31 07:05:25 +00:00
* @ param cb Callback to call in case DMA channel cannot be reset immediately
* @ param arg Argument to the callback
*
* @ return True when a DMA reset could be executed immediately . False when it could not ; in this
* case the callback will be called with the specified argument when the logic can execute
* a reset , after that reset .
*/
bool spicommon_dmaworkaround_req_reset ( int dmachan , dmaworkaround_cb_t cb , void * arg ) ;
/**
* @ brief Check if a DMA reset is requested but has not completed yet
*
* @ return True when a DMA reset is requested but hasn ' t completed yet . False otherwise .
*/
bool spicommon_dmaworkaround_reset_in_progress ( ) ;
/**
* @ brief Mark a DMA channel as idle .
*
* A call to this function tells the workaround logic that this channel will
* not be affected by a global SPI DMA reset .
*/
void spicommon_dmaworkaround_idle ( int dmachan ) ;
/**
* @ brief Mark a DMA channel as active .
*
* A call to this function tells the workaround logic that this channel will
* be affected by a global SPI DMA reset , and a reset like that should not be attempted .
*/
void spicommon_dmaworkaround_transfer_active ( int dmachan ) ;
# ifdef __cplusplus
}
# endif
2017-05-02 08:36:01 +00:00
# endif