Repo for ESP32 Weather Station Development
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

1138 lignes
44KB

  1. // Copyright 2015-2016 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. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. /*
  14. ----------------------------------------
  15. Non DMA version of the spi_master driver
  16. ----------------------------------------
  17. ------------------------------------------------------------------------------------
  18. Based on esp-idf 'spi_master', modified by LoBo (https://github.com/loboris) 03/2017
  19. ------------------------------------------------------------------------------------
  20. * Transfers data to SPI device in direct mode, not using DMA
  21. * All configuration options (bus, device, transaction) are the same as in spi_master driver
  22. * Transfers uses the semaphore (taken in select function & given in deselect function) to protect the transfer
  23. * Number of the devices attached to the bus which uses hardware CS can be 3 ('NO_CS')
  24. * Additional devices which uses software CS can be attached to the bus, up to 'NO_DEV'
  25. * 'spi_bus_initialize' & 'spi_bus_remove' functions are removed, spi bus is initiated/removed in spi_lobo_bus_add_device/spi_lobo_bus_remove_device when needed
  26. * 'spi_lobo_bus_add_device' function has added parameter 'bus_config' and automatically initializes spi bus device if not already initialized
  27. * 'spi_lobo_bus_remove_device' automatically removes spi bus device if no other devices are attached to it.
  28. * Devices can have individual bus_configs, so different mosi, miso, sck pins can be configured for each device
  29. Reconfiguring the bus is done automaticaly in 'spi_lobo_device_select' function
  30. * 'spi_lobo_device_select' & 'spi_lobo_device_deselect' functions handles devices configuration changes and software CS
  31. * Some helper functions are added ('spi_lobo_get_speed', 'spi_lobo_set_speed', ...)
  32. * All structures are available in header file for easy creation of user low level spi functions. See **tftfunc.c** source for examples.
  33. * Transimt and receive lenghts are limited only by available memory
  34. Main driver's function is 'spi_lobo_transfer_data()'
  35. * TRANSMIT 8-bit data to spi device from 'trans->tx_buffer' or 'trans->tx_data' (trans->lenght/8 bytes)
  36. * and RECEIVE data to 'trans->rx_buffer' or 'trans->rx_data' (trans->rx_length/8 bytes)
  37. * Lengths must be 8-bit multiples!
  38. * If trans->rx_buffer is NULL or trans->rx_length is 0, only transmits data
  39. * If trans->tx_buffer is NULL or trans->length is 0, only receives data
  40. * If the device is in duplex mode (LB_SPI_DEVICE_HALFDUPLEX flag NOT set), data are transmitted and received simultaneously.
  41. * If the device is in half duplex mode (LB_SPI_DEVICE_HALFDUPLEX flag IS set), data are received after transmission
  42. * 'address', 'command' and 'dummy bits' are transmitted before data phase IF set in device's configuration
  43. * and IF 'trans->length' and 'trans->rx_length' are NOT both 0
  44. * If configured, devices 'pre_cb' callback is called before and 'post_cb' after the transmission
  45. * If device was not previously selected, it will be selected before transmission and deselected after transmission.
  46. */
  47. /*
  48. Replace this include with
  49. #include "driver/spi_master_lobo.h"
  50. if the driver is located in esp-isf/components
  51. */
  52. #include "freertos/FreeRTOS.h"
  53. #include <string.h>
  54. #include "soc/spi_reg.h"
  55. #include "soc/dport_reg.h"
  56. #include "esp_log.h"
  57. #include "freertos/semphr.h"
  58. #include "driver/uart.h"
  59. #include "driver/gpio.h"
  60. #include "spi_master_lobo.h"
  61. #include "driver/periph_ctrl.h"
  62. static spi_lobo_host_t *spihost[3] = {NULL};
  63. static const char *SPI_TAG = "spi_lobo_master";
  64. #define SPI_CHECK(a, str, ret_val) \
  65. if (!(a)) { \
  66. ESP_LOGE(SPI_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
  67. return (ret_val); \
  68. }
  69. /*
  70. Stores a bunch of per-spi-peripheral data.
  71. */
  72. typedef struct {
  73. const uint8_t spiclk_out; //GPIO mux output signals
  74. const uint8_t spid_out;
  75. const uint8_t spiq_out;
  76. const uint8_t spiwp_out;
  77. const uint8_t spihd_out;
  78. const uint8_t spid_in; //GPIO mux input signals
  79. const uint8_t spiq_in;
  80. const uint8_t spiwp_in;
  81. const uint8_t spihd_in;
  82. const uint8_t spics_out[3]; // /CS GPIO output mux signals
  83. const uint8_t spiclk_native; //IO pins of IO_MUX muxed signals
  84. const uint8_t spid_native;
  85. const uint8_t spiq_native;
  86. const uint8_t spiwp_native;
  87. const uint8_t spihd_native;
  88. const uint8_t spics0_native;
  89. const uint8_t irq; //irq source for interrupt mux
  90. const uint8_t irq_dma; //dma irq source for interrupt mux
  91. const periph_module_t module; //peripheral module, for enabling clock etc
  92. spi_dev_t *hw; //Pointer to the hardware registers
  93. } spi_signal_conn_t;
  94. /*
  95. Bunch of constants for every SPI peripheral: GPIO signals, irqs, hw addr of registers etc
  96. */
  97. static const spi_signal_conn_t io_signal[3]={
  98. {
  99. .spiclk_out=SPICLK_OUT_IDX,
  100. .spid_out=SPID_OUT_IDX,
  101. .spiq_out=SPIQ_OUT_IDX,
  102. .spiwp_out=SPIWP_OUT_IDX,
  103. .spihd_out=SPIHD_OUT_IDX,
  104. .spid_in=SPID_IN_IDX,
  105. .spiq_in=SPIQ_IN_IDX,
  106. .spiwp_in=SPIWP_IN_IDX,
  107. .spihd_in=SPIHD_IN_IDX,
  108. .spics_out={SPICS0_OUT_IDX, SPICS1_OUT_IDX, SPICS2_OUT_IDX},
  109. .spiclk_native=6,
  110. .spid_native=8,
  111. .spiq_native=7,
  112. .spiwp_native=10,
  113. .spihd_native=9,
  114. .spics0_native=11,
  115. .irq=ETS_SPI1_INTR_SOURCE,
  116. .irq_dma=ETS_SPI1_DMA_INTR_SOURCE,
  117. .module=PERIPH_SPI_MODULE,
  118. .hw=&SPI1
  119. }, {
  120. .spiclk_out=HSPICLK_OUT_IDX,
  121. .spid_out=HSPID_OUT_IDX,
  122. .spiq_out=HSPIQ_OUT_IDX,
  123. .spiwp_out=HSPIWP_OUT_IDX,
  124. .spihd_out=HSPIHD_OUT_IDX,
  125. .spid_in=HSPID_IN_IDX,
  126. .spiq_in=HSPIQ_IN_IDX,
  127. .spiwp_in=HSPIWP_IN_IDX,
  128. .spihd_in=HSPIHD_IN_IDX,
  129. .spics_out={HSPICS0_OUT_IDX, HSPICS1_OUT_IDX, HSPICS2_OUT_IDX},
  130. .spiclk_native=14,
  131. .spid_native=13,
  132. .spiq_native=12,
  133. .spiwp_native=2,
  134. .spihd_native=4,
  135. .spics0_native=15,
  136. .irq=ETS_SPI2_INTR_SOURCE,
  137. .irq_dma=ETS_SPI2_DMA_INTR_SOURCE,
  138. .module=PERIPH_HSPI_MODULE,
  139. .hw=&SPI2
  140. }, {
  141. .spiclk_out=VSPICLK_OUT_IDX,
  142. .spid_out=VSPID_OUT_IDX,
  143. .spiq_out=VSPIQ_OUT_IDX,
  144. .spiwp_out=VSPIWP_OUT_IDX,
  145. .spihd_out=VSPIHD_OUT_IDX,
  146. .spid_in=VSPID_IN_IDX,
  147. .spiq_in=VSPIQ_IN_IDX,
  148. .spiwp_in=VSPIWP_IN_IDX,
  149. .spihd_in=VSPIHD_IN_IDX,
  150. .spics_out={VSPICS0_OUT_IDX, VSPICS1_OUT_IDX, VSPICS2_OUT_IDX},
  151. .spiclk_native=18,
  152. .spid_native=23,
  153. .spiq_native=19,
  154. .spiwp_native=22,
  155. .spihd_native=21,
  156. .spics0_native=5,
  157. .irq=ETS_SPI3_INTR_SOURCE,
  158. .irq_dma=ETS_SPI3_DMA_INTR_SOURCE,
  159. .module=PERIPH_VSPI_MODULE,
  160. .hw=&SPI3
  161. }
  162. };
  163. //======================================================================================================
  164. #define DMA_CHANNEL_ENABLED(dma_chan) (BIT(dma_chan-1))
  165. typedef void(*dmaworkaround_cb_t)(void *arg);
  166. //Set up a list of dma descriptors. dmadesc is an array of descriptors. Data is the buffer to point to.
  167. //--------------------------------------------------------------------------------------------
  168. void spi_lobo_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx)
  169. {
  170. int n = 0;
  171. while (len) {
  172. int dmachunklen = len;
  173. if (dmachunklen > SPI_MAX_DMA_LEN) dmachunklen = SPI_MAX_DMA_LEN;
  174. if (isrx) {
  175. //Receive needs DMA length rounded to next 32-bit boundary
  176. dmadesc[n].size = (dmachunklen + 3) & (~3);
  177. dmadesc[n].length = (dmachunklen + 3) & (~3);
  178. } else {
  179. dmadesc[n].size = dmachunklen;
  180. dmadesc[n].length = dmachunklen;
  181. }
  182. dmadesc[n].buf = (uint8_t *)data;
  183. dmadesc[n].eof = 0;
  184. dmadesc[n].sosf = 0;
  185. dmadesc[n].owner = 1;
  186. dmadesc[n].qe.stqe_next = &dmadesc[n + 1];
  187. len -= dmachunklen;
  188. data += dmachunklen;
  189. n++;
  190. }
  191. dmadesc[n - 1].eof = 1; //Mark last DMA desc as end of stream.
  192. dmadesc[n - 1].qe.stqe_next = NULL;
  193. }
  194. /*
  195. Code for workaround for DMA issue in ESP32 v0/v1 silicon
  196. */
  197. static volatile int dmaworkaround_channels_busy[2] = {0, 0};
  198. static dmaworkaround_cb_t dmaworkaround_cb;
  199. static void *dmaworkaround_cb_arg;
  200. static portMUX_TYPE dmaworkaround_mux = portMUX_INITIALIZER_UNLOCKED;
  201. static int dmaworkaround_waiting_for_chan = 0;
  202. static bool spi_periph_claimed[3] = {true, false, false};
  203. static uint8_t spi_dma_chan_enabled = 0;
  204. static portMUX_TYPE spi_dma_spinlock = portMUX_INITIALIZER_UNLOCKED;
  205. //--------------------------------------------------------------------------------------------
  206. bool IRAM_ATTR spi_lobo_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void *arg)
  207. {
  208. int otherchan = (dmachan == 1) ? 2 : 1;
  209. bool ret;
  210. portENTER_CRITICAL(&dmaworkaround_mux);
  211. if (dmaworkaround_channels_busy[otherchan-1]) {
  212. //Other channel is busy. Call back when it's done.
  213. dmaworkaround_cb = cb;
  214. dmaworkaround_cb_arg = arg;
  215. dmaworkaround_waiting_for_chan = otherchan;
  216. ret = false;
  217. } else {
  218. //Reset DMA
  219. DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST);
  220. DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST);
  221. ret = true;
  222. }
  223. portEXIT_CRITICAL(&dmaworkaround_mux);
  224. return ret;
  225. }
  226. //-------------------------------------------------------
  227. bool IRAM_ATTR spi_lobo_dmaworkaround_reset_in_progress()
  228. {
  229. return (dmaworkaround_waiting_for_chan != 0);
  230. }
  231. //-----------------------------------------------------
  232. void IRAM_ATTR spi_lobo_dmaworkaround_idle(int dmachan)
  233. {
  234. portENTER_CRITICAL(&dmaworkaround_mux);
  235. dmaworkaround_channels_busy[dmachan-1] = 0;
  236. if (dmaworkaround_waiting_for_chan == dmachan) {
  237. //Reset DMA
  238. DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST);
  239. DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST);
  240. dmaworkaround_waiting_for_chan = 0;
  241. //Call callback
  242. dmaworkaround_cb(dmaworkaround_cb_arg);
  243. }
  244. portEXIT_CRITICAL(&dmaworkaround_mux);
  245. }
  246. //----------------------------------------------------------------
  247. void IRAM_ATTR spi_lobo_dmaworkaround_transfer_active(int dmachan)
  248. {
  249. portENTER_CRITICAL(&dmaworkaround_mux);
  250. dmaworkaround_channels_busy[dmachan-1] = 1;
  251. portEXIT_CRITICAL(&dmaworkaround_mux);
  252. }
  253. //Returns true if this peripheral is successfully claimed, false if otherwise.
  254. //-----------------------------------------------------
  255. bool spi_lobo_periph_claim(spi_lobo_host_device_t host)
  256. {
  257. bool ret = __sync_bool_compare_and_swap(&spi_periph_claimed[host], false, true);
  258. if (ret) periph_module_enable(io_signal[host].module);
  259. return ret;
  260. }
  261. //Returns true if this peripheral is successfully freed, false if otherwise.
  262. //-----------------------------------------------
  263. bool spi_lobo_periph_free(spi_lobo_host_device_t host)
  264. {
  265. bool ret = __sync_bool_compare_and_swap(&spi_periph_claimed[host], true, false);
  266. if (ret) periph_module_disable(io_signal[host].module);
  267. return ret;
  268. }
  269. //-----------------------------------------
  270. bool spi_lobo_dma_chan_claim (int dma_chan)
  271. {
  272. bool ret = false;
  273. assert( dma_chan == 1 || dma_chan == 2 );
  274. portENTER_CRITICAL(&spi_dma_spinlock);
  275. if ( !(spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan)) ) {
  276. // get the channel only when it's not claimed yet.
  277. spi_dma_chan_enabled |= DMA_CHANNEL_ENABLED(dma_chan);
  278. ret = true;
  279. }
  280. periph_module_enable( PERIPH_SPI_DMA_MODULE );
  281. portEXIT_CRITICAL(&spi_dma_spinlock);
  282. return ret;
  283. }
  284. //---------------------------------------
  285. bool spi_lobo_dma_chan_free(int dma_chan)
  286. {
  287. assert( dma_chan == 1 || dma_chan == 2 );
  288. assert( spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan) );
  289. portENTER_CRITICAL(&spi_dma_spinlock);
  290. spi_dma_chan_enabled &= ~DMA_CHANNEL_ENABLED(dma_chan);
  291. if ( spi_dma_chan_enabled == 0 ) {
  292. //disable the DMA only when all the channels are freed.
  293. periph_module_disable( PERIPH_SPI_DMA_MODULE );
  294. }
  295. portEXIT_CRITICAL(&spi_dma_spinlock);
  296. return true;
  297. }
  298. //======================================================================================================
  299. //----------------------------------------------------------------------------------------------------------------
  300. static esp_err_t spi_lobo_bus_initialize(spi_lobo_host_device_t host, spi_lobo_bus_config_t *bus_config, int init)
  301. {
  302. bool native=true, spi_chan_claimed, dma_chan_claimed;
  303. if (init > 0) {
  304. /* ToDo: remove this when we have flash operations cooperating with this */
  305. SPI_CHECK(host!=TFT_SPI_HOST, "SPI1 is not supported", ESP_ERR_NOT_SUPPORTED);
  306. SPI_CHECK(host>=TFT_SPI_HOST && host<=TFT_VSPI_HOST, "invalid host", ESP_ERR_INVALID_ARG);
  307. SPI_CHECK(spihost[host]==NULL, "host already in use", ESP_ERR_INVALID_STATE);
  308. }
  309. else {
  310. SPI_CHECK(spihost[host]!=NULL, "host not in use", ESP_ERR_INVALID_STATE);
  311. }
  312. SPI_CHECK(bus_config->mosi_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->mosi_io_num), "spid pin invalid", ESP_ERR_INVALID_ARG);
  313. SPI_CHECK(bus_config->sclk_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->sclk_io_num), "spiclk pin invalid", ESP_ERR_INVALID_ARG);
  314. SPI_CHECK(bus_config->miso_io_num<0 || GPIO_IS_VALID_GPIO(bus_config->miso_io_num), "spiq pin invalid", ESP_ERR_INVALID_ARG);
  315. SPI_CHECK(bus_config->quadwp_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->quadwp_io_num), "spiwp pin invalid", ESP_ERR_INVALID_ARG);
  316. SPI_CHECK(bus_config->quadhd_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->quadhd_io_num), "spihd pin invalid", ESP_ERR_INVALID_ARG);
  317. if (init > 0) {
  318. spi_chan_claimed=spi_lobo_periph_claim(host);
  319. SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE);
  320. //spihost[host]=malloc(sizeof(spi_lobo_host_t));
  321. spihost[host]=heap_caps_malloc(sizeof(spi_lobo_host_t), MALLOC_CAP_DMA);
  322. if (spihost[host]==NULL) return ESP_ERR_NO_MEM;
  323. memset(spihost[host], 0, sizeof(spi_lobo_host_t));
  324. // Create semaphore
  325. spihost[host]->spi_lobo_bus_mutex = xSemaphoreCreateMutex();
  326. if (!spihost[host]->spi_lobo_bus_mutex) return ESP_ERR_NO_MEM;
  327. }
  328. spihost[host]->cur_device = -1;
  329. memcpy(&spihost[host]->cur_bus_config, bus_config, sizeof(spi_lobo_bus_config_t));
  330. //Check if the selected pins correspond to the native pins of the peripheral
  331. if (bus_config->mosi_io_num >= 0 && bus_config->mosi_io_num!=io_signal[host].spid_native) native=false;
  332. if (bus_config->miso_io_num >= 0 && bus_config->miso_io_num!=io_signal[host].spiq_native) native=false;
  333. if (bus_config->sclk_io_num >= 0 && bus_config->sclk_io_num!=io_signal[host].spiclk_native) native=false;
  334. if (bus_config->quadwp_io_num >= 0 && bus_config->quadwp_io_num!=io_signal[host].spiwp_native) native=false;
  335. if (bus_config->quadhd_io_num >= 0 && bus_config->quadhd_io_num!=io_signal[host].spihd_native) native=false;
  336. spihost[host]->no_gpio_matrix=native;
  337. if (native) {
  338. //All SPI native pin selections resolve to 1, so we put that here instead of trying to figure
  339. //out which FUNC_GPIOx_xSPIxx to grab; they all are defined to 1 anyway.
  340. if (bus_config->mosi_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->mosi_io_num], 1);
  341. if (bus_config->miso_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->miso_io_num], 1);
  342. if (bus_config->quadwp_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num], 1);
  343. if (bus_config->quadhd_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num], 1);
  344. if (bus_config->sclk_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->sclk_io_num], 1);
  345. } else {
  346. //Use GPIO
  347. if (bus_config->mosi_io_num>0) {
  348. PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->mosi_io_num], PIN_FUNC_GPIO);
  349. gpio_set_direction(bus_config->mosi_io_num, GPIO_MODE_OUTPUT);
  350. gpio_matrix_out(bus_config->mosi_io_num, io_signal[host].spid_out, false, false);
  351. gpio_matrix_in(bus_config->mosi_io_num, io_signal[host].spid_in, false);
  352. }
  353. if (bus_config->miso_io_num>0) {
  354. PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->miso_io_num], PIN_FUNC_GPIO);
  355. gpio_set_direction(bus_config->miso_io_num, GPIO_MODE_INPUT);
  356. gpio_matrix_out(bus_config->miso_io_num, io_signal[host].spiq_out, false, false);
  357. gpio_matrix_in(bus_config->miso_io_num, io_signal[host].spiq_in, false);
  358. }
  359. if (bus_config->quadwp_io_num>0) {
  360. PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num], PIN_FUNC_GPIO);
  361. gpio_set_direction(bus_config->quadwp_io_num, GPIO_MODE_OUTPUT);
  362. gpio_matrix_out(bus_config->quadwp_io_num, io_signal[host].spiwp_out, false, false);
  363. gpio_matrix_in(bus_config->quadwp_io_num, io_signal[host].spiwp_in, false);
  364. }
  365. if (bus_config->quadhd_io_num>0) {
  366. PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num], PIN_FUNC_GPIO);
  367. gpio_set_direction(bus_config->quadhd_io_num, GPIO_MODE_OUTPUT);
  368. gpio_matrix_out(bus_config->quadhd_io_num, io_signal[host].spihd_out, false, false);
  369. gpio_matrix_in(bus_config->quadhd_io_num, io_signal[host].spihd_in, false);
  370. }
  371. if (bus_config->sclk_io_num>0) {
  372. PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->sclk_io_num], PIN_FUNC_GPIO);
  373. gpio_set_direction(bus_config->sclk_io_num, GPIO_MODE_OUTPUT);
  374. gpio_matrix_out(bus_config->sclk_io_num, io_signal[host].spiclk_out, false, false);
  375. }
  376. }
  377. periph_module_enable(io_signal[host].module);
  378. spihost[host]->hw=io_signal[host].hw;
  379. if (init > 0) {
  380. dma_chan_claimed=spi_lobo_dma_chan_claim(init);
  381. if ( !dma_chan_claimed ) {
  382. spi_lobo_periph_free( host );
  383. SPI_CHECK(dma_chan_claimed, "dma channel already in use", ESP_ERR_INVALID_STATE);
  384. }
  385. spihost[host]->dma_chan = init;
  386. //See how many dma descriptors we need and allocate them
  387. int dma_desc_ct=(bus_config->max_transfer_sz+SPI_MAX_DMA_LEN-1)/SPI_MAX_DMA_LEN;
  388. if (dma_desc_ct==0) dma_desc_ct=1; //default to 4k when max is not given
  389. spihost[host]->max_transfer_sz = dma_desc_ct*SPI_MAX_DMA_LEN;
  390. spihost[host]->dmadesc_tx=heap_caps_malloc(sizeof(lldesc_t)*dma_desc_ct, MALLOC_CAP_DMA);
  391. spihost[host]->dmadesc_rx=heap_caps_malloc(sizeof(lldesc_t)*dma_desc_ct, MALLOC_CAP_DMA);
  392. if (!spihost[host]->dmadesc_tx || !spihost[host]->dmadesc_rx) goto nomem;
  393. //Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset.
  394. spi_lobo_dmaworkaround_idle(spihost[host]->dma_chan);
  395. // Reset DMA
  396. spihost[host]->hw->dma_conf.val |= SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST;
  397. spihost[host]->hw->dma_out_link.start=0;
  398. spihost[host]->hw->dma_in_link.start=0;
  399. spihost[host]->hw->dma_conf.val &= ~(SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST);
  400. spihost[host]->hw->dma_conf.out_data_burst_en=1;
  401. //Reset timing
  402. spihost[host]->hw->ctrl2.val=0;
  403. //Disable unneeded ints
  404. spihost[host]->hw->slave.rd_buf_done=0;
  405. spihost[host]->hw->slave.wr_buf_done=0;
  406. spihost[host]->hw->slave.rd_sta_done=0;
  407. spihost[host]->hw->slave.wr_sta_done=0;
  408. spihost[host]->hw->slave.rd_buf_inten=0;
  409. spihost[host]->hw->slave.wr_buf_inten=0;
  410. spihost[host]->hw->slave.rd_sta_inten=0;
  411. spihost[host]->hw->slave.wr_sta_inten=0;
  412. //Force a transaction done interrupt. This interrupt won't fire yet because we initialized the SPI interrupt as
  413. //disabled. This way, we can just enable the SPI interrupt and the interrupt handler will kick in, handling
  414. //any transactions that are queued.
  415. spihost[host]->hw->slave.trans_inten=1;
  416. spihost[host]->hw->slave.trans_done=1;
  417. //Select DMA channel.
  418. DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, init, (host * 2));
  419. }
  420. return ESP_OK;
  421. nomem:
  422. if (spihost[host]) {
  423. free(spihost[host]->dmadesc_tx);
  424. free(spihost[host]->dmadesc_rx);
  425. }
  426. free(spihost[host]);
  427. spi_lobo_periph_free(host);
  428. return ESP_ERR_NO_MEM;
  429. }
  430. //---------------------------------------------------------------------------
  431. static esp_err_t spi_lobo_bus_free(spi_lobo_host_device_t host, int dofree)
  432. {
  433. if ((host == TFT_SPI_HOST) || (host > TFT_VSPI_HOST)) return ESP_ERR_NOT_SUPPORTED; // invalid host
  434. if (spihost[host] == NULL) return ESP_ERR_INVALID_STATE; // host not in use
  435. if (dofree) {
  436. for (int x=0; x<NO_DEV; x++) {
  437. if (spihost[host]->device[x] != NULL) return ESP_ERR_INVALID_STATE; // not all devices freed
  438. }
  439. }
  440. if ( spihost[host]->dma_chan > 0 ) {
  441. spi_lobo_dma_chan_free ( spihost[host]->dma_chan );
  442. }
  443. spihost[host]->hw->slave.trans_inten=0;
  444. spihost[host]->hw->slave.trans_done=0;
  445. spi_lobo_periph_free(host);
  446. if (dofree) {
  447. vSemaphoreDelete(spihost[host]->spi_lobo_bus_mutex);
  448. free(spihost[host]->dmadesc_tx);
  449. free(spihost[host]->dmadesc_rx);
  450. free(spihost[host]);
  451. spihost[host] = NULL;
  452. }
  453. return ESP_OK;
  454. }
  455. //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  456. esp_err_t spi_lobo_bus_add_device(spi_lobo_host_device_t host, spi_lobo_bus_config_t *bus_config, spi_lobo_device_interface_config_t *dev_config, spi_lobo_device_handle_t *handle)
  457. {
  458. if ((host == TFT_SPI_HOST) || (host > TFT_VSPI_HOST)) return ESP_ERR_NOT_SUPPORTED; // invalid host
  459. if (spihost[host] == NULL) {
  460. esp_err_t ret = spi_lobo_bus_initialize(host, bus_config, 1);
  461. if (ret) return ret;
  462. }
  463. int freecs, maxdev;
  464. int apbclk=APB_CLK_FREQ;
  465. if (spihost[host] == NULL) return ESP_ERR_INVALID_STATE;
  466. if (dev_config->spics_io_num >= 0) {
  467. if (!GPIO_IS_VALID_OUTPUT_GPIO(dev_config->spics_io_num)) return ESP_ERR_INVALID_ARG;
  468. if (dev_config->spics_ext_io_num > 0) dev_config->spics_ext_io_num = -1;
  469. }
  470. else {
  471. //if ((dev_config->spics_ext_io_num <= 0) || (!GPIO_IS_VALID_OUTPUT_GPIO(dev_config->spics_ext_io_num))) return ESP_ERR_INVALID_ARG;
  472. }
  473. //ToDo: Check if some other device uses the same 'spics_ext_io_num'
  474. if (dev_config->clock_speed_hz == 0) return ESP_ERR_INVALID_ARG;
  475. if (dev_config->spics_io_num > 0) maxdev = NO_CS;
  476. else maxdev = NO_DEV;
  477. for (freecs=0; freecs<maxdev; freecs++) {
  478. //See if this slot is free; reserve if it is by putting a dummy pointer in the slot. We use an atomic compare&swap to make this thread-safe.
  479. if (__sync_bool_compare_and_swap(&spihost[host]->device[freecs], NULL, (spi_lobo_device_t *)1)) break;
  480. }
  481. if (freecs == maxdev) return ESP_ERR_NOT_FOUND;
  482. // The hardware looks like it would support this, but actually setting cs_ena_pretrans when transferring in full
  483. // duplex mode does absolutely nothing on the ESP32.
  484. if ((dev_config->cs_ena_pretrans != 0) && (dev_config->flags & LB_SPI_DEVICE_HALFDUPLEX)) return ESP_ERR_INVALID_ARG;
  485. // Speeds >=40MHz over GPIO matrix needs a dummy cycle, but these don't work for full-duplex connections.
  486. if (((dev_config->flags & LB_SPI_DEVICE_HALFDUPLEX)==0) && (dev_config->clock_speed_hz > ((apbclk*2)/5)) && (!spihost[host]->no_gpio_matrix)) return ESP_ERR_INVALID_ARG;
  487. //Allocate memory for device
  488. spi_lobo_device_t *dev=malloc(sizeof(spi_lobo_device_t));
  489. if (dev==NULL) return ESP_ERR_NO_MEM;
  490. memset(dev, 0, sizeof(spi_lobo_device_t));
  491. spihost[host]->device[freecs]=dev;
  492. if (dev_config->duty_cycle_pos==0) dev_config->duty_cycle_pos=128;
  493. dev->host=spihost[host];
  494. dev->host_dev = host;
  495. //We want to save a copy of the dev config in the dev struct.
  496. memcpy(&dev->cfg, dev_config, sizeof(spi_lobo_device_interface_config_t));
  497. //We want to save a copy of the bus config in the dev struct.
  498. memcpy(&dev->bus_config, bus_config, sizeof(spi_lobo_bus_config_t));
  499. //Set CS pin, CS options
  500. if (dev_config->spics_io_num > 0) {
  501. if (spihost[host]->no_gpio_matrix &&dev_config->spics_io_num == io_signal[host].spics0_native && freecs==0) {
  502. //Again, the cs0s for all SPI peripherals map to pin mux source 1, so we use that instead of a define.
  503. PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[dev_config->spics_io_num], 1);
  504. } else {
  505. //Use GPIO matrix
  506. PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[dev_config->spics_io_num], PIN_FUNC_GPIO);
  507. gpio_set_direction(dev_config->spics_io_num, GPIO_MODE_OUTPUT);
  508. gpio_matrix_out(dev_config->spics_io_num, io_signal[host].spics_out[freecs], false, false);
  509. }
  510. }
  511. else if (dev_config->spics_ext_io_num >= 0) {
  512. gpio_set_direction(dev_config->spics_ext_io_num, GPIO_MODE_OUTPUT);
  513. gpio_set_level(dev_config->spics_ext_io_num, 1);
  514. }
  515. if (dev_config->flags & LB_SPI_DEVICE_CLK_AS_CS) {
  516. spihost[host]->hw->pin.master_ck_sel |= (1<<freecs);
  517. } else {
  518. spihost[host]->hw->pin.master_ck_sel &= (1<<freecs);
  519. }
  520. if (dev_config->flags & LB_SPI_DEVICE_POSITIVE_CS) {
  521. spihost[host]->hw->pin.master_cs_pol |= (1<<freecs);
  522. } else {
  523. spihost[host]->hw->pin.master_cs_pol &= (1<<freecs);
  524. }
  525. *handle = dev;
  526. return ESP_OK;
  527. }
  528. //-------------------------------------------------------------------
  529. esp_err_t spi_lobo_bus_remove_device(spi_lobo_device_handle_t handle)
  530. {
  531. int x;
  532. if (handle == NULL) return ESP_ERR_INVALID_ARG;
  533. //Remove device from list of csses and free memory
  534. for (x=0; x<NO_DEV; x++) {
  535. if (handle->host->device[x] == handle) handle->host->device[x]=NULL;
  536. }
  537. // Check if all devices are removed from this host and free the bus if yes
  538. for (x=0; x<NO_DEV; x++) {
  539. if (spihost[handle->host_dev]->device[x] !=NULL) break;
  540. }
  541. if (x == NO_DEV) {
  542. free(handle);
  543. spi_lobo_bus_free(handle->host_dev, 1);
  544. }
  545. else free(handle);
  546. return ESP_OK;
  547. }
  548. //-----------------------------------------------------------------
  549. static int IRAM_ATTR spi_freq_for_pre_n(int fapb, int pre, int n) {
  550. return (fapb / (pre * n));
  551. }
  552. /*
  553. * Set the SPI clock to a certain frequency. Returns the effective frequency set, which may be slightly
  554. * different from the requested frequency.
  555. */
  556. //-----------------------------------------------------------------------------------
  557. static int IRAM_ATTR spi_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle) {
  558. int pre, n, h, l, eff_clk;
  559. //In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value.
  560. if (hz>((fapb/4)*3)) {
  561. //Using Fapb directly will give us the best result here.
  562. hw->clock.clkcnt_l=0;
  563. hw->clock.clkcnt_h=0;
  564. hw->clock.clkcnt_n=0;
  565. hw->clock.clkdiv_pre=0;
  566. hw->clock.clk_equ_sysclk=1;
  567. eff_clk=fapb;
  568. } else {
  569. //For best duty cycle resolution, we want n to be as close to 32 as possible, but
  570. //we also need a pre/n combo that gets us as close as possible to the intended freq.
  571. //To do this, we bruteforce n and calculate the best pre to go along with that.
  572. //If there's a choice between pre/n combos that give the same result, use the one
  573. //with the higher n.
  574. int bestn=-1;
  575. int bestpre=-1;
  576. int besterr=0;
  577. int errval;
  578. for (n=1; n<=64; n++) {
  579. //Effectively, this does pre=round((fapb/n)/hz).
  580. pre=((fapb/n)+(hz/2))/hz;
  581. if (pre<=0) pre=1;
  582. if (pre>8192) pre=8192;
  583. errval=abs(spi_freq_for_pre_n(fapb, pre, n)-hz);
  584. if (bestn==-1 || errval<=besterr) {
  585. besterr=errval;
  586. bestn=n;
  587. bestpre=pre;
  588. }
  589. }
  590. n=bestn;
  591. pre=bestpre;
  592. l=n;
  593. //This effectively does round((duty_cycle*n)/256)
  594. h=(duty_cycle*n+127)/256;
  595. if (h<=0) h=1;
  596. hw->clock.clk_equ_sysclk=0;
  597. hw->clock.clkcnt_n=n-1;
  598. hw->clock.clkdiv_pre=pre-1;
  599. hw->clock.clkcnt_h=h-1;
  600. hw->clock.clkcnt_l=l-1;
  601. eff_clk=spi_freq_for_pre_n(fapb, pre, n);
  602. }
  603. return eff_clk;
  604. }
  605. //------------------------------------------------------------------------------------
  606. esp_err_t IRAM_ATTR spi_lobo_device_select(spi_lobo_device_handle_t handle, int force)
  607. {
  608. if (handle == NULL) return ESP_ERR_INVALID_ARG;
  609. if ((handle->cfg.selected == 1) && (!force)) return ESP_OK; // already selected
  610. int i;
  611. spi_lobo_host_t *host=(spi_lobo_host_t*)handle->host;
  612. // find device's host bus
  613. for (i=0; i<NO_DEV; i++) {
  614. if (host->device[i] == handle) break;
  615. }
  616. if (i == NO_DEV) return ESP_ERR_INVALID_ARG;
  617. if (!(xSemaphoreTake(host->spi_lobo_bus_mutex, SPI_SEMAPHORE_WAIT))) return ESP_ERR_INVALID_STATE;
  618. // Check if previously used device's bus device is the same
  619. if (memcmp(&host->cur_bus_config, &handle->bus_config, sizeof(spi_lobo_bus_config_t)) != 0) {
  620. // device has different bus configuration, we need to reconfigure the bus
  621. esp_err_t err = spi_lobo_bus_free(1, 0);
  622. if (err) {
  623. xSemaphoreGive(host->spi_lobo_bus_mutex);
  624. return err;
  625. }
  626. err = spi_lobo_bus_initialize(i, &handle->bus_config, -1);
  627. if (err) {
  628. xSemaphoreGive(host->spi_lobo_bus_mutex);
  629. return err;
  630. }
  631. }
  632. //Reconfigure according to device settings, but only if the device changed or forced.
  633. if ((force) || (host->device[host->cur_device] != handle)) {
  634. //Assumes a hardcoded 80MHz Fapb for now. ToDo: figure out something better once we have clock scaling working.
  635. int apbclk=APB_CLK_FREQ;
  636. //Speeds >=40MHz over GPIO matrix needs a dummy cycle, but these don't work for full-duplex connections.
  637. if (((handle->cfg.flags & LB_SPI_DEVICE_HALFDUPLEX) == 0) && (handle->cfg.clock_speed_hz > ((apbclk*2)/5)) && (!host->no_gpio_matrix)) {
  638. // set speed to 32 MHz
  639. handle->cfg.clock_speed_hz = (apbclk*2)/5;
  640. }
  641. int effclk=spi_set_clock(host->hw, apbclk, handle->cfg.clock_speed_hz, handle->cfg.duty_cycle_pos);
  642. //Configure bit order
  643. host->hw->ctrl.rd_bit_order=(handle->cfg.flags & LB_SPI_DEVICE_RXBIT_LSBFIRST)?1:0;
  644. host->hw->ctrl.wr_bit_order=(handle->cfg.flags & LB_SPI_DEVICE_TXBIT_LSBFIRST)?1:0;
  645. //Configure polarity
  646. //SPI iface needs to be configured for a delay in some cases.
  647. int nodelay=0;
  648. int extra_dummy=0;
  649. if (host->no_gpio_matrix) {
  650. if (effclk >= apbclk/2) {
  651. nodelay=1;
  652. }
  653. } else {
  654. if (effclk >= apbclk/2) {
  655. nodelay=1;
  656. extra_dummy=1; //Note: This only works on half-duplex connections. spi_lobo_bus_add_device checks for this.
  657. } else if (effclk >= apbclk/4) {
  658. nodelay=1;
  659. }
  660. }
  661. if (handle->cfg.mode==0) {
  662. host->hw->pin.ck_idle_edge=0;
  663. host->hw->user.ck_out_edge=0;
  664. host->hw->ctrl2.miso_delay_mode=nodelay?0:2;
  665. } else if (handle->cfg.mode==1) {
  666. host->hw->pin.ck_idle_edge=0;
  667. host->hw->user.ck_out_edge=1;
  668. host->hw->ctrl2.miso_delay_mode=nodelay?0:1;
  669. } else if (handle->cfg.mode==2) {
  670. host->hw->pin.ck_idle_edge=1;
  671. host->hw->user.ck_out_edge=1;
  672. host->hw->ctrl2.miso_delay_mode=nodelay?0:1;
  673. } else if (handle->cfg.mode==3) {
  674. host->hw->pin.ck_idle_edge=1;
  675. host->hw->user.ck_out_edge=0;
  676. host->hw->ctrl2.miso_delay_mode=nodelay?0:2;
  677. }
  678. //Configure bit sizes, load addr and command
  679. host->hw->user.usr_dummy=(handle->cfg.dummy_bits+extra_dummy)?1:0;
  680. host->hw->user.usr_addr=(handle->cfg.address_bits)?1:0;
  681. host->hw->user.usr_command=(handle->cfg.command_bits)?1:0;
  682. host->hw->user1.usr_addr_bitlen=handle->cfg.address_bits-1;
  683. host->hw->user1.usr_dummy_cyclelen=handle->cfg.dummy_bits+extra_dummy-1;
  684. host->hw->user2.usr_command_bitlen=handle->cfg.command_bits-1;
  685. //Configure misc stuff
  686. host->hw->user.doutdin=(handle->cfg.flags & LB_SPI_DEVICE_HALFDUPLEX)?0:1;
  687. host->hw->user.sio=(handle->cfg.flags & LB_SPI_DEVICE_3WIRE)?1:0;
  688. host->hw->ctrl2.setup_time=handle->cfg.cs_ena_pretrans-1;
  689. host->hw->user.cs_setup=handle->cfg.cs_ena_pretrans?1:0;
  690. host->hw->ctrl2.hold_time=handle->cfg.cs_ena_posttrans-1;
  691. host->hw->user.cs_hold=(handle->cfg.cs_ena_posttrans)?1:0;
  692. //Configure CS pin
  693. host->hw->pin.cs0_dis=(i==0)?0:1;
  694. host->hw->pin.cs1_dis=(i==1)?0:1;
  695. host->hw->pin.cs2_dis=(i==2)?0:1;
  696. host->cur_device = i;
  697. }
  698. if ((handle->cfg.spics_io_num < 0) && (handle->cfg.spics_ext_io_num > 0)) {
  699. gpio_set_level(handle->cfg.spics_ext_io_num, 0);
  700. }
  701. handle->cfg.selected = 1;
  702. return ESP_OK;
  703. }
  704. //---------------------------------------------------------------------------
  705. esp_err_t IRAM_ATTR spi_lobo_device_deselect(spi_lobo_device_handle_t handle)
  706. {
  707. if (handle == NULL) return ESP_ERR_INVALID_ARG;
  708. if (handle->cfg.selected == 0) return ESP_OK; // already deselected
  709. int i;
  710. spi_lobo_host_t *host=(spi_lobo_host_t*)handle->host;
  711. for (i=0; i<NO_DEV; i++) {
  712. if (host->device[i] == handle) break;
  713. }
  714. if (i == NO_DEV) return ESP_ERR_INVALID_ARG;
  715. if (host->device[host->cur_device] == handle) {
  716. if ((handle->cfg.spics_io_num < 0) && (handle->cfg.spics_ext_io_num > 0)) {
  717. gpio_set_level(handle->cfg.spics_ext_io_num, 1);
  718. }
  719. }
  720. handle->cfg.selected = 0;
  721. xSemaphoreGive(host->spi_lobo_bus_mutex);
  722. return ESP_OK;
  723. }
  724. //--------------------------------------------------------------------------------
  725. esp_err_t IRAM_ATTR spi_lobo_device_TakeSemaphore(spi_lobo_device_handle_t handle)
  726. {
  727. if (!(xSemaphoreTake(handle->host->spi_lobo_bus_mutex, SPI_SEMAPHORE_WAIT))) return ESP_ERR_INVALID_STATE;
  728. else return ESP_OK;
  729. }
  730. //---------------------------------------------------------------------------
  731. void IRAM_ATTR spi_lobo_device_GiveSemaphore(spi_lobo_device_handle_t handle)
  732. {
  733. xSemaphoreTake(handle->host->spi_lobo_bus_mutex, portMAX_DELAY);
  734. }
  735. //----------------------------------------------------------
  736. uint32_t spi_lobo_get_speed(spi_lobo_device_handle_t handle)
  737. {
  738. spi_lobo_host_t *host=(spi_lobo_host_t*)handle->host;
  739. uint32_t speed = 0;
  740. if (spi_lobo_device_select(handle, 0) == ESP_OK) {
  741. if (host->hw->clock.clk_equ_sysclk == 1) speed = 80000000;
  742. else speed = 80000000/(host->hw->clock.clkdiv_pre+1)/(host->hw->clock.clkcnt_n+1);
  743. }
  744. spi_lobo_device_deselect(handle);
  745. return speed;
  746. }
  747. //--------------------------------------------------------------------------
  748. uint32_t spi_lobo_set_speed(spi_lobo_device_handle_t handle, uint32_t speed)
  749. {
  750. spi_lobo_host_t *host=(spi_lobo_host_t*)handle->host;
  751. uint32_t newspeed = 0;
  752. if (spi_lobo_device_select(handle, 0) == ESP_OK) {
  753. spi_lobo_device_deselect(handle);
  754. handle->cfg.clock_speed_hz = speed;
  755. if (spi_lobo_device_select(handle, 1) == ESP_OK) {
  756. if (host->hw->clock.clk_equ_sysclk == 1) newspeed = 80000000;
  757. else newspeed = 80000000/(host->hw->clock.clkdiv_pre+1)/(host->hw->clock.clkcnt_n+1);
  758. }
  759. }
  760. spi_lobo_device_deselect(handle);
  761. return newspeed;
  762. }
  763. //-------------------------------------------------------------
  764. bool spi_lobo_uses_native_pins(spi_lobo_device_handle_t handle)
  765. {
  766. return handle->host->no_gpio_matrix;
  767. }
  768. //-------------------------------------------------------------------
  769. void spi_lobo_get_native_pins(int host, int *sdi, int *sdo, int *sck)
  770. {
  771. *sdo = io_signal[host].spid_native;
  772. *sdi = io_signal[host].spiq_native;
  773. *sck = io_signal[host].spiclk_native;
  774. }
  775. /*
  776. When using 'spi_lobo_transfer_data' function we can have several scenarios:
  777. A: Send only (trans->rxlength = 0)
  778. B: Receive only (trans->txlength = 0)
  779. C: Send & receive (trans->txlength > 0 & trans->rxlength > 0)
  780. D: No operation (trans->txlength = 0 & trans->rxlength = 0)
  781. */
  782. //----------------------------------------------------------------------------------------------------------
  783. esp_err_t IRAM_ATTR spi_lobo_transfer_data(spi_lobo_device_handle_t handle, spi_lobo_transaction_t *trans) {
  784. if (!handle) return ESP_ERR_INVALID_ARG;
  785. // *** For now we can only handle 8-bit bytes transmission
  786. if (((trans->length % 8) != 0) || ((trans->rxlength % 8) != 0)) return ESP_ERR_INVALID_ARG;
  787. spi_lobo_host_t *host=(spi_lobo_host_t*)handle->host;
  788. esp_err_t ret;
  789. uint8_t do_deselect = 0;
  790. const uint8_t *txbuffer = NULL;
  791. uint8_t *rxbuffer = NULL;
  792. if (trans->flags & LB_SPI_TRANS_USE_TXDATA) {
  793. // Send data from 'trans->tx_data'
  794. txbuffer=(uint8_t*)&trans->tx_data[0];
  795. } else {
  796. // Send data from 'trans->tx_buffer'
  797. txbuffer=(uint8_t*)trans->tx_buffer;
  798. }
  799. if (trans->flags & LB_SPI_TRANS_USE_RXDATA) {
  800. // Receive data to 'trans->rx_data'
  801. rxbuffer=(uint8_t*)&trans->rx_data[0];
  802. } else {
  803. // Receive data to 'trans->rx_buffer'
  804. rxbuffer=(uint8_t*)trans->rx_buffer;
  805. }
  806. // ** Set transmit & receive length in bytes
  807. uint32_t txlen = trans->length / 8;
  808. uint32_t rxlen = trans->rxlength / 8;
  809. if (txbuffer == NULL) txlen = 0;
  810. if (rxbuffer == NULL) rxlen = 0;
  811. if ((rxlen == 0) && (txlen == 0)) {
  812. // ** NOTHING TO SEND or RECEIVE, return
  813. return ESP_ERR_INVALID_ARG;
  814. }
  815. // If using 'trans->tx_data' and/or 'trans->rx_data', maximum 4 bytes can be sent/received
  816. if ((txbuffer == &trans->tx_data[0]) && (txlen > 4)) return ESP_ERR_INVALID_ARG;
  817. if ((rxbuffer == &trans->rx_data[0]) && (rxlen > 4)) return ESP_ERR_INVALID_ARG;
  818. // --- Wait for SPI bus ready ---
  819. while (host->hw->cmd.usr);
  820. // ** If the device was not selected, select it
  821. if (handle->cfg.selected == 0) {
  822. ret = spi_lobo_device_select(handle, 0);
  823. if (ret) return ret;
  824. do_deselect = 1; // We will deselect the device after the operation !
  825. }
  826. // ** Call pre-transmission callback, if any
  827. if (handle->cfg.pre_cb) handle->cfg.pre_cb(trans);
  828. // Test if operating in full duplex mode
  829. uint8_t duplex = 1;
  830. if (handle->cfg.flags & LB_SPI_DEVICE_HALFDUPLEX) duplex = 0; // Half duplex mode !
  831. uint32_t bits, rdbits;
  832. uint32_t wd;
  833. uint8_t bc, rdidx;
  834. uint32_t rdcount = rxlen; // Total number of bytes to read
  835. uint32_t count = 0; // number of bytes transmitted
  836. uint32_t rd_read = 0; // Number of bytes read so far
  837. host->hw->user.usr_mosi_highpart = 0; // use the whole spi buffer
  838. // ** Check if address phase will be used
  839. host->hw->user2.usr_command_value=trans->command;
  840. if (handle->cfg.address_bits>32) {
  841. host->hw->addr=trans->address >> 32;
  842. host->hw->slv_wr_status=trans->address & 0xffffffff;
  843. } else {
  844. host->hw->addr=trans->address & 0xffffffff;
  845. }
  846. // Check if we have to transmit some data
  847. if (txlen > 0) {
  848. host->hw->user.usr_mosi = 1;
  849. uint8_t idx;
  850. bits = 0; // remaining bits to send
  851. idx = 0; // index to spi hw data_buf (16 32-bit words, 64 bytes, 512 bits)
  852. // ** Transmit 'txlen' bytes
  853. while (count < txlen) {
  854. wd = 0;
  855. for (bc=0;bc<32;bc+=8) {
  856. wd |= (uint32_t)txbuffer[count] << bc;
  857. count++; // Increment sent data count
  858. bits += 8; // Increment bits count
  859. if (count == txlen) break; // If all transmit data pushed to hw spi buffer break from the loop
  860. }
  861. host->hw->data_buf[idx] = wd;
  862. idx++;
  863. if (idx == 16) {
  864. // hw SPI buffer full (all 64 bytes filled, START THE TRANSSACTION
  865. host->hw->mosi_dlen.usr_mosi_dbitlen=bits-1; // Set mosi dbitlen
  866. if ((duplex) && (rdcount > 0)) {
  867. // In full duplex mode we are receiving while sending !
  868. host->hw->miso_dlen.usr_miso_dbitlen = bits-1; // Set miso dbitlen
  869. host->hw->user.usr_miso = 1;
  870. }
  871. else {
  872. host->hw->miso_dlen.usr_miso_dbitlen = 0; // In half duplex mode nothing will be received
  873. host->hw->user.usr_miso = 0;
  874. }
  875. // ** Start the transaction ***
  876. host->hw->cmd.usr=1;
  877. // Wait the transaction to finish
  878. while (host->hw->cmd.usr);
  879. if ((duplex) && (rdcount > 0)) {
  880. // *** in full duplex mode transfer received data to input buffer ***
  881. rdidx = 0;
  882. while (bits > 0) {
  883. wd = host->hw->data_buf[rdidx];
  884. rdidx++;
  885. for (bc=0;bc<32;bc+=8) { // get max 4 bytes
  886. rxbuffer[rd_read++] = (uint8_t)((wd >> bc) & 0xFF);
  887. rdcount--;
  888. bits -= 8;
  889. if (rdcount == 0) {
  890. bits = 0;
  891. break; // Finished reading data
  892. }
  893. }
  894. }
  895. }
  896. bits = 0; // nothing in hw spi buffer yet
  897. idx = 0; // start from the beginning of the hw spi buffer
  898. }
  899. }
  900. // *** All transmit data are sent or pushed to hw spi buffer
  901. // bits > 0 IF THERE ARE SOME DATA STILL WAITING IN THE HW SPI TRANSMIT BUFFER
  902. if (bits > 0) {
  903. // ** WE HAVE SOME DATA IN THE HW SPI TRANSMIT BUFFER
  904. host->hw->mosi_dlen.usr_mosi_dbitlen = bits-1; // Set mosi dbitlen
  905. if ((duplex) && (rdcount > 0)) {
  906. // In full duplex mode we are receiving while sending !
  907. host->hw->miso_dlen.usr_miso_dbitlen = bits-1; // Set miso dbitlen
  908. host->hw->user.usr_miso = 1;
  909. }
  910. else {
  911. host->hw->miso_dlen.usr_miso_dbitlen = 0; // In half duplex mode nothing will be received
  912. host->hw->user.usr_miso = 0;
  913. }
  914. // ** Start the transaction ***
  915. host->hw->cmd.usr=1;
  916. // Wait the transaction to finish
  917. while (host->hw->cmd.usr);
  918. if ((duplex) && (rdcount > 0)) {
  919. // *** in full duplex mode transfer received data to input buffer ***
  920. rdidx = 0;
  921. while (bits > 0) {
  922. wd = host->hw->data_buf[rdidx];
  923. rdidx++;
  924. for (bc=0;bc<32;bc+=8) { // get max 4 bytes
  925. rxbuffer[rd_read++] = (uint8_t)((wd >> bc) & 0xFF);
  926. rdcount--;
  927. bits -= 8;
  928. if (bits == 0) break;
  929. if (rdcount == 0) {
  930. bits = 0;
  931. break; // Finished reading data
  932. }
  933. }
  934. }
  935. }
  936. }
  937. //if (duplex) rdcount = 0; // In duplex mode receive only as many bytes as was transmitted
  938. }
  939. // ------------------------------------------------------------------------
  940. // *** If rdcount = 0 we have nothing to receive and we exit the function
  941. // This is true if no data receive was requested,
  942. // or all the data was received in Full duplex mode during the transmission
  943. // ------------------------------------------------------------------------
  944. if (rdcount > 0) {
  945. // ----------------------------------------------------------------------------------------------------------------
  946. // *** rdcount > 0, we have to receive some data
  947. // This is true if we operate in Half duplex mode when receiving after transmission is done,
  948. // or not all data was received in Full duplex mode during the transmission (trans->rxlength > trans->txlength)
  949. // ----------------------------------------------------------------------------------------------------------------
  950. host->hw->user.usr_mosi = 0; // do not send
  951. host->hw->user.usr_miso = 1; // do receive
  952. while (rdcount > 0) {
  953. if (rdcount <= 64) rdbits = rdcount * 8;
  954. else rdbits = 64 * 8;
  955. // Load receive buffer
  956. host->hw->mosi_dlen.usr_mosi_dbitlen=0;
  957. host->hw->miso_dlen.usr_miso_dbitlen=rdbits-1;
  958. // ** Start the transaction ***
  959. host->hw->cmd.usr=1;
  960. // Wait the transaction to finish
  961. while (host->hw->cmd.usr);
  962. // *** transfer received data to input buffer ***
  963. rdidx = 0;
  964. while (rdbits > 0) {
  965. wd = host->hw->data_buf[rdidx];
  966. rdidx++;
  967. for (bc=0;bc<32;bc+=8) {
  968. rxbuffer[rd_read++] = (uint8_t)((wd >> bc) & 0xFF);
  969. rdcount--;
  970. rdbits -= 8;
  971. if (rdcount == 0) {
  972. rdbits = 0;
  973. break;
  974. }
  975. }
  976. }
  977. }
  978. }
  979. // ** Call post-transmission callback, if any
  980. if (handle->cfg.post_cb) handle->cfg.post_cb(trans);
  981. if (do_deselect) {
  982. // Spi device was selected in this function, we have to deselect it now
  983. ret = spi_lobo_device_deselect(handle);
  984. if (ret) return ret;
  985. }
  986. return ESP_OK;
  987. }