loragw_sx125x.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /*
  2. / _____) _ | |
  3. ( (____ _____ ____ _| |_ _____ ____| |__
  4. \____ \| ___ | (_ _) ___ |/ ___) _ \
  5. _____) ) ____| | | || |_| ____( (___| | | |
  6. (______/|_____)_|_|_| \__)_____)\____)_| |_|
  7. (C)2019 Semtech
  8. Description:
  9. Functions used to handle LoRa concentrator SX1255/SX1257 radios.
  10. License: Revised BSD License, see LICENSE.TXT file include in the project
  11. */
  12. /* -------------------------------------------------------------------------- */
  13. /* --- DEPENDANCIES --------------------------------------------------------- */
  14. #include <stdint.h> /* C99 types */
  15. #include <stdbool.h> /* bool type */
  16. #include <stdio.h> /* printf fprintf */
  17. #include "sx125x_com.h"
  18. #include "loragw_sx125x.h"
  19. #include "loragw_com.h"
  20. #include "loragw_aux.h"
  21. #include "loragw_reg.h"
  22. #include "loragw_hal.h"
  23. /* -------------------------------------------------------------------------- */
  24. /* --- PRIVATE MACROS ------------------------------------------------------- */
  25. #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
  26. #if DEBUG_RAD == 1
  27. #define DEBUG_MSG(str) fprintf(stdout, str)
  28. #define DEBUG_PRINTF(fmt, args...) fprintf(stdout,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
  29. #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_REG_ERROR;}
  30. #else
  31. #define DEBUG_MSG(str)
  32. #define DEBUG_PRINTF(fmt, args...)
  33. #define CHECK_NULL(a) if(a==NULL){return LGW_REG_ERROR;}
  34. #endif
  35. /* -------------------------------------------------------------------------- */
  36. /* --- PRIVATE TYPES -------------------------------------------------------- */
  37. /* -------------------------------------------------------------------------- */
  38. /* --- PRIVATE CONSTANTS ---------------------------------------------------- */
  39. #define PLL_LOCK_MAX_ATTEMPTS 5
  40. static const struct radio_reg_s sx125x_regs[RADIO_TOTALREGS] = {
  41. {0,0,8}, /* MODE */
  42. {0,3,1}, /* MODE__PA_DRIVER_EN */
  43. {0,2,1}, /* MODE__TX_EN */
  44. {0,1,1}, /* MODE__RX_EN */
  45. {0,0,1}, /* MODE__STANDBY_EN */
  46. {1,0,8}, /* FRF_RX_MSB */
  47. {2,0,8}, /* FRF_RX_MID */
  48. {3,0,8}, /* FRF_RX_LSB */
  49. {4,0,8}, /* FRF_TX_MSB */
  50. {5,0,8}, /* FRF_TX_MID */
  51. {6,0,8}, /* FRF_TX_LSB */
  52. {7,0,8}, /* VERSION */
  53. {8,0,8}, /* TX_GAIN */
  54. {8,4,3}, /* TX_GAIN__DAC_GAIN */
  55. {8,0,4}, /* TX_GAIN__MIX_GAIN */
  56. {10,0,8}, /* TX_BW */
  57. {10,5,2}, /* TX_BW__PLL_BW */
  58. {10,0,5}, /* TX_BW__ANA_BW */
  59. {11,0,8}, /* TX_DAC_BW */
  60. {12,0,8}, /* RX_ANA_GAIN */
  61. {12,5,3}, /* RX_ANA_GAIN__LNA_GAIN */
  62. {12,1,4}, /* RX_ANA_GAIN__BB_GAIN */
  63. {12,0,1}, /* RX_ANA_GAIN__LNA_ZIN */
  64. {13,0,8}, /* RX_BW */
  65. {13,5,3}, /* RX_BW__ADC_BW */
  66. {13,2,3}, /* RX_BW__ADC_TRIM */
  67. {13,0,2}, /* RX_BW__BB_BW */
  68. {14,0,8}, /* RX_PLL_BW */
  69. {14,1,2}, /* RX_PLL_BW__PLL_BW */
  70. {14,0,1}, /* RX_PLL_BW__ADC_TEMP_EN */
  71. {15,0,8}, /* DIO_MAPPING */
  72. {15,6,2}, /* DIO_MAPPING__DIO_0_MAPPING */
  73. {15,4,2}, /* DIO_MAPPING__DIO_1_MAPPING */
  74. {15,2,2}, /* DIO_MAPPING__DIO_2_MAPPING */
  75. {15,0,2}, /* DIO_MAPPING__DIO_3_MAPPING */
  76. {16,0,8}, /* CLK_SELECT */
  77. {16,3,1}, /* CLK_SELECT__DIG_LOOPBACK_EN */
  78. {16,2,1}, /* CLK_SELECT__RF_LOOPBACK_EN */
  79. {16,1,1}, /* CLK_SELECT__CLK_OUT */
  80. {16,0,1}, /* CLK_SELECT__DAC_CLK_SELECT */
  81. {17,0,8}, /* MODE_STATUS */
  82. {17,2,1}, /* MODE_STATUS__LOW_BAT_EN */
  83. {17,1,1}, /* MODE_STATUS__RX_PLL_LOCKED */
  84. {17,0,1}, /* MODE_STATUS__TX_PLL_LOCKED */
  85. {26,0,8}, /* LOW_BAT_THRESH */
  86. {38,0,8}, /* SX1257_XOSC_TEST */
  87. {38,4,3}, /* SX1257_XOSC_TEST__DISABLE */
  88. {38,0,4}, /* SX1257_XOSC_TEST__GM_STARTUP */
  89. {40,0,8}, /* SX1255_XOSC_TEST */
  90. {40,4,3}, /* SX1255_XOSC_TEST__DISABLE */
  91. {40,0,4} /* SX1255_XOSC_TEST__GM_STARTUP */
  92. };
  93. /* -------------------------------------------------------------------------- */
  94. /* --- PRIVATE VARIABLES ---------------------------------------------------- */
  95. /* -------------------------------------------------------------------------- */
  96. /* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
  97. /* -------------------------------------------------------------------------- */
  98. /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
  99. int sx125x_reg_w(radio_reg_t idx, uint8_t data, uint8_t rf_chain) {
  100. int com_stat;
  101. struct radio_reg_s reg;
  102. uint8_t mask;
  103. uint8_t r;
  104. uint8_t w;
  105. uint8_t val_check;
  106. /* checking input parameters */
  107. if (rf_chain >= LGW_RF_CHAIN_NB) {
  108. DEBUG_MSG("ERROR: INVALID RF_CHAIN\n");
  109. return LGW_REG_ERROR;
  110. }
  111. if (idx >= RADIO_TOTALREGS) {
  112. DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n");
  113. return LGW_REG_ERROR;
  114. }
  115. reg = sx125x_regs[idx];
  116. if ((reg.leng == 8) && (reg.offs == 0)){
  117. /* direct write */
  118. com_stat = sx125x_com_w(lgw_com_type(), lgw_com_target(), ((rf_chain == 0) ? LGW_SPI_MUX_TARGET_RADIOA : LGW_SPI_MUX_TARGET_RADIOB), reg.addr, data);
  119. } else {
  120. /* read-modify-write */
  121. com_stat = sx125x_com_r(lgw_com_type(), lgw_com_target(), ((rf_chain == 0) ? LGW_SPI_MUX_TARGET_RADIOA : LGW_SPI_MUX_TARGET_RADIOB), reg.addr, &r);
  122. mask = ((1 << reg.leng) - 1) << reg.offs;
  123. w = (r & ~mask) | ((data << reg.offs) & mask);
  124. com_stat |= sx125x_com_w(lgw_com_type(), lgw_com_target(), ((rf_chain == 0) ? LGW_SPI_MUX_TARGET_RADIOA : LGW_SPI_MUX_TARGET_RADIOB), reg.addr, w);
  125. }
  126. /* Check that we can read what we have written */
  127. sx125x_reg_r(idx, &val_check, rf_chain);
  128. if (val_check != data) {
  129. printf("ERROR: sx125x register %d write failed (w:%u r:%u)!!\n", idx, data, val_check);
  130. com_stat = LGW_COM_ERROR;
  131. }
  132. if (com_stat != LGW_COM_SUCCESS) {
  133. DEBUG_MSG("ERROR: COM ERROR DURING RADIO REGISTER WRITE\n");
  134. return LGW_REG_ERROR;
  135. } else {
  136. return LGW_REG_SUCCESS;
  137. }
  138. }
  139. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  140. int sx125x_reg_r(radio_reg_t idx, uint8_t *data, uint8_t rf_chain) {
  141. int com_stat;
  142. struct radio_reg_s reg;
  143. uint8_t mask;
  144. uint8_t r;
  145. /* checking input parameters */
  146. if (rf_chain >= LGW_RF_CHAIN_NB) {
  147. DEBUG_MSG("ERROR: INVALID RF_CHAIN\n");
  148. return LGW_REG_ERROR;
  149. }
  150. if (idx >= RADIO_TOTALREGS) {
  151. DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n");
  152. return LGW_REG_ERROR;
  153. }
  154. reg = sx125x_regs[idx];
  155. com_stat = sx125x_com_r(lgw_com_type(), lgw_com_target(), ((rf_chain == 0) ? LGW_SPI_MUX_TARGET_RADIOA : LGW_SPI_MUX_TARGET_RADIOB), reg.addr, &r);
  156. mask = ((1 << reg.leng) - 1) << reg.offs;
  157. *data = (r & mask) >> reg.offs;
  158. if (com_stat != LGW_COM_SUCCESS) {
  159. DEBUG_MSG("ERROR: COM ERROR DURING RADIO REGISTER READ\n");
  160. return LGW_REG_ERROR;
  161. } else {
  162. return LGW_REG_SUCCESS;
  163. }
  164. }
  165. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  166. int sx125x_setup(uint8_t rf_chain, uint8_t rf_clkout, bool rf_enable, uint8_t rf_radio_type, uint32_t freq_hz) {
  167. uint32_t part_int = 0;
  168. uint32_t part_frac = 0;
  169. int cpt_attempts = 0;
  170. uint8_t val;
  171. if (rf_chain >= LGW_RF_CHAIN_NB) {
  172. DEBUG_MSG("ERROR: INVALID RF_CHAIN\n");
  173. return -1;
  174. }
  175. /* Get version to identify SX1255/57 silicon revision */
  176. sx125x_reg_r(SX125x_REG_VERSION, &val, rf_chain);
  177. DEBUG_PRINTF("Note: SX125x #%d version register returned 0x%02x\n", rf_chain, val);
  178. /* General radio setup */
  179. if (rf_clkout == rf_chain) {
  180. sx125x_reg_w(SX125x_REG_CLK_SELECT, SX125x_TX_DAC_CLK_SEL + 2, rf_chain);
  181. DEBUG_PRINTF("Note: SX125x #%d clock output enabled\n", rf_chain);
  182. } else {
  183. sx125x_reg_w(SX125x_REG_CLK_SELECT, SX125x_TX_DAC_CLK_SEL, rf_chain);
  184. DEBUG_PRINTF("Note: SX125x #%d clock output disabled\n", rf_chain);
  185. }
  186. switch (rf_radio_type) {
  187. case LGW_RADIO_TYPE_SX1255:
  188. sx125x_reg_w(SX125x_REG_SX1255_XOSC_TEST__GM_STARTUP, SX125x_XOSC_GM_STARTUP, rf_chain);
  189. sx125x_reg_w(SX125x_REG_SX1255_XOSC_TEST__DISABLE, SX125x_XOSC_DISABLE, rf_chain);
  190. break;
  191. case LGW_RADIO_TYPE_SX1257:
  192. sx125x_reg_w(SX125x_REG_SX1257_XOSC_TEST__GM_STARTUP, SX125x_XOSC_GM_STARTUP, rf_chain);
  193. sx125x_reg_w(SX125x_REG_SX1257_XOSC_TEST__DISABLE, SX125x_XOSC_DISABLE, rf_chain);
  194. break;
  195. default:
  196. DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d FOR RADIO TYPE\n", rf_radio_type);
  197. break;
  198. }
  199. if (rf_enable == true) {
  200. /* Tx gain and trim */
  201. sx125x_reg_w(SX125x_REG_TX_GAIN__MIX_GAIN, SX125x_TX_MIX_GAIN, rf_chain);
  202. sx125x_reg_w(SX125x_REG_TX_GAIN__DAC_GAIN, SX125x_TX_DAC_GAIN, rf_chain);
  203. sx125x_reg_w(SX125x_REG_TX_BW__ANA_BW, SX125x_TX_ANA_BW, rf_chain);
  204. sx125x_reg_w(SX125x_REG_TX_BW__PLL_BW, SX125x_TX_PLL_BW, rf_chain);
  205. sx125x_reg_w(SX125x_REG_TX_DAC_BW, SX125x_TX_DAC_BW, rf_chain);
  206. /* Rx gain and trim */
  207. sx125x_reg_w(SX125x_REG_RX_ANA_GAIN__LNA_ZIN, SX125x_LNA_ZIN, rf_chain);
  208. sx125x_reg_w(SX125x_REG_RX_ANA_GAIN__BB_GAIN, SX125x_RX_BB_GAIN, rf_chain);
  209. sx125x_reg_w(SX125x_REG_RX_ANA_GAIN__LNA_GAIN, SX125x_RX_LNA_GAIN, rf_chain);
  210. sx125x_reg_w(SX125x_REG_RX_BW__BB_BW, SX125x_RX_BB_BW, rf_chain);
  211. sx125x_reg_w(SX125x_REG_RX_BW__ADC_TRIM, SX125x_RX_ADC_TRIM, rf_chain);
  212. sx125x_reg_w(SX125x_REG_RX_BW__ADC_BW, SX125x_RX_ADC_BW, rf_chain);
  213. sx125x_reg_w(SX125x_REG_RX_PLL_BW__ADC_TEMP_EN, SX125x_ADC_TEMP, rf_chain);
  214. sx125x_reg_w(SX125x_REG_RX_PLL_BW__PLL_BW, SX125x_RX_PLL_BW, rf_chain);
  215. /* set RX PLL frequency */
  216. switch (rf_radio_type) {
  217. case LGW_RADIO_TYPE_SX1255:
  218. part_int = freq_hz / (SX125x_32MHz_FRAC << 7); /* integer part, gives the MSB */
  219. part_frac = ((freq_hz % (SX125x_32MHz_FRAC << 7)) << 9) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */
  220. break;
  221. case LGW_RADIO_TYPE_SX1257:
  222. part_int = freq_hz / (SX125x_32MHz_FRAC << 8); /* integer part, gives the MSB */
  223. part_frac = ((freq_hz % (SX125x_32MHz_FRAC << 8)) << 8) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */
  224. break;
  225. default:
  226. DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d FOR RADIO TYPE\n", rf_radio_type);
  227. break;
  228. }
  229. sx125x_reg_w(SX125x_REG_FRF_RX_MSB, 0xFF & part_int, rf_chain);
  230. sx125x_reg_w(SX125x_REG_FRF_RX_MID, 0xFF & (part_frac >> 8), rf_chain);
  231. sx125x_reg_w(SX125x_REG_FRF_RX_LSB, 0xFF & part_frac, rf_chain);
  232. /* start and PLL lock */
  233. do {
  234. if (cpt_attempts >= PLL_LOCK_MAX_ATTEMPTS) {
  235. DEBUG_MSG("ERROR: FAIL TO LOCK PLL\n");
  236. return -1;
  237. }
  238. sx125x_reg_w(SX125x_REG_MODE, 1, rf_chain);
  239. sx125x_reg_w(SX125x_REG_MODE, 3, rf_chain);
  240. ++cpt_attempts;
  241. DEBUG_PRINTF("Note: SX125x #%d PLL start (attempt %d)\n", rf_chain, cpt_attempts);
  242. wait_ms(1);
  243. sx125x_reg_r(SX125x_REG_MODE_STATUS, &val, rf_chain);
  244. } while ((val & 0x02) == 0);
  245. } else {
  246. DEBUG_PRINTF("Note: SX125x #%d kept in standby mode\n", rf_chain);
  247. }
  248. return 0;
  249. }
  250. /* --- EOF ------------------------------------------------------------------ */