Jonathan Jones
/
Radios
Radio Structures in OOP
drivers/CC1101/CC1101.cpp@3:dc7e9c6bc26c, 2015-01-03 (annotated)
- Committer:
- jjones646
- Date:
- Sat Jan 03 04:35:32 2015 +0000
- Revision:
- 3:dc7e9c6bc26c
- Parent:
- 2:7d523bdd2f50
- Child:
- 5:146523a0d1f4
updating with threaded tasks for communication classes
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
jjones646 | 2:7d523bdd2f50 | 1 | #include "CC1101.h" |
jjones646 | 2:7d523bdd2f50 | 2 | |
jjones646 | 2:7d523bdd2f50 | 3 | |
jjones646 | 2:7d523bdd2f50 | 4 | // Default constructor |
jjones646 | 2:7d523bdd2f50 | 5 | CC1101::CC1101() : |
jjones646 | 3:dc7e9c6bc26c | 6 | CommLink() |
jjones646 | 2:7d523bdd2f50 | 7 | { |
jjones646 | 2:7d523bdd2f50 | 8 | } |
jjones646 | 2:7d523bdd2f50 | 9 | |
jjones646 | 3:dc7e9c6bc26c | 10 | // Main constructor |
jjones646 | 3:dc7e9c6bc26c | 11 | CC1101::CC1101(PinName mosi, PinName miso, PinName sck, PinName cs, PinName int_pin) : |
jjones646 | 3:dc7e9c6bc26c | 12 | CommLink(mosi, miso, sck, cs, int_pin) |
jjones646 | 3:dc7e9c6bc26c | 13 | { |
jjones646 | 3:dc7e9c6bc26c | 14 | // [X] - 1 - Setup the chip |
jjones646 | 3:dc7e9c6bc26c | 15 | setup(); |
jjones646 | 3:dc7e9c6bc26c | 16 | |
jjones646 | 3:dc7e9c6bc26c | 17 | // [X] - 2 - Call the base class method for beginning full class operation with threads |
jjones646 | 3:dc7e9c6bc26c | 18 | // ================= |
jjones646 | 3:dc7e9c6bc26c | 19 | CommLink::ready(); |
jjones646 | 3:dc7e9c6bc26c | 20 | } |
jjones646 | 2:7d523bdd2f50 | 21 | |
jjones646 | 2:7d523bdd2f50 | 22 | // Deconstructor |
jjones646 | 2:7d523bdd2f50 | 23 | CC1101::~CC1101() |
jjones646 | 2:7d523bdd2f50 | 24 | { |
jjones646 | 3:dc7e9c6bc26c | 25 | if (_spi) |
jjones646 | 3:dc7e9c6bc26c | 26 | delete _spi; |
jjones646 | 3:dc7e9c6bc26c | 27 | if (_cs) |
jjones646 | 3:dc7e9c6bc26c | 28 | delete _cs; |
jjones646 | 3:dc7e9c6bc26c | 29 | if (_int_in) |
jjones646 | 3:dc7e9c6bc26c | 30 | delete _int_in; |
jjones646 | 3:dc7e9c6bc26c | 31 | } |
jjones646 | 2:7d523bdd2f50 | 32 | |
jjones646 | 3:dc7e9c6bc26c | 33 | |
jjones646 | 3:dc7e9c6bc26c | 34 | void CC1101::setup(void) |
jjones646 | 3:dc7e9c6bc26c | 35 | { |
jjones646 | 3:dc7e9c6bc26c | 36 | // [X] - 1 - Initialize the CC1101 radio transceiver for operation |
jjones646 | 3:dc7e9c6bc26c | 37 | // ================= |
jjones646 | 3:dc7e9c6bc26c | 38 | set_init_vars(); |
jjones646 | 3:dc7e9c6bc26c | 39 | assign_if_freq(CCXXX1_IF_FREQUENCY); |
jjones646 | 3:dc7e9c6bc26c | 40 | freq(CCXXX1_BASE_FREQUENCY); |
jjones646 | 3:dc7e9c6bc26c | 41 | assign_channel_spacing(200000); // 200kHz |
jjones646 | 3:dc7e9c6bc26c | 42 | datarate(250000); // 250 kBaud |
jjones646 | 3:dc7e9c6bc26c | 43 | set_rf_settings(); |
jjones646 | 3:dc7e9c6bc26c | 44 | |
jjones646 | 3:dc7e9c6bc26c | 45 | // [] - 2 - Test the interrupt pin for proper operation |
jjones646 | 3:dc7e9c6bc26c | 46 | // ================= |
jjones646 | 3:dc7e9c6bc26c | 47 | |
jjones646 | 3:dc7e9c6bc26c | 48 | // [] - 3 - Check the CC1101's version register to ensure the chip is what we believe it to be |
jjones646 | 3:dc7e9c6bc26c | 49 | // ================= |
jjones646 | 3:dc7e9c6bc26c | 50 | |
jjones646 | 3:dc7e9c6bc26c | 51 | } |
jjones646 | 3:dc7e9c6bc26c | 52 | |
jjones646 | 3:dc7e9c6bc26c | 53 | |
jjones646 | 3:dc7e9c6bc26c | 54 | int32_t CC1101::powerUp(void) |
jjones646 | 3:dc7e9c6bc26c | 55 | { |
jjones646 | 3:dc7e9c6bc26c | 56 | #if CCXXX1_DEBUG_MODE > 0 |
jjones646 | 3:dc7e9c6bc26c | 57 | std::printf("[CC1101 RADIO TRANSCEIVER INITILIZATION]\r\n"); |
jjones646 | 3:dc7e9c6bc26c | 58 | #endif |
jjones646 | 3:dc7e9c6bc26c | 59 | |
jjones646 | 3:dc7e9c6bc26c | 60 | // power_on_reset(); |
jjones646 | 3:dc7e9c6bc26c | 61 | |
jjones646 | 3:dc7e9c6bc26c | 62 | // now send the assigned rfSettings struct to the CC1101 for full inililization |
jjones646 | 3:dc7e9c6bc26c | 63 | // init(); |
jjones646 | 3:dc7e9c6bc26c | 64 | |
jjones646 | 3:dc7e9c6bc26c | 65 | // scan(); |
jjones646 | 3:dc7e9c6bc26c | 66 | |
jjones646 | 3:dc7e9c6bc26c | 67 | return 0; |
jjones646 | 2:7d523bdd2f50 | 68 | } |
jjones646 | 2:7d523bdd2f50 | 69 | |
jjones646 | 2:7d523bdd2f50 | 70 | |
jjones646 | 2:7d523bdd2f50 | 71 | bool CC1101::isConnected(void) |
jjones646 | 2:7d523bdd2f50 | 72 | { |
jjones646 | 2:7d523bdd2f50 | 73 | // [] - 1 - Perform a check to ensure the CC1101 can provide communication with a secondary base station link |
jjones646 | 3:dc7e9c6bc26c | 74 | // ================= |
jjones646 | 2:7d523bdd2f50 | 75 | // Note: This does not necessarily mean the link must be reliable, this only needs to determine: `Can the perheripial provide communication?` |
jjones646 | 3:dc7e9c6bc26c | 76 | |
jjones646 | 2:7d523bdd2f50 | 77 | // [] - 2 - Return true/false for indicating a connected communication link |
jjones646 | 3:dc7e9c6bc26c | 78 | // ================= |
jjones646 | 3:dc7e9c6bc26c | 79 | |
jjones646 | 2:7d523bdd2f50 | 80 | return true; |
jjones646 | 2:7d523bdd2f50 | 81 | } |
jjones646 | 2:7d523bdd2f50 | 82 | |
jjones646 | 2:7d523bdd2f50 | 83 | |
jjones646 | 2:7d523bdd2f50 | 84 | uint32_t CC1101::reset(void) |
jjones646 | 2:7d523bdd2f50 | 85 | { |
jjones646 | 3:dc7e9c6bc26c | 86 | // [X] - 1 - Perform a soft reset for the CC1101 transceiver |
jjones646 | 3:dc7e9c6bc26c | 87 | // ================= |
jjones646 | 3:dc7e9c6bc26c | 88 | strobe(CCXXX1_SRES); |
jjones646 | 3:dc7e9c6bc26c | 89 | return 0; // success |
jjones646 | 2:7d523bdd2f50 | 90 | } |
jjones646 | 2:7d523bdd2f50 | 91 | |
jjones646 | 2:7d523bdd2f50 | 92 | |
jjones646 | 2:7d523bdd2f50 | 93 | uint32_t CC1101::selfTest(void) |
jjones646 | 2:7d523bdd2f50 | 94 | { |
jjones646 | 3:dc7e9c6bc26c | 95 | // [X] - 1 - Get the chip's version number and fail if different from what was expected. |
jjones646 | 3:dc7e9c6bc26c | 96 | _chip_version = status(CCXXX1_VERSION); |
jjones646 | 3:dc7e9c6bc26c | 97 | |
jjones646 | 3:dc7e9c6bc26c | 98 | if (_chip_version != CCXXX1_EXPECTED_VERSION_NUMBER) { |
jjones646 | 3:dc7e9c6bc26c | 99 | |
jjones646 | 3:dc7e9c6bc26c | 100 | // send message over serial port |
jjones646 | 3:dc7e9c6bc26c | 101 | std::printf( |
jjones646 | 3:dc7e9c6bc26c | 102 | "[FATAL ERROR]\r\n" |
jjones646 | 3:dc7e9c6bc26c | 103 | " Wrong version number returned from chip's 'VERSION' register (Addr: 0x%02X)\r\n" |
jjones646 | 3:dc7e9c6bc26c | 104 | "\r\n" |
jjones646 | 3:dc7e9c6bc26c | 105 | " Expected: 0x%02X\r\n" |
jjones646 | 3:dc7e9c6bc26c | 106 | " Found: 0x%02X\r\n" |
jjones646 | 3:dc7e9c6bc26c | 107 | "\r\n" |
jjones646 | 3:dc7e9c6bc26c | 108 | " Troubleshooting Tips:\r\n" |
jjones646 | 3:dc7e9c6bc26c | 109 | " - Check that the chip is fully connected with no soldering errors\r\n" |
jjones646 | 3:dc7e9c6bc26c | 110 | " - Determine if chip is newer version & update firmware\r\n" |
jjones646 | 3:dc7e9c6bc26c | 111 | , CCXXX1_VERSION, CCXXX1_EXPECTED_VERSION_NUMBER, _chip_version); |
jjones646 | 3:dc7e9c6bc26c | 112 | |
jjones646 | 3:dc7e9c6bc26c | 113 | return 1; |
jjones646 | 3:dc7e9c6bc26c | 114 | } |
jjones646 | 3:dc7e9c6bc26c | 115 | return 0; // success |
jjones646 | 3:dc7e9c6bc26c | 116 | } |
jjones646 | 3:dc7e9c6bc26c | 117 | |
jjones646 | 3:dc7e9c6bc26c | 118 | void CC1101::set_init_vars(void) |
jjones646 | 3:dc7e9c6bc26c | 119 | { |
jjones646 | 3:dc7e9c6bc26c | 120 | // define an initial state of an unselected chip |
jjones646 | 3:dc7e9c6bc26c | 121 | *_cs = 1; |
jjones646 | 2:7d523bdd2f50 | 122 | |
jjones646 | 3:dc7e9c6bc26c | 123 | _channel = 1; |
jjones646 | 3:dc7e9c6bc26c | 124 | _address = 0x00; |
jjones646 | 3:dc7e9c6bc26c | 125 | |
jjones646 | 3:dc7e9c6bc26c | 126 | // frequency that radio links with another CC1101 over the air |
jjones646 | 3:dc7e9c6bc26c | 127 | _base_freq = CCXXX1_BASE_FREQUENCY; |
jjones646 | 3:dc7e9c6bc26c | 128 | |
jjones646 | 3:dc7e9c6bc26c | 129 | // turn off address packet filtering and assign 0 (broadcast address) to the address value |
jjones646 | 3:dc7e9c6bc26c | 130 | _pck_control.addr_check = ADDR_OFF; |
jjones646 | 3:dc7e9c6bc26c | 131 | |
jjones646 | 3:dc7e9c6bc26c | 132 | // these values determine how the CC1101 will handel a packet |
jjones646 | 3:dc7e9c6bc26c | 133 | _pck_control.whitening_en = false; |
jjones646 | 3:dc7e9c6bc26c | 134 | |
jjones646 | 3:dc7e9c6bc26c | 135 | // enable CRC calculation in TX and CRC checking in RX |
jjones646 | 3:dc7e9c6bc26c | 136 | _pck_control.crc_en = true; |
jjones646 | 3:dc7e9c6bc26c | 137 | |
jjones646 | 3:dc7e9c6bc26c | 138 | // enable automatically flushing the RX buffer on a bad CRC (only works if 1 packet is in the RX buffer) |
jjones646 | 3:dc7e9c6bc26c | 139 | _pck_control.autoflush_en = true; |
jjones646 | 3:dc7e9c6bc26c | 140 | |
jjones646 | 3:dc7e9c6bc26c | 141 | // enable appending 2 status bytes to the end of every packet that includes the CRC and |
jjones646 | 3:dc7e9c6bc26c | 142 | _pck_control.status_field_en = true; |
jjones646 | 3:dc7e9c6bc26c | 143 | |
jjones646 | 3:dc7e9c6bc26c | 144 | // normal packet mode uses RX and TX buffers |
jjones646 | 3:dc7e9c6bc26c | 145 | _pck_control.format_type = FORMAT_DEFAULT; |
jjones646 | 3:dc7e9c6bc26c | 146 | |
jjones646 | 3:dc7e9c6bc26c | 147 | // setup how the payload of the packet is transmitted - default to a fixed length of 61 bytes |
jjones646 | 3:dc7e9c6bc26c | 148 | _pck_control.length_type = PACKET_VARIABLE; |
jjones646 | 3:dc7e9c6bc26c | 149 | //_pck_control.length_type = PACKET_FIXED; |
jjones646 | 3:dc7e9c6bc26c | 150 | //_pck_control.size = 61; |
jjones646 | 3:dc7e9c6bc26c | 151 | |
jjones646 | 3:dc7e9c6bc26c | 152 | // this is a preamble threshold for determining when a packet should be accepted |
jjones646 | 3:dc7e9c6bc26c | 153 | _pck_control.preamble_thresh = 2; |
jjones646 | 3:dc7e9c6bc26c | 154 | |
jjones646 | 3:dc7e9c6bc26c | 155 | // these values determine how the frequency bands and channels are distributed as well as defining the modulation type |
jjones646 | 3:dc7e9c6bc26c | 156 | _modem.dc_filter_off_en = false; |
jjones646 | 3:dc7e9c6bc26c | 157 | _modem.manchester_encode_en = false; |
jjones646 | 3:dc7e9c6bc26c | 158 | _modem.fec_en = false; |
jjones646 | 3:dc7e9c6bc26c | 159 | |
jjones646 | 3:dc7e9c6bc26c | 160 | // bandwidth configurations |
jjones646 | 3:dc7e9c6bc26c | 161 | _modem.channel_bw = 2; |
jjones646 | 3:dc7e9c6bc26c | 162 | _modem.channel_bw_exp = 0; |
jjones646 | 3:dc7e9c6bc26c | 163 | _modem.channel_space_exp = 2; |
jjones646 | 3:dc7e9c6bc26c | 164 | _modem.data_rate_exp = 13; |
jjones646 | 3:dc7e9c6bc26c | 165 | |
jjones646 | 3:dc7e9c6bc26c | 166 | _modem.mod_type = MOD_GFSK; |
jjones646 | 3:dc7e9c6bc26c | 167 | _modem.sync_mode = SYNC_HIGH_ALLOW_TWO; |
jjones646 | 3:dc7e9c6bc26c | 168 | _modem.preamble_bytes = PREAM_FOUR; |
jjones646 | 3:dc7e9c6bc26c | 169 | |
jjones646 | 3:dc7e9c6bc26c | 170 | // the values assigned here are used for the frequency synthesizer control |
jjones646 | 3:dc7e9c6bc26c | 171 | // assign_if_freq(CCXXX1_IF_FREQUENCY); |
jjones646 | 3:dc7e9c6bc26c | 172 | |
jjones646 | 3:dc7e9c6bc26c | 173 | // set all the configuration values into the rfSettings struct |
jjones646 | 3:dc7e9c6bc26c | 174 | // set_rf_settings(); |
jjones646 | 3:dc7e9c6bc26c | 175 | } |
jjones646 | 3:dc7e9c6bc26c | 176 | |
jjones646 | 3:dc7e9c6bc26c | 177 | |
jjones646 | 3:dc7e9c6bc26c | 178 | // returns the current mode that the CC1101 is operating in |
jjones646 | 3:dc7e9c6bc26c | 179 | uint8_t CC1101::mode(void) |
jjones646 | 3:dc7e9c6bc26c | 180 | { |
jjones646 | 3:dc7e9c6bc26c | 181 | return status(CCXXX1_MARCSTATE); |
jjones646 | 3:dc7e9c6bc26c | 182 | } |
jjones646 | 3:dc7e9c6bc26c | 183 | |
jjones646 | 3:dc7e9c6bc26c | 184 | |
jjones646 | 3:dc7e9c6bc26c | 185 | int32_t CC1101::sendData(uint8_t *buf, uint8_t size) |
jjones646 | 3:dc7e9c6bc26c | 186 | { |
jjones646 | 3:dc7e9c6bc26c | 187 | // [X] - 1 - Move all values down by 1 to make room for the packet's size value. |
jjones646 | 3:dc7e9c6bc26c | 188 | // ================= |
jjones646 | 3:dc7e9c6bc26c | 189 | for (uint8_t i = size; i > 0; i--) |
jjones646 | 3:dc7e9c6bc26c | 190 | buf[i] = buf[i-1]; |
jjones646 | 3:dc7e9c6bc26c | 191 | |
jjones646 | 3:dc7e9c6bc26c | 192 | |
jjones646 | 3:dc7e9c6bc26c | 193 | // [X] - 2 - Place the packet's size as the array's first value. |
jjones646 | 3:dc7e9c6bc26c | 194 | // ================= |
jjones646 | 3:dc7e9c6bc26c | 195 | buf[0] = size; |
jjones646 | 3:dc7e9c6bc26c | 196 | |
jjones646 | 3:dc7e9c6bc26c | 197 | |
jjones646 | 3:dc7e9c6bc26c | 198 | #if CCXXX1_DEBUG_MODE > 0 |
jjones646 | 3:dc7e9c6bc26c | 199 | std::printf("\r\n[PACKET TRANSMITTED]\r\n Bytes: %u\r\n", size); |
jjones646 | 3:dc7e9c6bc26c | 200 | #endif |
jjones646 | 3:dc7e9c6bc26c | 201 | |
jjones646 | 3:dc7e9c6bc26c | 202 | |
jjones646 | 3:dc7e9c6bc26c | 203 | // [X] - 3 - Send the data to the CC1101. Increment the size value by 1 before doing so to account for the buffer's inserted value |
jjones646 | 3:dc7e9c6bc26c | 204 | // ================= |
jjones646 | 3:dc7e9c6bc26c | 205 | write_reg(CCXXX1_TXFIFO, buf, ++size); |
jjones646 | 3:dc7e9c6bc26c | 206 | |
jjones646 | 3:dc7e9c6bc26c | 207 | |
jjones646 | 3:dc7e9c6bc26c | 208 | #if CCXXX1_DEBUG_MODE > 1 |
jjones646 | 3:dc7e9c6bc26c | 209 | Timer t1; |
jjones646 | 3:dc7e9c6bc26c | 210 | #endif |
jjones646 | 3:dc7e9c6bc26c | 211 | |
jjones646 | 3:dc7e9c6bc26c | 212 | |
jjones646 | 3:dc7e9c6bc26c | 213 | // [X] - 4 - Enter the TX state. |
jjones646 | 3:dc7e9c6bc26c | 214 | // ================= |
jjones646 | 3:dc7e9c6bc26c | 215 | strobe(CCXXX1_STX); |
jjones646 | 3:dc7e9c6bc26c | 216 | |
jjones646 | 3:dc7e9c6bc26c | 217 | |
jjones646 | 3:dc7e9c6bc26c | 218 | #if CCXXX1_DEBUG_MODE > 1 |
jjones646 | 3:dc7e9c6bc26c | 219 | /* For the debug mode, this will determine how long the CC1101 takes to transmit everything in the TX buffer |
jjones646 | 3:dc7e9c6bc26c | 220 | and enter or return to the RX state. |
jjones646 | 3:dc7e9c6bc26c | 221 | */ |
jjones646 | 3:dc7e9c6bc26c | 222 | t1.start(); |
jjones646 | 3:dc7e9c6bc26c | 223 | float ti = t1.read(); |
jjones646 | 3:dc7e9c6bc26c | 224 | #endif |
jjones646 | 3:dc7e9c6bc26c | 225 | |
jjones646 | 3:dc7e9c6bc26c | 226 | |
jjones646 | 3:dc7e9c6bc26c | 227 | // [X] - 5 - Wait until radio enters back to the RX state. |
jjones646 | 3:dc7e9c6bc26c | 228 | // ================= |
jjones646 | 3:dc7e9c6bc26c | 229 | // *Note: Takes very few cycles, so might as well wait before returning to elimate querky errors. |
jjones646 | 3:dc7e9c6bc26c | 230 | while(mode() != 0x0D); |
jjones646 | 3:dc7e9c6bc26c | 231 | |
jjones646 | 3:dc7e9c6bc26c | 232 | #if CCXXX1_DEBUG_MODE > 1 |
jjones646 | 3:dc7e9c6bc26c | 233 | t1.stop(); |
jjones646 | 3:dc7e9c6bc26c | 234 | std::printf(" Time: %02.4f ms\r\n", (t1.read() - ti)*1000); |
jjones646 | 3:dc7e9c6bc26c | 235 | #endif |
jjones646 | 3:dc7e9c6bc26c | 236 | |
jjones646 | 3:dc7e9c6bc26c | 237 | // [] - 6 - Return any error codes if necessary. |
jjones646 | 3:dc7e9c6bc26c | 238 | // ================= |
jjones646 | 3:dc7e9c6bc26c | 239 | |
jjones646 | 3:dc7e9c6bc26c | 240 | return 0; // success |
jjones646 | 3:dc7e9c6bc26c | 241 | } |
jjones646 | 3:dc7e9c6bc26c | 242 | |
jjones646 | 3:dc7e9c6bc26c | 243 | |
jjones646 | 3:dc7e9c6bc26c | 244 | int32_t CC1101::getData(uint8_t *buf, uint8_t *length) |
jjones646 | 3:dc7e9c6bc26c | 245 | { |
jjones646 | 3:dc7e9c6bc26c | 246 | // [X] - 1 - Update the frequency offset estimate. |
jjones646 | 3:dc7e9c6bc26c | 247 | // ================= |
jjones646 | 3:dc7e9c6bc26c | 248 | write_reg(CCXXX1_FSCTRL0, status(CCXXX1_FREQEST)); |
jjones646 | 3:dc7e9c6bc26c | 249 | |
jjones646 | 3:dc7e9c6bc26c | 250 | |
jjones646 | 3:dc7e9c6bc26c | 251 | // [X] - 2 - Get the packet's size. |
jjones646 | 3:dc7e9c6bc26c | 252 | // ================= |
jjones646 | 3:dc7e9c6bc26c | 253 | uint8_t rx_size; |
jjones646 | 3:dc7e9c6bc26c | 254 | read_reg(CCXXX1_RXFIFO, &rx_size, 1); |
jjones646 | 3:dc7e9c6bc26c | 255 | |
jjones646 | 3:dc7e9c6bc26c | 256 | |
jjones646 | 3:dc7e9c6bc26c | 257 | // [X] - 3 - Check if there are indeed bytes to be read. |
jjones646 | 3:dc7e9c6bc26c | 258 | // ================= |
jjones646 | 3:dc7e9c6bc26c | 259 | if (rx_size & CCXXX1_RXFIFO_MASK) { |
jjones646 | 3:dc7e9c6bc26c | 260 | |
jjones646 | 3:dc7e9c6bc26c | 261 | // [X] - 3.1 - Check if the received data will fit in the provided buffer - fill the buffer if so. |
jjones646 | 3:dc7e9c6bc26c | 262 | // ================= |
jjones646 | 3:dc7e9c6bc26c | 263 | if (rx_size <= *length) { |
jjones646 | 3:dc7e9c6bc26c | 264 | |
jjones646 | 3:dc7e9c6bc26c | 265 | // [X] - 3.1a - Read in received data from the CC1101 and put the contents in the provided buffer. |
jjones646 | 3:dc7e9c6bc26c | 266 | *length = rx_size; // set the correct length |
jjones646 | 3:dc7e9c6bc26c | 267 | read_reg(CCXXX1_RXFIFO, buf, *length); |
jjones646 | 3:dc7e9c6bc26c | 268 | |
jjones646 | 3:dc7e9c6bc26c | 269 | /* The RSSI value takes a bit to be determined by the CC1101, so having 2 separate SPI reads gives |
jjones646 | 3:dc7e9c6bc26c | 270 | the CC1101 enough time to determine the correct value. |
jjones646 | 3:dc7e9c6bc26c | 271 | */ |
jjones646 | 3:dc7e9c6bc26c | 272 | |
jjones646 | 3:dc7e9c6bc26c | 273 | // [X] - 3.1b - Read the 2 appended status bytes. |
jjones646 | 3:dc7e9c6bc26c | 274 | // status[0] = RSSI. status[1] = LQI. |
jjones646 | 3:dc7e9c6bc26c | 275 | uint8_t status_bytes[2]; |
jjones646 | 3:dc7e9c6bc26c | 276 | read_reg(CCXXX1_RXFIFO, status_bytes, 2); |
jjones646 | 3:dc7e9c6bc26c | 277 | |
jjones646 | 3:dc7e9c6bc26c | 278 | // Update the RSSI reading. |
jjones646 | 3:dc7e9c6bc26c | 279 | rssi(status_bytes[0]); |
jjones646 | 3:dc7e9c6bc26c | 280 | _lqi = status_bytes[1] & CCXXX1_RXFIFO_MASK; // MSB of LQI is the CRC_OK bit - The interrupt is only triggered if CRC is OK, so no need to check again. |
jjones646 | 3:dc7e9c6bc26c | 281 | |
jjones646 | 3:dc7e9c6bc26c | 282 | #if CCXXX1_DEBUG_MODE > 0 |
jjones646 | 3:dc7e9c6bc26c | 283 | std::printf("\r\n[PACKET RECEIVED]\r\n Bytes: %u\r\n", *length); |
jjones646 | 3:dc7e9c6bc26c | 284 | std::printf(" RSSI: %ddBm\r\n", _rssi); |
jjones646 | 3:dc7e9c6bc26c | 285 | std::printf(" LQI: %u\r\n", _lqi); |
jjones646 | 3:dc7e9c6bc26c | 286 | #endif |
jjones646 | 3:dc7e9c6bc26c | 287 | |
jjones646 | 3:dc7e9c6bc26c | 288 | // [X] - 3.2c - Go back to the receiving state since CC1101 is configured for transitioning to IDLE on receiving a packet. |
jjones646 | 3:dc7e9c6bc26c | 289 | rx_mode(); |
jjones646 | 3:dc7e9c6bc26c | 290 | return 0; // success |
jjones646 | 3:dc7e9c6bc26c | 291 | } else { |
jjones646 | 3:dc7e9c6bc26c | 292 | *length = rx_size; |
jjones646 | 3:dc7e9c6bc26c | 293 | flush_rx(); |
jjones646 | 3:dc7e9c6bc26c | 294 | return -2; // passed buffer size is not large enough |
jjones646 | 3:dc7e9c6bc26c | 295 | } |
jjones646 | 3:dc7e9c6bc26c | 296 | } |
jjones646 | 3:dc7e9c6bc26c | 297 | |
jjones646 | 3:dc7e9c6bc26c | 298 | flush_rx(); |
jjones646 | 3:dc7e9c6bc26c | 299 | return -1; // there is no new data to read |
jjones646 | 2:7d523bdd2f50 | 300 | } |
jjones646 | 2:7d523bdd2f50 | 301 | |
jjones646 | 2:7d523bdd2f50 | 302 | |
jjones646 | 3:dc7e9c6bc26c | 303 | // Read Register |
jjones646 | 3:dc7e9c6bc26c | 304 | uint8_t CC1101::read_reg(uint8_t addr) |
jjones646 | 3:dc7e9c6bc26c | 305 | { |
jjones646 | 3:dc7e9c6bc26c | 306 | toggle_cs(); |
jjones646 | 3:dc7e9c6bc26c | 307 | _spi->write(addr | CCXXX1_READ_SINGLE); |
jjones646 | 3:dc7e9c6bc26c | 308 | uint8_t x = _spi->write(0); |
jjones646 | 3:dc7e9c6bc26c | 309 | toggle_cs(); |
jjones646 | 3:dc7e9c6bc26c | 310 | |
jjones646 | 3:dc7e9c6bc26c | 311 | #if CCXXX1_DEBUG_MODE > 1 |
jjones646 | 3:dc7e9c6bc26c | 312 | std::printf("\r\n== Single Register Read ==\r\n Address: 0x%02X\r\n Value: 0x%02X\r\n", addr, x); |
jjones646 | 3:dc7e9c6bc26c | 313 | #endif |
jjones646 | 3:dc7e9c6bc26c | 314 | return x; |
jjones646 | 3:dc7e9c6bc26c | 315 | } // read_reg |
jjones646 | 3:dc7e9c6bc26c | 316 | void CC1101::read_reg(uint8_t addr, uint8_t *buffer, uint8_t count) |
jjones646 | 3:dc7e9c6bc26c | 317 | { |
jjones646 | 3:dc7e9c6bc26c | 318 | toggle_cs(); |
jjones646 | 3:dc7e9c6bc26c | 319 | _spi->write(addr | CCXXX1_READ_BURST); |
jjones646 | 3:dc7e9c6bc26c | 320 | tiny_delay(); |
jjones646 | 3:dc7e9c6bc26c | 321 | for (uint8_t i = 0; i < count; i++) { |
jjones646 | 3:dc7e9c6bc26c | 322 | buffer[i] = _spi->write(0); |
jjones646 | 3:dc7e9c6bc26c | 323 | tiny_delay(); |
jjones646 | 3:dc7e9c6bc26c | 324 | } |
jjones646 | 3:dc7e9c6bc26c | 325 | toggle_cs(); |
jjones646 | 3:dc7e9c6bc26c | 326 | |
jjones646 | 3:dc7e9c6bc26c | 327 | #if CCXXX1_DEBUG_MODE > 1 |
jjones646 | 3:dc7e9c6bc26c | 328 | std::printf("\r\n== Burst Register Read ==\r\n Address: 0x%02X\r\n Bytes: %u\r\n", addr, count); |
jjones646 | 3:dc7e9c6bc26c | 329 | #endif |
jjones646 | 3:dc7e9c6bc26c | 330 | } // read_reg |
jjones646 | 3:dc7e9c6bc26c | 331 | |
jjones646 | 3:dc7e9c6bc26c | 332 | |
jjones646 | 3:dc7e9c6bc26c | 333 | |
jjones646 | 3:dc7e9c6bc26c | 334 | // Write Register |
jjones646 | 3:dc7e9c6bc26c | 335 | void CC1101::write_reg(uint8_t addr, uint8_t value) |
jjones646 | 3:dc7e9c6bc26c | 336 | { |
jjones646 | 3:dc7e9c6bc26c | 337 | toggle_cs(); |
jjones646 | 3:dc7e9c6bc26c | 338 | _spi->write(addr); |
jjones646 | 3:dc7e9c6bc26c | 339 | _spi->write(value); |
jjones646 | 3:dc7e9c6bc26c | 340 | toggle_cs(); |
jjones646 | 3:dc7e9c6bc26c | 341 | |
jjones646 | 3:dc7e9c6bc26c | 342 | #if CCXXX1_DEBUG_MODE > 1 |
jjones646 | 3:dc7e9c6bc26c | 343 | std::printf("\r\n== Single Register Write ==\r\n Address: 0x%02X\r\n Value: 0x%02X\r\n", addr, value); |
jjones646 | 3:dc7e9c6bc26c | 344 | #endif |
jjones646 | 3:dc7e9c6bc26c | 345 | } // write_reg |
jjones646 | 3:dc7e9c6bc26c | 346 | void CC1101::write_reg(uint8_t addr, uint8_t *buffer, uint8_t count) |
jjones646 | 3:dc7e9c6bc26c | 347 | { |
jjones646 | 3:dc7e9c6bc26c | 348 | toggle_cs(); |
jjones646 | 3:dc7e9c6bc26c | 349 | _spi->write(addr | CCXXX1_WRITE_BURST); |
jjones646 | 3:dc7e9c6bc26c | 350 | tiny_delay(); |
jjones646 | 3:dc7e9c6bc26c | 351 | for (uint8_t i = 0; i < count; i++) { |
jjones646 | 3:dc7e9c6bc26c | 352 | _spi->write(buffer[i]); |
jjones646 | 3:dc7e9c6bc26c | 353 | tiny_delay(); |
jjones646 | 3:dc7e9c6bc26c | 354 | } |
jjones646 | 3:dc7e9c6bc26c | 355 | toggle_cs(); |
jjones646 | 3:dc7e9c6bc26c | 356 | |
jjones646 | 3:dc7e9c6bc26c | 357 | #if CCXXX1_DEBUG_MODE > 1 |
jjones646 | 3:dc7e9c6bc26c | 358 | std::printf("\r\n== Burst Register Write ==\r\n Address: 0x%02X\r\n Bytes: %u\r\n", addr, count); |
jjones646 | 3:dc7e9c6bc26c | 359 | #endif |
jjones646 | 3:dc7e9c6bc26c | 360 | } // write_reg |
jjones646 | 3:dc7e9c6bc26c | 361 | |
jjones646 | 3:dc7e9c6bc26c | 362 | |
jjones646 | 3:dc7e9c6bc26c | 363 | // Strobe |
jjones646 | 3:dc7e9c6bc26c | 364 | uint8_t CC1101::strobe(uint8_t addr) |
jjones646 | 3:dc7e9c6bc26c | 365 | { |
jjones646 | 3:dc7e9c6bc26c | 366 | toggle_cs(); |
jjones646 | 3:dc7e9c6bc26c | 367 | uint8_t x = _spi->write(addr); |
jjones646 | 3:dc7e9c6bc26c | 368 | toggle_cs(); |
jjones646 | 3:dc7e9c6bc26c | 369 | return x; |
jjones646 | 3:dc7e9c6bc26c | 370 | } // strobe |
jjones646 | 3:dc7e9c6bc26c | 371 | |
jjones646 | 3:dc7e9c6bc26c | 372 | |
jjones646 | 3:dc7e9c6bc26c | 373 | // Macro to calibrate the frequency synthesizer |
jjones646 | 3:dc7e9c6bc26c | 374 | void CC1101::calibrate(void) |
jjones646 | 2:7d523bdd2f50 | 375 | { |
jjones646 | 3:dc7e9c6bc26c | 376 | // Send the calibration strobe |
jjones646 | 3:dc7e9c6bc26c | 377 | strobe(CCXXX1_SCAL); |
jjones646 | 3:dc7e9c6bc26c | 378 | |
jjones646 | 3:dc7e9c6bc26c | 379 | // Wait for the radio to leave the calibration step |
jjones646 | 3:dc7e9c6bc26c | 380 | while( (mode() == 0x04) | (mode() == 0x05) ); |
jjones646 | 3:dc7e9c6bc26c | 381 | |
jjones646 | 3:dc7e9c6bc26c | 382 | // The radio is now is IDLE mode, so go to RX mode |
jjones646 | 3:dc7e9c6bc26c | 383 | rx_mode(); |
jjones646 | 3:dc7e9c6bc26c | 384 | |
jjones646 | 3:dc7e9c6bc26c | 385 | // Wait for the radio to enter back into RX mode |
jjones646 | 3:dc7e9c6bc26c | 386 | while( mode() != 0x0D ); |
jjones646 | 3:dc7e9c6bc26c | 387 | } |
jjones646 | 3:dc7e9c6bc26c | 388 | |
jjones646 | 3:dc7e9c6bc26c | 389 | |
jjones646 | 3:dc7e9c6bc26c | 390 | void CC1101::tiny_delay(void) |
jjones646 | 3:dc7e9c6bc26c | 391 | { |
jjones646 | 3:dc7e9c6bc26c | 392 | int i = 0; |
jjones646 | 3:dc7e9c6bc26c | 393 | while(i < 5) { |
jjones646 | 3:dc7e9c6bc26c | 394 | i++; |
jjones646 | 3:dc7e9c6bc26c | 395 | } |
jjones646 | 3:dc7e9c6bc26c | 396 | } |
jjones646 | 3:dc7e9c6bc26c | 397 | |
jjones646 | 3:dc7e9c6bc26c | 398 | void CC1101::address(uint8_t addr) |
jjones646 | 3:dc7e9c6bc26c | 399 | { |
jjones646 | 3:dc7e9c6bc26c | 400 | _address = addr; |
jjones646 | 3:dc7e9c6bc26c | 401 | // NOW, WRITE THE ADDRESS TO THE CC1101 |
jjones646 | 3:dc7e9c6bc26c | 402 | } |
jjones646 | 3:dc7e9c6bc26c | 403 | |
jjones646 | 3:dc7e9c6bc26c | 404 | uint8_t CC1101::lqi(void) |
jjones646 | 3:dc7e9c6bc26c | 405 | { |
jjones646 | 3:dc7e9c6bc26c | 406 | return 0x3F - (_lqi & 0x3F); |
jjones646 | 3:dc7e9c6bc26c | 407 | } |
jjones646 | 3:dc7e9c6bc26c | 408 | |
jjones646 | 3:dc7e9c6bc26c | 409 | // returns the CC1101's VERSION register that specifices what exact chip version is being used |
jjones646 | 3:dc7e9c6bc26c | 410 | uint8_t CC1101::version(void) |
jjones646 | 3:dc7e9c6bc26c | 411 | { |
jjones646 | 3:dc7e9c6bc26c | 412 | return _chip_version; |
jjones646 | 3:dc7e9c6bc26c | 413 | } |
jjones646 | 3:dc7e9c6bc26c | 414 | |
jjones646 | 3:dc7e9c6bc26c | 415 | void CC1101::channel(uint16_t chan) |
jjones646 | 3:dc7e9c6bc26c | 416 | { |
jjones646 | 3:dc7e9c6bc26c | 417 | if ( chan != _channel ) { |
jjones646 | 3:dc7e9c6bc26c | 418 | _channel = chan; |
jjones646 | 3:dc7e9c6bc26c | 419 | write_reg(CCXXX1_CHANNR, _channel); |
jjones646 | 3:dc7e9c6bc26c | 420 | /* |
jjones646 | 3:dc7e9c6bc26c | 421 | #if CCXXX1_DEBUG_MODE > 0 |
jjones646 | 3:dc7e9c6bc26c | 422 | std::printf("\r\n[CHANNEL UPDATED]\r\n Channel: %02u\r\n Freq: %3.2f MHz\r\n", _channel, static_cast<float>(_final_freq)/1000000); |
jjones646 | 3:dc7e9c6bc26c | 423 | #endif |
jjones646 | 3:dc7e9c6bc26c | 424 | */ |
jjones646 | 3:dc7e9c6bc26c | 425 | } |
jjones646 | 3:dc7e9c6bc26c | 426 | } |
jjones646 | 3:dc7e9c6bc26c | 427 | |
jjones646 | 3:dc7e9c6bc26c | 428 | // RSSI |
jjones646 | 3:dc7e9c6bc26c | 429 | int16_t CC1101::rssi(void) |
jjones646 | 3:dc7e9c6bc26c | 430 | { |
jjones646 | 3:dc7e9c6bc26c | 431 | return _rssi; |
jjones646 | 3:dc7e9c6bc26c | 432 | } |
jjones646 | 3:dc7e9c6bc26c | 433 | void CC1101::rssi(uint8_t rssi_val) |
jjones646 | 3:dc7e9c6bc26c | 434 | { |
jjones646 | 3:dc7e9c6bc26c | 435 | int8_t temp; |
jjones646 | 3:dc7e9c6bc26c | 436 | |
jjones646 | 3:dc7e9c6bc26c | 437 | if (rssi_val & 0x80) { |
jjones646 | 3:dc7e9c6bc26c | 438 | temp = (rssi_val - 256)>>1; |
jjones646 | 3:dc7e9c6bc26c | 439 | } else { |
jjones646 | 3:dc7e9c6bc26c | 440 | temp = rssi_val>>1; // divide by 2 |
jjones646 | 3:dc7e9c6bc26c | 441 | } |
jjones646 | 3:dc7e9c6bc26c | 442 | _rssi = temp - 74; |
jjones646 | 3:dc7e9c6bc26c | 443 | } // rssi |
jjones646 | 3:dc7e9c6bc26c | 444 | |
jjones646 | 3:dc7e9c6bc26c | 445 | |
jjones646 | 3:dc7e9c6bc26c | 446 | void CC1101::flush_rx(void) |
jjones646 | 3:dc7e9c6bc26c | 447 | { |
jjones646 | 3:dc7e9c6bc26c | 448 | // Make sure that the radio is in IDLE state before flushing the FIFO |
jjones646 | 3:dc7e9c6bc26c | 449 | idle(); |
jjones646 | 3:dc7e9c6bc26c | 450 | |
jjones646 | 3:dc7e9c6bc26c | 451 | // Flush RX FIFO |
jjones646 | 3:dc7e9c6bc26c | 452 | strobe(CCXXX1_SFRX); |
jjones646 | 3:dc7e9c6bc26c | 453 | |
jjones646 | 3:dc7e9c6bc26c | 454 | // Enter back into a RX state |
jjones646 | 3:dc7e9c6bc26c | 455 | rx_mode(); |
jjones646 | 3:dc7e9c6bc26c | 456 | } |
jjones646 | 3:dc7e9c6bc26c | 457 | |
jjones646 | 3:dc7e9c6bc26c | 458 | void CC1101::flush_tx(void) |
jjones646 | 3:dc7e9c6bc26c | 459 | { |
jjones646 | 3:dc7e9c6bc26c | 460 | // Make sure that the radio is in IDLE state before flushing the FIFO |
jjones646 | 3:dc7e9c6bc26c | 461 | idle(); |
jjones646 | 3:dc7e9c6bc26c | 462 | |
jjones646 | 3:dc7e9c6bc26c | 463 | // Flush TX FIFO |
jjones646 | 3:dc7e9c6bc26c | 464 | strobe(CCXXX1_SFTX); |
jjones646 | 3:dc7e9c6bc26c | 465 | |
jjones646 | 3:dc7e9c6bc26c | 466 | // Enter back into a RX state |
jjones646 | 3:dc7e9c6bc26c | 467 | rx_mode(); |
jjones646 | 2:7d523bdd2f50 | 468 | } |
jjones646 | 2:7d523bdd2f50 | 469 | |
jjones646 | 3:dc7e9c6bc26c | 470 | |
jjones646 | 3:dc7e9c6bc26c | 471 | void CC1101::rx_mode(void) |
jjones646 | 3:dc7e9c6bc26c | 472 | { |
jjones646 | 3:dc7e9c6bc26c | 473 | //strobe(CCXXX1_SIDLE); |
jjones646 | 3:dc7e9c6bc26c | 474 | strobe(CCXXX1_SRX); |
jjones646 | 3:dc7e9c6bc26c | 475 | //while(mode() != 0x0D); |
jjones646 | 3:dc7e9c6bc26c | 476 | } |
jjones646 | 3:dc7e9c6bc26c | 477 | |
jjones646 | 3:dc7e9c6bc26c | 478 | |
jjones646 | 3:dc7e9c6bc26c | 479 | void CC1101::tx_mode(void) |
jjones646 | 3:dc7e9c6bc26c | 480 | { |
jjones646 | 3:dc7e9c6bc26c | 481 | //strobe(CCXXX1_SIDLE); |
jjones646 | 3:dc7e9c6bc26c | 482 | strobe(CCXXX1_STX); |
jjones646 | 3:dc7e9c6bc26c | 483 | // while(mode() != 0x13); |
jjones646 | 3:dc7e9c6bc26c | 484 | } |
jjones646 | 3:dc7e9c6bc26c | 485 | |
jjones646 | 3:dc7e9c6bc26c | 486 | void CC1101::idle(void) |
jjones646 | 3:dc7e9c6bc26c | 487 | { |
jjones646 | 3:dc7e9c6bc26c | 488 | // Send the IDLE strobe |
jjones646 | 3:dc7e9c6bc26c | 489 | strobe(CCXXX1_SIDLE); |
jjones646 | 3:dc7e9c6bc26c | 490 | // Wait before returning |
jjones646 | 3:dc7e9c6bc26c | 491 | // === THIS LIKELY ISN'T NEEDED === |
jjones646 | 3:dc7e9c6bc26c | 492 | while( mode() != 0x01); |
jjones646 | 3:dc7e9c6bc26c | 493 | } |
jjones646 | 3:dc7e9c6bc26c | 494 | |
jjones646 | 3:dc7e9c6bc26c | 495 | |
jjones646 | 3:dc7e9c6bc26c | 496 | // Status byte & status of a status register |
jjones646 | 3:dc7e9c6bc26c | 497 | uint8_t CC1101::status(void) |
jjones646 | 3:dc7e9c6bc26c | 498 | { |
jjones646 | 3:dc7e9c6bc26c | 499 | return strobe(CCXXX1_SNOP); |
jjones646 | 3:dc7e9c6bc26c | 500 | } |
jjones646 | 3:dc7e9c6bc26c | 501 | |
jjones646 | 3:dc7e9c6bc26c | 502 | uint8_t CC1101::status(uint8_t addr) |
jjones646 | 2:7d523bdd2f50 | 503 | { |
jjones646 | 3:dc7e9c6bc26c | 504 | toggle_cs(); |
jjones646 | 3:dc7e9c6bc26c | 505 | _spi->write(addr | CCXXX1_READ_BURST); |
jjones646 | 3:dc7e9c6bc26c | 506 | tiny_delay(); |
jjones646 | 3:dc7e9c6bc26c | 507 | uint8_t x = _spi->write(0); |
jjones646 | 3:dc7e9c6bc26c | 508 | toggle_cs(); |
jjones646 | 3:dc7e9c6bc26c | 509 | return x; |
jjones646 | 3:dc7e9c6bc26c | 510 | } // status |
jjones646 | 3:dc7e9c6bc26c | 511 | |
jjones646 | 3:dc7e9c6bc26c | 512 | |
jjones646 | 3:dc7e9c6bc26c | 513 | // SET FREQUENCY |
jjones646 | 3:dc7e9c6bc26c | 514 | void CC1101::freq(uint32_t freq) |
jjones646 | 3:dc7e9c6bc26c | 515 | { |
jjones646 | 3:dc7e9c6bc26c | 516 | /* calculate the value that is written to the register for settings the base frequency |
jjones646 | 3:dc7e9c6bc26c | 517 | * that the CC1101 should use for sending/receiving over the air. Default value is equivalent |
jjones646 | 3:dc7e9c6bc26c | 518 | * to 901.83 MHz. |
jjones646 | 3:dc7e9c6bc26c | 519 | */ |
jjones646 | 3:dc7e9c6bc26c | 520 | |
jjones646 | 3:dc7e9c6bc26c | 521 | // this is split into 3 bytes that are written to 3 different registers on the CC1101 |
jjones646 | 3:dc7e9c6bc26c | 522 | uint32_t reg_freq = _base_freq / (CCXXX1_CRYSTAL_FREQUENCY>>16); |
jjones646 | 3:dc7e9c6bc26c | 523 | |
jjones646 | 3:dc7e9c6bc26c | 524 | rfSettings.FREQ2 = (reg_freq>>16) & 0xFF; // high byte, bits 7..6 are always 0 for this register |
jjones646 | 3:dc7e9c6bc26c | 525 | rfSettings.FREQ1 = (reg_freq>>8) & 0xFF; // middle byte |
jjones646 | 3:dc7e9c6bc26c | 526 | rfSettings.FREQ0 = reg_freq & 0xFF; // low byte |
jjones646 | 3:dc7e9c6bc26c | 527 | } |
jjones646 | 3:dc7e9c6bc26c | 528 | |
jjones646 | 3:dc7e9c6bc26c | 529 | |
jjones646 | 3:dc7e9c6bc26c | 530 | void CC1101::datarate(uint32_t rate) |
jjones646 | 3:dc7e9c6bc26c | 531 | { |
jjones646 | 3:dc7e9c6bc26c | 532 | // update the baud rate class member |
jjones646 | 3:dc7e9c6bc26c | 533 | _datarate = rate; |
jjones646 | 3:dc7e9c6bc26c | 534 | |
jjones646 | 3:dc7e9c6bc26c | 535 | // have to be careful with bit shifting here since it requires a large amount of shifts |
jjones646 | 3:dc7e9c6bc26c | 536 | uint32_t shift_val = 28 - (_modem.data_rate_exp & 0x0F); |
jjones646 | 3:dc7e9c6bc26c | 537 | |
jjones646 | 3:dc7e9c6bc26c | 538 | // compute the register value and assign it |
jjones646 | 3:dc7e9c6bc26c | 539 | rfSettings.MDMCFG3 = ((_datarate)/(CCXXX1_CRYSTAL_FREQUENCY>>shift_val)) - 256; |
jjones646 | 2:7d523bdd2f50 | 540 | } |
jjones646 | 2:7d523bdd2f50 | 541 | |
jjones646 | 3:dc7e9c6bc26c | 542 | |
jjones646 | 3:dc7e9c6bc26c | 543 | // =============== |
jjones646 | 3:dc7e9c6bc26c | 544 | void CC1101::assign_modem_params() |
jjones646 | 3:dc7e9c6bc26c | 545 | { |
jjones646 | 3:dc7e9c6bc26c | 546 | rfSettings.MDMCFG4 = (_modem.channel_bw_exp & 0x03)<<6 | (_modem.channel_bw & 0x03)<<4 | (_modem.data_rate_exp & 0x0F); |
jjones646 | 3:dc7e9c6bc26c | 547 | rfSettings.MDMCFG2 = _modem.dc_filter_off_en<<7 | (_modem.mod_type & 0x07)<<4 | _modem.manchester_encode_en<<3 | (_modem.sync_mode & 0x07); |
jjones646 | 3:dc7e9c6bc26c | 548 | rfSettings.MDMCFG1 = _modem.fec_en<<7 | (_modem.preamble_bytes & 0x07)<<4 | (_modem.channel_space_exp & 0x03); |
jjones646 | 3:dc7e9c6bc26c | 549 | } |
jjones646 | 3:dc7e9c6bc26c | 550 | // =============== |
jjones646 | 3:dc7e9c6bc26c | 551 | void CC1101::assign_packet_params() |
jjones646 | 3:dc7e9c6bc26c | 552 | { |
jjones646 | 3:dc7e9c6bc26c | 553 | rfSettings.PCKCTRL0 = _pck_control.whitening_en<<6 | (_pck_control.format_type & 0x3)<<4 | _pck_control.crc_en<<2 | (_pck_control.length_type & 0x3); |
jjones646 | 3:dc7e9c6bc26c | 554 | rfSettings.PCKCTRL1 = (_pck_control.preamble_thresh & 0x07)<<5 | _pck_control.autoflush_en<<3 | _pck_control.status_field_en<<2 | (_pck_control.addr_check & 0x03); |
jjones646 | 3:dc7e9c6bc26c | 555 | rfSettings.PCKLEN = _pck_control.size; |
jjones646 | 3:dc7e9c6bc26c | 556 | } |
jjones646 | 3:dc7e9c6bc26c | 557 | // =============== |
jjones646 | 3:dc7e9c6bc26c | 558 | void CC1101::assign_if_freq(uint32_t freq) |
jjones646 | 3:dc7e9c6bc26c | 559 | { |
jjones646 | 3:dc7e9c6bc26c | 560 | // The desired IF frequency for RX. Subtracted from FS base frequency in RX. |
jjones646 | 3:dc7e9c6bc26c | 561 | // bits 7..5 are always 0 |
jjones646 | 3:dc7e9c6bc26c | 562 | rfSettings.FSCTRL1 = (freq/(CCXXX1_CRYSTAL_FREQUENCY>>10)) & 0x1F; |
jjones646 | 3:dc7e9c6bc26c | 563 | rfSettings.FSCTRL0 = 0x00; // set the initial freq calibration to 0 |
jjones646 | 3:dc7e9c6bc26c | 564 | } |
jjones646 | 3:dc7e9c6bc26c | 565 | // =============== |
jjones646 | 3:dc7e9c6bc26c | 566 | void CC1101::assign_channel_spacing(uint32_t spacing) |
jjones646 | 3:dc7e9c6bc26c | 567 | { |
jjones646 | 3:dc7e9c6bc26c | 568 | // have to be careful with bit shifting here since it requires a large amount of shifts |
jjones646 | 3:dc7e9c6bc26c | 569 | uint32_t shift_val = 18 - (_modem.channel_space_exp & 0x03); |
jjones646 | 3:dc7e9c6bc26c | 570 | |
jjones646 | 3:dc7e9c6bc26c | 571 | // compute the register value and assign it |
jjones646 | 3:dc7e9c6bc26c | 572 | rfSettings.MDMCFG0 = (spacing/(CCXXX1_CRYSTAL_FREQUENCY>>shift_val)) - 256; |
jjones646 | 3:dc7e9c6bc26c | 573 | } |
jjones646 | 3:dc7e9c6bc26c | 574 | void CC1101::set_rf_settings(void) |
jjones646 | 3:dc7e9c6bc26c | 575 | { |
jjones646 | 3:dc7e9c6bc26c | 576 | // set the fields for packet controls |
jjones646 | 3:dc7e9c6bc26c | 577 | assign_packet_params(); |
jjones646 | 3:dc7e9c6bc26c | 578 | |
jjones646 | 3:dc7e9c6bc26c | 579 | // set the fields for the frequency limits of the modem |
jjones646 | 3:dc7e9c6bc26c | 580 | assign_modem_params(); |
jjones646 | 3:dc7e9c6bc26c | 581 | |
jjones646 | 3:dc7e9c6bc26c | 582 | // assign an address to the CC1101. This can be used to filter packets |
jjones646 | 3:dc7e9c6bc26c | 583 | rfSettings.ADDR = _address; |
jjones646 | 3:dc7e9c6bc26c | 584 | |
jjones646 | 3:dc7e9c6bc26c | 585 | // there can be 16 different channel numbers. The bandwidth and spacing are defined in other registers |
jjones646 | 3:dc7e9c6bc26c | 586 | rfSettings.CHANNR = _channel; |
jjones646 | 3:dc7e9c6bc26c | 587 | |
jjones646 | 3:dc7e9c6bc26c | 588 | // compute the final adjusted frequency so that it will be correct after the constructor |
jjones646 | 3:dc7e9c6bc26c | 589 | // compute_freq(); |
jjones646 | 3:dc7e9c6bc26c | 590 | |
jjones646 | 3:dc7e9c6bc26c | 591 | // disable GDO0 |
jjones646 | 3:dc7e9c6bc26c | 592 | rfSettings.IOCFG0 = 0x2E; |
jjones646 | 3:dc7e9c6bc26c | 593 | |
jjones646 | 3:dc7e9c6bc26c | 594 | // setup for SPI |
jjones646 | 3:dc7e9c6bc26c | 595 | rfSettings.IOCFG1 = 0x0C; |
jjones646 | 3:dc7e9c6bc26c | 596 | |
jjones646 | 3:dc7e9c6bc26c | 597 | // setup for going HIGH when packet received and CRC is ok |
jjones646 | 3:dc7e9c6bc26c | 598 | rfSettings.IOCFG2 = 0x07; |
jjones646 | 3:dc7e9c6bc26c | 599 | |
jjones646 | 3:dc7e9c6bc26c | 600 | rfSettings.DEVIATN = 0x62; |
jjones646 | 3:dc7e9c6bc26c | 601 | |
jjones646 | 3:dc7e9c6bc26c | 602 | rfSettings.FREND1 = 0xB6; |
jjones646 | 3:dc7e9c6bc26c | 603 | rfSettings.FREND0 = 0x10; |
jjones646 | 3:dc7e9c6bc26c | 604 | |
jjones646 | 3:dc7e9c6bc26c | 605 | bool RX_TIME_RSSI = false; |
jjones646 | 3:dc7e9c6bc26c | 606 | bool RX_TIME_QUAL = false; |
jjones646 | 3:dc7e9c6bc26c | 607 | uint8_t RX_TIME = 0x07; // no timeout |
jjones646 | 3:dc7e9c6bc26c | 608 | |
jjones646 | 3:dc7e9c6bc26c | 609 | rfSettings.MCSM2 = (RX_TIME_RSSI<<4) | (RX_TIME_QUAL<<3) | (RX_TIME & 0x07); |
jjones646 | 3:dc7e9c6bc26c | 610 | |
jjones646 | 3:dc7e9c6bc26c | 611 | uint8_t CCA_MODE = 0x00; |
jjones646 | 3:dc7e9c6bc26c | 612 | uint8_t RXOFF_MODE = 0x00; // go directly to IDLE when existing RX |
jjones646 | 3:dc7e9c6bc26c | 613 | //uint8_t RXOFF_MODE = 0x03; // stay in RX when existing RX |
jjones646 | 3:dc7e9c6bc26c | 614 | uint8_t TXOFF_MODE = 0x03; // go directly to RX when existing TX |
jjones646 | 3:dc7e9c6bc26c | 615 | // uint8_t TXOFF_MODE = 0x00; // go directly to IDLE when existing TX |
jjones646 | 3:dc7e9c6bc26c | 616 | |
jjones646 | 3:dc7e9c6bc26c | 617 | rfSettings.MCSM1 = ((CCA_MODE & 0x03)<<4) | ((RXOFF_MODE & 0x03)<<2) | (TXOFF_MODE & 0x03); |
jjones646 | 3:dc7e9c6bc26c | 618 | |
jjones646 | 3:dc7e9c6bc26c | 619 | uint8_t FS_AUTOCAL = 0x01; // calibrate when going from IDLE to RX or TX |
jjones646 | 3:dc7e9c6bc26c | 620 | uint8_t PO_TIMEOUT = 0x02; |
jjones646 | 3:dc7e9c6bc26c | 621 | bool PIN_CTRL_EN = false; |
jjones646 | 3:dc7e9c6bc26c | 622 | bool XOSC_FORCE_ON = false; |
jjones646 | 3:dc7e9c6bc26c | 623 | |
jjones646 | 3:dc7e9c6bc26c | 624 | rfSettings.MCSM0 = ((FS_AUTOCAL & 0x03)<<4) | ((PO_TIMEOUT & 0x03)<<2) | (PIN_CTRL_EN<<1) | (XOSC_FORCE_ON); |
jjones646 | 3:dc7e9c6bc26c | 625 | |
jjones646 | 3:dc7e9c6bc26c | 626 | bool FOC_BS_CS_GATE = false; |
jjones646 | 3:dc7e9c6bc26c | 627 | uint8_t FOC_PRE_K = 0x03; |
jjones646 | 3:dc7e9c6bc26c | 628 | bool FOC_POST_K = true; |
jjones646 | 3:dc7e9c6bc26c | 629 | uint8_t FOC_LIMIT = 0x01; |
jjones646 | 3:dc7e9c6bc26c | 630 | |
jjones646 | 3:dc7e9c6bc26c | 631 | rfSettings.FOCCFG = 0x40 | (FOC_BS_CS_GATE<<5) | ((FOC_PRE_K & 0x03)<<3) | (FOC_POST_K<<2) | (FOC_LIMIT & 0x03); |
jjones646 | 3:dc7e9c6bc26c | 632 | |
jjones646 | 3:dc7e9c6bc26c | 633 | rfSettings.BSCFG = 0x1C; |
jjones646 | 3:dc7e9c6bc26c | 634 | |
jjones646 | 3:dc7e9c6bc26c | 635 | rfSettings.AGCCTRL2 = 0xC7; |
jjones646 | 3:dc7e9c6bc26c | 636 | rfSettings.AGCCTRL1 = 0x00; |
jjones646 | 3:dc7e9c6bc26c | 637 | rfSettings.AGCCTRL0 = 0xB0; |
jjones646 | 3:dc7e9c6bc26c | 638 | |
jjones646 | 3:dc7e9c6bc26c | 639 | // rfSettings.FIFOTHR = 0x0F; // RXFIFO and TXFIFO thresholds. |
jjones646 | 3:dc7e9c6bc26c | 640 | |
jjones646 | 3:dc7e9c6bc26c | 641 | // 33 byte TX FIFO & 32 byte RX FIFO |
jjones646 | 3:dc7e9c6bc26c | 642 | rfSettings.FIFOTHR = 0x07; // RXFIFO and TXFIFO thresholds. |
jjones646 | 3:dc7e9c6bc26c | 643 | } |