spi_host_cxx.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /*
  2. * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #if __cpp_exceptions
  7. #include <stdint.h>
  8. #include <cstring>
  9. #include "freertos/FreeRTOS.h"
  10. #include "freertos/portmacro.h"
  11. #include "hal/spi_types.h"
  12. #include "driver/spi_master.h"
  13. #include "spi_host_cxx.hpp"
  14. #include "spi_host_private_cxx.hpp"
  15. using namespace std;
  16. namespace idf {
  17. SPIException::SPIException(esp_err_t error) : ESPException(error) { }
  18. SPITransferException::SPITransferException(esp_err_t error) : SPIException(error) { }
  19. SPIMaster::SPIMaster(SPINum host,
  20. const MOSI &mosi,
  21. const MISO &miso,
  22. const SCLK &sclk,
  23. SPI_DMAConfig dma_config,
  24. SPITransferSize transfer_size)
  25. : spi_host(host)
  26. {
  27. spi_bus_config_t bus_config = {};
  28. bus_config.mosi_io_num = mosi.get_num();
  29. bus_config.miso_io_num = miso.get_num();
  30. bus_config.sclk_io_num = sclk.get_num();
  31. bus_config.quadwp_io_num = -1;
  32. bus_config.quadhd_io_num = -1;
  33. bus_config.max_transfer_sz = transfer_size.get_value();
  34. SPI_CHECK_THROW(spi_bus_initialize(spi_num_to_driver_type(spi_host), &bus_config, dma_config.get_num()));
  35. }
  36. SPIMaster::SPIMaster(SPINum host,
  37. const MOSI &mosi,
  38. const MISO &miso,
  39. const SCLK &sclk,
  40. const QSPIWP &qspiwp,
  41. const QSPIHD &qspihd,
  42. SPI_DMAConfig dma_config,
  43. SPITransferSize transfer_size)
  44. : spi_host(host)
  45. {
  46. spi_bus_config_t bus_config = {};
  47. bus_config.mosi_io_num = mosi.get_num();
  48. bus_config.miso_io_num = miso.get_num();
  49. bus_config.sclk_io_num = sclk.get_num();
  50. bus_config.quadwp_io_num = qspiwp.get_num();
  51. bus_config.quadhd_io_num = qspihd.get_num();
  52. bus_config.max_transfer_sz = transfer_size.get_value();
  53. SPI_CHECK_THROW(spi_bus_initialize(spi_num_to_driver_type(spi_host), &bus_config, dma_config.get_num()));
  54. }
  55. SPIMaster::~SPIMaster()
  56. {
  57. spi_bus_free(spi_num_to_driver_type(spi_host));
  58. }
  59. shared_ptr<SPIDevice> SPIMaster::create_dev(CS cs, Frequency frequency)
  60. {
  61. return make_shared<SPIDevice>(spi_host, cs, frequency);
  62. }
  63. SPIFuture::SPIFuture()
  64. : transaction(), is_valid(false)
  65. {
  66. }
  67. SPIFuture::SPIFuture(shared_ptr<SPITransactionDescriptor> transaction)
  68. : transaction(transaction), is_valid(true)
  69. {
  70. }
  71. SPIFuture::SPIFuture(SPIFuture &&other) noexcept
  72. : transaction(std::move(other.transaction)), is_valid(true)
  73. {
  74. other.is_valid = false;
  75. }
  76. SPIFuture &SPIFuture::operator=(SPIFuture &&other) noexcept
  77. {
  78. if (this != &other) {
  79. transaction = std::move(other.transaction);
  80. is_valid = other.is_valid;
  81. other.is_valid = false;
  82. }
  83. return *this;
  84. }
  85. vector<uint8_t> SPIFuture::get()
  86. {
  87. if (!is_valid) {
  88. throw std::future_error(future_errc::no_state);
  89. }
  90. return transaction->get();
  91. }
  92. future_status SPIFuture::wait_for(chrono::milliseconds timeout)
  93. {
  94. if (transaction->wait_for(timeout)) {
  95. return std::future_status::ready;
  96. } else {
  97. return std::future_status::timeout;
  98. }
  99. }
  100. void SPIFuture::wait()
  101. {
  102. transaction->wait();
  103. }
  104. bool SPIFuture::valid() const noexcept
  105. {
  106. return is_valid;
  107. }
  108. SPIDevice::SPIDevice(SPINum spi_host, CS cs, Frequency frequency, QueueSize q_size) : device_handle()
  109. {
  110. device_handle = new SPIDeviceHandle(spi_host, cs, frequency, q_size);
  111. }
  112. SPIDevice::~SPIDevice()
  113. {
  114. delete device_handle;
  115. }
  116. SPIFuture SPIDevice::transfer(const vector<uint8_t> &data_to_send,
  117. std::function<void(void *)> pre_callback,
  118. std::function<void(void *)> post_callback,
  119. void* user_data)
  120. {
  121. current_transaction = make_shared<SPITransactionDescriptor>(data_to_send,
  122. device_handle,
  123. std::move(pre_callback),
  124. std::move(post_callback),
  125. user_data);
  126. current_transaction->start();
  127. return SPIFuture(current_transaction);
  128. }
  129. SPITransactionDescriptor::SPITransactionDescriptor(const std::vector<uint8_t> &data_to_send,
  130. SPIDeviceHandle *handle,
  131. std::function<void(void *)> pre_callback,
  132. std::function<void(void *)> post_callback,
  133. void* user_data_arg)
  134. : device_handle(handle),
  135. pre_callback(std::move(pre_callback)),
  136. post_callback(std::move(post_callback)),
  137. user_data(user_data_arg),
  138. received_data(false),
  139. started(false)
  140. {
  141. // C++11 vectors don't have size() or empty() members yet
  142. if (data_to_send.begin() == data_to_send.end()) {
  143. throw SPITransferException(ESP_ERR_INVALID_ARG);
  144. }
  145. if (handle == nullptr) {
  146. throw SPITransferException(ESP_ERR_INVALID_ARG);
  147. }
  148. size_t trans_size = data_to_send.size();
  149. spi_transaction_t *trans_desc;
  150. trans_desc = new spi_transaction_t;
  151. memset(trans_desc, 0, sizeof(spi_transaction_t));
  152. trans_desc->rx_buffer = new uint8_t [trans_size];
  153. tx_buffer = new uint8_t [trans_size];
  154. for (size_t i = 0; i < trans_size; i++) {
  155. tx_buffer[i] = data_to_send[i];
  156. }
  157. trans_desc->length = trans_size * 8;
  158. trans_desc->tx_buffer = tx_buffer;
  159. trans_desc->user = this;
  160. private_transaction_desc = trans_desc;
  161. }
  162. SPITransactionDescriptor::~SPITransactionDescriptor()
  163. {
  164. if (started) {
  165. assert(received_data); // We need to make sure that trans_desc has been received, otherwise the
  166. // driver may still write into it afterwards.
  167. }
  168. spi_transaction_t *trans_desc = reinterpret_cast<spi_transaction_t*>(private_transaction_desc);
  169. delete [] tx_buffer;
  170. delete [] static_cast<uint8_t*>(trans_desc->rx_buffer);
  171. delete trans_desc;
  172. }
  173. void SPITransactionDescriptor::start()
  174. {
  175. spi_transaction_t *trans_desc = reinterpret_cast<spi_transaction_t*>(private_transaction_desc);
  176. SPI_CHECK_THROW(device_handle->acquire_bus(portMAX_DELAY));
  177. SPI_CHECK_THROW(device_handle->queue_trans(trans_desc, 0));
  178. started = true;
  179. }
  180. void SPITransactionDescriptor::wait()
  181. {
  182. while (wait_for(chrono::milliseconds(portMAX_DELAY)) == false) { }
  183. }
  184. bool SPITransactionDescriptor::wait_for(const chrono::milliseconds &timeout_duration)
  185. {
  186. if (received_data) {
  187. return true;
  188. }
  189. if (!started) {
  190. throw SPITransferException(ESP_ERR_INVALID_STATE);
  191. }
  192. spi_transaction_t *acquired_trans_desc;
  193. esp_err_t err = device_handle->get_trans_result(&acquired_trans_desc,
  194. (TickType_t) timeout_duration.count() / portTICK_PERIOD_MS);
  195. if (err == ESP_ERR_TIMEOUT) {
  196. return false;
  197. }
  198. if (err != ESP_OK) {
  199. throw SPITransferException(err);
  200. }
  201. if (acquired_trans_desc != reinterpret_cast<spi_transaction_t*>(private_transaction_desc)) {
  202. throw SPITransferException(ESP_ERR_INVALID_STATE);
  203. }
  204. received_data = true;
  205. device_handle->release_bus();
  206. return true;
  207. }
  208. std::vector<uint8_t> SPITransactionDescriptor::get()
  209. {
  210. if (!received_data) {
  211. wait();
  212. }
  213. spi_transaction_t *trans_desc = reinterpret_cast<spi_transaction_t*>(private_transaction_desc);
  214. const size_t TRANSACTION_LENGTH = trans_desc->length / 8;
  215. vector<uint8_t> result(TRANSACTION_LENGTH);
  216. for (int i = 0; i < TRANSACTION_LENGTH; i++) {
  217. result[i] = static_cast<uint8_t*>(trans_desc->rx_buffer)[i];
  218. }
  219. return result;
  220. }
  221. } // idf
  222. #endif // __cpp_exceptions