cc1101.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. #include <furi.h>
  2. #include <api-hal.h>
  3. #include "cc1101-workaround/cc1101.h"
  4. #include "spi.h"
  5. #include <math.h>
  6. // ******************************************************************************
  7. #define WRITE_BURST 0x40
  8. #define READ_SINGLE 0x80
  9. #define READ_BURST 0xC0
  10. #define BYTES_IN_FIFO 0x7F //used to detect FIFO underflow or overflow
  11. /*********************ss_pin as global variable****************************** */
  12. /* cc1101 */
  13. /******************************************************************************/
  14. GpioPin ss_pin;
  15. CC1101::CC1101(GpioPin* ss_pin) {
  16. /*
  17. pinMode(gdo0_pin, OUTPUT); //GDO0 as asynchronous serial mode input
  18. pinMode(gdo2_pin, INPUT); //GDO2 as asynchronous serial mode output
  19. */
  20. gpio_init(ss_pin, GpioModeOutputPushPull);
  21. this->ss_pin = ss_pin;
  22. // TODO open record
  23. this->miso_pin = MISO_PIN;
  24. this->miso_pin_record = &this->miso_pin;
  25. }
  26. //******************************************************************************
  27. //SpiInit
  28. /******************************************************************************/
  29. extern SPI_HandleTypeDef SPI_R;
  30. void CC1101::SpiInit(void) {
  31. //initialize spi pins
  32. //Enable spi master, MSB, SPI mode 0, FOSC/4
  33. SpiMode(0);
  34. CC1101_SPI_Reconfigure();
  35. }
  36. void CC1101::SpiEnd(void) {
  37. /*
  38. SPCR = ((0<<SPE) | // SPI Enable
  39. (0<<SPIE)| // SPI Interupt Enable
  40. (0<<DORD)| // Data Order (0:MSB first / 1:LSB first)
  41. (1<<MSTR)| // Master/Slave select
  42. (0<<SPR1)|(0<<SPR0)| // SPI Clock Rate ( 0 0 = osc/4; 0 1 = osc/16; 1 0 = osc/64; 1 1= 0sc/128)
  43. (0<<CPOL)| // Clock Polarity (0:SCK low / 1:SCK hi when idle)
  44. (0<<CPHA)); // Clock Phase (0:leading / 1:trailing edge sampling)
  45. //SPSR = (0<<SPI2X); // Double Clock Rate
  46. */
  47. }
  48. /******************************************************************************
  49. Function: SpiMode
  50. *INPUT : config mode
  51. (0<<CPOL) | (0 << CPHA) 0
  52. (0<<CPOL) | (1 << CPHA) 1
  53. (1<<CPOL) | (0 << CPHA) 2
  54. (1<<CPOL) | (1 << CPHA) 3
  55. *OUTPUT :none
  56. ******************************************************************************/
  57. void CC1101::SpiMode(uint8_t config) {
  58. /*
  59. uint8_t tmp;
  60. // enable SPI master with configuration byte specified
  61. SPCR = 0;
  62. SPCR = (config & 0x7F) | (1<<SPE) | (1<<MSTR);
  63. tmp = SPSR;
  64. tmp = SPDR;
  65. */
  66. }
  67. /****************************************************************
  68. *FUNCTION NAME:SpiTransfer
  69. *FUNCTION :spi transfer
  70. *INPUT :value: data to send
  71. *OUTPUT :data to receive
  72. ****************************************************************/
  73. uint8_t CC1101::SpiTransfer(uint8_t value) {
  74. uint8_t buf[1] = {value};
  75. uint8_t rxbuf[1] = {0};
  76. HAL_SPI_TransmitReceive(&SPI_R, buf, rxbuf, 1, HAL_MAX_DELAY);
  77. return rxbuf[0];
  78. }
  79. uint8_t last_status;
  80. /****************************************************************
  81. *FUNCTION NAME:SpiWriteReg
  82. *FUNCTION :CC1101 write data to register
  83. *INPUT :addr: register address; value: register value
  84. *OUTPUT :none
  85. ****************************************************************/
  86. void CC1101::SpiWriteReg(uint8_t addr, uint8_t value) {
  87. gpio_write(ss_pin, false);
  88. while(gpio_read(this->miso_pin_record))
  89. ;
  90. last_status = SpiTransfer(addr);
  91. last_status = SpiTransfer(value);
  92. gpio_write(ss_pin, true);
  93. }
  94. /****************************************************************
  95. *FUNCTION NAME:SpiWriteBurstReg
  96. *FUNCTION :CC1101 write burst data to register
  97. *INPUT :addr: register address; buffer:register value array; num:number to write
  98. *OUTPUT :none
  99. ****************************************************************/
  100. void CC1101::SpiWriteBurstReg(uint8_t addr, uint8_t* buffer, uint8_t num) {
  101. gpio_write(ss_pin, false);
  102. while(gpio_read(this->miso_pin_record))
  103. ;
  104. last_status = SpiTransfer(addr | WRITE_BURST);
  105. for(uint8_t i = 0; i < num; i++) {
  106. last_status = SpiTransfer(buffer[i]);
  107. }
  108. gpio_write(ss_pin, true);
  109. }
  110. /****************************************************************
  111. *FUNCTION NAME:SpiStrobe
  112. *FUNCTION :CC1101 Strobe
  113. *INPUT :strobe: command; //refer define in CC1101.h//
  114. *OUTPUT :none
  115. ****************************************************************/
  116. void CC1101::SpiStrobe(uint8_t strobe) {
  117. gpio_write(ss_pin, false);
  118. while(gpio_read(this->miso_pin_record))
  119. ;
  120. last_status = SpiTransfer(strobe);
  121. gpio_write(ss_pin, true);
  122. }
  123. /****************************************************************
  124. *FUNCTION NAME:SpiReadReg
  125. *FUNCTION :CC1101 read data from register
  126. *INPUT :addr: register address
  127. *OUTPUT :register value
  128. ****************************************************************/
  129. uint8_t CC1101::SpiReadReg(uint8_t addr) {
  130. gpio_write(ss_pin, false);
  131. while(gpio_read(this->miso_pin_record))
  132. ;
  133. last_status = SpiTransfer(addr | READ_SINGLE);
  134. uint8_t value = SpiTransfer(0);
  135. gpio_write(ss_pin, true);
  136. return value;
  137. }
  138. /****************************************************************
  139. *FUNCTION NAME:SpiReadBurstReg
  140. *FUNCTION :CC1101 read burst data from register
  141. *INPUT :addr: register address; buffer:array to store register value; num: number to read
  142. *OUTPUT :none
  143. ****************************************************************/
  144. void CC1101::SpiReadBurstReg(uint8_t addr, uint8_t* buffer, uint8_t num) {
  145. gpio_write(ss_pin, false);
  146. while(gpio_read(this->miso_pin_record))
  147. ;
  148. last_status = SpiTransfer(addr | READ_BURST);
  149. for(uint8_t i = 0; i < num; i++) {
  150. buffer[i] = SpiTransfer(0);
  151. }
  152. gpio_write(ss_pin, true);
  153. }
  154. /****************************************************************
  155. *FUNCTION NAME:SpiReadStatus
  156. *FUNCTION :CC1101 read status register
  157. *INPUT :addr: register address
  158. *OUTPUT :status value
  159. ****************************************************************/
  160. uint8_t CC1101::SpiReadStatus(uint8_t addr) {
  161. gpio_write(ss_pin, false);
  162. while(gpio_read(this->miso_pin_record))
  163. ;
  164. last_status = SpiTransfer(addr | READ_BURST);
  165. uint8_t value = SpiTransfer(0);
  166. gpio_write(ss_pin, true);
  167. return value;
  168. }
  169. /****************************************************************
  170. *FUNCTION NAME:Reset
  171. *FUNCTION :CC1101 reset //details refer datasheet of CC1101/CC1100//
  172. *INPUT :none
  173. *OUTPUT :none
  174. ****************************************************************/
  175. void CC1101::Reset(void) {
  176. gpio_write(ss_pin, false);
  177. delay(1);
  178. gpio_write(ss_pin, true);
  179. delay(1);
  180. gpio_write(ss_pin, false);
  181. while(gpio_read(this->miso_pin_record))
  182. ;
  183. last_status = SpiTransfer(CC1101_SRES);
  184. while(gpio_read(this->miso_pin_record))
  185. ;
  186. gpio_write(ss_pin, true);
  187. }
  188. bool CC1101::SpiSetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t lsb) {
  189. if((msb > 7) || (lsb > 7) || (lsb > msb)) {
  190. return false;
  191. }
  192. uint8_t current_value = SpiReadReg(reg);
  193. uint8_t mask = ~((0b11111111 << (msb + 1)) | (0b11111111 >> (8 - lsb)));
  194. uint8_t new_value = (current_value & ~mask) | (value & mask);
  195. SpiWriteReg(reg, new_value);
  196. return true;
  197. }
  198. /****************************************************************
  199. *FUNCTION NAME:Init
  200. *FUNCTION :CC1101 initialization
  201. *INPUT :none
  202. *OUTPUT :none
  203. ****************************************************************/
  204. uint8_t CC1101::Init(void) {
  205. #ifdef CC1101_DEBUG
  206. printf("Init SPI...\r\n");
  207. #endif
  208. SpiInit(); //spi initialization
  209. gpio_write(ss_pin, true);
  210. // gpio_write(SCK_PIN, true);
  211. // gpio_write(MOSI_PIN, false);
  212. #ifdef CC1101_DEBUG
  213. printf("Reset CC1101...\r\n");
  214. #endif
  215. Reset(); // CC1101 reset
  216. osDelay(150);
  217. uint8_t partnum __attribute__((unused));
  218. uint8_t version;
  219. partnum = SpiReadStatus(CC1101_PARTNUM);
  220. version = SpiReadStatus(CC1101_VERSION);
  221. #ifdef CC1101_DEBUG
  222. printf("Partnum:0x%02X, Version:0x%02X\n", partnum, version);
  223. #endif
  224. #ifdef CC1101_DEBUG
  225. printf("Init CC1101...");
  226. #endif
  227. // RegConfigSettings(); //CC1101 register config
  228. #ifdef CC1101_DEBUG
  229. printf("Done!\r\n");
  230. #endif
  231. return version;
  232. }
  233. /****************************************************************
  234. *FUNCTION NAME:SetMod
  235. *FUNCTION :CC1101 modulation type
  236. *INPUT :byte mode
  237. *OUTPUT :none
  238. ****************************************************************/
  239. void CC1101::SetMod(uint8_t mode) {
  240. SpiWriteReg(CC1101_MDMCFG2, mode); //no sync/preamble; ASK/OOK only support up to -1dbm
  241. if((mode | 0x30) == ASK) {
  242. SpiWriteReg(CC1101_FREND0, 0x11); //use first up to PATABLE(0)
  243. uint8_t PaTabel[8] = {0x00, POWER, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  244. SpiWriteBurstReg(CC1101_PATABLE, PaTabel, 8); //CC1101 PATABLE config
  245. } else {
  246. SpiWriteReg(CC1101_FREND0, 0x10); //use first up to PATABLE(0)
  247. uint8_t PaTabel[8] = {POWER, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  248. SpiWriteBurstReg(CC1101_PATABLE, PaTabel, 8); //CC1101 PATABLE config
  249. }
  250. #ifdef CC1101_DEBUG
  251. switch(mode | 0x30) {
  252. case GFSK: {
  253. printf("CC1101 Modulation: GFSK");
  254. break;
  255. }
  256. case MSK: {
  257. printf("CC1101 Modulation: MSK");
  258. break;
  259. }
  260. case ASK: {
  261. printf("CC1101 Modulation: ASK/OOK");
  262. break;
  263. }
  264. case FSK2: {
  265. printf("CC1101 Modulation: 2-FSK");
  266. break;
  267. }
  268. case FSK4: {
  269. printf("CC1101 Modulation: 4-FSK");
  270. break;
  271. }
  272. default: //default to GFSK
  273. {
  274. printf("Modulation mode not supported");
  275. break;
  276. }
  277. }
  278. printf("\r\n");
  279. #endif
  280. }
  281. /****************************************************************
  282. *FUNCTION NAME:RegConfigSettings
  283. *FUNCTION :CC1101 register config //details refer datasheet of CC1101/CC1100//
  284. *INPUT :none
  285. *OUTPUT :none
  286. ****************************************************************/
  287. void CC1101::RegConfigSettings(void) {
  288. SpiWriteReg(CC1101_FSCTRL1, 0x06); //IF frequency
  289. SpiWriteReg(CC1101_FSCTRL0, 0x00); //frequency offset before synthesizer
  290. SpiWriteReg(CC1101_MDMCFG4, 0xCC); // RX filter bandwidth 100k(0xcc)
  291. SpiWriteReg(
  292. CC1101_MDMCFG3, 0x43); //datarate config 512kBaud for the purpose of fast rssi measurement
  293. SpiWriteReg(CC1101_MDMCFG1, 0x21); //FEC preamble etc. last 2 bits for channel spacing
  294. SpiWriteReg(CC1101_MDMCFG0, 0xF8); //100khz channel spacing
  295. //CC1101_CHANNR moved to SetChannel func
  296. //SpiWriteReg(CC1101_DEVIATN, 0x47);
  297. SpiWriteReg(
  298. CC1101_MCSM0, 0x18); // calibrate when going from IDLE to RX or TX ; 149 - 155 μs timeout
  299. SpiWriteReg(CC1101_FOCCFG, 0x16); //frequency compensation
  300. //SpiWriteReg(CC1101_BSCFG, 0x1C); //bit synchronization config
  301. SpiWriteReg(CC1101_AGCCTRL2, 0x43);
  302. SpiWriteReg(CC1101_AGCCTRL1, 0x49);
  303. SpiWriteReg(CC1101_AGCCTRL0, 0x91);
  304. //freq synthesizer calibration
  305. SpiWriteReg(CC1101_FSCAL3, 0xEA);
  306. SpiWriteReg(CC1101_FSCAL2, 0x2A);
  307. SpiWriteReg(CC1101_FSCAL1, 0x00);
  308. SpiWriteReg(CC1101_FSCAL0, 0x1F);
  309. SpiWriteReg(CC1101_TEST2, 0x81);
  310. SpiWriteReg(CC1101_TEST1, 0x35);
  311. SpiWriteReg(CC1101_TEST0, 0x0B); //should be 0x0B for lower than 430.6MHz and 0x09 for higher
  312. //SpiWriteReg(CC1101_FREND1, 0x56);
  313. //SpiWriteReg(CC1101_IOCFG2, 0x0B); //serial clock.synchronous to the data in synchronous serial mode
  314. //SpiWriteReg(CC1101_IOCFG0, 0x06); //asserts when sync word has been sent/received, and de-asserts at the end of the packet
  315. SpiWriteReg(CC1101_IOCFG2, 0x0D); //data output pin for asynchronous mode
  316. SpiWriteReg(
  317. CC1101_IOCFG0,
  318. 0x2E); //High impedance (3-state), GDO0 configed as data input for asynchronous mode
  319. //SpiWriteReg(CC1101_PKTCTRL0, 0x05); //whitening off;CRC Enable;variable length packets, packet length configured by the first byte after sync word
  320. SpiWriteReg(
  321. CC1101_PKTCTRL0, 0x33); //whitening off; asynchronous serial mode; CRC diable;reserved
  322. //SpiWriteReg(CC1101_PKTLEN, 0x3D); //61 bytes max length
  323. SpiWriteReg(
  324. CC1101_FIFOTHR,
  325. 0x47); //Adc_retention enabled for RX filter bandwidth less than 325KHz; defalut fifo threthold.
  326. }
  327. /****************************************************************
  328. *FUNCTION NAME:SetFreq
  329. *FUNCTION :SetFreq
  330. *INPUT :Freq2, Freq1, Freq0
  331. *OUTPUT :none
  332. ****************************************************************/
  333. void CC1101::SetFreq(uint8_t freq2, uint8_t freq1, uint8_t freq0) {
  334. SpiWriteReg(CC1101_FREQ2, freq2);
  335. SpiWriteReg(CC1101_FREQ1, freq1);
  336. SpiWriteReg(CC1101_FREQ0, freq0);
  337. }
  338. /****************************************************************
  339. *FUNCTION NAME:SetChannel
  340. *FUNCTION :SetChannel
  341. *INPUT :int channel
  342. *OUTPUT :none
  343. ****************************************************************/
  344. void CC1101::SetChannel(int channel) {
  345. #ifdef CC1101_DEBUG
  346. printf("Set CC1101 channel to: %d \n", channel);
  347. #endif
  348. SpiWriteReg(CC1101_CHANNR, (uint8_t)channel); //related to channel numbers
  349. }
  350. /****************************************************************
  351. *FUNCTION NAME:SetReceive
  352. *FUNCTION :SetReceive
  353. *INPUT :none
  354. *OUTPUT :none
  355. ****************************************************************/
  356. void CC1101::SetReceive(void) {
  357. SpiStrobe(CC1101_SRX);
  358. while(SpiReadStatus(CC1101_MARCSTATE) ^ CC1101_STATUS_RX) {
  359. // delay(1);
  360. // printf("wait status\r\n");
  361. }
  362. }
  363. /****************************************************************
  364. *FUNCTION NAME:SetTransmit
  365. *FUNCTION :
  366. *INPUT :none
  367. *OUTPUT :none
  368. ****************************************************************/
  369. void CC1101::SetTransmit(void) {
  370. SpiStrobe(CC1101_STX);
  371. while(SpiReadStatus(CC1101_MARCSTATE) ^ CC1101_STATUS_TX)
  372. ;
  373. }
  374. //cc1101 cc1101;
  375. bool CC1101::setRxBandwidth(float bandwidth) {
  376. if(bandwidth < 58.0 || bandwidth > 821.0) return false;
  377. // set mode to standby
  378. SpiStrobe(CC1101_SIDLE);
  379. // calculate exponent and mantissa values
  380. for(int8_t e = 3; e >= 0; e--) {
  381. for(int8_t m = 3; m >= 0; m--) {
  382. float point = (F_OSC) / (8 * (m + 4) * ((uint32_t)1 << e));
  383. if(fabs((bandwidth * 1000.0) - point) <= 1000) {
  384. // set Rx channel filter bandwidth
  385. SpiSetRegValue(CC1101_MDMCFG4, (e << 6) | (m << 4), 7, 4);
  386. return true;
  387. }
  388. }
  389. }
  390. return false;
  391. }
  392. static void getExpMant(
  393. float target,
  394. uint16_t mantOffset,
  395. uint8_t divExp,
  396. uint8_t expMax,
  397. uint8_t& exp,
  398. uint8_t& mant) {
  399. // get table origin point (exp = 0, mant = 0)
  400. float origin = (mantOffset * F_OSC) / ((uint32_t)1 << divExp);
  401. // iterate over possible exponent values
  402. for(int8_t e = expMax; e >= 0; e--) {
  403. // get table column start value (exp = e, mant = 0);
  404. float intervalStart = ((uint32_t)1 << e) * origin;
  405. // check if target value is in this column
  406. if(target >= intervalStart) {
  407. // save exponent value
  408. exp = e;
  409. // calculate size of step between table rows
  410. float stepSize = intervalStart / (float)mantOffset;
  411. // get target point position (exp = e, mant = m)
  412. mant = ((target - intervalStart) / stepSize);
  413. // we only need the first match, terminate
  414. return;
  415. }
  416. }
  417. }
  418. bool CC1101::setBitRate(float bitrate) {
  419. if(bitrate < 0.6 || bitrate > 500.0) return false;
  420. // set mode to standby
  421. SpiStrobe(CC1101_SIDLE);
  422. // calculate exponent and mantissa values
  423. uint8_t e = 0;
  424. uint8_t m = 0;
  425. getExpMant(bitrate * 1000.0, 256, 28, 14, e, m);
  426. // set bit rate value
  427. SpiSetRegValue(CC1101_MDMCFG4, e, 3, 0);
  428. SpiSetRegValue(CC1101_MDMCFG3, m, 7, 0);
  429. return true;
  430. }