1 // Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 /*******************************************************************************
16  * NOTICE
17  * The hal is not public api, don't use in application code.
18  * See readme.md in hal/include/hal/readme.md
19  ******************************************************************************/
20 
21 // The HAL layer for SPI master (common part)
22 
23 // SPI HAL usages:
24 // 1. initialize the bus
25 // 2. initialize the DMA descriptors if DMA used
26 // 3. setup the clock speed (since this takes long time)
27 // 4. call setup_device to update parameters for the specific device
28 // 5. call setup_trans to update parameters for the specific transaction
29 // 6. prepare data to send, and prepare the receiving buffer
30 // 7. trigger user defined SPI transaction to start
31 // 8. wait until the user transaction is done
32 // 9. fetch the received data
33 // Parameter to be updated only during ``setup_device`` will be highlighted in the
34 // field comments.
35 
36 #pragma once
37 #include "hal/spi_ll.h"
38 #include <esp_err.h>
39 #include "soc/lldesc.h"
40 #include "soc/soc_caps.h"
41 #include "hal/spi_types.h"
42 
43 /**
44  * Input parameters to the ``spi_hal_cal_clock_conf`` to calculate the timing configuration
45  */
46 typedef struct {
47     uint32_t half_duplex;               ///< Whether half duplex mode is used, device specific
48     uint32_t no_compensate;             ///< No need to add dummy to compensate the timing, device specific
49     uint32_t clock_speed_hz;            ///< Desired frequency.
50     uint32_t duty_cycle;                ///< Desired duty cycle of SPI clock
51     uint32_t input_delay_ns;            /**< Maximum delay between SPI launch clock and the data to be valid.
52                                          *   This is used to compensate/calculate the maximum frequency allowed.
53                                          *   Left 0 if not known.
54                                          */
55     bool use_gpio;                      ///< True if the GPIO matrix is used, otherwise false
56 } spi_hal_timing_param_t;
57 
58 /**
59  * Timing configuration structure that should be calculated by
60  * ``spi_hal_cal_clock_conf`` at initialization and hold. Filled into the
61  * ``timing_conf`` member of the context of HAL before setup a device.
62  */
63 typedef struct {
64     spi_ll_clock_val_t clock_reg;       ///< Register value used by the LL layer
65     int timing_dummy;                   ///< Extra dummy needed to compensate the timing
66     int timing_miso_delay;              ///< Extra miso delay clocks to compensate the timing
67 } spi_hal_timing_conf_t;
68 
69 /**
70  * DMA configuration structure
71  * Should be set by driver at initialization
72  */
73 typedef struct {
74     spi_dma_dev_t *dma_in;              ///< Input  DMA(DMA -> RAM) peripheral register address
75     spi_dma_dev_t *dma_out;             ///< Output DMA(RAM -> DMA) peripheral register address
76     bool dma_enabled;                   ///< Whether the DMA is enabled, do not update after initialization
77     lldesc_t  *dmadesc_tx;              /**< Array of DMA descriptor used by the TX DMA.
78                                          *   The amount should be larger than dmadesc_n. The driver should ensure that
79                                          *   the data to be sent is shorter than the descriptors can hold.
80                                          */
81     lldesc_t *dmadesc_rx;               /**< Array of DMA descriptor used by the RX DMA.
82                                          *   The amount should be larger than dmadesc_n. The driver should ensure that
83                                          *   the data to be sent is shorter than the descriptors can hold.
84                                          */
85     uint32_t tx_dma_chan;               ///< TX DMA channel
86     uint32_t rx_dma_chan;               ///< RX DMA channel
87     int dmadesc_n;                      ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use.
88 } spi_hal_config_t;
89 
90 /**
91  * Transaction configuration structure, this should be assigned by driver each time.
92  * All these parameters will be updated to the peripheral every transaction.
93  */
94 typedef struct {
95     uint16_t cmd;                       ///< Command value to be sent
96     int cmd_bits;                       ///< Length (in bits) of the command phase
97     int addr_bits;                      ///< Length (in bits) of the address phase
98     int dummy_bits;                     ///< Base length (in bits) of the dummy phase. Note when the compensation is enabled, some extra dummy bits may be appended.
99     int tx_bitlen;                      ///< TX length, in bits
100     int rx_bitlen;                      ///< RX length, in bits
101     uint64_t addr;                      ///< Address value to be sent
102     uint8_t *send_buffer;               ///< Data to be sent
103     uint8_t *rcv_buffer;                ///< Buffer to hold the receive data.
104     spi_line_mode_t line_mode;          ///< SPI line mode of this transaction
105     int cs_keep_active;                 ///< Keep CS active after transaction
106 } spi_hal_trans_config_t;
107 
108 /**
109  * Context that should be maintained by both the driver and the HAL.
110  */
111 typedef struct {
112     /* These two need to be malloced by the driver first */
113     lldesc_t  *dmadesc_tx;              /**< Array of DMA descriptor used by the TX DMA.
114                                          *   The amount should be larger than dmadesc_n. The driver should ensure that
115                                          *   the data to be sent is shorter than the descriptors can hold.
116                                          */
117     lldesc_t *dmadesc_rx;               /**< Array of DMA descriptor used by the RX DMA.
118                                          *   The amount should be larger than dmadesc_n. The driver should ensure that
119                                          *   the data to be sent is shorter than the descriptors can hold.
120                                          */
121 
122     /* Configured by driver at initialization, don't touch */
123     spi_dev_t     *hw;                  ///< Beginning address of the peripheral registers.
124     spi_dma_dev_t *dma_in;              ///< Address of the DMA peripheral registers which stores the data received from a peripheral into RAM (DMA -> RAM).
125     spi_dma_dev_t *dma_out;             ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral (RAM -> DMA).
126     bool  dma_enabled;                  ///< Whether the DMA is enabled, do not update after initialization
127     uint32_t tx_dma_chan;               ///< TX DMA channel
128     uint32_t rx_dma_chan;               ///< RX DMA channel
129     int dmadesc_n;                      ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use.
130 
131     /* Internal parameters, don't touch */
132     spi_hal_trans_config_t trans_config; ///< Transaction configuration
133 } spi_hal_context_t;
134 
135 /**
136  * Device configuration structure, this should be initialised by driver based on different devices respectively.
137  * All these parameters will be updated to the peripheral only when ``spi_hal_setup_device``.
138  * They may not get updated when ``spi_hal_setup_trans``.
139  */
140 typedef struct {
141     int mode;                           ///< SPI mode, device specific
142     int cs_setup;                       ///< Setup time of CS active edge before the first SPI clock, device specific
143     int cs_hold;                        ///< Hold time of CS inactive edge after the last SPI clock, device specific
144     int cs_pin_id;                      ///< CS pin to use, 0-2, otherwise all the CS pins are not used. Device specific
145     spi_hal_timing_conf_t timing_conf;  /**< This structure holds the pre-calculated timing configuration for the device
146                                          *   at initialization, device specific
147                                          */
148     struct {
149         uint32_t sio : 1;               ///< Whether to use SIO mode, device specific
150         uint32_t half_duplex : 1;       ///< Whether half duplex mode is used, device specific
151         uint32_t tx_lsbfirst : 1;       ///< Whether LSB is sent first for TX data, device specific
152         uint32_t rx_lsbfirst : 1;       ///< Whether LSB is received first for RX data, device specific
153         uint32_t no_compensate : 1;     ///< No need to add dummy to compensate the timing, device specific
154 #if SOC_SPI_SUPPORT_AS_CS
155         uint32_t as_cs  : 1;            ///< Whether to toggle the CS while the clock toggles, device specific
156 #endif
157         uint32_t positive_cs : 1;       ///< Whether the postive CS feature is abled, device specific
158     };//boolean configurations
159 } spi_hal_dev_config_t;
160 
161 /**
162  * Init the peripheral and the context.
163  *
164  * @param hal        Context of the HAL layer.
165  * @param host_id    Index of the SPI peripheral. 0 for SPI1, 1 for SPI2 and 2 for SPI3.
166  * @param hal_config Configuration of the hal defined by the upper layer.
167  */
168 void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id, const spi_hal_config_t *hal_config);
169 
170 /**
171  * Deinit the peripheral (and the context if needed).
172  *
173  * @param hal Context of the HAL layer.
174  */
175 void spi_hal_deinit(spi_hal_context_t *hal);
176 
177 /**
178  * Setup device-related configurations according to the settings in the context.
179  *
180  * @param hal       Context of the HAL layer.
181  * @param hal_dev   Device configuration
182  */
183 void spi_hal_setup_device(spi_hal_context_t *hal, const spi_hal_dev_config_t *hal_dev);
184 
185 /**
186  * Setup transaction related configurations according to the settings in the context.
187  *
188  * @param hal       Context of the HAL layer.
189  * @param hal_dev   Device configuration
190  * @param hal_trans Transaction configuration
191  */
192 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);
193 
194 /**
195  * Prepare the data for the current transaction.
196  *
197  * @param hal            Context of the HAL layer.
198  * @param hal_dev        Device configuration
199  * @param hal_trans      Transaction configuration
200  */
201 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);
202 
203 /**
204  * Trigger start a user-defined transaction.
205  *
206  * @param hal Context of the HAL layer.
207  */
208 void spi_hal_user_start(const spi_hal_context_t *hal);
209 
210 /**
211  * Check whether the transaction is done (trans_done is set).
212  *
213  * @param hal Context of the HAL layer.
214  */
215 bool spi_hal_usr_is_done(const spi_hal_context_t *hal);
216 
217 /**
218  * Post transaction operations, mainly fetch data from the buffer.
219  *
220  * @param hal       Context of the HAL layer.
221  */
222 void spi_hal_fetch_result(const spi_hal_context_t *hal);
223 
224 /*----------------------------------------------------------
225  * Utils
226  * ---------------------------------------------------------*/
227 /**
228  * Calculate the configuration of clock and timing. The configuration will be used when ``spi_hal_setup_device``.
229  *
230  * It is highly suggested to do this at initialization, since it takes long time.
231  *
232  * @param timing_param   Input parameters to calculate timing configuration
233  * @param out_freq       Output of the actual frequency, left NULL if not required.
234  * @param timing_conf    Output of the timing configuration.
235  *
236  * @return ESP_OK if desired is available, otherwise fail.
237  */
238 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);
239 
240 /**
241  * Get the frequency actual used.
242  *
243  * @param hal            Context of the HAL layer.
244  * @param fapb           APB clock frequency.
245  * @param hz             Desired frequencyc.
246  * @param duty_cycle     Desired duty cycle.
247  */
248 int spi_hal_master_cal_clock(int fapb, int hz, int duty_cycle);
249 
250 /**
251  * Get the timing configuration for given parameters.
252  *
253  * @param eff_clk        Actual SPI clock frequency
254  * @param gpio_is_used   true if the GPIO matrix is used, otherwise false.
255  * @param input_delay_ns Maximum delay between SPI launch clock and the data to
256  *                       be valid. This is used to compensate/calculate the maximum frequency
257  *                       allowed. Left 0 if not known.
258  * @param dummy_n        Dummy cycles required to correctly read the data.
259  * @param miso_delay_n   suggested delay on the MISO line, in APB clocks.
260  */
261 void spi_hal_cal_timing(int eff_clk, bool gpio_is_used, int input_delay_ns, int *dummy_n, int *miso_delay_n);
262 
263 /**
264  * Get the maximum frequency allowed to read if no compensation is used.
265  *
266  * @param gpio_is_used   true if the GPIO matrix is used, otherwise false.
267  * @param input_delay_ns Maximum delay between SPI launch clock and the data to
268  *                       be valid. This is used to compensate/calculate the maximum frequency
269  *                       allowed. Left 0 if not known.
270  */
271 int spi_hal_get_freq_limit(bool gpio_is_used, int input_delay_ns);
272