Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 

1154 řádky
44 KiB

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