1 /* 2 * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 /******************************************************************************* 8 * NOTICE 9 * The hal is not public api, don't use in application code. 10 * See readme.md in hal/include/hal/readme.md 11 ******************************************************************************/ 12 13 /* 14 * The HAL layer for SPI Slave HD mode. 15 * 16 * Usage (segment mode): 17 * - Firstly, initialize the slave with `spi_slave_hd_hal_init` 18 * 19 * - Event handling: 20 * - (Optional) Call ``spi_slave_hd_hal_enable_event_intr`` to enable the used interrupts 21 * - (Basic) Call ``spi_slave_hd_hal_check_clear_event`` to check whether an event happen, and also 22 * clear its interrupt. For events: SPI_EV_BUF_TX, SPI_EV_BUF_RX, SPI_EV_BUF_RX, SPI_EV_CMD9, 23 * SPI_EV_CMDA. 24 * - (Advanced) Call ``spi_slave_hd_hal_check_disable_event`` to disable the interrupt of an event, 25 * so that the task can call ``spi_slave_hd_hal_invoke_event_intr`` later to manually invoke the 26 * ISR. For SPI_EV_SEND, SPI_EV_RECV. 27 * 28 * - TXDMA: 29 * - To send data through DMA, call `spi_slave_hd_hal_txdma` 30 * - When the operation is done, SPI_EV_SEND will be triggered. 31 * 32 * - RXDMA: 33 * - To receive data through DMA, call `spi_slave_hd_hal_rxdma` 34 * - When the operation is done, SPI_EV_RECV will be triggered. 35 * - Call ``spi_slave_hd_hal_rxdma_seg_get_len`` to get the received length 36 * 37 * - Shared buffer: 38 * - Call ``spi_slave_hd_hal_write_buffer`` to write the shared register buffer. When the buffer is 39 * read by the master (regardless of the read address), SPI_EV_BUF_TX will be triggered 40 * - Call ``spi_slave_hd_hal_read_buffer`` to read the shared register buffer. When the buffer is 41 * written by the master (regardless of the written address), SPI_EV_BUF_RX will be triggered. 42 */ 43 44 #pragma once 45 46 #include <esp_types.h> 47 #include "esp_err.h" 48 #include "hal/spi_ll.h" 49 #include "hal/spi_types.h" 50 51 /** 52 * @brief Type of dma descriptor with appended members 53 * this structure inherits DMA descriptor, with a pointer to the transaction descriptor passed from users. 54 */ 55 typedef struct { 56 lldesc_t desc; ///< DMA descriptor 57 void *arg; ///< This points to the transaction descriptor user passed in 58 } spi_slave_hd_hal_desc_append_t; 59 60 /// Configuration of the HAL 61 typedef struct { 62 uint32_t host_id; ///< Host ID of the spi peripheral 63 spi_dma_dev_t *dma_in; ///< Input DMA(DMA -> RAM) peripheral register address 64 spi_dma_dev_t *dma_out; ///< Output DMA(RAM -> DMA) peripheral register address 65 bool dma_enabled; ///< DMA enabled or not 66 uint32_t tx_dma_chan; ///< TX DMA channel used. 67 uint32_t rx_dma_chan; ///< RX DMA channel used. 68 bool append_mode; ///< True for DMA append mode, false for segment mode 69 uint32_t spics_io_num; ///< CS GPIO pin for this device 70 uint8_t mode; ///< SPI mode (0-3) 71 uint32_t command_bits; ///< command field bits, multiples of 8 and at least 8. 72 uint32_t address_bits; ///< address field bits, multiples of 8 and at least 8. 73 uint32_t dummy_bits; ///< dummy field bits, multiples of 8 and at least 8. 74 75 struct { 76 uint32_t tx_lsbfirst : 1; ///< Whether TX data should be sent with LSB first. 77 uint32_t rx_lsbfirst : 1; ///< Whether RX data should be read with LSB first. 78 }; 79 } spi_slave_hd_hal_config_t; 80 81 /// Context of the HAL, initialized by :cpp:func:`spi_slave_hd_hal_init`. 82 typedef struct { 83 /* These two need to be malloced by the driver first */ 84 spi_slave_hd_hal_desc_append_t *dmadesc_tx; ///< Head of the TX DMA descriptors. 85 spi_slave_hd_hal_desc_append_t *dmadesc_rx; ///< Head of the RX DMA descriptors. 86 87 /* address of the hardware */ 88 spi_dev_t *dev; ///< Beginning address of the peripheral registers. 89 spi_dma_dev_t *dma_in; ///< Address of the DMA peripheral registers which stores the data received from a peripheral into RAM. 90 spi_dma_dev_t *dma_out; ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral. 91 bool dma_enabled; ///< DMA enabled or not 92 uint32_t tx_dma_chan; ///< TX DMA channel used. 93 uint32_t rx_dma_chan; ///< RX DMA channel used. 94 bool append_mode; ///< True for DMA append mode, false for segment mode 95 uint32_t dma_desc_num; ///< Number of the available DMA descriptors. Calculated from ``bus_max_transfer_size``. 96 spi_slave_hd_hal_desc_append_t *tx_cur_desc; ///< Current TX DMA descriptor that could be linked (set up). 97 spi_slave_hd_hal_desc_append_t *tx_dma_head; ///< Head of the linked TX DMA descriptors which are not used by hardware 98 spi_slave_hd_hal_desc_append_t *tx_dma_tail; ///< Tail of the linked TX DMA descriptors which are not used by hardware 99 spi_slave_hd_hal_desc_append_t tx_dummy_head; ///< Dummy descriptor for ``tx_dma_head`` to start 100 uint32_t tx_used_desc_cnt; ///< Number of the TX descriptors that have been setup 101 uint32_t tx_recycled_desc_cnt; ///< Number of the TX descriptors that could be recycled 102 spi_slave_hd_hal_desc_append_t *rx_cur_desc; ///< Current RX DMA descriptor that could be linked (set up). 103 spi_slave_hd_hal_desc_append_t *rx_dma_head; ///< Head of the linked RX DMA descriptors which are not used by hardware 104 spi_slave_hd_hal_desc_append_t *rx_dma_tail; ///< Tail of the linked RX DMA descriptors which are not used by hardware 105 spi_slave_hd_hal_desc_append_t rx_dummy_head; ///< Dummy descriptor for ``rx_dma_head`` to start 106 uint32_t rx_used_desc_cnt; ///< Number of the RX descriptors that have been setup 107 uint32_t rx_recycled_desc_cnt; ///< Number of the RX descriptors that could be recycled 108 109 /* Internal status used by the HAL implementation, initialized as 0. */ 110 uint32_t intr_not_triggered; 111 bool tx_dma_started; 112 bool rx_dma_started; 113 } spi_slave_hd_hal_context_t; 114 115 /** 116 * @brief Initialize the hardware and part of the context 117 * 118 * @param hal Context of the HAL layer 119 * @param hal_config Configuration of the HAL 120 */ 121 void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_hal_config_t *hal_config); 122 123 /** 124 * @brief Get the size of one DMA descriptor 125 * 126 * @param hal Context of the HAL layer 127 * @param bus_size SPI bus maximum transfer size, in bytes. 128 * @return Total size needed for all the DMA descriptors 129 */ 130 uint32_t spi_slave_hd_hal_get_total_desc_size(spi_slave_hd_hal_context_t *hal, uint32_t bus_size); 131 132 /** 133 * @brief Get the actual bus size 134 * 135 * @param hal Context of the HAL layer 136 * @return Actual bus transaction size 137 */ 138 uint32_t spi_salve_hd_hal_get_max_bus_size(spi_slave_hd_hal_context_t *hal); 139 140 /** 141 * @brief Check and clear signal of one event 142 * 143 * @param hal Context of the HAL layer 144 * @param ev Event to check 145 * @return True if event triggered, otherwise false 146 */ 147 bool spi_slave_hd_hal_check_clear_event(spi_slave_hd_hal_context_t* hal, spi_event_t ev); 148 149 /** 150 * @brief Check and clear the interrupt of one event. 151 * 152 * @note The event source will be kept, so that the interrupt can be invoked by 153 * :cpp:func:`spi_slave_hd_hal_invoke_event_intr`. If event not triggered, its interrupt source 154 * will not be disabled either. 155 * 156 * @param hal Context of the HAL layer 157 * @param ev Event to check and disable 158 * @return True if event triggered, otherwise false 159 */ 160 bool spi_slave_hd_hal_check_disable_event(spi_slave_hd_hal_context_t* hal, spi_event_t ev); 161 162 /** 163 * @brief Enable to invole the ISR of corresponding event. 164 * 165 * @note The function, compared with :cpp:func:`spi_slave_hd_hal_enable_event_intr`, contains a 166 * workaround to force trigger the interrupt, even if the interrupt source cannot be initialized 167 * correctly. 168 * 169 * @param hal Context of the HAL layer 170 * @param ev Event (reason) to invoke the ISR 171 */ 172 void spi_slave_hd_hal_invoke_event_intr(spi_slave_hd_hal_context_t* hal, spi_event_t ev); 173 174 /** 175 * @brief Enable the interrupt source of corresponding event. 176 * 177 * @param hal Context of the HAL layer 178 * @param ev Event whose corresponding interrupt source should be enabled. 179 */ 180 void spi_slave_hd_hal_enable_event_intr(spi_slave_hd_hal_context_t* hal, spi_event_t ev); 181 182 //////////////////////////////////////////////////////////////////////////////// 183 // RX DMA 184 //////////////////////////////////////////////////////////////////////////////// 185 /** 186 * @brief Start the RX DMA operation to the specified buffer. 187 * 188 * @param hal Context of the HAL layer 189 * @param[out] out_buf Buffer to receive the data 190 * @param len Maximul length to receive 191 */ 192 void spi_slave_hd_hal_rxdma(spi_slave_hd_hal_context_t *hal, uint8_t *out_buf, size_t len); 193 194 /** 195 * @brief Get the length of total received data 196 * 197 * @param hal Context of the HAL layer 198 * @return The received length 199 */ 200 int spi_slave_hd_hal_rxdma_seg_get_len(spi_slave_hd_hal_context_t *hal); 201 202 //////////////////////////////////////////////////////////////////////////////// 203 // TX DMA 204 //////////////////////////////////////////////////////////////////////////////// 205 /** 206 * @brief Start the TX DMA operation with the specified buffer 207 * 208 * @param hal Context of the HAL layer 209 * @param data Buffer of data to send 210 * @param len Size of the buffer, also the maximum length to send 211 */ 212 void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len); 213 214 //////////////////////////////////////////////////////////////////////////////// 215 // Shared buffer 216 //////////////////////////////////////////////////////////////////////////////// 217 /** 218 * @brief Read from the shared register buffer 219 * 220 * @param hal Context of the HAL layer 221 * @param addr Address of the shared regsiter to read 222 * @param out_data Buffer to store the read data 223 * @param len Length to read from the shared buffer 224 */ 225 void spi_slave_hd_hal_read_buffer(spi_slave_hd_hal_context_t *hal, int addr, uint8_t *out_data, size_t len); 226 227 /** 228 * @brief Write the shared register buffer 229 * 230 * @param hal Context of the HAL layer 231 * @param addr Address of the shared register to write 232 * @param data Buffer of the data to write 233 * @param len Length to write into the shared buffer 234 */ 235 void spi_slave_hd_hal_write_buffer(spi_slave_hd_hal_context_t *hal, int addr, uint8_t *data, size_t len); 236 237 /** 238 * @brief Get the length of previous transaction. 239 * 240 * @param hal Context of the HAL layer 241 * @return The length of previous transaction 242 */ 243 int spi_slave_hd_hal_get_rxlen(spi_slave_hd_hal_context_t *hal); 244 245 /** 246 * @brief Get the address of last transaction 247 * 248 * @param hal Context of the HAL layer 249 * @return The address of last transaction 250 */ 251 int spi_slave_hd_hal_get_last_addr(spi_slave_hd_hal_context_t *hal); 252 253 254 //////////////////////////////////////////////////////////////////////////////// 255 // Append Mode 256 //////////////////////////////////////////////////////////////////////////////// 257 /** 258 * @brief Return the finished TX transaction 259 * 260 * @note This API is based on this assumption: the hardware behaviour of current transaction completion is only modified by the its own caller layer. 261 * This means if some other code changed the hardware behaviour (e.g. clear intr raw bit), or the caller call this API without noticing the HW behaviour, 262 * this API will go wrong. 263 * 264 * @param hal Context of the HAL layer 265 * @param out_trans Pointer to the caller-defined transaction 266 * @return 1: Transaction is finished; 0: Transaction is not finished 267 */ 268 bool spi_slave_hd_hal_get_tx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans); 269 270 /** 271 * @brief Return the finished RX transaction 272 * 273 * @note This API is based on this assumption: the hardware behaviour of current transaction completion is only modified by the its own caller layer. 274 * This means if some other code changed the hardware behaviour (e.g. clear intr raw bit), or the caller call this API without noticing the HW behaviour, 275 * this API will go wrong. 276 * 277 * @param hal Context of the HAL layer 278 * @param out_trans Pointer to the caller-defined transaction 279 * @param out_len Actual number of bytes of received data 280 * @return 1: Transaction is finished; 0: Transaction is not finished 281 */ 282 bool spi_slave_hd_hal_get_rx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, size_t *out_len); 283 284 /** 285 * @brief Load the TX DMA descriptors without stopping the DMA 286 * 287 * @param hal Context of the HAL layer 288 * @param data Buffer of the transaction data 289 * @param len Length of the data 290 * @param arg Pointer used by the caller to indicate the tranaction. Will be returned by ``spi_slave_hd_hal_get_tx_finished_trans`` when transaction is finished 291 * @return 292 * - ESP_OK: on success 293 * - ESP_ERR_INVALID_STATE: Function called in invalid state. 294 */ 295 esp_err_t spi_slave_hd_hal_txdma_append(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len, void *arg); 296 297 /** 298 * @brief Load the RX DMA descriptors without stopping the DMA 299 * 300 * @param hal Context of the HAL layer 301 * @param data Buffer of the transaction data 302 * @param len Length of the data 303 * @param arg Pointer used by the caller to indicate the tranaction. Will be returned by ``spi_slave_hd_hal_get_rx_finished_trans`` when transaction is finished 304 * @return 305 * - ESP_OK: on success 306 * - ESP_ERR_INVALID_STATE: Function called in invalid state. 307 */ 308 esp_err_t spi_slave_hd_hal_rxdma_append(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len, void *arg); 309