Files
esp-idf/components/hal/include/hal/spi_hal.h
T
Planck (Lu Zeyu) 333553caf2 fix(hal): check the public header files and fix violations
fix(hal/include): fix header violations in hal component
fix(hal/include): Move type definitions from `xx_hal.h` to `xx_types.h`
fix(hal/include): Move type definitions from `xx_hal.h` to `xx_types.h`
fix(hal/include): Add comment for a far away `#endif`
fix(hal/include): change scope for cpp guard
ci: Remove components/hal/ comment from public headers check exceptions
Add missing include macro sdkconfig.h for header files
Add missing include macro stdbool.h for header files
Add missing include macro stdint.h for header files
Add missing capability guard macro for header files
Add missing cpp guard macro for header files
Remove some useless include macros
Add some missing `inline` attribute for functions defined in header files
Remove components/hal/ from public headers check exceptions
fix(hal/include): fix invalid licenses
fix(hal/include): fix invalid licenses
fix(hal/include): add missing soc_caps.h
fix(hal): include soc_caps.h before cap macro is used
fix(hal): Remove unnecessary target check
fix(hal): fix header and macro problems
Add missing include macro
Remove loop dependency in hal
Add comment for far-away endif
fix(hal): Add missing soc_caps.h
ci: update check_copyright_ignore.txt
Change the sequence of `#include` macro, cpp guard macro
Change the wrap scope of capacity macro

fix(hal): Change position of C++ guard to pass test
2023-07-05 17:33:32 +08:00

275 lines
13 KiB
C

/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for SPI master (common part)
// SPI HAL usages:
// 1. initialize the bus
// 2. initialize the DMA descriptors if DMA used
// 3. setup the clock speed (since this takes long time)
// 4. call setup_device to update parameters for the specific device
// 5. call setup_trans to update parameters for the specific transaction
// 6. prepare data to send, and prepare the receiving buffer
// 7. trigger user defined SPI transaction to start
// 8. wait until the user transaction is done
// 9. fetch the received data
// Parameter to be updated only during ``setup_device`` will be highlighted in the
// field comments.
#pragma once
#include "hal/spi_ll.h"
#include <esp_err.h>
#include "soc/lldesc.h"
#include "soc/soc_caps.h"
#include "hal/spi_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Input parameters to the ``spi_hal_cal_clock_conf`` to calculate the timing configuration
*/
typedef struct {
uint32_t clk_src_hz; ///< Selected SPI clock source speed in Hz
uint32_t half_duplex; ///< Whether half duplex mode is used, device specific
uint32_t no_compensate; ///< No need to add dummy to compensate the timing, device specific
uint32_t expected_freq; ///< Expected frequency in Hz.
uint32_t duty_cycle; ///< Expected duty cycle of SPI clock
uint32_t input_delay_ns; /**< Maximum delay between SPI launch clock and the data to be valid.
* This is used to compensate/calculate the maximum frequency allowed.
* Left 0 if not known.
*/
bool use_gpio; ///< True if the GPIO matrix is used, otherwise false
} spi_hal_timing_param_t;
/**
* Timing configuration structure that should be calculated by
* ``spi_hal_cal_clock_conf`` at initialization and hold. Filled into the
* ``timing_conf`` member of the context of HAL before setup a device.
*/
typedef struct {
spi_ll_clock_val_t clock_reg; ///< Register value used by the LL layer
spi_clock_source_t clock_source; ///< Clock source of each device used by LL layer
int timing_dummy; ///< Extra dummy needed to compensate the timing
int timing_miso_delay; ///< Extra miso delay clocks to compensate the timing
} spi_hal_timing_conf_t;
/**
* DMA configuration structure
* Should be set by driver at initialization
*/
typedef struct {
spi_dma_dev_t *dma_in; ///< Input DMA(DMA -> RAM) peripheral register address
spi_dma_dev_t *dma_out; ///< Output DMA(RAM -> DMA) peripheral register address
bool dma_enabled; ///< Whether the DMA is enabled, do not update after initialization
lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the TX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that
* the data to be sent is shorter than the descriptors can hold.
*/
lldesc_t *dmadesc_rx; /**< Array of DMA descriptor used by the RX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that
* the data to be sent is shorter than the descriptors can hold.
*/
uint32_t tx_dma_chan; ///< TX DMA channel
uint32_t rx_dma_chan; ///< RX DMA channel
int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use.
} spi_hal_config_t;
/**
* Transaction configuration structure, this should be assigned by driver each time.
* All these parameters will be updated to the peripheral every transaction.
*/
typedef struct {
uint16_t cmd; ///< Command value to be sent
int cmd_bits; ///< Length (in bits) of the command phase
int addr_bits; ///< Length (in bits) of the address phase
int dummy_bits; ///< Base length (in bits) of the dummy phase. Note when the compensation is enabled, some extra dummy bits may be appended.
int tx_bitlen; ///< TX length, in bits
int rx_bitlen; ///< RX length, in bits
uint64_t addr; ///< Address value to be sent
uint8_t *send_buffer; ///< Data to be sent
uint8_t *rcv_buffer; ///< Buffer to hold the receive data.
spi_line_mode_t line_mode; ///< SPI line mode of this transaction
int cs_keep_active; ///< Keep CS active after transaction
} spi_hal_trans_config_t;
/**
* Context that should be maintained by both the driver and the HAL.
*/
typedef struct {
/* These two need to be malloced by the driver first */
lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the TX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that
* the data to be sent is shorter than the descriptors can hold.
*/
lldesc_t *dmadesc_rx; /**< Array of DMA descriptor used by the RX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that
* the data to be sent is shorter than the descriptors can hold.
*/
/* Configured by driver at initialization, don't touch */
spi_dev_t *hw; ///< Beginning address of the peripheral registers.
spi_dma_dev_t *dma_in; ///< Address of the DMA peripheral registers which stores the data received from a peripheral into RAM (DMA -> RAM).
spi_dma_dev_t *dma_out; ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral (RAM -> DMA).
bool dma_enabled; ///< Whether the DMA is enabled, do not update after initialization
uint32_t tx_dma_chan; ///< TX DMA channel
uint32_t rx_dma_chan; ///< RX DMA channel
int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use.
/* Internal parameters, don't touch */
spi_hal_trans_config_t trans_config; ///< Transaction configuration
} spi_hal_context_t;
/**
* Device configuration structure, this should be initialised by driver based on different devices respectively.
* All these parameters will be updated to the peripheral only when ``spi_hal_setup_device``.
* They may not get updated when ``spi_hal_setup_trans``.
*/
typedef struct {
int mode; ///< SPI mode, device specific
int cs_setup; ///< Setup time of CS active edge before the first SPI clock, device specific
int cs_hold; ///< Hold time of CS inactive edge after the last SPI clock, device specific
int cs_pin_id; ///< CS pin to use, 0-2, otherwise all the CS pins are not used. Device specific
spi_hal_timing_conf_t timing_conf; /**< This structure holds the pre-calculated timing configuration for the device
* at initialization, device specific
*/
struct {
uint32_t sio : 1; ///< Whether to use SIO mode, device specific
uint32_t half_duplex : 1; ///< Whether half duplex mode is used, device specific
uint32_t tx_lsbfirst : 1; ///< Whether LSB is sent first for TX data, device specific
uint32_t rx_lsbfirst : 1; ///< Whether LSB is received first for RX data, device specific
uint32_t no_compensate : 1; ///< No need to add dummy to compensate the timing, device specific
#if SOC_SPI_AS_CS_SUPPORTED
uint32_t as_cs : 1; ///< Whether to toggle the CS while the clock toggles, device specific
#endif
uint32_t positive_cs : 1; ///< Whether the postive CS feature is abled, device specific
};//boolean configurations
} spi_hal_dev_config_t;
/**
* Init the peripheral and the context.
*
* @param hal Context of the HAL layer.
* @param host_id Index of the SPI peripheral. 0 for SPI1, 1 for SPI2 and 2 for SPI3.
* @param hal_config Configuration of the hal defined by the upper layer.
*/
void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id, const spi_hal_config_t *hal_config);
/**
* Deinit the peripheral (and the context if needed).
*
* @param hal Context of the HAL layer.
*/
void spi_hal_deinit(spi_hal_context_t *hal);
/**
* Setup device-related configurations according to the settings in the context.
*
* @param hal Context of the HAL layer.
* @param hal_dev Device configuration
*/
void spi_hal_setup_device(spi_hal_context_t *hal, const spi_hal_dev_config_t *hal_dev);
/**
* Setup transaction related configurations according to the settings in the context.
*
* @param hal Context of the HAL layer.
* @param hal_dev Device configuration
* @param hal_trans Transaction configuration
*/
void spi_hal_setup_trans(spi_hal_context_t *hal, const spi_hal_dev_config_t *hal_dev, const spi_hal_trans_config_t *hal_trans);
/**
* Prepare the data for the current transaction.
*
* @param hal Context of the HAL layer.
* @param hal_dev Device configuration
* @param hal_trans Transaction configuration
*/
void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *hal_dev, const spi_hal_trans_config_t *hal_trans);
/**
* Trigger start a user-defined transaction.
*
* @param hal Context of the HAL layer.
*/
void spi_hal_user_start(const spi_hal_context_t *hal);
/**
* Check whether the transaction is done (trans_done is set).
*
* @param hal Context of the HAL layer.
*/
bool spi_hal_usr_is_done(const spi_hal_context_t *hal);
/**
* Post transaction operations, mainly fetch data from the buffer.
*
* @param hal Context of the HAL layer.
*/
void spi_hal_fetch_result(const spi_hal_context_t *hal);
/*----------------------------------------------------------
* Utils
* ---------------------------------------------------------*/
/**
* Calculate the configuration of clock and timing. The configuration will be used when ``spi_hal_setup_device``.
*
* It is highly suggested to do this at initialization, since it takes long time.
*
* @param timing_param Input parameters to calculate timing configuration
* @param out_freq Output of the actual frequency, left NULL if not required.
* @param timing_conf Output of the timing configuration.
*
* @return ESP_OK if desired is available, otherwise fail.
*/
esp_err_t spi_hal_cal_clock_conf(const spi_hal_timing_param_t *timing_param, int *out_freq, spi_hal_timing_conf_t *timing_conf);
/**
* Get the frequency actual used.
*
* @param hal Context of the HAL layer.
* @param fapb APB clock frequency.
* @param hz Desired frequencyc.
* @param duty_cycle Desired duty cycle.
*/
int spi_hal_master_cal_clock(int fapb, int hz, int duty_cycle);
/**
* Get the timing configuration for given parameters.
*
* @param source_freq_hz Clock freq of selected clock source for SPI in Hz.
* @param eff_clk Actual SPI clock frequency
* @param gpio_is_used true if the GPIO matrix is used, otherwise false.
* @param input_delay_ns Maximum delay between SPI launch clock and the data to
* be valid. This is used to compensate/calculate the maximum frequency
* allowed. Left 0 if not known.
* @param dummy_n Dummy cycles required to correctly read the data.
* @param miso_delay_n suggested delay on the MISO line, in APB clocks.
*/
void spi_hal_cal_timing(int source_freq_hz, int eff_clk, bool gpio_is_used, int input_delay_ns, int *dummy_n, int *miso_delay_n);
/**
* Get the maximum frequency allowed to read if no compensation is used.
*
* @param gpio_is_used true if the GPIO matrix is used, otherwise false.
* @param input_delay_ns Maximum delay between SPI launch clock and the data to
* be valid. This is used to compensate/calculate the maximum frequency
* allowed. Left 0 if not known.
*/
int spi_hal_get_freq_limit(bool gpio_is_used, int input_delay_ns);
#ifdef __cplusplus
}
#endif