Prototype RF driver for STM Sub-1 GHz RF expansion board based on the SPSGRF-868 module for STM32 Nucleo.
Embed:
(wiki syntax)
Show/hide line numbers
SimpleSpirit1.h
00001 /*** Mbed Includes ***/ 00002 #include "mbed.h" 00003 #include "mbed_debug.h" 00004 00005 00006 /*** Cube Includes ***/ 00007 #include "SPIRIT_Radio.h" 00008 #include "SPIRIT_Management.h" 00009 #include "SPIRIT_Commands.h" 00010 #include "MCU_Interface.h" 00011 00012 00013 /*** Contiki Lib Includes ***/ 00014 #include "spirit1.h" 00015 #include "spirit1-config.h" 00016 #include "spirit1-const.h" 00017 00018 00019 // betzw: enable beyond macro if you want debug messages also from IRQ handler 00020 // #define DEBUG_IRQ 00021 00022 00023 /*** Macros from Cube Implementation ***/ 00024 #define CLEAR_TXBUF() (spirit_tx_len = 0) 00025 #define IS_RXBUF_EMPTY() (spirit_rx_len == 0) 00026 #define CLEAR_RXBUF() do { \ 00027 spirit_rx_len = 0; \ 00028 _spirit_rx_pos = 0; \ 00029 } while(0) 00030 00031 00032 /*** Macros from Cube Implementation ***/ 00033 /* transceiver state. */ 00034 #define ON 0 00035 #define OFF 1 00036 00037 00038 /*** Macros for Spirit1 API ***/ 00039 /* max payload */ 00040 #define SPIRIT1_MAX_PAYLOAD (MAX_PACKET_LEN) 00041 00042 00043 /*** Missing Cube External Declarations ***/ 00044 extern "C" void SpiritManagementSetFrequencyBase(uint32_t); 00045 00046 00047 /*** UnlockedSPI for Usage in IRQ context ***/ 00048 class UnlockedSPI : public SPI { 00049 public: 00050 UnlockedSPI(PinName mosi, PinName miso, PinName sclk) : 00051 SPI(mosi, miso, sclk) { } 00052 virtual ~UnlockedSPI() {} 00053 virtual void lock() { } 00054 virtual void unlock() { } 00055 }; 00056 00057 00058 /*** A Simple Spirit1 Class ***/ 00059 // NOTE: must be a singleton (due to mix of MBED/CUBE code)!!! 00060 // NOTE: implementation is IRQ-save but (intentionally) NOT thread-safe!!! 00061 /** Simple Spirit1 Class 00062 * 00063 * @Note Synchronization level: implementation is IRQ-save but (intentionally) NOT thread-safe!!! 00064 * 00065 * Example: 00066 * @code 00067 * #include "mbed.h" 00068 * #include "SimpleSpirit1.h" 00069 * 00070 * static char send_buf[] = "Hello World!"; 00071 * 00072 * static SimpleSpirit1 &myspirit = SimpleSpirit1::CreateInstance(D11, D12, D3, D9, D10, D2); 00073 * 00074 * static volatile bool tx_done_flag = false; 00075 * 00076 * static void callback_func(int event) 00077 * { 00078 * if (event == SimpleSpirit1::TX_DONE) { 00079 * tx_done_flag = true; 00080 * } 00081 * } 00082 * 00083 * int main() 00084 * { 00085 * myspirit.attach_irq_callback(callback_func); 00086 * myspirit.on(); 00087 * 00088 * while(1) 00089 * { 00090 * size_t curr_len = strlen((const char*)send_buf); 00091 * myspirit.send(send_buf, curr_len); 00092 * 00093 * while(!tx_done_flag); 00094 * tx_done_flag = false; 00095 * } 00096 * } 00097 * @endcode 00098 */ 00099 class SimpleSpirit1 { 00100 protected: 00101 static SimpleSpirit1 *_singleton; 00102 00103 /** Communication Interface Instance Variables **/ 00104 UnlockedSPI _spi; // betzw - NOTE: Morpho/Zio pins are valid only for NUCLEO-F401RE 00105 // mosi: PA_7 (D11) 00106 // miso: PA_6 (D12) 00107 // sclk: PB_3 (D3) or 00108 // PA_5 (D13) (only in case you unmount R4 & mount R7, 00109 // (note: in this case you may not use LED1 on some platforms) 00110 // bits: 8-bit 00111 // mode: 0 00112 // ordr: MSB 00113 // freq: max 10MHz 00114 InterruptIn _irq; // PC_7 (D9) (falling) 00115 DigitalOut _chip_select; // PB_6 (D10) ('1' == chip unselected) 00116 DigitalOut _shut_down; // PA_10 (D2) ('1' == shut_down) 00117 DigitalOut _led; // PB_4 (D5) (optional) 00118 00119 Callback<void(int)> _current_irq_callback; 00120 Timeout _rx_receiving_timeout; 00121 00122 void rx_timeout_handler(void) { 00123 set_ready_state(); 00124 cmd_strobe(SPIRIT1_STROBE_RX); 00125 #ifdef DEBUG_IRQ 00126 debug("\r\n%s (%d)\r\n", __func__, __LINE__); 00127 #endif 00128 } 00129 00130 void start_rx_timeout(void) { 00131 _rx_receiving_timeout.attach_us(Callback<void()>(this, &SimpleSpirit1::rx_timeout_handler), 100 * 1000); // 100ms 00132 } 00133 00134 void stop_rx_timeout(void) { 00135 _rx_receiving_timeout.detach(); 00136 } 00137 00138 /** Static Variables from Cube Implementation **/ 00139 /* 00140 * The buffers which hold incoming data. 00141 * The +1 because of the first byte, 00142 * which will contain the length of the packet. 00143 */ 00144 volatile uint16_t spirit_tx_len; 00145 volatile bool _spirit_tx_started; 00146 volatile uint16_t spirit_rx_len; 00147 volatile uint16_t _spirit_rx_pos; 00148 volatile bool _spirit_rx_err; 00149 uint8_t spirit_rx_buf[MAX_PACKET_LEN]; 00150 volatile bool _is_receiving; 00151 00152 /** Status Variables from Cube Implementation **/ 00153 unsigned int spirit_on; 00154 uint8_t last_rssi; //MGR 00155 uint8_t last_sqi; //MGR 00156 00157 /** Low Level Instance Variables **/ 00158 unsigned int _nr_of_irq_disables; 00159 00160 /** Low Level Instance Methods **/ 00161 void disable_spirit_irq(void) { 00162 _irq.disable_irq(); 00163 _nr_of_irq_disables++; 00164 #ifndef NDEBUG 00165 debug_if(_nr_of_irq_disables == 0, "\r\nassert failed in: %s (%d)\r\n", __func__, __LINE__); 00166 #endif 00167 } 00168 00169 void enable_spirit_irq(void) { 00170 #ifndef NDEBUG 00171 debug_if(_nr_of_irq_disables == 0, "\r\nassert failed in: %s (%d)\r\n", __func__, __LINE__); 00172 #endif 00173 if(--_nr_of_irq_disables == 0) 00174 _irq.enable_irq(); 00175 } 00176 00177 void chip_select() { _chip_select = 0; } 00178 void chip_unselect() { _chip_select = 1; } 00179 00180 void enter_shutdown() { 00181 _shut_down = 1; 00182 wait_ms(5); // wait 5 milliseconds (to allow Spirit1 to shut down) 00183 } 00184 00185 void exit_shutdown() { 00186 _shut_down = 0; 00187 wait_ms(10); // wait 10 milliseconds (to allow Spirit1 a proper boot-up sequence) 00188 } 00189 00190 void cs_to_sclk_delay(void) { 00191 wait_us(1); // heuristic value 00192 } 00193 00194 /** 00195 * @brief Write and read a buffer to/from the SPI peripheral device at the same time 00196 * in 8-bit data mode using synchronous SPI communication. 00197 * @param[in] pBufferToWrite pointer to the buffer of data to send. 00198 * @param[out] pBufferToRead pointer to the buffer to read data into. 00199 * @param[in] NumBytes number of bytes to read and write. 00200 * @retval 0 if ok. 00201 * @retval -1 if data format error. 00202 * @note When using the SPI in Interrupt-mode, remember to disable interrupts 00203 * before calling this function and to enable them again after. 00204 */ 00205 void spi_write_read(uint8_t* pBufferToWrite, uint8_t* pBufferToRead, uint16_t NumBytes) 00206 { 00207 /* Read and write data at the same time. */ 00208 for (int i = 0; i < NumBytes; i++) { 00209 pBufferToRead[i] = _spi.write(pBufferToWrite[i]); 00210 } 00211 } 00212 00213 /** Radio Instance Methods **/ 00214 void radio_set_xtal_freq(uint32_t freq) { 00215 SpiritRadioSetXtalFrequency(freq); 00216 } 00217 00218 void radio_set_pa_level_dbm(uint8_t cIndex, float fPowerdBm) { 00219 SpiritRadioSetPALeveldBm(cIndex, fPowerdBm); 00220 } 00221 00222 void radio_set_pa_level_max_index(uint8_t cIndex) { 00223 SpiritRadioSetPALevelMaxIndex(cIndex); 00224 } 00225 00226 uint8_t radio_init(SRadioInit *init_struct) { 00227 return SpiritRadioInit(init_struct); 00228 } 00229 00230 void radio_persistent_rx(SpiritFunctionalState xNewState) { 00231 SpiritRadioPersistenRx(xNewState); 00232 } 00233 00234 void radio_afc_freeze_on_sync(SpiritFunctionalState xNewState) { 00235 SpiritRadioAFCFreezeOnSync(xNewState); 00236 } 00237 00238 /** Packet System Instance Methods **/ 00239 void pkt_basic_init(PktBasicInit* pxPktBasicInit) { 00240 SpiritPktBasicInit(pxPktBasicInit); 00241 } 00242 00243 void pkt_basic_set_payload_length(uint16_t nPayloadLength) { 00244 SpiritPktBasicSetPayloadLength(nPayloadLength); 00245 } 00246 00247 uint16_t pkt_basic_get_received_pkt_length(void) { 00248 return SpiritPktBasicGetReceivedPktLength(); 00249 } 00250 00251 /** IRQ Instance Methods **/ 00252 void irq_de_init(SpiritIrqs* pxIrqInit) { 00253 SpiritIrqDeInit(pxIrqInit); 00254 } 00255 00256 void irq_clear_status(void) { 00257 SpiritIrqClearStatus(); 00258 } 00259 00260 void irq_set_status(IrqList xIrq, SpiritFunctionalState xNewState) { 00261 SpiritIrq(xIrq, xNewState); 00262 } 00263 00264 void irq_get_status(SpiritIrqs* pxIrqStatus) { 00265 SpiritIrqGetStatus(pxIrqStatus); 00266 } 00267 00268 /** Management Instance Methods **/ 00269 void mgmt_set_freq_base(uint32_t freq) { 00270 SpiritManagementSetFrequencyBase(freq); 00271 } 00272 00273 void mgmt_refresh_status(void) { 00274 SpiritRefreshStatus(); 00275 } 00276 00277 /** Spirit GPIO Instance Methods **/ 00278 void spirit_gpio_init(SGpioInit* pxGpioInitStruct) { 00279 SpiritGpioInit(pxGpioInitStruct); 00280 } 00281 00282 /** Qi Instance Methods **/ 00283 void qi_set_sqi_threshold(SqiThreshold xSqiThr) { 00284 SpiritQiSetSqiThreshold(xSqiThr); 00285 } 00286 00287 void qi_sqi_check(SpiritFunctionalState xNewState) { 00288 SpiritQiSqiCheck(xNewState); 00289 } 00290 00291 void qi_set_rssi_threshold_dbm(int nDbmValue) { 00292 SpiritQiSetRssiThresholddBm(nDbmValue); 00293 } 00294 00295 float qi_get_rssi_dbm() { 00296 last_rssi = qi_get_rssi(); 00297 return get_last_rssi_dbm(); 00298 } 00299 00300 uint8_t qi_get_rssi() { 00301 return SpiritQiGetRssi(); 00302 } 00303 00304 uint8_t qi_get_sqi() { 00305 return SpiritQiGetSqi(); 00306 } 00307 00308 /** Timer Instance Methods **/ 00309 void timer_set_rx_timeout_stop_condition(RxTimeoutStopCondition xStopCondition) { 00310 SpiritTimerSetRxTimeoutStopCondition(xStopCondition); 00311 } 00312 00313 void timer_set_rx_timeout_counter(uint8_t cCounter) { 00314 SpiritTimerSetRxTimeoutCounter(cCounter); 00315 } 00316 00317 void timer_set_infinite_rx_timeout(void) { 00318 timer_set_rx_timeout_counter(0); 00319 } 00320 00321 /** CSMA/CA Instance Methods **/ 00322 void csma_ca_state(SpiritFunctionalState xNewState) { 00323 SpiritCsma(xNewState); 00324 } 00325 00326 void csma_ca_init(CsmaInit* pxCsmaInit) { 00327 csma_ca_state(S_DISABLE); // Disabled at init 00328 SpiritCsmaInit(pxCsmaInit); 00329 SpiritCsmaSeedReloadMode(S_DISABLE); // always disable seed reload 00330 } 00331 00332 /** Command Instance Methods**/ 00333 void cmd_strobe(uint8_t cmd) { 00334 SpiritCmdStrobeCommand((SpiritCmd)cmd); 00335 } 00336 00337 void cmd_strobe_flush_rx_fifo() { 00338 SpiritCmdStrobeCommand(CMD_FLUSHRXFIFO); 00339 } 00340 00341 /** SPI Instance Methods **/ 00342 StatusBytes spi_write_linear_fifo(uint8_t cNbBytes, uint8_t* pcBuffer) { 00343 return SdkEvalSpiWriteFifo(cNbBytes, pcBuffer); 00344 } 00345 00346 StatusBytes spi_read_linear_fifo(uint8_t cNbBytes, uint8_t* pcBuffer) { 00347 return SdkEvalSpiReadFifo(cNbBytes, pcBuffer); 00348 } 00349 00350 /** Linear FIFO Instance Methods **/ 00351 uint8_t linear_fifo_read_num_elements_rx_fifo(void) { 00352 return SpiritLinearFifoReadNumElementsRxFifo(); 00353 } 00354 00355 uint8_t linear_fifo_read_num_elements_tx_fifo(void) { 00356 return SpiritLinearFifoReadNumElementsTxFifo(); 00357 } 00358 00359 void linear_fifo_set_almost_full_thr_rx(uint8_t cThrRxFifo) { 00360 SpiritLinearFifoSetAlmostFullThresholdRx(cThrRxFifo); 00361 } 00362 00363 /** Calibration Instance Methods **/ 00364 void calibration_rco(SpiritFunctionalState xNewState) { 00365 SpiritCalibrationRco(xNewState); 00366 } 00367 00368 /** Internal Spirit Methods */ 00369 void set_ready_state(void); 00370 uint8_t refresh_state(void); 00371 00372 /** Friend Functions **/ 00373 friend StatusBytes SdkEvalSpiWriteRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer); 00374 friend StatusBytes SdkEvalSpiReadRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer); 00375 friend StatusBytes SdkEvalSpiCommandStrobes(uint8_t cCommandCode); 00376 friend StatusBytes SdkEvalSpiWriteFifo(uint8_t cNbBytes, uint8_t* pcBuffer); 00377 friend StatusBytes SdkEvalSpiReadFifo(uint8_t cNbBytes, uint8_t* pcBuffer); 00378 00379 /** Sdk Instance Methods **/ 00380 StatusBytes SdkEvalSpiWriteRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer); 00381 StatusBytes SdkEvalSpiReadRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer); 00382 StatusBytes SdkEvalSpiCommandStrobes(uint8_t cCommandCode); 00383 StatusBytes SdkEvalSpiWriteFifo(uint8_t cNbBytes, uint8_t* pcBuffer); 00384 StatusBytes SdkEvalSpiReadFifo(uint8_t cNbBytes, uint8_t* pcBuffer); 00385 00386 /** Helper Instance Methods **/ 00387 void chip_sync_select() { 00388 disable_spirit_irq(); 00389 chip_select(); 00390 cs_to_sclk_delay(); 00391 } 00392 00393 void chip_sync_unselect() { 00394 chip_unselect(); 00395 enable_spirit_irq(); 00396 } 00397 00398 /** Init Instance Method **/ 00399 void init(); 00400 00401 /** Spirit Irq Callback */ 00402 void IrqHandler(); 00403 00404 /** Constructor **/ 00405 SimpleSpirit1(PinName mosi, PinName miso, PinName sclk, 00406 PinName irq, PinName cs, PinName sdn, 00407 PinName led); 00408 00409 /** Destructor **/ 00410 ~SimpleSpirit1(void); // should never be called! 00411 00412 public: 00413 enum { 00414 RX_DONE, 00415 TX_DONE, 00416 TX_ERR 00417 }; 00418 00419 /** Create singleton instance of 'SimpleSpirit1' 00420 * 00421 * @param mosi 'PinName' of mosi pin to use 00422 * @param miso 'PinName' of miso pin to use 00423 * @param sclk 'PinName' of clock pin to use 00424 * @param irq 'PinName' of interrupt pin to use 00425 * @param cs 'PinName' of chip-select pin pin to use 00426 * @param sdn 'PinName' of pin to use for device shutdown 00427 * 00428 * @returns reference to singleton instance 00429 */ 00430 static SimpleSpirit1& CreateInstance(PinName mosi, PinName miso, PinName sclk, 00431 PinName irq, PinName cs, PinName sdn, 00432 PinName led = NC) { 00433 00434 if(_singleton == NULL) { 00435 _singleton = new SimpleSpirit1(mosi, miso, sclk, 00436 irq, cs, sdn, led); 00437 _singleton->init(); 00438 } else { 00439 error("SimpleSpirit1 singleton already created!\n"); 00440 } 00441 00442 return *_singleton; 00443 } 00444 00445 /** Get singleton instance of 'SimpleSpirit1' 00446 * 00447 * @returns reference to singleton instance 00448 */ 00449 static SimpleSpirit1& Instance() { 00450 if(_singleton == NULL) { 00451 error("SimpleSpirit1 must be created before used!\n"); 00452 } 00453 00454 return *_singleton; 00455 } 00456 00457 /** Attach a function to be called by the Spirit Irq handler when an event has occurred 00458 * 00459 * @param func A void(int) callback, or 0 to set as none 00460 * 00461 * @note Function 'func' will be executed in interrupt context! 00462 * @note Function 'func' will be call with either 'RX_DONE', 'TX_DONE', or 'TX_ERR' as parameter 00463 * to indicate which event has occurred. 00464 */ 00465 void attach_irq_callback(Callback<void(int)> func) { 00466 _current_irq_callback = func; 00467 } 00468 00469 /** Switch Radio On 00470 */ 00471 int on(void); 00472 00473 /** Switch Radio Off 00474 */ 00475 int off(void); 00476 00477 /** Set Channel 00478 */ 00479 void set_channel(uint8_t channel) { 00480 SpiritRadioSetChannel(channel); 00481 } 00482 00483 /** Send a Buffer 00484 * 00485 * @param payload pointer to buffer to be send 00486 * @param payload_len length of payload buffer in bytes 00487 * @param use_csma_ca should CSMA/CA be enabled for transmission 00488 * 00489 * @returns zero in case of success, non-zero error code otherwise 00490 * 00491 * @note the maximum payload size in bytes allowed is defined by macro 'SPIRIT1_MAX_PAYLOAD' 00492 */ 00493 int send(const void *payload, unsigned int payload_len, bool use_csma_ca = true); 00494 00495 /** Copy received data into buffer 00496 * 00497 * @param buf pointer to buffer to be filled 00498 * @param bufsize size of buffer 00499 * 00500 * @returns number of bytes copied into the buffer 00501 * 00502 * @note the buffer should be (at least) of size 'SPIRIT1_MAX_PAYLOAD' (in bytes). 00503 */ 00504 int read(void *buf, unsigned int bufsize); 00505 00506 /** Perform a Clear-Channel Assessment (CCA) to find out whether the medium is idle or not. 00507 * 00508 * @returns 1 if the medium is busy. 00509 */ 00510 int channel_clear(void); 00511 00512 /** Check if the radio driver has just received a packet 00513 */ 00514 int get_pending_packet(void); 00515 00516 /** Is radio currently receiving 00517 */ 00518 bool is_receiving(void) { 00519 return _is_receiving; 00520 } 00521 00522 /** Get latest value of RSSI (in dBm) 00523 */ 00524 float get_last_rssi_dbm(void) { 00525 get_last_rssi_raw(); 00526 return (-120.0+((float)(last_rssi-20))/2); 00527 } 00528 00529 /** Get latest value of RSSI (as Spirit1 raw value) 00530 */ 00531 uint8_t get_last_rssi_raw(void) { 00532 if(last_rssi == 0) { 00533 last_rssi = qi_get_rssi(); 00534 } 00535 return last_rssi; 00536 } 00537 00538 /** Get latest value of LQI (scaled to 8-bit) 00539 */ 00540 uint8_t get_last_sqi(void) { 00541 const uint8_t max_sqi = 8 * ((SYNC_LENGTH>>1)+1); 00542 if(last_sqi == 0) { 00543 last_sqi = qi_get_sqi(); 00544 } 00545 if(last_sqi > max_sqi) last_sqi = max_sqi; 00546 00547 return (last_sqi * 255 / max_sqi); 00548 } 00549 00550 /** Reset Board 00551 */ 00552 void reset_board() { 00553 init(); 00554 } 00555 };
Generated on Tue Jul 12 2022 16:35:33 by
1.7.2
X-NUCLEO-IDS01A4 Sub-1GHz RF Expansion Board