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