PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

hal_aci_tl.cpp 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. /* Copyright (c) 2009 Nordic Semiconductor. All Rights Reserved.
  2. *
  3. * The information contained herein is property of Nordic Semiconductor ASA.
  4. * Terms and conditions of usage are described in detail in NORDIC
  5. * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
  6. *
  7. * Licensees are granted free, non-transferable use of the information. NO
  8. * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
  9. * the file.
  10. *
  11. * $LastChangedRevision: 4808 $
  12. */
  13. /** @file
  14. @brief Implementation of the ACI transport layer module
  15. */
  16. #include <SPI.h>
  17. #include "hal_platform.h"
  18. #include "hal/hal_aci_tl.h"
  19. #include "hal/hal_io.h"
  20. #include "ble_system.h"
  21. #include <avr/sleep.h>
  22. extern int8_t HAL_IO_RADIO_RESET, HAL_IO_RADIO_REQN, HAL_IO_RADIO_RDY, HAL_IO_RADIO_IRQ;
  23. #ifdef SPI_HAS_TRANSACTION
  24. static volatile uint8_t doing_aci_transaction = 0;
  25. #endif
  26. static const uint8_t dreqinttable[] = {
  27. #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined (__AVR_ATmega328__) || defined(__AVR_ATmega8__)
  28. 2, 0,
  29. 3, 1,
  30. #elif defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)
  31. 2, 0,
  32. 3, 1,
  33. 21, 2,
  34. 20, 3,
  35. 19, 4,
  36. 18, 5,
  37. #elif defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY)
  38. 5, 0,
  39. 6, 1,
  40. 7, 2,
  41. 8, 3,
  42. #elif defined(__AVR_AT90USB1286__) && defined(CORE_TEENSY)
  43. 0, 0,
  44. 1, 1,
  45. 2, 2,
  46. 3, 3,
  47. 36, 4,
  48. 37, 5,
  49. 18, 6,
  50. 19, 7,
  51. #elif defined(__arm__) && defined(CORE_TEENSY)
  52. 0, 0, 1, 1, 2, 2, 3, 3, 4, 4,
  53. 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
  54. 10, 10, 11, 11, 12, 12, 13, 13, 14, 14,
  55. 15, 15, 16, 16, 17, 17, 18, 18, 19, 19,
  56. 20, 20, 21, 21, 22, 22, 23, 23, 24, 24,
  57. 25, 25, 26, 26, 27, 27, 28, 28, 29, 29,
  58. 30, 30, 31, 31, 32, 32, 33, 33,
  59. #elif defined(__AVR_ATmega32U4__)
  60. 7, 4,
  61. 3, 0,
  62. 2, 1,
  63. 0, 2,
  64. 1, 3,
  65. #elif defined(__AVR_ATmega256RFR2__)
  66. 4, 0,
  67. 5, 1,
  68. 15, 2,
  69. 16, 3,
  70. 13, 4,
  71. 14, 5,
  72. 7, 6,
  73. 18, 7,
  74. #endif
  75. };
  76. static void m_print_aci_data(hal_aci_data_t *p_data);
  77. typedef struct {
  78. hal_aci_data_t aci_data[ACI_QUEUE_SIZE];
  79. uint8_t head;
  80. uint8_t tail;
  81. } aci_queue_t;
  82. static hal_aci_data_t received_data;
  83. static uint8_t spi_readwrite(uint8_t aci_byte);
  84. static bool aci_debug_print;
  85. static aci_queue_t aci_tx_q;
  86. static aci_queue_t aci_rx_q;
  87. static void m_aci_q_init(aci_queue_t *aci_q)
  88. {
  89. uint8_t loop;
  90. aci_debug_print = false;
  91. aci_q->head = 0;
  92. aci_q->tail = 0;
  93. for(loop=0; loop<ACI_QUEUE_SIZE; loop++)
  94. {
  95. aci_tx_q.aci_data[loop].buffer[0] = 0x00;
  96. aci_tx_q.aci_data[loop].buffer[1] = 0x00;
  97. }
  98. }
  99. void hal_aci_debug_print(bool enable)
  100. {
  101. aci_debug_print = enable;
  102. }
  103. static bool m_aci_q_enqueue(aci_queue_t *aci_q, hal_aci_data_t *p_data)
  104. {
  105. const uint8_t next = (aci_q->tail + 1) % ACI_QUEUE_SIZE;
  106. const uint8_t length = p_data->buffer[0];
  107. if (next == aci_q->head)
  108. {
  109. /* full queue */
  110. return false;
  111. }
  112. aci_q->aci_data[aci_q->tail].status_byte = 0;
  113. memcpy((uint8_t *)&(aci_q->aci_data[aci_q->tail].buffer[0]), (uint8_t *)&p_data->buffer[0], length + 1);
  114. aci_q->tail = next;
  115. return true;
  116. }
  117. //@comment after a port have test for the queue states, esp. the full and the empty states
  118. static bool m_aci_q_dequeue(aci_queue_t *aci_q, hal_aci_data_t *p_data)
  119. {
  120. if (aci_q->head == aci_q->tail)
  121. {
  122. /* empty queue */
  123. return false;
  124. }
  125. memcpy((uint8_t *)p_data, (uint8_t *)&(aci_q->aci_data[aci_q->head]), sizeof(hal_aci_data_t));
  126. aci_q->head = (aci_q->head + 1) % ACI_QUEUE_SIZE;
  127. return true;
  128. }
  129. static bool m_aci_q_is_empty(aci_queue_t *aci_q)
  130. {
  131. return (aci_q->head == aci_q->tail);
  132. }
  133. static bool m_aci_q_is_full(aci_queue_t *aci_q)
  134. {
  135. uint8_t next;
  136. bool state;
  137. //This should be done in a critical section
  138. noInterrupts();
  139. next = (aci_q->tail + 1) % ACI_QUEUE_SIZE;
  140. if (next == aci_q->head)
  141. {
  142. state = true;
  143. }
  144. else
  145. {
  146. state = false;
  147. }
  148. interrupts();
  149. //end
  150. return state;
  151. }
  152. void m_print_aci_data(hal_aci_data_t *p_data)
  153. {
  154. const uint8_t length = p_data->buffer[0];
  155. uint8_t i;
  156. Serial.print(length, DEC);
  157. Serial.print(" :");
  158. for (i=0; i<=length; i++)
  159. {
  160. Serial.print(p_data->buffer[i], HEX);
  161. Serial.print(F(", "));
  162. }
  163. Serial.println(F(""));
  164. }
  165. static void toggle_eimsk(bool state)
  166. {
  167. /* ToDo: This will currently only work with the UNO/ATMega48/88/128/328 */
  168. /* due to EIMSK. Abstract this away to something MCU nuetral! */
  169. if (HAL_IO_RADIO_IRQ != 0xFF)
  170. {
  171. if (state)
  172. EIMSK |= (1 << HAL_IO_RADIO_IRQ);
  173. else
  174. EIMSK &= ~(1 << HAL_IO_RADIO_IRQ);
  175. }
  176. else
  177. {
  178. /* RDY isn't a valid HW INT pin! */
  179. while(1);
  180. }
  181. }
  182. void m_rdy_line_handle(void)
  183. {
  184. hal_aci_data_t *p_aci_data;
  185. sleep_disable();
  186. detachInterrupt(HAL_IO_RADIO_IRQ);
  187. // Receive or transmit data
  188. p_aci_data = hal_aci_tl_poll_get();
  189. // Check if we received data
  190. if (p_aci_data->buffer[0] > 0)
  191. {
  192. if (!m_aci_q_enqueue(&aci_rx_q, p_aci_data))
  193. {
  194. /* Receive Buffer full.
  195. Should never happen.
  196. Spin in a while loop.
  197. */
  198. while(1);
  199. }
  200. if (m_aci_q_is_full(&aci_rx_q))
  201. {
  202. /* Disable RDY line interrupt.
  203. Will latch any pending RDY lines, so when enabled it again this
  204. routine should be taken again */
  205. toggle_eimsk(false);
  206. }
  207. }
  208. }
  209. bool hal_aci_tl_event_get(hal_aci_data_t *p_aci_data)
  210. {
  211. bool was_full = m_aci_q_is_full(&aci_rx_q);
  212. if (m_aci_q_dequeue(&aci_rx_q, p_aci_data))
  213. {
  214. if (true == aci_debug_print)
  215. {
  216. Serial.print(" E");
  217. m_print_aci_data(p_aci_data);
  218. }
  219. if (was_full)
  220. {
  221. toggle_eimsk(true);
  222. }
  223. return true;
  224. }
  225. else
  226. {
  227. return false;
  228. }
  229. }
  230. void hal_aci_tl_init()
  231. {
  232. received_data.buffer[0] = 0;
  233. SPI.begin();
  234. SPI.setBitOrder(LSBFIRST);
  235. SPI.setClockDivider(SPI_CLOCK_DIV8);
  236. SPI.setDataMode(SPI_MODE0);
  237. /* initialize aci cmd queue */
  238. m_aci_q_init(&aci_tx_q);
  239. m_aci_q_init(&aci_rx_q);
  240. //Configure the IO lines
  241. pinMode(HAL_IO_RADIO_RESET, OUTPUT);
  242. pinMode(HAL_IO_RADIO_RDY, INPUT_PULLUP);
  243. pinMode(HAL_IO_RADIO_REQN, OUTPUT);
  244. digitalWrite(HAL_IO_RADIO_RESET, 1);
  245. delay(100);
  246. digitalWrite(HAL_IO_RADIO_RESET, 0);
  247. #ifdef __arm__
  248. delayMicroseconds(10);
  249. #endif
  250. digitalWrite(HAL_IO_RADIO_RESET, 1);
  251. digitalWrite(SCK, 0);
  252. digitalWrite(MOSI, 0);
  253. digitalWrite(HAL_IO_RADIO_REQN, 1);
  254. digitalWrite(SCK, 0);
  255. HAL_IO_RADIO_IRQ = 0xFF;
  256. for (uint8_t i=0; i<sizeof(dreqinttable); i+=2) {
  257. if (HAL_IO_RADIO_RDY == dreqinttable[i]) {
  258. HAL_IO_RADIO_IRQ = dreqinttable[i+1];
  259. }
  260. }
  261. delay(30); //Wait for the nRF8001 to get hold of its lines - the lines float for a few ms after the reset
  262. if (HAL_IO_RADIO_IRQ != 0xFF) {
  263. #ifdef SPI_HAS_TRANSACTION
  264. doing_aci_transaction = 0;
  265. SPI.usingInterrupt(HAL_IO_RADIO_IRQ);
  266. #endif
  267. attachInterrupt(HAL_IO_RADIO_IRQ, m_rdy_line_handle, LOW);
  268. }
  269. // We use the LOW level of the RDYN line as the atmega328 can wakeup from sleep only on LOW
  270. }
  271. bool hal_aci_tl_send(hal_aci_data_t *p_aci_cmd)
  272. {
  273. const uint8_t length = p_aci_cmd->buffer[0];
  274. bool ret_val = false;
  275. if (length > HAL_ACI_MAX_LENGTH)
  276. {
  277. return false;
  278. }
  279. else
  280. {
  281. if (m_aci_q_enqueue(&aci_tx_q, p_aci_cmd))
  282. {
  283. ret_val = true;
  284. }
  285. }
  286. if (true == aci_debug_print)
  287. {
  288. Serial.print("C");
  289. m_print_aci_data(p_aci_cmd);
  290. }
  291. #ifdef SPI_HAS_TRANSACTION
  292. while (doing_aci_transaction) /*wait*/ ;
  293. SPI.beginTransaction(SPISettings(2000000, LSBFIRST, SPI_MODE0));
  294. doing_aci_transaction = 1;
  295. HAL_IO_SET_STATE(HAL_IO_RADIO_REQN, 0);
  296. toggle_eimsk(true);
  297. #else
  298. HAL_IO_SET_STATE(HAL_IO_RADIO_REQN, 0);
  299. #endif
  300. return ret_val;
  301. }
  302. hal_aci_data_t * hal_aci_tl_poll_get(void)
  303. {
  304. uint8_t byte_cnt;
  305. uint8_t byte_sent_cnt;
  306. uint8_t max_bytes;
  307. hal_aci_data_t data_to_send;
  308. //SPI.begin();
  309. #ifdef SPI_HAS_TRANSACTION
  310. if (!doing_aci_transaction) {
  311. doing_aci_transaction = 1;
  312. SPI.beginTransaction(SPISettings(2000000, LSBFIRST, SPI_MODE0));
  313. }
  314. #endif
  315. HAL_IO_SET_STATE(HAL_IO_RADIO_REQN, 0);
  316. // Receive from queue
  317. if (m_aci_q_dequeue(&aci_tx_q, &data_to_send) == false)
  318. {
  319. /* queue was empty, nothing to send */
  320. data_to_send.status_byte = 0;
  321. data_to_send.buffer[0] = 0;
  322. }
  323. //Change this if your mcu has DMA for the master SPI
  324. // Send length, receive header
  325. byte_sent_cnt = 0;
  326. received_data.status_byte = spi_readwrite(data_to_send.buffer[byte_sent_cnt++]);
  327. // Send first byte, receive length from slave
  328. received_data.buffer[0] = spi_readwrite(data_to_send.buffer[byte_sent_cnt++]);
  329. if (0 == data_to_send.buffer[0])
  330. {
  331. max_bytes = received_data.buffer[0];
  332. }
  333. else
  334. {
  335. // Set the maximum to the biggest size. One command byte is already sent
  336. max_bytes = (received_data.buffer[0] > (data_to_send.buffer[0] - 1))
  337. ? received_data.buffer[0] : (data_to_send.buffer[0] - 1);
  338. }
  339. if (max_bytes > HAL_ACI_MAX_LENGTH)
  340. {
  341. max_bytes = HAL_ACI_MAX_LENGTH;
  342. }
  343. // Transmit/receive the rest of the packet
  344. for (byte_cnt = 0; byte_cnt < max_bytes; byte_cnt++)
  345. {
  346. received_data.buffer[byte_cnt+1] = spi_readwrite(data_to_send.buffer[byte_sent_cnt++]);
  347. }
  348. HAL_IO_SET_STATE(HAL_IO_RADIO_REQN, 1);
  349. //SPI.end()
  350. //RDYN should follow the REQN line in approx 100ns
  351. #ifdef SPI_HAS_TRANSACTION
  352. SPI.endTransaction();
  353. doing_aci_transaction = 0;
  354. #endif
  355. sleep_enable();
  356. attachInterrupt(HAL_IO_RADIO_IRQ, m_rdy_line_handle, LOW);
  357. if (false == m_aci_q_is_empty(&aci_tx_q))
  358. {
  359. //Lower the REQN line to start a new ACI transaction
  360. #ifdef SPI_HAS_TRANSACTION
  361. doing_aci_transaction = 1;
  362. SPI.beginTransaction(SPISettings(2000000, LSBFIRST, SPI_MODE0));
  363. toggle_eimsk(true);
  364. #endif
  365. HAL_IO_SET_STATE(HAL_IO_RADIO_REQN, 0);
  366. }
  367. /* valid Rx available or transmit finished*/
  368. return (&received_data);
  369. }
  370. static uint8_t spi_readwrite(const uint8_t aci_byte)
  371. {
  372. return SPI.transfer(aci_byte);
  373. }
  374. void m_aci_q_flush(void)
  375. {
  376. noInterrupts();
  377. /* re-initialize aci cmd queue and aci event queue to flush them*/
  378. m_aci_q_init(&aci_tx_q);
  379. m_aci_q_init(&aci_rx_q);
  380. interrupts();
  381. }