For robots and stuff
Wireless/CC1101/CC1101.cpp@0:c5afea7b9057, 2014-12-28 (annotated)
- Committer:
- jjones646
- Date:
- Sun Dec 28 06:27:18 2014 +0000
- Revision:
- 0:c5afea7b9057
initial commit;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
jjones646 | 0:c5afea7b9057 | 1 | #include "CC1101.h" |
jjones646 | 0:c5afea7b9057 | 2 | |
jjones646 | 0:c5afea7b9057 | 3 | #define DEBUG_MODE 0 |
jjones646 | 0:c5afea7b9057 | 4 | #define ACK_SHOW 1 |
jjones646 | 0:c5afea7b9057 | 5 | |
jjones646 | 0:c5afea7b9057 | 6 | // 0db power |
jjones646 | 0:c5afea7b9057 | 7 | #define RF_DB 10 |
jjones646 | 0:c5afea7b9057 | 8 | |
jjones646 | 0:c5afea7b9057 | 9 | CC1101::CC1101() : |
jjones646 | 0:c5afea7b9057 | 10 | Radio() |
jjones646 | 0:c5afea7b9057 | 11 | { }; |
jjones646 | 0:c5afea7b9057 | 12 | |
jjones646 | 0:c5afea7b9057 | 13 | CC1101::CC1101(PinName mosi, PinName miso, PinName clk, PinName csn, PinName tx_led, PinName rx_led, PinName interpt, unsigned int xosc) : |
jjones646 | 0:c5afea7b9057 | 14 | Radio(_tx_led, _rx_led), |
jjones646 | 0:c5afea7b9057 | 15 | _crystal_freq(xosc) |
jjones646 | 0:c5afea7b9057 | 16 | { |
jjones646 | 0:c5afea7b9057 | 17 | setup_spi(mosi, miso, clk); |
jjones646 | 0:c5afea7b9057 | 18 | setup_pins(csn, interpt); |
jjones646 | 0:c5afea7b9057 | 19 | setup_chip(); |
jjones646 | 0:c5afea7b9057 | 20 | } |
jjones646 | 0:c5afea7b9057 | 21 | |
jjones646 | 0:c5afea7b9057 | 22 | // Deconstructor |
jjones646 | 0:c5afea7b9057 | 23 | CC1101::~CC1101() |
jjones646 | 0:c5afea7b9057 | 24 | { |
jjones646 | 0:c5afea7b9057 | 25 | if ( _spi ) { |
jjones646 | 0:c5afea7b9057 | 26 | delete _spi; |
jjones646 | 0:c5afea7b9057 | 27 | } |
jjones646 | 0:c5afea7b9057 | 28 | if ( _rx_int ) { |
jjones646 | 0:c5afea7b9057 | 29 | delete _rx_int; |
jjones646 | 0:c5afea7b9057 | 30 | } |
jjones646 | 0:c5afea7b9057 | 31 | if ( _csn ) { |
jjones646 | 0:c5afea7b9057 | 32 | delete _csn; |
jjones646 | 0:c5afea7b9057 | 33 | } |
jjones646 | 0:c5afea7b9057 | 34 | } |
jjones646 | 0:c5afea7b9057 | 35 | |
jjones646 | 0:c5afea7b9057 | 36 | // Configuration method that is called from the constructors |
jjones646 | 0:c5afea7b9057 | 37 | void CC1101::setup_spi(PinName mosi, PinName miso, PinName clk) |
jjones646 | 0:c5afea7b9057 | 38 | { |
jjones646 | 0:c5afea7b9057 | 39 | if (mosi != NC & miso != NC & clk != NC) { |
jjones646 | 0:c5afea7b9057 | 40 | // Setup the spi for 8 bit data, high steady state clock, second edge capture |
jjones646 | 0:c5afea7b9057 | 41 | _so = miso; |
jjones646 | 0:c5afea7b9057 | 42 | _si = mosi; |
jjones646 | 0:c5afea7b9057 | 43 | _sck = clk; |
jjones646 | 0:c5afea7b9057 | 44 | _spi = new SPI(mosi, miso, clk); |
jjones646 | 0:c5afea7b9057 | 45 | _spi->format(8,0); |
jjones646 | 0:c5afea7b9057 | 46 | _spi->frequency(5000000); |
jjones646 | 0:c5afea7b9057 | 47 | } |
jjones646 | 0:c5afea7b9057 | 48 | } |
jjones646 | 0:c5afea7b9057 | 49 | |
jjones646 | 0:c5afea7b9057 | 50 | |
jjones646 | 0:c5afea7b9057 | 51 | // Configuration method that is called from the constructors |
jjones646 | 0:c5afea7b9057 | 52 | void CC1101::setup_pins(PinName csn, PinName int_pin) |
jjones646 | 0:c5afea7b9057 | 53 | { |
jjones646 | 0:c5afea7b9057 | 54 | if (csn != NC) { |
jjones646 | 0:c5afea7b9057 | 55 | _csn = new DigitalOut(csn); |
jjones646 | 0:c5afea7b9057 | 56 | } |
jjones646 | 0:c5afea7b9057 | 57 | if (int_pin != NC) { |
jjones646 | 0:c5afea7b9057 | 58 | InterruptIn *_rx_int = new InterruptIn(int_pin); |
jjones646 | 0:c5afea7b9057 | 59 | _rx_int->mode(PullDown); |
jjones646 | 0:c5afea7b9057 | 60 | _rx_int->rise(this, &CC1101::isr_receive); // attach member function for interrupt trigger |
jjones646 | 0:c5afea7b9057 | 61 | } |
jjones646 | 0:c5afea7b9057 | 62 | } |
jjones646 | 0:c5afea7b9057 | 63 | |
jjones646 | 0:c5afea7b9057 | 64 | /* |
jjones646 | 0:c5afea7b9057 | 65 | // Configuration method that is called from the constructors |
jjones646 | 0:c5afea7b9057 | 66 | void CC1101::setup_lights(void) |
jjones646 | 0:c5afea7b9057 | 67 | { |
jjones646 | 0:c5afea7b9057 | 68 | for (int i=0; i<10; i++) { |
jjones646 | 0:c5afea7b9057 | 69 | _tx_led_thread.signal_set(SET_LED_TICK); |
jjones646 | 0:c5afea7b9057 | 70 | _rx_led_thread.signal_set(SET_LED_TICK); |
jjones646 | 0:c5afea7b9057 | 71 | } |
jjones646 | 0:c5afea7b9057 | 72 | } |
jjones646 | 0:c5afea7b9057 | 73 | */ |
jjones646 | 0:c5afea7b9057 | 74 | |
jjones646 | 0:c5afea7b9057 | 75 | |
jjones646 | 0:c5afea7b9057 | 76 | // Configuration method that is called from the constructors |
jjones646 | 0:c5afea7b9057 | 77 | void CC1101::setup_chip() |
jjones646 | 0:c5afea7b9057 | 78 | { |
jjones646 | 0:c5afea7b9057 | 79 | // define an initial state of an unselected chip |
jjones646 | 0:c5afea7b9057 | 80 | *_csn = 1; |
jjones646 | 0:c5afea7b9057 | 81 | |
jjones646 | 0:c5afea7b9057 | 82 | // frequency that radio links with another CC1101 over the air |
jjones646 | 0:c5afea7b9057 | 83 | _carrier_freq = _902MHZ_; |
jjones646 | 0:c5afea7b9057 | 84 | |
jjones646 | 0:c5afea7b9057 | 85 | // turn off address packet filtering and assign 0 (broadcast address) to the address value |
jjones646 | 0:c5afea7b9057 | 86 | _pck_control.addr_check = ADDR_OFF; |
jjones646 | 0:c5afea7b9057 | 87 | |
jjones646 | 0:c5afea7b9057 | 88 | // these values determine how the CC1101 will handel a packet |
jjones646 | 0:c5afea7b9057 | 89 | _pck_control.whitening_en = 0; |
jjones646 | 0:c5afea7b9057 | 90 | |
jjones646 | 0:c5afea7b9057 | 91 | // enable CRC calculation in TX and CRC checking in RX |
jjones646 | 0:c5afea7b9057 | 92 | _pck_control.crc_en = 1; |
jjones646 | 0:c5afea7b9057 | 93 | |
jjones646 | 0:c5afea7b9057 | 94 | // enable automatically flushing the RX buffer on a bad CRC (only works if 1 packet is in the RX buffer) |
jjones646 | 0:c5afea7b9057 | 95 | _pck_control.autoflush_en = 1; |
jjones646 | 0:c5afea7b9057 | 96 | |
jjones646 | 0:c5afea7b9057 | 97 | // enable appending 2 status bytes to the end of every packet that includes the CRC and |
jjones646 | 0:c5afea7b9057 | 98 | _pck_control.status_field_en = 1; |
jjones646 | 0:c5afea7b9057 | 99 | |
jjones646 | 0:c5afea7b9057 | 100 | // normal packet mode uses RX and TX buffers |
jjones646 | 0:c5afea7b9057 | 101 | _pck_control.format_type = FORMAT_DEFAULT; |
jjones646 | 0:c5afea7b9057 | 102 | |
jjones646 | 0:c5afea7b9057 | 103 | // setup how the payload of the packet is transmitted - default to a fixed length of 61 bytes |
jjones646 | 0:c5afea7b9057 | 104 | _pck_control.length_type = PACKET_VARIABLE; |
jjones646 | 0:c5afea7b9057 | 105 | |
jjones646 | 0:c5afea7b9057 | 106 | //_pck_control.length_type = PACKET_FIXED; |
jjones646 | 0:c5afea7b9057 | 107 | //_pck_control.size = 61; |
jjones646 | 0:c5afea7b9057 | 108 | |
jjones646 | 0:c5afea7b9057 | 109 | // this is a preamble threshold for determining when a packet should be accepted |
jjones646 | 0:c5afea7b9057 | 110 | _pck_control.preamble_thresh = 2; |
jjones646 | 0:c5afea7b9057 | 111 | |
jjones646 | 0:c5afea7b9057 | 112 | // these values determine how the frequency bands and channels are distributed as well as defining the modulation type |
jjones646 | 0:c5afea7b9057 | 113 | _modem.dc_filter_off_en = 0; |
jjones646 | 0:c5afea7b9057 | 114 | _modem.manchester_encode_en = 0; |
jjones646 | 0:c5afea7b9057 | 115 | _modem.fec_en = 0; |
jjones646 | 0:c5afea7b9057 | 116 | |
jjones646 | 0:c5afea7b9057 | 117 | // bandwidth configurations |
jjones646 | 0:c5afea7b9057 | 118 | _modem.channel_bw = 2; |
jjones646 | 0:c5afea7b9057 | 119 | _modem.channel_bw_exp = 0; |
jjones646 | 0:c5afea7b9057 | 120 | _modem.channel_space_exp = 2; |
jjones646 | 0:c5afea7b9057 | 121 | _modem.data_rate_exp = 13; |
jjones646 | 0:c5afea7b9057 | 122 | |
jjones646 | 0:c5afea7b9057 | 123 | _modem.mod_type = MOD_GFSK; |
jjones646 | 0:c5afea7b9057 | 124 | _modem.sync_mode = SYNC_HIGH_ALLOW_TWO; |
jjones646 | 0:c5afea7b9057 | 125 | _modem.preamble_bytes = PREAM_FOUR; |
jjones646 | 0:c5afea7b9057 | 126 | |
jjones646 | 0:c5afea7b9057 | 127 | _send_count = 1; |
jjones646 | 0:c5afea7b9057 | 128 | _receive_count = 0; |
jjones646 | 0:c5afea7b9057 | 129 | |
jjones646 | 0:c5afea7b9057 | 130 | // the values assigned here are used for the frequency synthesizer control |
jjones646 | 0:c5afea7b9057 | 131 | assign_if_freq(_316KHZ_); |
jjones646 | 0:c5afea7b9057 | 132 | assign_freq_offset(0); |
jjones646 | 0:c5afea7b9057 | 133 | |
jjones646 | 0:c5afea7b9057 | 134 | // set all the configuration values into the rfSettings struct |
jjones646 | 0:c5afea7b9057 | 135 | set_rf_settings(); |
jjones646 | 0:c5afea7b9057 | 136 | |
jjones646 | 0:c5afea7b9057 | 137 | // get the chip's partnumber |
jjones646 | 0:c5afea7b9057 | 138 | _partnum = status(CCxxx0_PARTNUM); |
jjones646 | 0:c5afea7b9057 | 139 | |
jjones646 | 0:c5afea7b9057 | 140 | // get the chip's version number and fail if different from what was expected |
jjones646 | 0:c5afea7b9057 | 141 | _chip_version = status(CCxxx0_VERSION); |
jjones646 | 0:c5afea7b9057 | 142 | uint8_t expected_version = 0x04; |
jjones646 | 0:c5afea7b9057 | 143 | |
jjones646 | 0:c5afea7b9057 | 144 | if (_chip_version != expected_version) { |
jjones646 | 0:c5afea7b9057 | 145 | |
jjones646 | 0:c5afea7b9057 | 146 | // write results to the log file before killing mbed from going any further |
jjones646 | 0:c5afea7b9057 | 147 | #if RJ_BOOT_LOG |
jjones646 | 0:c5afea7b9057 | 148 | FILE *fp = fopen("/local/log.txt", "a"); // Open text file for tracking boot sequence results |
jjones646 | 0:c5afea7b9057 | 149 | if (fp == NULL) { |
jjones646 | 0:c5afea7b9057 | 150 | error("Could not get file pointer to log file\r\n"); |
jjones646 | 0:c5afea7b9057 | 151 | } |
jjones646 | 0:c5afea7b9057 | 152 | fprintf(fp, "FATAL ERROR: CC1101 Version Error\n"); |
jjones646 | 0:c5afea7b9057 | 153 | fclose(fp); |
jjones646 | 0:c5afea7b9057 | 154 | #endif |
jjones646 | 0:c5afea7b9057 | 155 | // send message over serial port and kill mbed |
jjones646 | 0:c5afea7b9057 | 156 | error( |
jjones646 | 0:c5afea7b9057 | 157 | "[FATAL ERROR]\r\n" |
jjones646 | 0:c5afea7b9057 | 158 | " Wrong version number returned from chip's 'VERSION' register (Addr: 0x%02X)\r\n" |
jjones646 | 0:c5afea7b9057 | 159 | "\r\n" |
jjones646 | 0:c5afea7b9057 | 160 | " Expected: 0x%02X\r\n" |
jjones646 | 0:c5afea7b9057 | 161 | " Found: 0x%02X\r\n" |
jjones646 | 0:c5afea7b9057 | 162 | "\r\n" |
jjones646 | 0:c5afea7b9057 | 163 | " Troubleshooting Tips:\r\n" |
jjones646 | 0:c5afea7b9057 | 164 | " - Check that the chip is fully connected with no soldering errors\r\n" |
jjones646 | 0:c5afea7b9057 | 165 | " - Determine if chip is newer version & update firmware\r\n" |
jjones646 | 0:c5afea7b9057 | 166 | , CCxxx0_VERSION, expected_version, _chip_version); |
jjones646 | 0:c5afea7b9057 | 167 | } |
jjones646 | 0:c5afea7b9057 | 168 | } |
jjones646 | 0:c5afea7b9057 | 169 | |
jjones646 | 0:c5afea7b9057 | 170 | |
jjones646 | 0:c5afea7b9057 | 171 | void powerUp(void) |
jjones646 | 0:c5afea7b9057 | 172 | { |
jjones646 | 0:c5afea7b9057 | 173 | #if DEBUG_MODE > 0 |
jjones646 | 0:c5afea7b9057 | 174 | std::printf("[CC1101 RADIO TRANSCEIVER INITILIZATION]\r\n"); |
jjones646 | 0:c5afea7b9057 | 175 | #endif |
jjones646 | 0:c5afea7b9057 | 176 | // execute a power-on-reset call to the CC1101 before writing all configuration values |
jjones646 | 0:c5afea7b9057 | 177 | power_on_reset(); |
jjones646 | 0:c5afea7b9057 | 178 | |
jjones646 | 0:c5afea7b9057 | 179 | // now send the assigned rfSettings struct to the CC1101 for full inililization |
jjones646 | 0:c5afea7b9057 | 180 | init(); |
jjones646 | 0:c5afea7b9057 | 181 | |
jjones646 | 0:c5afea7b9057 | 182 | scan(); |
jjones646 | 0:c5afea7b9057 | 183 | |
jjones646 | 0:c5afea7b9057 | 184 | // start the regular class operations for the thread. This should always be the last call in the constructor! |
jjones646 | 0:c5afea7b9057 | 185 | _transmit_thread.signal_set(START_THREAD); |
jjones646 | 0:c5afea7b9057 | 186 | _receive_thread.signal_set(START_THREAD); |
jjones646 | 0:c5afea7b9057 | 187 | |
jjones646 | 0:c5afea7b9057 | 188 | |
jjones646 | 0:c5afea7b9057 | 189 | #if DEBUG_MODE > 1 |
jjones646 | 0:c5afea7b9057 | 190 | uint8_t start_address = 0x00; |
jjones646 | 0:c5afea7b9057 | 191 | uint16_t reg_count = 46; |
jjones646 | 0:c5afea7b9057 | 192 | uint8_t buf[reg_count]; |
jjones646 | 0:c5afea7b9057 | 193 | |
jjones646 | 0:c5afea7b9057 | 194 | read_reg(start_address ,buf, reg_count); |
jjones646 | 0:c5afea7b9057 | 195 | std::printf("\r\nDumping CC1101 register contents\r\n ___________________\r\n | Address | Value |\r\n |===================|\r\n"); |
jjones646 | 0:c5afea7b9057 | 196 | for (int i = 0; i<reg_count+1; i++) { |
jjones646 | 0:c5afea7b9057 | 197 | std::printf(" | 0x%02X | 0x%02X |\r\n", start_address + i, buf[start_address + i]); |
jjones646 | 0:c5afea7b9057 | 198 | } |
jjones646 | 0:c5afea7b9057 | 199 | |
jjones646 | 0:c5afea7b9057 | 200 | std::printf(" |_________|_________|\r\n\r\nDumping CC1101 status register conetnts\r\n ___________________\r\n | Address | Value |\r\n |===================|\r\n"); |
jjones646 | 0:c5afea7b9057 | 201 | for (int i = 0; i<14; i++) { |
jjones646 | 0:c5afea7b9057 | 202 | std::printf(" | 0x%02X | 0x%02X |\r\n", CCxxx0_PARTNUM + i, status(CCxxx0_PARTNUM + i)); |
jjones646 | 0:c5afea7b9057 | 203 | } |
jjones646 | 0:c5afea7b9057 | 204 | std::printf(" |_________|_________|\r\n\r\n"); |
jjones646 | 0:c5afea7b9057 | 205 | #endif |
jjones646 | 0:c5afea7b9057 | 206 | |
jjones646 | 0:c5afea7b9057 | 207 | #if DEBUG_MODE > 0 |
jjones646 | 0:c5afea7b9057 | 208 | compute_freq(); |
jjones646 | 0:c5afea7b9057 | 209 | std::printf(" CC1101 READY!\r\n Chip Version: %-02u\r\n Channel: %-02u\r\n Frequency: %-3.2f MHz\r\n Baud Rate: %3u kHz\r\n", _chip_version, Radio::channel(), static_cast<float>(Radio::freq()/1000000), _baud_rate/1000 ); |
jjones646 | 0:c5afea7b9057 | 210 | #endif |
jjones646 | 0:c5afea7b9057 | 211 | |
jjones646 | 0:c5afea7b9057 | 212 | } |
jjones646 | 0:c5afea7b9057 | 213 | |
jjones646 | 0:c5afea7b9057 | 214 | // =============== |
jjones646 | 0:c5afea7b9057 | 215 | void CC1101::set_rf_settings() |
jjones646 | 0:c5afea7b9057 | 216 | { |
jjones646 | 0:c5afea7b9057 | 217 | // set rfSettings carrier frequency fields |
jjones646 | 0:c5afea7b9057 | 218 | freq(_carrier_freq); |
jjones646 | 0:c5afea7b9057 | 219 | |
jjones646 | 0:c5afea7b9057 | 220 | // set the fields for packet controls |
jjones646 | 0:c5afea7b9057 | 221 | assign_packet_params(); |
jjones646 | 0:c5afea7b9057 | 222 | |
jjones646 | 0:c5afea7b9057 | 223 | // set the fields for the frequency limits of the modem |
jjones646 | 0:c5afea7b9057 | 224 | assign_modem_params(); |
jjones646 | 0:c5afea7b9057 | 225 | |
jjones646 | 0:c5afea7b9057 | 226 | // assign an address to the CC1101. This can be used to filter packets |
jjones646 | 0:c5afea7b9057 | 227 | rfSettings.ADDR = _addr; |
jjones646 | 0:c5afea7b9057 | 228 | |
jjones646 | 0:c5afea7b9057 | 229 | // there can be 16 different channel numbers. The bandwidth and spacing are defined in other registers |
jjones646 | 0:c5afea7b9057 | 230 | rfSettings.CHANNR = _channel; |
jjones646 | 0:c5afea7b9057 | 231 | |
jjones646 | 0:c5afea7b9057 | 232 | // compute the final adjusted frequency so that it will be correct after the constructor |
jjones646 | 0:c5afea7b9057 | 233 | compute_freq(); |
jjones646 | 0:c5afea7b9057 | 234 | |
jjones646 | 0:c5afea7b9057 | 235 | assign_baud_rate(250000); // 250 kBaud |
jjones646 | 0:c5afea7b9057 | 236 | |
jjones646 | 0:c5afea7b9057 | 237 | assign_channel_spacing(200000); // 200kHz |
jjones646 | 0:c5afea7b9057 | 238 | |
jjones646 | 0:c5afea7b9057 | 239 | // disable GDO0 |
jjones646 | 0:c5afea7b9057 | 240 | rfSettings.IOCFG0 = 0x2E; |
jjones646 | 0:c5afea7b9057 | 241 | |
jjones646 | 0:c5afea7b9057 | 242 | // setup for serial synchronous data output |
jjones646 | 0:c5afea7b9057 | 243 | rfSettings.IOCFG1 = 0x0C; |
jjones646 | 0:c5afea7b9057 | 244 | |
jjones646 | 0:c5afea7b9057 | 245 | // setup for going HIGH when packet received and CRC is ok |
jjones646 | 0:c5afea7b9057 | 246 | rfSettings.IOCFG2 = 0x07; |
jjones646 | 0:c5afea7b9057 | 247 | |
jjones646 | 0:c5afea7b9057 | 248 | rfSettings.DEVIATN = 0x62; |
jjones646 | 0:c5afea7b9057 | 249 | |
jjones646 | 0:c5afea7b9057 | 250 | rfSettings.FREND1 = 0xB6; |
jjones646 | 0:c5afea7b9057 | 251 | rfSettings.FREND0 = 0x10; |
jjones646 | 0:c5afea7b9057 | 252 | |
jjones646 | 0:c5afea7b9057 | 253 | bool RX_TIME_RSSI = 0; |
jjones646 | 0:c5afea7b9057 | 254 | bool RX_TIME_QUAL = 0; |
jjones646 | 0:c5afea7b9057 | 255 | uint8_t RX_TIME = 0x07; // no timeout |
jjones646 | 0:c5afea7b9057 | 256 | |
jjones646 | 0:c5afea7b9057 | 257 | rfSettings.MCSM2 = (RX_TIME_RSSI<<4) | (RX_TIME_QUAL<<3) | (RX_TIME & 0x07); |
jjones646 | 0:c5afea7b9057 | 258 | |
jjones646 | 0:c5afea7b9057 | 259 | uint8_t CCA_MODE = 0x00; |
jjones646 | 0:c5afea7b9057 | 260 | uint8_t RXOFF_MODE = 0x00; // go directly to IDLE when existing RX |
jjones646 | 0:c5afea7b9057 | 261 | //uint8_t RXOFF_MODE = 0x03; // stay in RX when existing RX |
jjones646 | 0:c5afea7b9057 | 262 | uint8_t TXOFF_MODE = 0x03; // go directly to RX when existing TX |
jjones646 | 0:c5afea7b9057 | 263 | // uint8_t TXOFF_MODE = 0x00; // go directly to IDLE when existing TX |
jjones646 | 0:c5afea7b9057 | 264 | |
jjones646 | 0:c5afea7b9057 | 265 | rfSettings.MCSM1 = ((CCA_MODE & 0x03)<<4) | ((RXOFF_MODE & 0x03)<<2) | (TXOFF_MODE & 0x03); |
jjones646 | 0:c5afea7b9057 | 266 | |
jjones646 | 0:c5afea7b9057 | 267 | uint8_t FS_AUTOCAL = 0x01; // calibrate when going from IDLE to RX or TX |
jjones646 | 0:c5afea7b9057 | 268 | uint8_t PO_TIMEOUT = 0x02; |
jjones646 | 0:c5afea7b9057 | 269 | bool PIN_CTRL_EN = 0; |
jjones646 | 0:c5afea7b9057 | 270 | bool XOSC_FORCE_ON = 0; |
jjones646 | 0:c5afea7b9057 | 271 | |
jjones646 | 0:c5afea7b9057 | 272 | rfSettings.MCSM0 = ((FS_AUTOCAL & 0x03)<<4) | ((PO_TIMEOUT & 0x03)<<2) | (PIN_CTRL_EN<<1) | (XOSC_FORCE_ON); |
jjones646 | 0:c5afea7b9057 | 273 | |
jjones646 | 0:c5afea7b9057 | 274 | bool FOC_BS_CS_GATE = 0; |
jjones646 | 0:c5afea7b9057 | 275 | uint8_t FOC_PRE_K = 0x03; |
jjones646 | 0:c5afea7b9057 | 276 | bool FOC_POST_K = 1; |
jjones646 | 0:c5afea7b9057 | 277 | uint8_t FOC_LIMIT = 0x01; |
jjones646 | 0:c5afea7b9057 | 278 | |
jjones646 | 0:c5afea7b9057 | 279 | rfSettings.FOCCFG = 0x40 | (FOC_BS_CS_GATE<<5) | ((FOC_PRE_K & 0x03)<<3) | (FOC_POST_K<<2) | (FOC_LIMIT & 0x03); |
jjones646 | 0:c5afea7b9057 | 280 | |
jjones646 | 0:c5afea7b9057 | 281 | rfSettings.BSCFG = 0x1C; |
jjones646 | 0:c5afea7b9057 | 282 | |
jjones646 | 0:c5afea7b9057 | 283 | rfSettings.AGCCTRL2 = 0xC7; |
jjones646 | 0:c5afea7b9057 | 284 | rfSettings.AGCCTRL1 = 0x00; |
jjones646 | 0:c5afea7b9057 | 285 | rfSettings.AGCCTRL0 = 0xB0; |
jjones646 | 0:c5afea7b9057 | 286 | |
jjones646 | 0:c5afea7b9057 | 287 | // rfSettings.FIFOTHR = 0x0F; // RXFIFO and TXFIFO thresholds. |
jjones646 | 0:c5afea7b9057 | 288 | |
jjones646 | 0:c5afea7b9057 | 289 | // 33 byte TX FIFO & 32 byte RX FIFO |
jjones646 | 0:c5afea7b9057 | 290 | rfSettings.FIFOTHR = 0x07; // RXFIFO and TXFIFO thresholds. |
jjones646 | 0:c5afea7b9057 | 291 | } |
jjones646 | 0:c5afea7b9057 | 292 | |
jjones646 | 0:c5afea7b9057 | 293 | #if RF_DB == 0 |
jjones646 | 0:c5afea7b9057 | 294 | // PATABLE (0 dBm output power) |
jjones646 | 0:c5afea7b9057 | 295 | char paTable[] = {0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
jjones646 | 0:c5afea7b9057 | 296 | #elif RF_DB == 10 |
jjones646 | 0:c5afea7b9057 | 297 | // PATABLE (10 dBm output power) |
jjones646 | 0:c5afea7b9057 | 298 | char paTable[] = {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
jjones646 | 0:c5afea7b9057 | 299 | #endif |
jjones646 | 0:c5afea7b9057 | 300 | |
jjones646 | 0:c5afea7b9057 | 301 | |
jjones646 | 0:c5afea7b9057 | 302 | // =============== |
jjones646 | 0:c5afea7b9057 | 303 | void CC1101::assign_baud_rate(uint32_t rate) |
jjones646 | 0:c5afea7b9057 | 304 | { |
jjones646 | 0:c5afea7b9057 | 305 | // update the baud rate class member |
jjones646 | 0:c5afea7b9057 | 306 | _baud_rate = rate; |
jjones646 | 0:c5afea7b9057 | 307 | |
jjones646 | 0:c5afea7b9057 | 308 | // have to be careful with bit shifting here since it requires a large amount of shifts |
jjones646 | 0:c5afea7b9057 | 309 | uint32_t shift_val = 28 - (_modem.data_rate_exp & 0x0F); |
jjones646 | 0:c5afea7b9057 | 310 | |
jjones646 | 0:c5afea7b9057 | 311 | // compute the register value and assign it |
jjones646 | 0:c5afea7b9057 | 312 | rfSettings.MDMCFG3 = ((_baud_rate)/(_crystal_freq>>shift_val)) - 256; |
jjones646 | 0:c5afea7b9057 | 313 | } |
jjones646 | 0:c5afea7b9057 | 314 | |
jjones646 | 0:c5afea7b9057 | 315 | |
jjones646 | 0:c5afea7b9057 | 316 | // =============== |
jjones646 | 0:c5afea7b9057 | 317 | void CC1101::assign_channel_spacing(uint32_t freq) |
jjones646 | 0:c5afea7b9057 | 318 | { |
jjones646 | 0:c5afea7b9057 | 319 | // update the channel spacing frequency's class member |
jjones646 | 0:c5afea7b9057 | 320 | _channel_spacing = freq; |
jjones646 | 0:c5afea7b9057 | 321 | |
jjones646 | 0:c5afea7b9057 | 322 | // have to be careful with bit shifting here since it requires a large amount of shifts |
jjones646 | 0:c5afea7b9057 | 323 | uint32_t shift_val = 18 - (_modem.channel_space_exp & 0x03); |
jjones646 | 0:c5afea7b9057 | 324 | |
jjones646 | 0:c5afea7b9057 | 325 | // compute the register value and assign it |
jjones646 | 0:c5afea7b9057 | 326 | rfSettings.MDMCFG0 = (_channel_spacing/(_crystal_freq>>shift_val)) - 256; |
jjones646 | 0:c5afea7b9057 | 327 | } |
jjones646 | 0:c5afea7b9057 | 328 | |
jjones646 | 0:c5afea7b9057 | 329 | |
jjones646 | 0:c5afea7b9057 | 330 | // =============== |
jjones646 | 0:c5afea7b9057 | 331 | void CC1101::assign_modem_params() |
jjones646 | 0:c5afea7b9057 | 332 | { |
jjones646 | 0:c5afea7b9057 | 333 | rfSettings.MDMCFG4 = (_modem.channel_bw_exp & 0x03)<<6 | (_modem.channel_bw & 0x03)<<4 | (_modem.data_rate_exp & 0x0F); |
jjones646 | 0:c5afea7b9057 | 334 | rfSettings.MDMCFG2 = _modem.dc_filter_off_en<<7 | (_modem.mod_type & 0x07)<<4 | _modem.manchester_encode_en<<3 | (_modem.sync_mode & 0x07); |
jjones646 | 0:c5afea7b9057 | 335 | rfSettings.MDMCFG1 = _modem.fec_en<<7 | (_modem.preamble_bytes & 0x07)<<4 | (_modem.channel_space_exp & 0x03); |
jjones646 | 0:c5afea7b9057 | 336 | } |
jjones646 | 0:c5afea7b9057 | 337 | |
jjones646 | 0:c5afea7b9057 | 338 | // =============== |
jjones646 | 0:c5afea7b9057 | 339 | void CC1101::assign_packet_params() |
jjones646 | 0:c5afea7b9057 | 340 | { |
jjones646 | 0:c5afea7b9057 | 341 | rfSettings.PCKCTRL0 = _pck_control.whitening_en<<6 | (_pck_control.format_type & 0x3)<<4 | _pck_control.crc_en<<2 | (_pck_control.length_type & 0x3); |
jjones646 | 0:c5afea7b9057 | 342 | 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 | 0:c5afea7b9057 | 343 | rfSettings.PCKLEN = _pck_control.size; |
jjones646 | 0:c5afea7b9057 | 344 | } |
jjones646 | 0:c5afea7b9057 | 345 | |
jjones646 | 0:c5afea7b9057 | 346 | |
jjones646 | 0:c5afea7b9057 | 347 | void CC1101::assign_if_freq(uint32_t freq) |
jjones646 | 0:c5afea7b9057 | 348 | { |
jjones646 | 0:c5afea7b9057 | 349 | // The desired IF frequency for RX. Subtracted from FS base frequency in RX. |
jjones646 | 0:c5afea7b9057 | 350 | // bits 7..5 are always 0 |
jjones646 | 0:c5afea7b9057 | 351 | _if_freq = freq; |
jjones646 | 0:c5afea7b9057 | 352 | rfSettings.FSCTRL1 = (_if_freq/(_crystal_freq>>10)) & 0x1F; |
jjones646 | 0:c5afea7b9057 | 353 | rfSettings.FSCTRL0 = 0x00; // set the initial freq calibration to 0 |
jjones646 | 0:c5afea7b9057 | 354 | } |
jjones646 | 0:c5afea7b9057 | 355 | |
jjones646 | 0:c5afea7b9057 | 356 | |
jjones646 | 0:c5afea7b9057 | 357 | // computes the final adjusted operating frequency |
jjones646 | 0:c5afea7b9057 | 358 | void CC1101::compute_freq() |
jjones646 | 0:c5afea7b9057 | 359 | { |
jjones646 | 0:c5afea7b9057 | 360 | // there's no need to make this heavy computation numerous times when it rarely ever changes - that's why it has its own class method |
jjones646 | 0:c5afea7b9057 | 361 | uint32_t freq = (rfSettings.FREQ2<<16) | (rfSettings.FREQ1<<8) | (rfSettings.FREQ0); |
jjones646 | 0:c5afea7b9057 | 362 | uint32_t offset = (_channel & 0xFF)*((256 + rfSettings.MDMCFG0)<<(_modem.channel_space_exp & 0x03)); |
jjones646 | 0:c5afea7b9057 | 363 | _freq = (_crystal_freq>>16)*(freq + offset); // set the frequency from the base class |
jjones646 | 0:c5afea7b9057 | 364 | } |
jjones646 | 0:c5afea7b9057 | 365 | |
jjones646 | 0:c5afea7b9057 | 366 | |
jjones646 | 0:c5afea7b9057 | 367 | // SET FREQUENCY |
jjones646 | 0:c5afea7b9057 | 368 | void CC1101::freq(uint32_t freq) |
jjones646 | 0:c5afea7b9057 | 369 | { |
jjones646 | 0:c5afea7b9057 | 370 | /* calculate the value that is written to the register for settings the base frequency |
jjones646 | 0:c5afea7b9057 | 371 | * that the CC1101 should use for sending/receiving over the air. Default value is equivalent |
jjones646 | 0:c5afea7b9057 | 372 | * to 901.83 MHz. |
jjones646 | 0:c5afea7b9057 | 373 | */ |
jjones646 | 0:c5afea7b9057 | 374 | |
jjones646 | 0:c5afea7b9057 | 375 | // update the class's frequency value |
jjones646 | 0:c5afea7b9057 | 376 | _carrier_freq = freq; |
jjones646 | 0:c5afea7b9057 | 377 | |
jjones646 | 0:c5afea7b9057 | 378 | // this is split into 3 bytes that are written to 3 different registers on the CC1101 |
jjones646 | 0:c5afea7b9057 | 379 | uint32_t reg_freq = _carrier_freq / (_crystal_freq>>16); |
jjones646 | 0:c5afea7b9057 | 380 | |
jjones646 | 0:c5afea7b9057 | 381 | rfSettings.FREQ2 = (reg_freq>>16) & 0xFF; // high byte, bits 7..6 are always 0 for this register |
jjones646 | 0:c5afea7b9057 | 382 | rfSettings.FREQ1 = (reg_freq>>8) & 0xFF; // middle byte |
jjones646 | 0:c5afea7b9057 | 383 | rfSettings.FREQ0 = reg_freq & 0xFF; // low byte |
jjones646 | 0:c5afea7b9057 | 384 | } |
jjones646 | 0:c5afea7b9057 | 385 | |
jjones646 | 0:c5afea7b9057 | 386 | |
jjones646 | 0:c5afea7b9057 | 387 | // set the device's hardware address (8 bits) |
jjones646 | 0:c5afea7b9057 | 388 | void CC1101::address(uint8_t addr) |
jjones646 | 0:c5afea7b9057 | 389 | { |
jjones646 | 0:c5afea7b9057 | 390 | _addr = addr; |
jjones646 | 0:c5afea7b9057 | 391 | } |
jjones646 | 0:c5afea7b9057 | 392 | |
jjones646 | 0:c5afea7b9057 | 393 | |
jjones646 | 0:c5afea7b9057 | 394 | // returns the CC1101's VERSION register that specifices what exact chip version is being used |
jjones646 | 0:c5afea7b9057 | 395 | uint8_t CC1101::version(void) |
jjones646 | 0:c5afea7b9057 | 396 | { |
jjones646 | 0:c5afea7b9057 | 397 | return _chip_version; |
jjones646 | 0:c5afea7b9057 | 398 | } |
jjones646 | 0:c5afea7b9057 | 399 | |
jjones646 | 0:c5afea7b9057 | 400 | |
jjones646 | 0:c5afea7b9057 | 401 | // return's the part number for the CC1101 chip being used |
jjones646 | 0:c5afea7b9057 | 402 | uint8_t CC1101::partnum(void) |
jjones646 | 0:c5afea7b9057 | 403 | { |
jjones646 | 0:c5afea7b9057 | 404 | return _partnum; |
jjones646 | 0:c5afea7b9057 | 405 | } |
jjones646 | 0:c5afea7b9057 | 406 | |
jjones646 | 0:c5afea7b9057 | 407 | |
jjones646 | 0:c5afea7b9057 | 408 | // returns the current mode that the CC1101 is operating in |
jjones646 | 0:c5afea7b9057 | 409 | uint8_t CC1101::mode(void) |
jjones646 | 0:c5afea7b9057 | 410 | { |
jjones646 | 0:c5afea7b9057 | 411 | return status(CCxxx0_MARCSTATE); |
jjones646 | 0:c5afea7b9057 | 412 | } |
jjones646 | 0:c5afea7b9057 | 413 | |
jjones646 | 0:c5afea7b9057 | 414 | |
jjones646 | 0:c5afea7b9057 | 415 | // returns the LQI value from the most recently received packet |
jjones646 | 0:c5afea7b9057 | 416 | uint8_t CC1101::lqi(void) |
jjones646 | 0:c5afea7b9057 | 417 | { |
jjones646 | 0:c5afea7b9057 | 418 | return 0x3F - (_lqi & 0x3F); |
jjones646 | 0:c5afea7b9057 | 419 | } |
jjones646 | 0:c5afea7b9057 | 420 | |
jjones646 | 0:c5afea7b9057 | 421 | |
jjones646 | 0:c5afea7b9057 | 422 | // update the channel within the class and also update the CC1101's channel register |
jjones646 | 0:c5afea7b9057 | 423 | void CC1101::channel(uint8_t chan) |
jjones646 | 0:c5afea7b9057 | 424 | { |
jjones646 | 0:c5afea7b9057 | 425 | // only update channel numbers that are valid (8 bits) |
jjones646 | 0:c5afea7b9057 | 426 | if ( chan != _channel ) { |
jjones646 | 0:c5afea7b9057 | 427 | // channels start at 0 for the CC1101. this subtracts 1 before saving the channel number for the reason defined in the _channel member's getter method |
jjones646 | 0:c5afea7b9057 | 428 | _channel = chan; |
jjones646 | 0:c5afea7b9057 | 429 | |
jjones646 | 0:c5afea7b9057 | 430 | // update the value with the CC1101's channel number register |
jjones646 | 0:c5afea7b9057 | 431 | write_reg(CCxxx0_CHANNR, _channel); |
jjones646 | 0:c5afea7b9057 | 432 | |
jjones646 | 0:c5afea7b9057 | 433 | // recalculate the adjusted frequency value since the channel number has changed |
jjones646 | 0:c5afea7b9057 | 434 | compute_freq(); |
jjones646 | 0:c5afea7b9057 | 435 | |
jjones646 | 0:c5afea7b9057 | 436 | #if DEBUG_MODE > 0 |
jjones646 | 0:c5afea7b9057 | 437 | 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 | 0:c5afea7b9057 | 438 | #endif |
jjones646 | 0:c5afea7b9057 | 439 | } |
jjones646 | 0:c5afea7b9057 | 440 | } |
jjones646 | 0:c5afea7b9057 | 441 | |
jjones646 | 0:c5afea7b9057 | 442 | |
jjones646 | 0:c5afea7b9057 | 443 | // returns the RSSI value from the most recently received packet |
jjones646 | 0:c5afea7b9057 | 444 | uint8_t CC1101::rssi(void) |
jjones646 | 0:c5afea7b9057 | 445 | { |
jjones646 | 0:c5afea7b9057 | 446 | return _rssi; |
jjones646 | 0:c5afea7b9057 | 447 | } |
jjones646 | 0:c5afea7b9057 | 448 | |
jjones646 | 0:c5afea7b9057 | 449 | void CC1101::rssi(uint8_t rssi_reg) |
jjones646 | 0:c5afea7b9057 | 450 | { |
jjones646 | 0:c5afea7b9057 | 451 | int8_t temp; |
jjones646 | 0:c5afea7b9057 | 452 | |
jjones646 | 0:c5afea7b9057 | 453 | if (rssi_reg & 0x80) { |
jjones646 | 0:c5afea7b9057 | 454 | temp = (rssi_reg - 256)>>1; |
jjones646 | 0:c5afea7b9057 | 455 | } else { |
jjones646 | 0:c5afea7b9057 | 456 | temp = rssi_reg>>1; // divide by 2 |
jjones646 | 0:c5afea7b9057 | 457 | } |
jjones646 | 0:c5afea7b9057 | 458 | _rssi = temp - 74; |
jjones646 | 0:c5afea7b9057 | 459 | } |
jjones646 | 0:c5afea7b9057 | 460 | |
jjones646 | 0:c5afea7b9057 | 461 | |
jjones646 | 0:c5afea7b9057 | 462 | // Assign the offset frequency to the class definition |
jjones646 | 0:c5afea7b9057 | 463 | void CC1101::assign_freq_offset(uint8_t freq) |
jjones646 | 0:c5afea7b9057 | 464 | { |
jjones646 | 0:c5afea7b9057 | 465 | _offset_freq = freq; |
jjones646 | 0:c5afea7b9057 | 466 | } |
jjones646 | 0:c5afea7b9057 | 467 | |
jjones646 | 0:c5afea7b9057 | 468 | |
jjones646 | 0:c5afea7b9057 | 469 | // Macro to calibrate the frequency synthesizer |
jjones646 | 0:c5afea7b9057 | 470 | void CC1101::calibrate() |
jjones646 | 0:c5afea7b9057 | 471 | { |
jjones646 | 0:c5afea7b9057 | 472 | // Send the calibration strobe |
jjones646 | 0:c5afea7b9057 | 473 | strobe(CCxxx0_SCAL); |
jjones646 | 0:c5afea7b9057 | 474 | |
jjones646 | 0:c5afea7b9057 | 475 | // Wait for the radio to leave the calibration step |
jjones646 | 0:c5afea7b9057 | 476 | while( (mode() == 0x04) | (mode() == 0x05) ); |
jjones646 | 0:c5afea7b9057 | 477 | |
jjones646 | 0:c5afea7b9057 | 478 | // The radio is now is IDLE mode, so go to RX mode |
jjones646 | 0:c5afea7b9057 | 479 | rx_mode(); |
jjones646 | 0:c5afea7b9057 | 480 | |
jjones646 | 0:c5afea7b9057 | 481 | // Wait for the radio to enter back into RX mode |
jjones646 | 0:c5afea7b9057 | 482 | while( mode() != 0x0D ); |
jjones646 | 0:c5afea7b9057 | 483 | } |
jjones646 | 0:c5afea7b9057 | 484 | |
jjones646 | 0:c5afea7b9057 | 485 | |
jjones646 | 0:c5afea7b9057 | 486 | // Macro to reset the CCxxx0 and wait for it to be ready |
jjones646 | 0:c5afea7b9057 | 487 | void CC1101::reset(void) |
jjones646 | 0:c5afea7b9057 | 488 | { |
jjones646 | 0:c5afea7b9057 | 489 | strobe(CCxxx0_SRES); |
jjones646 | 0:c5afea7b9057 | 490 | } |
jjones646 | 0:c5afea7b9057 | 491 | |
jjones646 | 0:c5afea7b9057 | 492 | |
jjones646 | 0:c5afea7b9057 | 493 | void CC1101::power_on_reset(void) |
jjones646 | 0:c5afea7b9057 | 494 | { |
jjones646 | 0:c5afea7b9057 | 495 | #if DEBUG_MODE > 0 |
jjones646 | 0:c5afea7b9057 | 496 | std::printf(" Starting Power-on-Reset procedure..."); |
jjones646 | 0:c5afea7b9057 | 497 | #endif |
jjones646 | 0:c5afea7b9057 | 498 | delete _spi; |
jjones646 | 0:c5afea7b9057 | 499 | |
jjones646 | 0:c5afea7b9057 | 500 | // make sure chip is not selected |
jjones646 | 0:c5afea7b9057 | 501 | *_csn = 1; |
jjones646 | 0:c5afea7b9057 | 502 | |
jjones646 | 0:c5afea7b9057 | 503 | DigitalOut *SI = new DigitalOut(_si); |
jjones646 | 0:c5afea7b9057 | 504 | DigitalOut *SCK = new DigitalOut(_sck); |
jjones646 | 0:c5afea7b9057 | 505 | DigitalIn *SO = new DigitalIn(_so); |
jjones646 | 0:c5afea7b9057 | 506 | |
jjones646 | 0:c5afea7b9057 | 507 | // bring SPI lines to a defined state. Reasons are outlined in CC1101 datasheet - section 11.3 |
jjones646 | 0:c5afea7b9057 | 508 | *SI = 0; |
jjones646 | 0:c5afea7b9057 | 509 | *SCK = 1; |
jjones646 | 0:c5afea7b9057 | 510 | |
jjones646 | 0:c5afea7b9057 | 511 | // toggle chip select and remain in high state afterwards |
jjones646 | 0:c5afea7b9057 | 512 | *_csn = 0; |
jjones646 | 0:c5afea7b9057 | 513 | *_csn = 1; |
jjones646 | 0:c5afea7b9057 | 514 | |
jjones646 | 0:c5afea7b9057 | 515 | // wait at least 40us |
jjones646 | 0:c5afea7b9057 | 516 | wait_us(45); |
jjones646 | 0:c5afea7b9057 | 517 | |
jjones646 | 0:c5afea7b9057 | 518 | // pull CSn low & wait for the serial out line to go low |
jjones646 | 0:c5afea7b9057 | 519 | *_csn = 0; |
jjones646 | 0:c5afea7b9057 | 520 | |
jjones646 | 0:c5afea7b9057 | 521 | while(*SO); |
jjones646 | 0:c5afea7b9057 | 522 | |
jjones646 | 0:c5afea7b9057 | 523 | // cleanup everything before the mbed's SPI library calls take back over |
jjones646 | 0:c5afea7b9057 | 524 | delete SI; |
jjones646 | 0:c5afea7b9057 | 525 | delete SO; |
jjones646 | 0:c5afea7b9057 | 526 | delete SCK; |
jjones646 | 0:c5afea7b9057 | 527 | |
jjones646 | 0:c5afea7b9057 | 528 | // reestablish the SPI bus and call the reset strobe |
jjones646 | 0:c5afea7b9057 | 529 | setup_spi(_si, _so, _sck); |
jjones646 | 0:c5afea7b9057 | 530 | reset(); |
jjones646 | 0:c5afea7b9057 | 531 | |
jjones646 | 0:c5afea7b9057 | 532 | delete _spi; |
jjones646 | 0:c5afea7b9057 | 533 | // wait for the SO line to go low again. Once low, reset is complete and CC1101 is in IDLE state |
jjones646 | 0:c5afea7b9057 | 534 | DigitalIn *SO2 = new DigitalIn(_so); |
jjones646 | 0:c5afea7b9057 | 535 | while(*SO2); |
jjones646 | 0:c5afea7b9057 | 536 | |
jjones646 | 0:c5afea7b9057 | 537 | // make sure chip is deselected before returning |
jjones646 | 0:c5afea7b9057 | 538 | *_csn = 1; |
jjones646 | 0:c5afea7b9057 | 539 | |
jjones646 | 0:c5afea7b9057 | 540 | // reestablish the SPI bus for the final time after removing the DigitalIn object |
jjones646 | 0:c5afea7b9057 | 541 | delete SO2; |
jjones646 | 0:c5afea7b9057 | 542 | setup_spi(_si, _so, _sck); |
jjones646 | 0:c5afea7b9057 | 543 | |
jjones646 | 0:c5afea7b9057 | 544 | #if DEBUG_MODE > 0 |
jjones646 | 0:c5afea7b9057 | 545 | std::printf("done\r\n"); |
jjones646 | 0:c5afea7b9057 | 546 | #endif |
jjones646 | 0:c5afea7b9057 | 547 | } |
jjones646 | 0:c5afea7b9057 | 548 | |
jjones646 | 0:c5afea7b9057 | 549 | /////////////////////////////////////////////////////////////////////////////////////// |
jjones646 | 0:c5afea7b9057 | 550 | uint8_t CC1101::status(void) |
jjones646 | 0:c5afea7b9057 | 551 | { |
jjones646 | 0:c5afea7b9057 | 552 | return strobe(CCxxx0_SNOP); |
jjones646 | 0:c5afea7b9057 | 553 | } |
jjones646 | 0:c5afea7b9057 | 554 | |
jjones646 | 0:c5afea7b9057 | 555 | /////////////////////////////////////////////////////////////////////////////////////// |
jjones646 | 0:c5afea7b9057 | 556 | // uint8_t status(uint8_t addr) |
jjones646 | 0:c5afea7b9057 | 557 | // |
jjones646 | 0:c5afea7b9057 | 558 | // DESCRIPTION: |
jjones646 | 0:c5afea7b9057 | 559 | // This function reads a CCxxx0 status register. |
jjones646 | 0:c5afea7b9057 | 560 | // |
jjones646 | 0:c5afea7b9057 | 561 | // ARGUMENTS: |
jjones646 | 0:c5afea7b9057 | 562 | // uint8_t addr |
jjones646 | 0:c5afea7b9057 | 563 | // Address of the CCxxx0 status register to be accessed. |
jjones646 | 0:c5afea7b9057 | 564 | // |
jjones646 | 0:c5afea7b9057 | 565 | // RETURN VALUE: |
jjones646 | 0:c5afea7b9057 | 566 | // uint8_t |
jjones646 | 0:c5afea7b9057 | 567 | // Value of the accessed CCxxx0 status register. |
jjones646 | 0:c5afea7b9057 | 568 | /////////////////////////////////////////////////////////////////////////////////////// |
jjones646 | 0:c5afea7b9057 | 569 | uint8_t CC1101::status(uint8_t addr) |
jjones646 | 0:c5afea7b9057 | 570 | { |
jjones646 | 0:c5afea7b9057 | 571 | *_csn = 0; |
jjones646 | 0:c5afea7b9057 | 572 | _spi->write(addr | READ_BURST); |
jjones646 | 0:c5afea7b9057 | 573 | tiny_delay(); |
jjones646 | 0:c5afea7b9057 | 574 | uint8_t x = _spi->write(0); |
jjones646 | 0:c5afea7b9057 | 575 | *_csn = 1; |
jjones646 | 0:c5afea7b9057 | 576 | return x; |
jjones646 | 0:c5afea7b9057 | 577 | }// status |
jjones646 | 0:c5afea7b9057 | 578 | |
jjones646 | 0:c5afea7b9057 | 579 | |
jjones646 | 0:c5afea7b9057 | 580 | /////////////////////////////////////////////////////////////////////////////////////// |
jjones646 | 0:c5afea7b9057 | 581 | // uint8_t strobe(uint8_t strobe) |
jjones646 | 0:c5afea7b9057 | 582 | // |
jjones646 | 0:c5afea7b9057 | 583 | // DESCRIPTION: |
jjones646 | 0:c5afea7b9057 | 584 | // Function for writing a strobe command to the CCxxx0 |
jjones646 | 0:c5afea7b9057 | 585 | // |
jjones646 | 0:c5afea7b9057 | 586 | // ARGUMENTS: |
jjones646 | 0:c5afea7b9057 | 587 | // uint8_t strobe |
jjones646 | 0:c5afea7b9057 | 588 | // strobe command |
jjones646 | 0:c5afea7b9057 | 589 | /////////////////////////////////////////////////////////////////////////////////////// |
jjones646 | 0:c5afea7b9057 | 590 | uint8_t CC1101::strobe(uint8_t strobe) |
jjones646 | 0:c5afea7b9057 | 591 | { |
jjones646 | 0:c5afea7b9057 | 592 | *_csn = 0; |
jjones646 | 0:c5afea7b9057 | 593 | uint8_t x = _spi->write(strobe); |
jjones646 | 0:c5afea7b9057 | 594 | *_csn = 1; |
jjones646 | 0:c5afea7b9057 | 595 | return x; |
jjones646 | 0:c5afea7b9057 | 596 | }// strobe |
jjones646 | 0:c5afea7b9057 | 597 | |
jjones646 | 0:c5afea7b9057 | 598 | |
jjones646 | 0:c5afea7b9057 | 599 | /////////////////////////////////////////////////////////////////////////////////////// |
jjones646 | 0:c5afea7b9057 | 600 | // void put_rf_settings(rf_settings_t *pRfSettings) |
jjones646 | 0:c5afea7b9057 | 601 | // |
jjones646 | 0:c5afea7b9057 | 602 | // DESCRIPTION: |
jjones646 | 0:c5afea7b9057 | 603 | // This function is used to configure the CCxxx0 based on a given rf setting |
jjones646 | 0:c5afea7b9057 | 604 | // |
jjones646 | 0:c5afea7b9057 | 605 | // ARGUMENTS: |
jjones646 | 0:c5afea7b9057 | 606 | // rf_settings_t *pRfSettings |
jjones646 | 0:c5afea7b9057 | 607 | // Pointer to a struct containing rf register settings |
jjones646 | 0:c5afea7b9057 | 608 | /////////////////////////////////////////////////////////////////////////////////////// |
jjones646 | 0:c5afea7b9057 | 609 | void CC1101::put_rf_settings() |
jjones646 | 0:c5afea7b9057 | 610 | { |
jjones646 | 0:c5afea7b9057 | 611 | write_reg(CCxxx0_IOCFG2, rfSettings.IOCFG2); |
jjones646 | 0:c5afea7b9057 | 612 | write_reg(CCxxx0_IOCFG1, rfSettings.IOCFG1); |
jjones646 | 0:c5afea7b9057 | 613 | write_reg(CCxxx0_IOCFG0, rfSettings.IOCFG0); |
jjones646 | 0:c5afea7b9057 | 614 | write_reg(CCxxx0_FIFOTHR, rfSettings.FIFOTHR); |
jjones646 | 0:c5afea7b9057 | 615 | // SYNC1 |
jjones646 | 0:c5afea7b9057 | 616 | // SYNC0 |
jjones646 | 0:c5afea7b9057 | 617 | write_reg(CCxxx0_PCKLEN, rfSettings.PCKLEN); |
jjones646 | 0:c5afea7b9057 | 618 | write_reg(CCxxx0_PCKCTRL1, rfSettings.PCKCTRL1); |
jjones646 | 0:c5afea7b9057 | 619 | write_reg(CCxxx0_PCKCTRL0, rfSettings.PCKCTRL0); |
jjones646 | 0:c5afea7b9057 | 620 | write_reg(CCxxx0_ADDR, rfSettings.ADDR); |
jjones646 | 0:c5afea7b9057 | 621 | write_reg(CCxxx0_CHANNR, rfSettings.CHANNR); |
jjones646 | 0:c5afea7b9057 | 622 | write_reg(CCxxx0_FSCTRL1, rfSettings.FSCTRL1); |
jjones646 | 0:c5afea7b9057 | 623 | write_reg(CCxxx0_FSCTRL0, rfSettings.FSCTRL0); |
jjones646 | 0:c5afea7b9057 | 624 | write_reg(CCxxx0_FREQ2, rfSettings.FREQ2); |
jjones646 | 0:c5afea7b9057 | 625 | write_reg(CCxxx0_FREQ1, rfSettings.FREQ1); |
jjones646 | 0:c5afea7b9057 | 626 | write_reg(CCxxx0_FREQ0, rfSettings.FREQ0); |
jjones646 | 0:c5afea7b9057 | 627 | write_reg(CCxxx0_MDMCFG4, rfSettings.MDMCFG4); |
jjones646 | 0:c5afea7b9057 | 628 | write_reg(CCxxx0_MDMCFG3, rfSettings.MDMCFG3); |
jjones646 | 0:c5afea7b9057 | 629 | write_reg(CCxxx0_MDMCFG2, rfSettings.MDMCFG2); |
jjones646 | 0:c5afea7b9057 | 630 | write_reg(CCxxx0_MDMCFG1, rfSettings.MDMCFG1); |
jjones646 | 0:c5afea7b9057 | 631 | write_reg(CCxxx0_MDMCFG0, rfSettings.MDMCFG0); |
jjones646 | 0:c5afea7b9057 | 632 | write_reg(CCxxx0_DEVIATN, rfSettings.DEVIATN); |
jjones646 | 0:c5afea7b9057 | 633 | write_reg(CCxxx0_MCSM2 , rfSettings.MCSM2); |
jjones646 | 0:c5afea7b9057 | 634 | write_reg(CCxxx0_MCSM1 , rfSettings.MCSM1); |
jjones646 | 0:c5afea7b9057 | 635 | write_reg(CCxxx0_MCSM0 , rfSettings.MCSM0 ); |
jjones646 | 0:c5afea7b9057 | 636 | write_reg(CCxxx0_FOCCFG, rfSettings.FOCCFG); |
jjones646 | 0:c5afea7b9057 | 637 | write_reg(CCxxx0_BSCFG, rfSettings.BSCFG); |
jjones646 | 0:c5afea7b9057 | 638 | write_reg(CCxxx0_AGCCTRL2, rfSettings.AGCCTRL2); |
jjones646 | 0:c5afea7b9057 | 639 | write_reg(CCxxx0_AGCCTRL1, rfSettings.AGCCTRL1); |
jjones646 | 0:c5afea7b9057 | 640 | write_reg(CCxxx0_AGCCTRL0, rfSettings.AGCCTRL0); |
jjones646 | 0:c5afea7b9057 | 641 | // WOREVT1 |
jjones646 | 0:c5afea7b9057 | 642 | // WOREVT0 |
jjones646 | 0:c5afea7b9057 | 643 | // WORCTRL |
jjones646 | 0:c5afea7b9057 | 644 | write_reg(CCxxx0_FREND1, rfSettings.FREND1); |
jjones646 | 0:c5afea7b9057 | 645 | write_reg(CCxxx0_FREND0, rfSettings.FREND0); |
jjones646 | 0:c5afea7b9057 | 646 | // FSCAL3 |
jjones646 | 0:c5afea7b9057 | 647 | // FSCAL2 |
jjones646 | 0:c5afea7b9057 | 648 | // FSCAL1 |
jjones646 | 0:c5afea7b9057 | 649 | //write_reg(CCxxx0_FSCAL0, rfSettings.FSCAL0); |
jjones646 | 0:c5afea7b9057 | 650 | // PCCTRL1 |
jjones646 | 0:c5afea7b9057 | 651 | // PCCTRL0 |
jjones646 | 0:c5afea7b9057 | 652 | // FSTEST |
jjones646 | 0:c5afea7b9057 | 653 | // PTEST |
jjones646 | 0:c5afea7b9057 | 654 | // AGCTEST |
jjones646 | 0:c5afea7b9057 | 655 | // TEST2 |
jjones646 | 0:c5afea7b9057 | 656 | // TEST1 |
jjones646 | 0:c5afea7b9057 | 657 | // TEST0 |
jjones646 | 0:c5afea7b9057 | 658 | } // put_rf_settings |
jjones646 | 0:c5afea7b9057 | 659 | |
jjones646 | 0:c5afea7b9057 | 660 | |
jjones646 | 0:c5afea7b9057 | 661 | // main ititilization |
jjones646 | 0:c5afea7b9057 | 662 | void CC1101::init(void) |
jjones646 | 0:c5afea7b9057 | 663 | { |
jjones646 | 0:c5afea7b9057 | 664 | // strobe(CCxxx0_SIDLE); |
jjones646 | 0:c5afea7b9057 | 665 | // send all configuration values to the CC1101 registers |
jjones646 | 0:c5afea7b9057 | 666 | #if DEBUG_MODE > 0 |
jjones646 | 0:c5afea7b9057 | 667 | std::printf(" Writing configuration registers..."); |
jjones646 | 0:c5afea7b9057 | 668 | #endif |
jjones646 | 0:c5afea7b9057 | 669 | put_rf_settings(); |
jjones646 | 0:c5afea7b9057 | 670 | write_reg(CCxxx0_PATABLE, paTable[0]); |
jjones646 | 0:c5afea7b9057 | 671 | #if DEBUG_MODE > 0 |
jjones646 | 0:c5afea7b9057 | 672 | std::printf("done\r\n"); |
jjones646 | 0:c5afea7b9057 | 673 | #endif |
jjones646 | 0:c5afea7b9057 | 674 | |
jjones646 | 0:c5afea7b9057 | 675 | |
jjones646 | 0:c5afea7b9057 | 676 | #if DEBUG_MODE > 0 |
jjones646 | 0:c5afea7b9057 | 677 | std::printf(" Calibrating..."); |
jjones646 | 0:c5afea7b9057 | 678 | #endif |
jjones646 | 0:c5afea7b9057 | 679 | calibrate(); |
jjones646 | 0:c5afea7b9057 | 680 | // while( (mode() == 0x04) | (mode() == 0x05) ); // wait until it leaves calibration |
jjones646 | 0:c5afea7b9057 | 681 | write_reg(CCxxx0_FSCTRL0, status(CCxxx0_FREQEST)); |
jjones646 | 0:c5afea7b9057 | 682 | #if DEBUG_MODE > 0 |
jjones646 | 0:c5afea7b9057 | 683 | std::printf("done\r\n"); |
jjones646 | 0:c5afea7b9057 | 684 | #endif |
jjones646 | 0:c5afea7b9057 | 685 | |
jjones646 | 0:c5afea7b9057 | 686 | |
jjones646 | 0:c5afea7b9057 | 687 | // flush TX and RX buffers before beginning |
jjones646 | 0:c5afea7b9057 | 688 | #if DEBUG_MODE > 0 |
jjones646 | 0:c5afea7b9057 | 689 | std::printf(" Clearing TX and RX buffers..."); |
jjones646 | 0:c5afea7b9057 | 690 | #endif |
jjones646 | 0:c5afea7b9057 | 691 | flush_rx(); |
jjones646 | 0:c5afea7b9057 | 692 | flush_tx(); |
jjones646 | 0:c5afea7b9057 | 693 | #if DEBUG_MODE > 0 |
jjones646 | 0:c5afea7b9057 | 694 | std::printf("done\r\n"); |
jjones646 | 0:c5afea7b9057 | 695 | #endif |
jjones646 | 0:c5afea7b9057 | 696 | |
jjones646 | 0:c5afea7b9057 | 697 | |
jjones646 | 0:c5afea7b9057 | 698 | // Enter RX mode |
jjones646 | 0:c5afea7b9057 | 699 | #if DEBUG_MODE > 0 |
jjones646 | 0:c5afea7b9057 | 700 | std::printf(" Entering RX mode..."); |
jjones646 | 0:c5afea7b9057 | 701 | #endif |
jjones646 | 0:c5afea7b9057 | 702 | rx_mode(); |
jjones646 | 0:c5afea7b9057 | 703 | while( mode() != 0x0D ); // wait until it enters RX state |
jjones646 | 0:c5afea7b9057 | 704 | #if DEBUG_MODE > 0 |
jjones646 | 0:c5afea7b9057 | 705 | std::printf("done\r\n"); |
jjones646 | 0:c5afea7b9057 | 706 | #endif |
jjones646 | 0:c5afea7b9057 | 707 | } |
jjones646 | 0:c5afea7b9057 | 708 | |
jjones646 | 0:c5afea7b9057 | 709 | |
jjones646 | 0:c5afea7b9057 | 710 | /////////////////////////////////////////////////////////////////////////////////////// |
jjones646 | 0:c5afea7b9057 | 711 | // uint8_t read_reg(uint8_t addr) |
jjones646 | 0:c5afea7b9057 | 712 | // |
jjones646 | 0:c5afea7b9057 | 713 | // DESCRIPTION: |
jjones646 | 0:c5afea7b9057 | 714 | // This function gets the value of a single specified CCxxx0 register. |
jjones646 | 0:c5afea7b9057 | 715 | // |
jjones646 | 0:c5afea7b9057 | 716 | // ARGUMENTS: |
jjones646 | 0:c5afea7b9057 | 717 | // uint8_t addr |
jjones646 | 0:c5afea7b9057 | 718 | // Address of the CCxxx0 register to be accessed. |
jjones646 | 0:c5afea7b9057 | 719 | // |
jjones646 | 0:c5afea7b9057 | 720 | // RETURN VALUE: |
jjones646 | 0:c5afea7b9057 | 721 | // uint8_t |
jjones646 | 0:c5afea7b9057 | 722 | // Value of the accessed CCxxx0 register. |
jjones646 | 0:c5afea7b9057 | 723 | /////////////////////////////////////////////////////////////////////////////////////// |
jjones646 | 0:c5afea7b9057 | 724 | uint8_t CC1101::read_reg(uint8_t addr) |
jjones646 | 0:c5afea7b9057 | 725 | { |
jjones646 | 0:c5afea7b9057 | 726 | *_csn = 0; |
jjones646 | 0:c5afea7b9057 | 727 | _spi->write(addr | READ_SINGLE); |
jjones646 | 0:c5afea7b9057 | 728 | uint8_t x = _spi->write(0); |
jjones646 | 0:c5afea7b9057 | 729 | *_csn = 1; |
jjones646 | 0:c5afea7b9057 | 730 | |
jjones646 | 0:c5afea7b9057 | 731 | #if DEBUG_MODE > 1 |
jjones646 | 0:c5afea7b9057 | 732 | std::printf("\r\n== Single Register Read ==\r\n Address: 0x%02X\r\n Value: 0x%02X\r\n", addr, x); |
jjones646 | 0:c5afea7b9057 | 733 | #endif |
jjones646 | 0:c5afea7b9057 | 734 | return x; |
jjones646 | 0:c5afea7b9057 | 735 | } // read |
jjones646 | 0:c5afea7b9057 | 736 | |
jjones646 | 0:c5afea7b9057 | 737 | |
jjones646 | 0:c5afea7b9057 | 738 | /////////////////////////////////////////////////////////////////////////////////////// |
jjones646 | 0:c5afea7b9057 | 739 | // void read_reg(uint8_t addr, uint8_t *buffer, uint8_t count) |
jjones646 | 0:c5afea7b9057 | 740 | // |
jjones646 | 0:c5afea7b9057 | 741 | // DESCRIPTION: |
jjones646 | 0:c5afea7b9057 | 742 | // This function reads multiple CCxxx0 register, using SPI burst access. |
jjones646 | 0:c5afea7b9057 | 743 | // |
jjones646 | 0:c5afea7b9057 | 744 | // ARGUMENTS: |
jjones646 | 0:c5afea7b9057 | 745 | // uint8_t addr |
jjones646 | 0:c5afea7b9057 | 746 | // Address of the first CCxxx0 register to be accessed. |
jjones646 | 0:c5afea7b9057 | 747 | // uint8_t *buffer |
jjones646 | 0:c5afea7b9057 | 748 | // Pointer to a byte array which stores the values read from a |
jjones646 | 0:c5afea7b9057 | 749 | // corresponding range of CCxxx0 registers. |
jjones646 | 0:c5afea7b9057 | 750 | // uint8_t count |
jjones646 | 0:c5afea7b9057 | 751 | // Number of bytes to be read from the subsequent CCxxx0 registers. |
jjones646 | 0:c5afea7b9057 | 752 | /////////////////////////////////////////////////////////////////////////////////////// |
jjones646 | 0:c5afea7b9057 | 753 | void CC1101::read_reg(uint8_t addr, uint8_t *buffer, uint8_t count) |
jjones646 | 0:c5afea7b9057 | 754 | { |
jjones646 | 0:c5afea7b9057 | 755 | *_csn = 0; |
jjones646 | 0:c5afea7b9057 | 756 | _spi->write(addr | READ_BURST); |
jjones646 | 0:c5afea7b9057 | 757 | tiny_delay(); |
jjones646 | 0:c5afea7b9057 | 758 | for (uint8_t i = 0; i < count; i++) { |
jjones646 | 0:c5afea7b9057 | 759 | buffer[i] = _spi->write(0); |
jjones646 | 0:c5afea7b9057 | 760 | tiny_delay(); |
jjones646 | 0:c5afea7b9057 | 761 | } |
jjones646 | 0:c5afea7b9057 | 762 | *_csn = 1; |
jjones646 | 0:c5afea7b9057 | 763 | |
jjones646 | 0:c5afea7b9057 | 764 | #if DEBUG_MODE > 1 |
jjones646 | 0:c5afea7b9057 | 765 | std::printf("\r\n== Burst Register Read ==\r\n Address: 0x%02X\r\n Bytes: %u\r\n", addr, count); |
jjones646 | 0:c5afea7b9057 | 766 | #endif |
jjones646 | 0:c5afea7b9057 | 767 | } // read |
jjones646 | 0:c5afea7b9057 | 768 | |
jjones646 | 0:c5afea7b9057 | 769 | |
jjones646 | 0:c5afea7b9057 | 770 | /////////////////////////////////////////////////////////////////////////////////////// |
jjones646 | 0:c5afea7b9057 | 771 | // void write_reg(uint8_t addr, uint8_t value) |
jjones646 | 0:c5afea7b9057 | 772 | // |
jjones646 | 0:c5afea7b9057 | 773 | // DESCRIPTION: |
jjones646 | 0:c5afea7b9057 | 774 | // Function for writing to a single CCxxx0 register |
jjones646 | 0:c5afea7b9057 | 775 | // |
jjones646 | 0:c5afea7b9057 | 776 | // ARGUMENTS: |
jjones646 | 0:c5afea7b9057 | 777 | // uint8_t addr |
jjones646 | 0:c5afea7b9057 | 778 | // Address of a specific CCxxx0 register to accessed. |
jjones646 | 0:c5afea7b9057 | 779 | // uint8_t value |
jjones646 | 0:c5afea7b9057 | 780 | // Value to be written to the specified CCxxx0 register. |
jjones646 | 0:c5afea7b9057 | 781 | /////////////////////////////////////////////////////////////////////////////////////// |
jjones646 | 0:c5afea7b9057 | 782 | void CC1101::write_reg(uint8_t addr, uint8_t value) |
jjones646 | 0:c5afea7b9057 | 783 | { |
jjones646 | 0:c5afea7b9057 | 784 | *_csn = 0; |
jjones646 | 0:c5afea7b9057 | 785 | _spi->write(addr); |
jjones646 | 0:c5afea7b9057 | 786 | _spi->write(value); |
jjones646 | 0:c5afea7b9057 | 787 | *_csn = 1; |
jjones646 | 0:c5afea7b9057 | 788 | |
jjones646 | 0:c5afea7b9057 | 789 | #if DEBUG_MODE > 1 |
jjones646 | 0:c5afea7b9057 | 790 | std::printf("\r\n== Single Register Write ==\r\n Address: 0x%02X\r\n Value: 0x%02X\r\n", _addr, value); |
jjones646 | 0:c5afea7b9057 | 791 | #endif |
jjones646 | 0:c5afea7b9057 | 792 | } // write |
jjones646 | 0:c5afea7b9057 | 793 | |
jjones646 | 0:c5afea7b9057 | 794 | |
jjones646 | 0:c5afea7b9057 | 795 | /////////////////////////////////////////////////////////////////////////////////////// |
jjones646 | 0:c5afea7b9057 | 796 | // void write_reg(uint8_t addr, uint8_t *buffer, uint8_t count) |
jjones646 | 0:c5afea7b9057 | 797 | // |
jjones646 | 0:c5afea7b9057 | 798 | // DESCRIPTION: |
jjones646 | 0:c5afea7b9057 | 799 | // This function writes to multiple CCxxx0 register, using SPI burst access. |
jjones646 | 0:c5afea7b9057 | 800 | // |
jjones646 | 0:c5afea7b9057 | 801 | // ARGUMENTS: |
jjones646 | 0:c5afea7b9057 | 802 | // uint8_t addr |
jjones646 | 0:c5afea7b9057 | 803 | // Address of the first CCxxx0 register to be accessed. |
jjones646 | 0:c5afea7b9057 | 804 | // uint8_t *buffer |
jjones646 | 0:c5afea7b9057 | 805 | // Array of bytes to be written into a corresponding range of |
jjones646 | 0:c5afea7b9057 | 806 | // CCxx00 registers, starting by the address specified in _addr_. |
jjones646 | 0:c5afea7b9057 | 807 | // uint8_t count |
jjones646 | 0:c5afea7b9057 | 808 | // Number of bytes to be written to the subsequent CCxxx0 registers. |
jjones646 | 0:c5afea7b9057 | 809 | /////////////////////////////////////////////////////////////////////////////////////// |
jjones646 | 0:c5afea7b9057 | 810 | void CC1101::write_reg(uint8_t addr, uint8_t *buffer, uint8_t count) |
jjones646 | 0:c5afea7b9057 | 811 | { |
jjones646 | 0:c5afea7b9057 | 812 | *_csn = 0; |
jjones646 | 0:c5afea7b9057 | 813 | _spi->write(addr | WRITE_BURST); |
jjones646 | 0:c5afea7b9057 | 814 | tiny_delay(); |
jjones646 | 0:c5afea7b9057 | 815 | for (uint8_t i = 0; i < count; i++) { |
jjones646 | 0:c5afea7b9057 | 816 | _spi->write(buffer[i]); |
jjones646 | 0:c5afea7b9057 | 817 | tiny_delay(); |
jjones646 | 0:c5afea7b9057 | 818 | } |
jjones646 | 0:c5afea7b9057 | 819 | *_csn = 1; |
jjones646 | 0:c5afea7b9057 | 820 | |
jjones646 | 0:c5afea7b9057 | 821 | #if DEBUG_MODE > 1 |
jjones646 | 0:c5afea7b9057 | 822 | std::printf("\r\n== Burst Register Write ==\r\n Address: 0x%02X\r\n Bytes: %u\r\n", addr, count); |
jjones646 | 0:c5afea7b9057 | 823 | #endif |
jjones646 | 0:c5afea7b9057 | 824 | } // write |
jjones646 | 0:c5afea7b9057 | 825 | |
jjones646 | 0:c5afea7b9057 | 826 | |
jjones646 | 0:c5afea7b9057 | 827 | void CC1101::tiny_delay(void) |
jjones646 | 0:c5afea7b9057 | 828 | { |
jjones646 | 0:c5afea7b9057 | 829 | int i = 0; |
jjones646 | 0:c5afea7b9057 | 830 | while(i < 5) { |
jjones646 | 0:c5afea7b9057 | 831 | i++; |
jjones646 | 0:c5afea7b9057 | 832 | } |
jjones646 | 0:c5afea7b9057 | 833 | } |
jjones646 | 0:c5afea7b9057 | 834 | |
jjones646 | 0:c5afea7b9057 | 835 | |
jjones646 | 0:c5afea7b9057 | 836 | |
jjones646 | 0:c5afea7b9057 | 837 | /////////////////////////////////////////////////////////////////////////////////////// |
jjones646 | 0:c5afea7b9057 | 838 | // void put_pck(uint8_t *txBuffer, uint8_t size) |
jjones646 | 0:c5afea7b9057 | 839 | // |
jjones646 | 0:c5afea7b9057 | 840 | // DESCRIPTION: |
jjones646 | 0:c5afea7b9057 | 841 | // This function can be used to transmit a packet with packet length up to 63 bytes. |
jjones646 | 0:c5afea7b9057 | 842 | // |
jjones646 | 0:c5afea7b9057 | 843 | // ARGUMENTS: |
jjones646 | 0:c5afea7b9057 | 844 | // uint8_t *txBuffer |
jjones646 | 0:c5afea7b9057 | 845 | // Pointer to a buffer containing the data that are going to be transmitted |
jjones646 | 0:c5afea7b9057 | 846 | // |
jjones646 | 0:c5afea7b9057 | 847 | // uint8_t size |
jjones646 | 0:c5afea7b9057 | 848 | // The size of the txBuffer |
jjones646 | 0:c5afea7b9057 | 849 | // |
jjones646 | 0:c5afea7b9057 | 850 | void CC1101::put_pck(uint8_t *txBuffer, uint8_t size) |
jjones646 | 0:c5afea7b9057 | 851 | { |
jjones646 | 0:c5afea7b9057 | 852 | // Blink the TX LED |
jjones646 | 0:c5afea7b9057 | 853 | _tx_led_thread.signal_set(SET_LED_TICK); |
jjones646 | 0:c5afea7b9057 | 854 | |
jjones646 | 0:c5afea7b9057 | 855 | // move all values down by 1 to make room for the packet size value |
jjones646 | 0:c5afea7b9057 | 856 | for (uint8_t i = size; i > 0; i--) |
jjones646 | 0:c5afea7b9057 | 857 | txBuffer[i] = txBuffer[i-1]; |
jjones646 | 0:c5afea7b9057 | 858 | |
jjones646 | 0:c5afea7b9057 | 859 | // place the packet's size as the array's first value |
jjones646 | 0:c5afea7b9057 | 860 | txBuffer[0] = size++; |
jjones646 | 0:c5afea7b9057 | 861 | |
jjones646 | 0:c5afea7b9057 | 862 | #if DEBUG_MODE > 0 |
jjones646 | 0:c5afea7b9057 | 863 | std::printf("\r\n[PACKET TRANSMITTED]\r\n Bytes: %u\r\n ACK: %sRequested\r\n", size, (ack==1 ? "":"Not ") ); |
jjones646 | 0:c5afea7b9057 | 864 | #endif |
jjones646 | 0:c5afea7b9057 | 865 | |
jjones646 | 0:c5afea7b9057 | 866 | // send the data to the CC1101 |
jjones646 | 0:c5afea7b9057 | 867 | write_reg(CCxxx0_TXFIFO, txBuffer, size); |
jjones646 | 0:c5afea7b9057 | 868 | |
jjones646 | 0:c5afea7b9057 | 869 | #if DEBUG_MODE > 1 |
jjones646 | 0:c5afea7b9057 | 870 | Timer t1; |
jjones646 | 0:c5afea7b9057 | 871 | #endif |
jjones646 | 0:c5afea7b9057 | 872 | // enter the TX state |
jjones646 | 0:c5afea7b9057 | 873 | strobe(CCxxx0_STX); |
jjones646 | 0:c5afea7b9057 | 874 | |
jjones646 | 0:c5afea7b9057 | 875 | /* For the debug mode, this will determine how long the CC1101 takes to transmit everything in the TX buffer |
jjones646 | 0:c5afea7b9057 | 876 | and enter or return to the RX state. |
jjones646 | 0:c5afea7b9057 | 877 | */ |
jjones646 | 0:c5afea7b9057 | 878 | #if DEBUG_MODE > 1 |
jjones646 | 0:c5afea7b9057 | 879 | t1.start(); |
jjones646 | 0:c5afea7b9057 | 880 | float ti = t1.read(); |
jjones646 | 0:c5afea7b9057 | 881 | #endif |
jjones646 | 0:c5afea7b9057 | 882 | |
jjones646 | 0:c5afea7b9057 | 883 | |
jjones646 | 0:c5afea7b9057 | 884 | // wait until radio enters back to the RX state. takes very few cycles, so might as well wait before returning to elimate querky errors |
jjones646 | 0:c5afea7b9057 | 885 | while(mode() != 0x0D); |
jjones646 | 0:c5afea7b9057 | 886 | |
jjones646 | 0:c5afea7b9057 | 887 | #if DEBUG_MODE > 1 |
jjones646 | 0:c5afea7b9057 | 888 | t1.stop(); |
jjones646 | 0:c5afea7b9057 | 889 | std::printf(" Time: %02.4f ms\r\n", (t1.read() - ti)*1000); |
jjones646 | 0:c5afea7b9057 | 890 | #endif |
jjones646 | 0:c5afea7b9057 | 891 | |
jjones646 | 0:c5afea7b9057 | 892 | } // put_pck |
jjones646 | 0:c5afea7b9057 | 893 | |
jjones646 | 0:c5afea7b9057 | 894 | |
jjones646 | 0:c5afea7b9057 | 895 | /////////////////////////////////////////////////////////////////////////////////////// |
jjones646 | 0:c5afea7b9057 | 896 | // bool get_pck(uint8_t *rxBuffer, uint8_t *length) |
jjones646 | 0:c5afea7b9057 | 897 | // |
jjones646 | 0:c5afea7b9057 | 898 | // DESCRIPTION: |
jjones646 | 0:c5afea7b9057 | 899 | // This function can be used to receive a packet of variable packet length (first byte in the packet |
jjones646 | 0:c5afea7b9057 | 900 | // must be the length byte). The packet length should not exceed the RX FIFO size. |
jjones646 | 0:c5afea7b9057 | 901 | // |
jjones646 | 0:c5afea7b9057 | 902 | // ARGUMENTS: |
jjones646 | 0:c5afea7b9057 | 903 | // uint8_t *rxBuffer |
jjones646 | 0:c5afea7b9057 | 904 | // Pointer to the buffer where the incoming data should be stored |
jjones646 | 0:c5afea7b9057 | 905 | // uint8_t *length |
jjones646 | 0:c5afea7b9057 | 906 | // Pointer to a variable containing the size of the buffer where the incoming data should be |
jjones646 | 0:c5afea7b9057 | 907 | // stored. After this function returns, that variable holds the packet length. |
jjones646 | 0:c5afea7b9057 | 908 | // |
jjones646 | 0:c5afea7b9057 | 909 | // RETURN VALUE: |
jjones646 | 0:c5afea7b9057 | 910 | // BOOL |
jjones646 | 0:c5afea7b9057 | 911 | // 1: CRC OK |
jjones646 | 0:c5afea7b9057 | 912 | // 0: CRC NOT OK (or no packet was put in the RX FIFO due to filtering) |
jjones646 | 0:c5afea7b9057 | 913 | // |
jjones646 | 0:c5afea7b9057 | 914 | bool CC1101::get_pck(uint8_t *rxBuffer, uint8_t *length) |
jjones646 | 0:c5afea7b9057 | 915 | { |
jjones646 | 0:c5afea7b9057 | 916 | // Blink the RX LED |
jjones646 | 0:c5afea7b9057 | 917 | _rx_led_thread.signal_set(SET_LED_TICK); |
jjones646 | 0:c5afea7b9057 | 918 | |
jjones646 | 0:c5afea7b9057 | 919 | // Update the frequency offset estimate |
jjones646 | 0:c5afea7b9057 | 920 | write_reg(CCxxx0_FSCTRL0, status(CCxxx0_FREQEST)); |
jjones646 | 0:c5afea7b9057 | 921 | |
jjones646 | 0:c5afea7b9057 | 922 | // Get the packet's size |
jjones646 | 0:c5afea7b9057 | 923 | uint8_t rx_size; |
jjones646 | 0:c5afea7b9057 | 924 | read_reg(CCxxx0_RXFIFO, &rx_size, 1); |
jjones646 | 0:c5afea7b9057 | 925 | |
jjones646 | 0:c5afea7b9057 | 926 | if (rx_size & BYTES_IN_RXFIFO) { |
jjones646 | 0:c5afea7b9057 | 927 | |
jjones646 | 0:c5afea7b9057 | 928 | // Read data from RX FIFO and store in rxBuffer |
jjones646 | 0:c5afea7b9057 | 929 | if (rx_size <= *length) { |
jjones646 | 0:c5afea7b9057 | 930 | |
jjones646 | 0:c5afea7b9057 | 931 | *length = rx_size; |
jjones646 | 0:c5afea7b9057 | 932 | read_reg(CCxxx0_RXFIFO, rxBuffer, *length); |
jjones646 | 0:c5afea7b9057 | 933 | |
jjones646 | 0:c5afea7b9057 | 934 | // Read the 2 appended status bytes (status[0] = RSSI, status[1] = LQI) |
jjones646 | 0:c5afea7b9057 | 935 | uint8_t status_bytes[2]; |
jjones646 | 0:c5afea7b9057 | 936 | read_reg(CCxxx0_RXFIFO, status_bytes, 2); |
jjones646 | 0:c5afea7b9057 | 937 | |
jjones646 | 0:c5afea7b9057 | 938 | // update the RSSI reading |
jjones646 | 0:c5afea7b9057 | 939 | rssi(status_bytes[RSSI]); |
jjones646 | 0:c5afea7b9057 | 940 | _lqi = status_bytes[LQI] & 0x7F; // MSB of LQI is the CRC_OK bit |
jjones646 | 0:c5afea7b9057 | 941 | |
jjones646 | 0:c5afea7b9057 | 942 | #if DEBUG_MODE > 0 |
jjones646 | 0:c5afea7b9057 | 943 | std::printf("\r\n[PACKET RECEIVED]\r\n Bytes: %u\r\n", *length); |
jjones646 | 0:c5afea7b9057 | 944 | std::printf(" RSSI: %ddBm\r\n", _rssi); |
jjones646 | 0:c5afea7b9057 | 945 | std::printf(" LQI: %u\r\n", _lqi); |
jjones646 | 0:c5afea7b9057 | 946 | #endif |
jjones646 | 0:c5afea7b9057 | 947 | |
jjones646 | 0:c5afea7b9057 | 948 | if (_p_count%5 == 0) { |
jjones646 | 0:c5afea7b9057 | 949 | //calibrate the frequency synthesizer |
jjones646 | 0:c5afea7b9057 | 950 | calibrate(); |
jjones646 | 0:c5afea7b9057 | 951 | } |
jjones646 | 0:c5afea7b9057 | 952 | |
jjones646 | 0:c5afea7b9057 | 953 | // Go back to the receiving state since CC1101 is configured for transitioning to IDLE on receiving a packet |
jjones646 | 0:c5afea7b9057 | 954 | rx_mode(); |
jjones646 | 0:c5afea7b9057 | 955 | return 1; |
jjones646 | 0:c5afea7b9057 | 956 | |
jjones646 | 0:c5afea7b9057 | 957 | } else { |
jjones646 | 0:c5afea7b9057 | 958 | *length = size; |
jjones646 | 0:c5afea7b9057 | 959 | } |
jjones646 | 0:c5afea7b9057 | 960 | } |
jjones646 | 0:c5afea7b9057 | 961 | |
jjones646 | 0:c5afea7b9057 | 962 | flush_rx(); |
jjones646 | 0:c5afea7b9057 | 963 | return 0; |
jjones646 | 0:c5afea7b9057 | 964 | |
jjones646 | 0:c5afea7b9057 | 965 | } // get_pck |
jjones646 | 0:c5afea7b9057 | 966 | |
jjones646 | 0:c5afea7b9057 | 967 | |
jjones646 | 0:c5afea7b9057 | 968 | void CC1101::flush_rx(void) |
jjones646 | 0:c5afea7b9057 | 969 | { |
jjones646 | 0:c5afea7b9057 | 970 | // Make sure that the radio is in IDLE state before flushing the FIFO |
jjones646 | 0:c5afea7b9057 | 971 | idle(); |
jjones646 | 0:c5afea7b9057 | 972 | |
jjones646 | 0:c5afea7b9057 | 973 | // Flush RX FIFO |
jjones646 | 0:c5afea7b9057 | 974 | strobe(CCxxx0_SFRX); |
jjones646 | 0:c5afea7b9057 | 975 | |
jjones646 | 0:c5afea7b9057 | 976 | // Enter back into a RX state |
jjones646 | 0:c5afea7b9057 | 977 | rx_mode(); |
jjones646 | 0:c5afea7b9057 | 978 | } |
jjones646 | 0:c5afea7b9057 | 979 | |
jjones646 | 0:c5afea7b9057 | 980 | |
jjones646 | 0:c5afea7b9057 | 981 | void CC1101::flush_tx(void) |
jjones646 | 0:c5afea7b9057 | 982 | { |
jjones646 | 0:c5afea7b9057 | 983 | // Make sure that the radio is in IDLE state before flushing the FIFO |
jjones646 | 0:c5afea7b9057 | 984 | idle(); |
jjones646 | 0:c5afea7b9057 | 985 | |
jjones646 | 0:c5afea7b9057 | 986 | // Flush TX FIFO |
jjones646 | 0:c5afea7b9057 | 987 | strobe(CCxxx0_SFTX); |
jjones646 | 0:c5afea7b9057 | 988 | |
jjones646 | 0:c5afea7b9057 | 989 | // Enter back into a RX state |
jjones646 | 0:c5afea7b9057 | 990 | rx_mode(); |
jjones646 | 0:c5afea7b9057 | 991 | } |
jjones646 | 0:c5afea7b9057 | 992 | |
jjones646 | 0:c5afea7b9057 | 993 | |
jjones646 | 0:c5afea7b9057 | 994 | void CC1101::rx_mode(void) |
jjones646 | 0:c5afea7b9057 | 995 | { |
jjones646 | 0:c5afea7b9057 | 996 | //strobe(CCxxx0_SIDLE); |
jjones646 | 0:c5afea7b9057 | 997 | strobe(CCxxx0_SRX); |
jjones646 | 0:c5afea7b9057 | 998 | //while(mode() != 0x0D); |
jjones646 | 0:c5afea7b9057 | 999 | } |
jjones646 | 0:c5afea7b9057 | 1000 | |
jjones646 | 0:c5afea7b9057 | 1001 | |
jjones646 | 0:c5afea7b9057 | 1002 | void CC1101::tx_mode(void) |
jjones646 | 0:c5afea7b9057 | 1003 | { |
jjones646 | 0:c5afea7b9057 | 1004 | //strobe(CCxxx0_SIDLE); |
jjones646 | 0:c5afea7b9057 | 1005 | strobe(CCxxx0_STX); |
jjones646 | 0:c5afea7b9057 | 1006 | // while(mode() != 0x13); |
jjones646 | 0:c5afea7b9057 | 1007 | } |
jjones646 | 0:c5afea7b9057 | 1008 | |
jjones646 | 0:c5afea7b9057 | 1009 | void CC1101::idle(void) |
jjones646 | 0:c5afea7b9057 | 1010 | { |
jjones646 | 0:c5afea7b9057 | 1011 | // Send the IDLE strobe |
jjones646 | 0:c5afea7b9057 | 1012 | strobe(CCxxx0_SIDLE); |
jjones646 | 0:c5afea7b9057 | 1013 | // Wait before returning |
jjones646 | 0:c5afea7b9057 | 1014 | // === THIS LIKELY ISN'T NEEDED === |
jjones646 | 0:c5afea7b9057 | 1015 | while( mode() != 0x01); |
jjones646 | 0:c5afea7b9057 | 1016 | } |