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.

RH_NRF51.cpp 8.0KB

3 jaren geleden
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. // NRF51.cpp
  2. //
  3. // Per: nRF51_Series_Reference_manual v3.0.pdf
  4. // Copyright (C) 2012 Mike McCauley
  5. // $Id: RH_NRF51.cpp,v 1.1 2015/07/01 00:46:05 mikem Exp $
  6. // Set by Arduino IDE when compiling for nRF51 chips:
  7. #ifdef NRF51
  8. #include <RH_NRF51.h>
  9. RH_NRF51::RH_NRF51()
  10. : _rxBufValid(false)
  11. {
  12. }
  13. bool RH_NRF51::init()
  14. {
  15. // Enable the High Frequency clock to the system as a whole
  16. NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
  17. NRF_CLOCK->TASKS_HFCLKSTART = 1;
  18. /* Wait for the external oscillator to start up */
  19. while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) { }
  20. // Enables the DC/DC converter when the radio is enabled. Need this!
  21. NRF_POWER->DCDCEN = 0x00000001;
  22. // Disable and reset the radio
  23. NRF_RADIO->POWER = RADIO_POWER_POWER_Disabled;
  24. NRF_RADIO->POWER = RADIO_POWER_POWER_Enabled;
  25. NRF_RADIO->EVENTS_DISABLED = 0;
  26. NRF_RADIO->TASKS_DISABLE = 1;
  27. // Wait until we are in DISABLE state
  28. while (NRF_RADIO->EVENTS_DISABLED == 0) {}
  29. // Physical on-air address is set in PREFIX0 + BASE0 by setNetworkAddress
  30. NRF_RADIO->TXADDRESS = 0x00; // Use logical address 0 (PREFIX0 + BASE0)
  31. NRF_RADIO->RXADDRESSES = 0x01; // Enable reception on logical address 0 (PREFIX0 + BASE0)
  32. // Configure the CRC
  33. NRF_RADIO->CRCCNF = (RADIO_CRCCNF_LEN_Two << RADIO_CRCCNF_LEN_Pos); // Number of checksum bits
  34. NRF_RADIO->CRCINIT = 0xFFFFUL; // Initial value
  35. NRF_RADIO->CRCPOLY = 0x11021UL; // CRC poly: x^16+x^12^x^5+1
  36. // These shorts will make the radio transition from Ready to Start to Disable automatically
  37. // for both TX and RX, which makes for much shorter on-air times
  38. NRF_RADIO->SHORTS = (RADIO_SHORTS_READY_START_Enabled << RADIO_SHORTS_READY_START_Pos)
  39. | (RADIO_SHORTS_END_DISABLE_Enabled << RADIO_SHORTS_END_DISABLE_Pos);
  40. NRF_RADIO->PCNF0 = ((8 << RADIO_PCNF0_LFLEN_Pos) & RADIO_PCNF0_LFLEN_Msk); // Payload length in bits
  41. // Make sure we are powered down
  42. setModeIdle();
  43. // Set a default network address
  44. uint8_t default_network_address[] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7};
  45. setNetworkAddress(default_network_address, sizeof(default_network_address));
  46. setChannel(2); // The default, in case it was set by another app without powering down
  47. setRF(RH_NRF51::DataRate2Mbps, RH_NRF51::TransmitPower0dBm);
  48. return true;
  49. }
  50. bool RH_NRF51::setChannel(uint8_t channel)
  51. {
  52. NRF_RADIO->FREQUENCY = ((channel << RADIO_FREQUENCY_FREQUENCY_Pos) & RADIO_FREQUENCY_FREQUENCY_Msk);
  53. return true;
  54. }
  55. bool RH_NRF51::setNetworkAddress(uint8_t* address, uint8_t len)
  56. {
  57. if (len < 3 || len > 5)
  58. return false;
  59. // First byte is the prefix, remainder are base
  60. NRF_RADIO->PREFIX0 = ((address[0] << RADIO_PREFIX0_AP0_Pos) & RADIO_PREFIX0_AP0_Msk);
  61. uint32_t base;
  62. memcpy(&base, address+1, len-1);
  63. NRF_RADIO->BASE0 = base;
  64. NRF_RADIO->PCNF1 = (
  65. (((sizeof(_buf)) << RADIO_PCNF1_MAXLEN_Pos) & RADIO_PCNF1_MAXLEN_Msk) // maximum length of payload
  66. | (((0UL) << RADIO_PCNF1_STATLEN_Pos) & RADIO_PCNF1_STATLEN_Msk) // expand the payload with 0 bytes
  67. | (((len-1) << RADIO_PCNF1_BALEN_Pos) & RADIO_PCNF1_BALEN_Msk)); // base address length in number of bytes.
  68. return true;
  69. }
  70. bool RH_NRF51::setRF(DataRate data_rate, TransmitPower power)
  71. {
  72. uint8_t mode;
  73. uint8_t p;
  74. if (data_rate == DataRate2Mbps)
  75. mode = RADIO_MODE_MODE_Nrf_2Mbit;
  76. else if (data_rate == DataRate1Mbps)
  77. mode = RADIO_MODE_MODE_Nrf_1Mbit;
  78. else if (data_rate == DataRate250kbps)
  79. mode = RADIO_MODE_MODE_Nrf_250Kbit;
  80. else
  81. return false;// Invalid
  82. if (power == TransmitPower4dBm)
  83. p = RADIO_TXPOWER_TXPOWER_Pos4dBm;
  84. else if (power == TransmitPower0dBm)
  85. p = RADIO_TXPOWER_TXPOWER_0dBm;
  86. else if (power == TransmitPowerm4dBm)
  87. p = RADIO_TXPOWER_TXPOWER_Neg4dBm;
  88. else if (power == TransmitPowerm8dBm)
  89. p = RADIO_TXPOWER_TXPOWER_Neg8dBm;
  90. else if (power == TransmitPowerm12dBm)
  91. p = RADIO_TXPOWER_TXPOWER_Neg12dBm;
  92. else if (power == TransmitPowerm16dBm)
  93. p = RADIO_TXPOWER_TXPOWER_Neg16dBm;
  94. else if (power == TransmitPowerm20dBm)
  95. p = RADIO_TXPOWER_TXPOWER_Neg20dBm;
  96. else if (power == TransmitPowerm30dBm)
  97. p = RADIO_TXPOWER_TXPOWER_Neg30dBm;
  98. else
  99. return false; // Invalid
  100. NRF_RADIO->TXPOWER = ((p << RADIO_TXPOWER_TXPOWER_Pos) & RADIO_TXPOWER_TXPOWER_Msk);
  101. NRF_RADIO->MODE = ((mode << RADIO_MODE_MODE_Pos) & RADIO_MODE_MODE_Msk);
  102. return true;
  103. }
  104. void RH_NRF51::setModeIdle()
  105. {
  106. if (_mode != RHModeIdle)
  107. {
  108. NRF_RADIO->TASKS_DISABLE = 1;
  109. _mode = RHModeIdle;
  110. }
  111. }
  112. void RH_NRF51::setModeRx()
  113. {
  114. if (_mode != RHModeRx)
  115. {
  116. setModeIdle(); // Can only start RX from DISABLE state
  117. // Radio will transition automatically to Disable state when a messageis received
  118. NRF_RADIO->PACKETPTR = (uint32_t)_buf;
  119. NRF_RADIO->EVENTS_DISABLED = 0U; // So we can detect end of transmission
  120. NRF_RADIO->TASKS_RXEN = 1;
  121. _mode = RHModeRx;
  122. }
  123. }
  124. void RH_NRF51::setModeTx()
  125. {
  126. if (_mode != RHModeTx)
  127. {
  128. setModeIdle(); // Can only start RX from DISABLE state
  129. // Radio will transition automatically to Disable state at the end of transmission
  130. NRF_RADIO->PACKETPTR = (uint32_t)_buf;
  131. NRF_RADIO->EVENTS_DISABLED = 0U; // So we can detect end of transmission
  132. NRF_RADIO->TASKS_TXEN = 1;
  133. _mode = RHModeTx;
  134. }
  135. }
  136. bool RH_NRF51::send(const uint8_t* data, uint8_t len)
  137. {
  138. if (len > RH_NRF51_MAX_MESSAGE_LEN)
  139. return false;
  140. // Set up the headers
  141. _buf[0] = len + RH_NRF51_HEADER_LEN;
  142. _buf[1] = _txHeaderTo;
  143. _buf[2] = _txHeaderFrom;
  144. _buf[3] = _txHeaderId;
  145. _buf[4] = _txHeaderFlags;
  146. memcpy(_buf+RH_NRF51_HEADER_LEN+1, data, len);
  147. _rxBufValid = false;
  148. setModeTx();
  149. // Radio will return to Disabled state after transmission is complete
  150. _txGood++;
  151. return true;
  152. }
  153. bool RH_NRF51::waitPacketSent()
  154. {
  155. // If we are not currently in transmit mode, there is no packet to wait for
  156. if (_mode != RHModeTx)
  157. return false;
  158. // When the Disabled event occurs we know the transmission has completed
  159. while (NRF_RADIO->EVENTS_DISABLED == 0U)
  160. {
  161. YIELD;
  162. }
  163. setModeIdle();
  164. return true;
  165. }
  166. bool RH_NRF51::isSending()
  167. {
  168. return (NRF_RADIO->STATE == RADIO_STATE_STATE_Tx) ? true : false;
  169. }
  170. bool RH_NRF51::printRegisters()
  171. {
  172. #ifdef RH_HAVE_SERIAL
  173. uint16_t i;
  174. uint32_t* p = (uint32_t*)NRF_RADIO;
  175. for (i = 0; (p + i) < (uint32_t*) (((NRF_RADIO_Type*)NRF_RADIO) + 1); i++)
  176. {
  177. Serial.print("Offset: ");
  178. Serial.print(i, DEC);
  179. Serial.print(" ");
  180. Serial.println(*(p+i), HEX);
  181. }
  182. #endif
  183. return true;
  184. }
  185. // Check whether the latest received message is complete and uncorrupted
  186. void RH_NRF51::validateRxBuf()
  187. {
  188. if (_buf[0] < 4)
  189. return; // Too short to be a real message
  190. // Extract the 4 headers
  191. _rxHeaderTo = _buf[1];
  192. _rxHeaderFrom = _buf[2];
  193. _rxHeaderId = _buf[3];
  194. _rxHeaderFlags = _buf[4];
  195. if (_promiscuous ||
  196. _rxHeaderTo == _thisAddress ||
  197. _rxHeaderTo == RH_BROADCAST_ADDRESS)
  198. {
  199. _rxGood++;
  200. _rxBufValid = true;
  201. }
  202. }
  203. bool RH_NRF51::available()
  204. {
  205. if (!_rxBufValid)
  206. {
  207. if (_mode == RHModeTx)
  208. return false;
  209. setModeRx();
  210. if (NRF_RADIO->EVENTS_DISABLED == 0U)
  211. return false; // No message yet
  212. if (NRF_RADIO->CRCSTATUS == ((RADIO_CRCSTATUS_CRCSTATUS_CRCError << RADIO_CRCSTATUS_CRCSTATUS_Pos) & RADIO_CRCSTATUS_CRCSTATUS_Msk))
  213. {
  214. // Bad CRC, restart the radio
  215. _rxBad++;
  216. setModeRx();
  217. return false;
  218. }
  219. validateRxBuf();
  220. if (_rxBufValid)
  221. setModeIdle(); // Got one
  222. }
  223. return _rxBufValid;
  224. }
  225. void RH_NRF51::clearRxBuf()
  226. {
  227. _rxBufValid = false;
  228. _buf[0] = 0;
  229. }
  230. bool RH_NRF51::recv(uint8_t* buf, uint8_t* len)
  231. {
  232. if (!available())
  233. return false;
  234. if (buf && len)
  235. {
  236. // Skip the 4 headers that are at the beginning of the rxBuf
  237. // the payload length is the first octet in _buf
  238. if (*len > _buf[0]-RH_NRF51_HEADER_LEN)
  239. *len = _buf[0]-RH_NRF51_HEADER_LEN;
  240. memcpy(buf, _buf+RH_NRF51_HEADER_LEN+1, *len);
  241. }
  242. clearRxBuf(); // This message accepted and cleared
  243. return true;
  244. }
  245. uint8_t RH_NRF51::maxMessageLength()
  246. {
  247. return RH_NRF51_MAX_MESSAGE_LEN;
  248. }
  249. #endif // NRF51