Prototype RF driver for STM Sub-1 GHz RF expansion board based on the SPSGRF-868 module for STM32 Nucleo.
Prototype RF Driver for STM Sub-1 GHz RF Expansion Boards based on the SPSGRF-868 and SPSGRF-915 Modules for STM32 Nucleo
Currently supported boards:
Note, in order to use expansion board X-NUCLEO-IDS01A4
in mbed you need to perform the following HW modifications on the board:
- Unmount resistor
R4
- Mount resistor
R7
Furthermore, on some Nucleo development boards (e.g. the NUCLEO_F429ZI), in order to be able to use Ethernet together with these Sub-1 GHz RF expansion boards, you need to compile this driver with macro SPIRIT1_SPI_MOSI=PB_5
defined, while the development board typically requires some HW modification as e.g. described here!
This driver can be used together with the 6LoWPAN stack (a.k.a. Nanostack).
source/SimpleSpirit1.cpp@64:28ef790e4ef7, 2017-07-03 (annotated)
- Committer:
- Wolfgang Betz
- Date:
- Mon Jul 03 14:39:01 2017 +0200
- Revision:
- 64:28ef790e4ef7
- Parent:
- 60:956afcef7ef7
- Child:
- 65:a16f0064110a
Implement indications received by Kevin Bracey
Date: Mon, 3 Jul 2017 10:14:23 +0000
From: Kevin Bracey <notifications@github.com>
https://github.com/ARMmbed/mbed-os-example-client/issues/266#issuecomment-312606944
I've just spent a little while reviewing the Spirit driver code, just to see if I can see any obvious flaws. (Hard to say much without knowing the hardware, but I can look for general issues.)
I'm a bit wary about the software ack handling - can be tricky.
There is one specific problem that could be affecting performance now - it seems to me the acks are sent with a common send() routine that enables hardware CSMA-CD. An ack should be being sent 192us after transmission completion, without CSMA. Backing off the ack will greatly reduce the chance of packets being successfully acknowledged.
Other notes on ack reception - you're calling TX_DONE whenever tx_sequence == seq_number, whether you were expecting an ack or not. This could cause stack confusion in various ways (eg if you were backing off while someone else used the same sequence number). You should only process an ACK when you actually expect one (TX completed, and AR bit was set in it)
Also, while expecting an ack, it can be beneficial to report TX_FAIL and stop expecting when you receive anything other then an ack with the expected sequence number. The stack will eventually time out if it doesn't get TX_DONE, but receipt of anything else (including a wrongly-numbered ack) indicates a lack of acknowledgment, which can be reported immediately.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Wolfgang Betz |
34:edda6a7238ec | 1 | /*** Mbed Includes ***/ |
Wolfgang Betz |
34:edda6a7238ec | 2 | #include "SimpleSpirit1.h" |
Wolfgang Betz |
34:edda6a7238ec | 3 | #include "radio_spi.h" |
Wolfgang Betz |
34:edda6a7238ec | 4 | |
Wolfgang Betz |
34:edda6a7238ec | 5 | #define SPIRIT_GPIO_IRQ (SPIRIT_GPIO_3) |
Wolfgang Betz |
34:edda6a7238ec | 6 | |
Wolfgang Betz |
34:edda6a7238ec | 7 | static uint16_t last_state; |
Wolfgang Betz |
34:edda6a7238ec | 8 | #define SPIRIT1_STATUS() ((last_state = (uint16_t)refresh_state()) & SPIRIT1_STATE_STATEBITS) |
Wolfgang Betz |
34:edda6a7238ec | 9 | |
Wolfgang Betz |
34:edda6a7238ec | 10 | #define XO_ON (0x1) |
Wolfgang Betz |
34:edda6a7238ec | 11 | |
Wolfgang Betz |
34:edda6a7238ec | 12 | #define BUSYWAIT_UNTIL(cond, millisecs) \ |
Wolfgang Betz |
34:edda6a7238ec | 13 | do { \ |
Wolfgang Betz |
34:edda6a7238ec | 14 | uint32_t start = us_ticker_read(); \ |
Wolfgang Betz |
34:edda6a7238ec | 15 | while (!(cond) && ((us_ticker_read() - start) < ((uint32_t)millisecs)*1000U)); \ |
Wolfgang Betz |
34:edda6a7238ec | 16 | } while(0) |
Wolfgang Betz |
34:edda6a7238ec | 17 | |
Wolfgang Betz |
34:edda6a7238ec | 18 | #define st_lib_spirit_irqs SpiritIrqs |
Wolfgang Betz |
34:edda6a7238ec | 19 | |
Wolfgang Betz |
37:bc043030b55a | 20 | #define STATE_TIMEOUT (100) |
Wolfgang Betz |
34:edda6a7238ec | 21 | |
Wolfgang Betz |
34:edda6a7238ec | 22 | // betzw: switching force & back from standby is on some devices quite unstable |
Wolfgang Betz |
34:edda6a7238ec | 23 | #define USE_STANDBY_STATE |
Wolfgang Betz |
34:edda6a7238ec | 24 | |
Wolfgang Betz |
34:edda6a7238ec | 25 | /*** Class Implementation ***/ |
Wolfgang Betz |
34:edda6a7238ec | 26 | /** Static Class Variables **/ |
Wolfgang Betz |
34:edda6a7238ec | 27 | SimpleSpirit1 *SimpleSpirit1::_singleton = NULL; |
Wolfgang Betz |
34:edda6a7238ec | 28 | |
Wolfgang Betz |
34:edda6a7238ec | 29 | /** Constructor **/ |
Wolfgang Betz |
34:edda6a7238ec | 30 | SimpleSpirit1::SimpleSpirit1(PinName mosi, PinName miso, PinName sclk, |
Wolfgang Betz |
34:edda6a7238ec | 31 | PinName irq, PinName cs, PinName sdn, |
Wolfgang Betz |
34:edda6a7238ec | 32 | PinName led) : |
Wolfgang Betz |
34:edda6a7238ec | 33 | _spi(mosi, miso, sclk), |
Wolfgang Betz |
34:edda6a7238ec | 34 | _irq(irq), |
Wolfgang Betz |
34:edda6a7238ec | 35 | _chip_select(cs), |
Wolfgang Betz |
34:edda6a7238ec | 36 | _shut_down(sdn), |
Wolfgang Betz |
34:edda6a7238ec | 37 | _led(led), |
Wolfgang Betz |
34:edda6a7238ec | 38 | _current_irq_callback(), |
Wolfgang Betz |
34:edda6a7238ec | 39 | _rx_receiving_timeout() |
Wolfgang Betz |
34:edda6a7238ec | 40 | { |
Wolfgang Betz |
34:edda6a7238ec | 41 | } |
Wolfgang Betz |
34:edda6a7238ec | 42 | |
Wolfgang Betz |
34:edda6a7238ec | 43 | /** Init Function **/ |
Wolfgang Betz |
34:edda6a7238ec | 44 | void SimpleSpirit1::init() { |
Wolfgang Betz |
34:edda6a7238ec | 45 | /* reset irq disable counter and irq callback & disable irq */ |
Wolfgang Betz |
34:edda6a7238ec | 46 | _nr_of_irq_disables = 0; |
Wolfgang Betz |
34:edda6a7238ec | 47 | disable_spirit_irq(); |
Wolfgang Betz |
34:edda6a7238ec | 48 | |
Wolfgang Betz |
34:edda6a7238ec | 49 | /* unselect chip */ |
Wolfgang Betz |
34:edda6a7238ec | 50 | chip_unselect(); |
Wolfgang Betz |
34:edda6a7238ec | 51 | |
Wolfgang Betz |
34:edda6a7238ec | 52 | /* configure spi */ |
Wolfgang Betz |
34:edda6a7238ec | 53 | _spi.format(8, 0); /* 8-bit, mode = 0, [order = SPI_MSB] only available in mbed3 */ |
Wolfgang Betz |
60:956afcef7ef7 | 54 | _spi.frequency(10000000); // 10MHz (i.e. max speed allowed for Spirit1) |
Wolfgang Betz |
34:edda6a7238ec | 55 | |
Wolfgang Betz |
34:edda6a7238ec | 56 | /* install irq handler */ |
Wolfgang Betz |
34:edda6a7238ec | 57 | _irq.mode(PullUp); |
Wolfgang Betz |
34:edda6a7238ec | 58 | _irq.fall(Callback<void()>(this, &SimpleSpirit1::IrqHandler)); |
Wolfgang Betz |
34:edda6a7238ec | 59 | |
Wolfgang Betz |
34:edda6a7238ec | 60 | /* init cube vars */ |
Wolfgang Betz |
34:edda6a7238ec | 61 | spirit_on = OFF; |
Wolfgang Betz |
34:edda6a7238ec | 62 | last_rssi = 0 ; //MGR |
Wolfgang Betz |
34:edda6a7238ec | 63 | last_sqi = 0 ; //MGR |
Wolfgang Betz |
34:edda6a7238ec | 64 | |
Wolfgang Betz |
34:edda6a7238ec | 65 | /* set frequencies */ |
Wolfgang Betz |
34:edda6a7238ec | 66 | radio_set_xtal_freq(XTAL_FREQUENCY); |
Wolfgang Betz |
34:edda6a7238ec | 67 | mgmt_set_freq_base((uint32_t)BASE_FREQUENCY); |
Wolfgang Betz |
34:edda6a7238ec | 68 | |
Wolfgang Betz |
34:edda6a7238ec | 69 | /* restart board */ |
Wolfgang Betz |
34:edda6a7238ec | 70 | enter_shutdown(); |
Wolfgang Betz |
34:edda6a7238ec | 71 | exit_shutdown(); |
Wolfgang Betz |
34:edda6a7238ec | 72 | |
Wolfgang Betz |
34:edda6a7238ec | 73 | /* soft core reset */ |
Wolfgang Betz |
34:edda6a7238ec | 74 | cmd_strobe(SPIRIT1_STROBE_SRES); |
Wolfgang Betz |
34:edda6a7238ec | 75 | |
Wolfgang Betz |
34:edda6a7238ec | 76 | /* Configures the SPIRIT1 radio part */ |
Wolfgang Betz |
34:edda6a7238ec | 77 | SRadioInit x_radio_init = { |
Wolfgang Betz |
34:edda6a7238ec | 78 | XTAL_OFFSET_PPM, |
Wolfgang Betz |
34:edda6a7238ec | 79 | (uint32_t)BASE_FREQUENCY, |
Wolfgang Betz |
34:edda6a7238ec | 80 | (uint32_t)CHANNEL_SPACE, |
Wolfgang Betz |
34:edda6a7238ec | 81 | CHANNEL_NUMBER, |
Wolfgang Betz |
34:edda6a7238ec | 82 | MODULATION_SELECT, |
Wolfgang Betz |
34:edda6a7238ec | 83 | DATARATE, |
Wolfgang Betz |
34:edda6a7238ec | 84 | (uint32_t)FREQ_DEVIATION, |
Wolfgang Betz |
34:edda6a7238ec | 85 | (uint32_t)BANDWIDTH |
Wolfgang Betz |
34:edda6a7238ec | 86 | }; |
Wolfgang Betz |
34:edda6a7238ec | 87 | radio_init(&x_radio_init); |
Wolfgang Betz |
34:edda6a7238ec | 88 | radio_set_pa_level_dbm(0,POWER_DBM); |
Wolfgang Betz |
34:edda6a7238ec | 89 | radio_set_pa_level_max_index(0); |
Wolfgang Betz |
34:edda6a7238ec | 90 | |
Wolfgang Betz |
34:edda6a7238ec | 91 | /* Configures the SPIRIT1 packet handler part*/ |
Wolfgang Betz |
34:edda6a7238ec | 92 | PktBasicInit x_basic_init = { |
Wolfgang Betz |
34:edda6a7238ec | 93 | PREAMBLE_LENGTH, |
Wolfgang Betz |
34:edda6a7238ec | 94 | SYNC_LENGTH, |
Wolfgang Betz |
34:edda6a7238ec | 95 | SYNC_WORD, |
Wolfgang Betz |
34:edda6a7238ec | 96 | LENGTH_TYPE, |
Wolfgang Betz |
34:edda6a7238ec | 97 | LENGTH_WIDTH, |
Wolfgang Betz |
34:edda6a7238ec | 98 | CRC_MODE, |
Wolfgang Betz |
34:edda6a7238ec | 99 | CONTROL_LENGTH, |
Wolfgang Betz |
34:edda6a7238ec | 100 | EN_ADDRESS, |
Wolfgang Betz |
34:edda6a7238ec | 101 | EN_FEC, |
Wolfgang Betz |
34:edda6a7238ec | 102 | EN_WHITENING |
Wolfgang Betz |
34:edda6a7238ec | 103 | }; |
Wolfgang Betz |
34:edda6a7238ec | 104 | pkt_basic_init(&x_basic_init); |
Wolfgang Betz |
34:edda6a7238ec | 105 | |
Wolfgang Betz |
34:edda6a7238ec | 106 | /* Enable the following interrupt sources, routed to GPIO */ |
Wolfgang Betz |
34:edda6a7238ec | 107 | irq_de_init(NULL); |
Wolfgang Betz |
34:edda6a7238ec | 108 | irq_clear_status(); |
Wolfgang Betz |
34:edda6a7238ec | 109 | irq_set_status(TX_DATA_SENT, S_ENABLE); |
Wolfgang Betz |
34:edda6a7238ec | 110 | irq_set_status(RX_DATA_READY,S_ENABLE); |
Wolfgang Betz |
34:edda6a7238ec | 111 | irq_set_status(RX_DATA_DISC, S_ENABLE); |
Wolfgang Betz |
47:3a30b960a8c2 | 112 | irq_set_status(VALID_SYNC, S_ENABLE); |
Wolfgang Betz |
34:edda6a7238ec | 113 | irq_set_status(TX_FIFO_ERROR, S_ENABLE); |
Wolfgang Betz |
34:edda6a7238ec | 114 | irq_set_status(RX_FIFO_ERROR, S_ENABLE); |
Wolfgang Betz |
47:3a30b960a8c2 | 115 | #ifndef RX_FIFO_THR_WA |
Wolfgang Betz |
47:3a30b960a8c2 | 116 | irq_set_status(TX_FIFO_ALMOST_EMPTY, S_ENABLE); |
Wolfgang Betz |
34:edda6a7238ec | 117 | irq_set_status(RX_FIFO_ALMOST_FULL, S_ENABLE); |
Wolfgang Betz |
47:3a30b960a8c2 | 118 | #endif // !RX_FIFO_THR_WA |
Wolfgang Betz |
34:edda6a7238ec | 119 | |
Wolfgang Betz |
34:edda6a7238ec | 120 | /* Configure Spirit1 */ |
Wolfgang Betz |
34:edda6a7238ec | 121 | radio_persistent_rx(S_ENABLE); |
Wolfgang Betz |
34:edda6a7238ec | 122 | qi_set_sqi_threshold(SQI_TH_0); |
Wolfgang Betz |
34:edda6a7238ec | 123 | qi_sqi_check(S_ENABLE); |
Wolfgang Betz |
34:edda6a7238ec | 124 | qi_set_rssi_threshold_dbm(CCA_THRESHOLD); |
Wolfgang Betz |
34:edda6a7238ec | 125 | timer_set_rx_timeout_stop_condition(SQI_ABOVE_THRESHOLD); |
Wolfgang Betz |
34:edda6a7238ec | 126 | timer_set_infinite_rx_timeout(); |
Wolfgang Betz |
34:edda6a7238ec | 127 | radio_afc_freeze_on_sync(S_ENABLE); |
Wolfgang Betz |
34:edda6a7238ec | 128 | calibration_rco(S_ENABLE); |
Wolfgang Betz |
34:edda6a7238ec | 129 | |
Wolfgang Betz |
34:edda6a7238ec | 130 | spirit_on = OFF; |
Wolfgang Betz |
34:edda6a7238ec | 131 | CLEAR_TXBUF(); |
Wolfgang Betz |
34:edda6a7238ec | 132 | CLEAR_RXBUF(); |
Wolfgang Betz |
34:edda6a7238ec | 133 | _spirit_tx_started = false; |
Wolfgang Betz |
34:edda6a7238ec | 134 | _is_receiving = false; |
Wolfgang Betz |
34:edda6a7238ec | 135 | |
Wolfgang Betz |
34:edda6a7238ec | 136 | /* Configure the radio to route the IRQ signal to its GPIO 3 */ |
Wolfgang Betz |
34:edda6a7238ec | 137 | SGpioInit x_gpio_init = { |
Wolfgang Betz |
34:edda6a7238ec | 138 | SPIRIT_GPIO_IRQ, |
Wolfgang Betz |
34:edda6a7238ec | 139 | SPIRIT_GPIO_MODE_DIGITAL_OUTPUT_LP, |
Wolfgang Betz |
34:edda6a7238ec | 140 | SPIRIT_GPIO_DIG_OUT_IRQ |
Wolfgang Betz |
34:edda6a7238ec | 141 | }; |
Wolfgang Betz |
34:edda6a7238ec | 142 | spirit_gpio_init(&x_gpio_init); |
Wolfgang Betz |
34:edda6a7238ec | 143 | |
Wolfgang Betz |
34:edda6a7238ec | 144 | /* Setup CSMA/CA */ |
Wolfgang Betz |
34:edda6a7238ec | 145 | CsmaInit x_csma_init = { |
Wolfgang Betz |
34:edda6a7238ec | 146 | S_ENABLE, // enable persistent mode |
Wolfgang Betz |
34:edda6a7238ec | 147 | TBIT_TIME_64, // Tcca time |
Wolfgang Betz |
34:edda6a7238ec | 148 | TCCA_TIME_3, // Lcca length |
Wolfgang Betz |
34:edda6a7238ec | 149 | 3, // max nr of backoffs (<8) |
Wolfgang Betz |
34:edda6a7238ec | 150 | 1, // BU counter seed |
Wolfgang Betz |
34:edda6a7238ec | 151 | 8 // BU prescaler |
Wolfgang Betz |
34:edda6a7238ec | 152 | }; |
Wolfgang Betz |
34:edda6a7238ec | 153 | csma_ca_init(&x_csma_init); |
Wolfgang Betz |
34:edda6a7238ec | 154 | |
Wolfgang Betz |
34:edda6a7238ec | 155 | #ifdef USE_STANDBY_STATE |
Wolfgang Betz |
34:edda6a7238ec | 156 | /* Puts the SPIRIT1 in STANDBY mode (125us -> rx/tx) */ |
Wolfgang Betz |
34:edda6a7238ec | 157 | cmd_strobe(SPIRIT1_STROBE_STANDBY); |
Wolfgang Betz |
34:edda6a7238ec | 158 | #endif // USE_STANDBY_STATE |
Wolfgang Betz |
34:edda6a7238ec | 159 | } |
Wolfgang Betz |
34:edda6a7238ec | 160 | |
Wolfgang Betz |
45:2d01cc9bc761 | 161 | static volatile int tx_fifo_remaining = 0; // to be used in irq handler |
Wolfgang Betz |
45:2d01cc9bc761 | 162 | static volatile int tx_buffer_pos = 0; // to be used in irq handler |
Wolfgang Betz |
45:2d01cc9bc761 | 163 | const volatile uint8_t *tx_fifo_buffer = NULL; // to be used in irq handler |
Wolfgang Betz |
64:28ef790e4ef7 | 164 | int SimpleSpirit1::send(const void *payload, unsigned int payload_len, bool use_csma_ca) { |
Wolfgang Betz |
34:edda6a7238ec | 165 | /* Checks if the payload length is supported */ |
Wolfgang Betz |
34:edda6a7238ec | 166 | if(payload_len > MAX_PACKET_LEN) { |
Wolfgang Betz |
34:edda6a7238ec | 167 | return RADIO_TX_ERR; |
Wolfgang Betz |
34:edda6a7238ec | 168 | } |
Wolfgang Betz |
34:edda6a7238ec | 169 | |
Wolfgang Betz |
34:edda6a7238ec | 170 | disable_spirit_irq(); |
Wolfgang Betz |
34:edda6a7238ec | 171 | |
Wolfgang Betz |
34:edda6a7238ec | 172 | BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, STATE_TIMEOUT); |
Wolfgang Betz |
34:edda6a7238ec | 173 | #ifndef NDEBUG |
Wolfgang Betz |
34:edda6a7238ec | 174 | if((last_state & SPIRIT1_STATE_STATEBITS) != SPIRIT1_STATE_RX) { |
Wolfgang Betz |
34:edda6a7238ec | 175 | debug("\n\rAssert failed in: %s (%d): state=%x\n\r", __func__, __LINE__, last_state>>1); |
Wolfgang Betz |
34:edda6a7238ec | 176 | } |
Wolfgang Betz |
34:edda6a7238ec | 177 | #endif |
Wolfgang Betz |
34:edda6a7238ec | 178 | |
Wolfgang Betz |
34:edda6a7238ec | 179 | /* Reset State to Ready */ |
Wolfgang Betz |
34:edda6a7238ec | 180 | set_ready_state(); |
Wolfgang Betz |
34:edda6a7238ec | 181 | |
Wolfgang Betz |
34:edda6a7238ec | 182 | cmd_strobe(SPIRIT1_STROBE_FTX); // flush TX FIFO buffer |
Wolfgang Betz |
34:edda6a7238ec | 183 | |
Wolfgang Betz |
34:edda6a7238ec | 184 | #ifndef NDEBUG |
Wolfgang Betz |
34:edda6a7238ec | 185 | debug_if(!(linear_fifo_read_num_elements_tx_fifo() == 0), "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__); |
Wolfgang Betz |
34:edda6a7238ec | 186 | #endif |
Wolfgang Betz |
34:edda6a7238ec | 187 | |
Wolfgang Betz |
34:edda6a7238ec | 188 | pkt_basic_set_payload_length(payload_len); // set desired payload len |
Wolfgang Betz |
34:edda6a7238ec | 189 | |
Wolfgang Betz |
64:28ef790e4ef7 | 190 | if(use_csma_ca) { |
Wolfgang Betz |
64:28ef790e4ef7 | 191 | csma_ca_state(S_ENABLE); // enable CSMA/CA |
Wolfgang Betz |
64:28ef790e4ef7 | 192 | } |
Wolfgang Betz |
34:edda6a7238ec | 193 | |
Wolfgang Betz |
45:2d01cc9bc761 | 194 | /* Init buffer & number of bytes to be send */ |
Wolfgang Betz |
45:2d01cc9bc761 | 195 | tx_fifo_remaining = payload_len; |
Wolfgang Betz |
45:2d01cc9bc761 | 196 | tx_fifo_buffer = (const uint8_t*)payload; |
Wolfgang Betz |
45:2d01cc9bc761 | 197 | |
Wolfgang Betz |
45:2d01cc9bc761 | 198 | int8_t fifo_available = SPIRIT_MAX_FIFO_LEN; // fill-up whole fifo |
Wolfgang Betz |
45:2d01cc9bc761 | 199 | int8_t to_send = (tx_fifo_remaining > fifo_available) ? fifo_available : tx_fifo_remaining; |
Wolfgang Betz |
34:edda6a7238ec | 200 | |
Wolfgang Betz |
45:2d01cc9bc761 | 201 | tx_fifo_remaining -= to_send; |
Wolfgang Betz |
34:edda6a7238ec | 202 | |
Wolfgang Betz |
45:2d01cc9bc761 | 203 | /* Fill FIFO Buffer */ |
Wolfgang Betz |
45:2d01cc9bc761 | 204 | if(to_send > 0) { |
Wolfgang Betz |
45:2d01cc9bc761 | 205 | spi_write_linear_fifo(to_send, (uint8_t*)&tx_fifo_buffer[0]); |
Wolfgang Betz |
45:2d01cc9bc761 | 206 | } |
Wolfgang Betz |
34:edda6a7238ec | 207 | |
Wolfgang Betz |
45:2d01cc9bc761 | 208 | tx_buffer_pos = to_send; |
Wolfgang Betz |
34:edda6a7238ec | 209 | _spirit_tx_started = true; |
Wolfgang Betz |
34:edda6a7238ec | 210 | |
Wolfgang Betz |
34:edda6a7238ec | 211 | enable_spirit_irq(); |
Wolfgang Betz |
34:edda6a7238ec | 212 | |
Wolfgang Betz |
45:2d01cc9bc761 | 213 | /* Start transmitting */ |
Wolfgang Betz |
45:2d01cc9bc761 | 214 | cmd_strobe(SPIRIT1_STROBE_TX); |
Wolfgang Betz |
45:2d01cc9bc761 | 215 | |
Wolfgang Betz |
45:2d01cc9bc761 | 216 | while(tx_fifo_remaining != 0); // wait until not everything is yet send (evtl. by irq handler) |
Wolfgang Betz |
45:2d01cc9bc761 | 217 | |
Wolfgang Betz |
34:edda6a7238ec | 218 | BUSYWAIT_UNTIL(!_spirit_tx_started, STATE_TIMEOUT); |
Wolfgang Betz |
34:edda6a7238ec | 219 | #ifdef HEAVY_DEBUG |
Wolfgang Betz |
34:edda6a7238ec | 220 | debug("\n\r%s (%d): state=%x, _spirit_tx_started=%d\n\r", __func__, __LINE__, SPIRIT1_STATUS()>>1, _spirit_tx_started); |
Wolfgang Betz |
34:edda6a7238ec | 221 | #endif |
Wolfgang Betz |
34:edda6a7238ec | 222 | |
Wolfgang Betz |
34:edda6a7238ec | 223 | _spirit_tx_started = false; // in case of state timeout |
Wolfgang Betz |
34:edda6a7238ec | 224 | |
Wolfgang Betz |
64:28ef790e4ef7 | 225 | if(use_csma_ca) { |
Wolfgang Betz |
64:28ef790e4ef7 | 226 | csma_ca_state(S_DISABLE); // disable CSMA/CA |
Wolfgang Betz |
64:28ef790e4ef7 | 227 | } |
Wolfgang Betz |
43:a512f909514a | 228 | |
Wolfgang Betz |
34:edda6a7238ec | 229 | cmd_strobe(SPIRIT1_STROBE_RX); // Return to RX state |
Wolfgang Betz |
34:edda6a7238ec | 230 | |
Wolfgang Betz |
34:edda6a7238ec | 231 | return RADIO_TX_OK; |
Wolfgang Betz |
34:edda6a7238ec | 232 | } |
Wolfgang Betz |
34:edda6a7238ec | 233 | |
Wolfgang Betz |
34:edda6a7238ec | 234 | /** Set Ready State **/ |
Wolfgang Betz |
34:edda6a7238ec | 235 | void SimpleSpirit1::set_ready_state(void) { |
Wolfgang Betz |
34:edda6a7238ec | 236 | uint16_t state; |
Wolfgang Betz |
34:edda6a7238ec | 237 | |
Wolfgang Betz |
34:edda6a7238ec | 238 | disable_spirit_irq(); |
Wolfgang Betz |
34:edda6a7238ec | 239 | |
Wolfgang Betz |
34:edda6a7238ec | 240 | _spirit_tx_started = false; |
Wolfgang Betz |
34:edda6a7238ec | 241 | _is_receiving = false; |
Wolfgang Betz |
34:edda6a7238ec | 242 | stop_rx_timeout(); |
Wolfgang Betz |
34:edda6a7238ec | 243 | |
Wolfgang Betz |
34:edda6a7238ec | 244 | cmd_strobe(SPIRIT1_STROBE_FRX); |
Wolfgang Betz |
34:edda6a7238ec | 245 | CLEAR_RXBUF(); |
Wolfgang Betz |
34:edda6a7238ec | 246 | CLEAR_TXBUF(); |
Wolfgang Betz |
34:edda6a7238ec | 247 | |
Wolfgang Betz |
34:edda6a7238ec | 248 | state = SPIRIT1_STATUS(); |
Wolfgang Betz |
34:edda6a7238ec | 249 | if(state == SPIRIT1_STATE_STANDBY) { |
Wolfgang Betz |
34:edda6a7238ec | 250 | cmd_strobe(SPIRIT1_STROBE_READY); |
Wolfgang Betz |
34:edda6a7238ec | 251 | } else if(state == SPIRIT1_STATE_RX) { |
Wolfgang Betz |
34:edda6a7238ec | 252 | cmd_strobe(SPIRIT1_STROBE_SABORT); |
Wolfgang Betz |
34:edda6a7238ec | 253 | } else if(state != SPIRIT1_STATE_READY) { |
Wolfgang Betz |
34:edda6a7238ec | 254 | #ifndef NDEBUG |
Wolfgang Betz |
34:edda6a7238ec | 255 | debug("\n\rAssert failed in: %s (%d): state=%x\n\r", __func__, __LINE__, state>>1); |
Wolfgang Betz |
34:edda6a7238ec | 256 | #endif |
Wolfgang Betz |
34:edda6a7238ec | 257 | } |
Wolfgang Betz |
34:edda6a7238ec | 258 | |
Wolfgang Betz |
34:edda6a7238ec | 259 | BUSYWAIT_UNTIL((SPIRIT1_STATUS() == SPIRIT1_STATE_READY) && ((last_state & XO_ON) == XO_ON), STATE_TIMEOUT); |
Wolfgang Betz |
34:edda6a7238ec | 260 | if(last_state != (SPIRIT1_STATE_READY | XO_ON)) { |
Wolfgang Betz |
34:edda6a7238ec | 261 | error("\n\rSpirit1: failed to become ready (%x) => pls. reset!\n\r", last_state); |
Wolfgang Betz |
34:edda6a7238ec | 262 | enable_spirit_irq(); |
Wolfgang Betz |
34:edda6a7238ec | 263 | return; |
Wolfgang Betz |
34:edda6a7238ec | 264 | } |
Wolfgang Betz |
34:edda6a7238ec | 265 | |
Wolfgang Betz |
34:edda6a7238ec | 266 | irq_clear_status(); |
Wolfgang Betz |
34:edda6a7238ec | 267 | |
Wolfgang Betz |
34:edda6a7238ec | 268 | enable_spirit_irq(); |
Wolfgang Betz |
34:edda6a7238ec | 269 | } |
Wolfgang Betz |
34:edda6a7238ec | 270 | |
Wolfgang Betz |
34:edda6a7238ec | 271 | int SimpleSpirit1::off(void) { |
Wolfgang Betz |
34:edda6a7238ec | 272 | if(spirit_on == ON) { |
Wolfgang Betz |
34:edda6a7238ec | 273 | /* Disables the mcu to get IRQ from the SPIRIT1 */ |
Wolfgang Betz |
34:edda6a7238ec | 274 | disable_spirit_irq(); |
Wolfgang Betz |
34:edda6a7238ec | 275 | |
Wolfgang Betz |
34:edda6a7238ec | 276 | /* first stop rx/tx */ |
Wolfgang Betz |
34:edda6a7238ec | 277 | set_ready_state(); |
Wolfgang Betz |
34:edda6a7238ec | 278 | |
Wolfgang Betz |
34:edda6a7238ec | 279 | #ifdef USE_STANDBY_STATE |
Wolfgang Betz |
34:edda6a7238ec | 280 | /* Puts the SPIRIT1 in STANDBY */ |
Wolfgang Betz |
34:edda6a7238ec | 281 | cmd_strobe(SPIRIT1_STROBE_STANDBY); |
Wolfgang Betz |
34:edda6a7238ec | 282 | BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_STANDBY, STATE_TIMEOUT); |
Wolfgang Betz |
34:edda6a7238ec | 283 | if((last_state & SPIRIT1_STATE_STATEBITS) != SPIRIT1_STATE_STANDBY) { |
Wolfgang Betz |
34:edda6a7238ec | 284 | error("\n\rSpirit1: failed to enter standby (%x)\n\r", last_state>>1); |
Wolfgang Betz |
34:edda6a7238ec | 285 | return 1; |
Wolfgang Betz |
34:edda6a7238ec | 286 | } |
Wolfgang Betz |
34:edda6a7238ec | 287 | #endif // USE_STANDBY_STATE |
Wolfgang Betz |
34:edda6a7238ec | 288 | |
Wolfgang Betz |
34:edda6a7238ec | 289 | spirit_on = OFF; |
Wolfgang Betz |
34:edda6a7238ec | 290 | _nr_of_irq_disables = 1; |
Wolfgang Betz |
34:edda6a7238ec | 291 | } |
Wolfgang Betz |
34:edda6a7238ec | 292 | return 0; |
Wolfgang Betz |
34:edda6a7238ec | 293 | } |
Wolfgang Betz |
34:edda6a7238ec | 294 | |
Wolfgang Betz |
34:edda6a7238ec | 295 | int SimpleSpirit1::on(void) { |
Wolfgang Betz |
34:edda6a7238ec | 296 | if(spirit_on == OFF) { |
Wolfgang Betz |
34:edda6a7238ec | 297 | set_ready_state(); |
Wolfgang Betz |
34:edda6a7238ec | 298 | |
Wolfgang Betz |
34:edda6a7238ec | 299 | /* now we go to Rx */ |
Wolfgang Betz |
34:edda6a7238ec | 300 | cmd_strobe(SPIRIT1_STROBE_RX); |
Wolfgang Betz |
34:edda6a7238ec | 301 | |
Wolfgang Betz |
34:edda6a7238ec | 302 | BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, STATE_TIMEOUT); |
Wolfgang Betz |
34:edda6a7238ec | 303 | if((last_state & SPIRIT1_STATE_STATEBITS) != SPIRIT1_STATE_RX) { |
Wolfgang Betz |
34:edda6a7238ec | 304 | error("\n\rSpirit1: failed to enter rx (%x) => retry\n\r", last_state>>1); |
Wolfgang Betz |
34:edda6a7238ec | 305 | } |
Wolfgang Betz |
34:edda6a7238ec | 306 | |
Wolfgang Betz |
34:edda6a7238ec | 307 | /* Enables the mcu to get IRQ from the SPIRIT1 */ |
Wolfgang Betz |
34:edda6a7238ec | 308 | spirit_on = ON; |
Wolfgang Betz |
34:edda6a7238ec | 309 | #ifndef NDEBUG |
Wolfgang Betz |
34:edda6a7238ec | 310 | debug_if(!(_nr_of_irq_disables == 1), "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__); |
Wolfgang Betz |
34:edda6a7238ec | 311 | #endif |
Wolfgang Betz |
34:edda6a7238ec | 312 | enable_spirit_irq(); |
Wolfgang Betz |
34:edda6a7238ec | 313 | } |
Wolfgang Betz |
34:edda6a7238ec | 314 | |
Wolfgang Betz |
34:edda6a7238ec | 315 | #ifndef NDEBUG |
Wolfgang Betz |
34:edda6a7238ec | 316 | if(SPIRIT1_STATUS() != SPIRIT1_STATE_RX) { |
Wolfgang Betz |
34:edda6a7238ec | 317 | debug("\n\rAssert failed in: %s (%d): state=%x\n\r", __func__, __LINE__, last_state>>1); |
Wolfgang Betz |
34:edda6a7238ec | 318 | } |
Wolfgang Betz |
34:edda6a7238ec | 319 | #endif |
Wolfgang Betz |
34:edda6a7238ec | 320 | |
Wolfgang Betz |
34:edda6a7238ec | 321 | return 0; |
Wolfgang Betz |
34:edda6a7238ec | 322 | } |
Wolfgang Betz |
34:edda6a7238ec | 323 | |
Wolfgang Betz |
34:edda6a7238ec | 324 | uint8_t SimpleSpirit1::refresh_state(void) { |
Wolfgang Betz |
34:edda6a7238ec | 325 | uint8_t mcstate; |
Wolfgang Betz |
34:edda6a7238ec | 326 | |
Wolfgang Betz |
34:edda6a7238ec | 327 | SpiritSpiReadRegisters(MC_STATE0_BASE, 1, &mcstate); |
Wolfgang Betz |
34:edda6a7238ec | 328 | |
Wolfgang Betz |
34:edda6a7238ec | 329 | return mcstate; |
Wolfgang Betz |
34:edda6a7238ec | 330 | } |
Wolfgang Betz |
34:edda6a7238ec | 331 | |
Wolfgang Betz |
34:edda6a7238ec | 332 | int SimpleSpirit1::read(void *buf, unsigned int bufsize) |
Wolfgang Betz |
34:edda6a7238ec | 333 | { |
Wolfgang Betz |
34:edda6a7238ec | 334 | disable_spirit_irq(); |
Wolfgang Betz |
34:edda6a7238ec | 335 | |
Wolfgang Betz |
34:edda6a7238ec | 336 | /* Checks if the RX buffer is empty */ |
Wolfgang Betz |
34:edda6a7238ec | 337 | if(IS_RXBUF_EMPTY()) { |
Wolfgang Betz |
43:a512f909514a | 338 | #ifndef NDEBUG |
Wolfgang Betz |
43:a512f909514a | 339 | debug("\n\rBuffer is empty\n\r"); |
Wolfgang Betz |
43:a512f909514a | 340 | #endif |
Wolfgang Betz |
34:edda6a7238ec | 341 | set_ready_state(); |
Wolfgang Betz |
34:edda6a7238ec | 342 | |
Wolfgang Betz |
34:edda6a7238ec | 343 | cmd_strobe(SPIRIT1_STROBE_RX); |
Wolfgang Betz |
34:edda6a7238ec | 344 | BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, STATE_TIMEOUT); |
Wolfgang Betz |
34:edda6a7238ec | 345 | enable_spirit_irq(); |
Wolfgang Betz |
34:edda6a7238ec | 346 | return 0; |
Wolfgang Betz |
34:edda6a7238ec | 347 | } |
Wolfgang Betz |
34:edda6a7238ec | 348 | |
Wolfgang Betz |
34:edda6a7238ec | 349 | if(bufsize < spirit_rx_len) { |
Wolfgang Betz |
34:edda6a7238ec | 350 | enable_spirit_irq(); |
Wolfgang Betz |
34:edda6a7238ec | 351 | |
Wolfgang Betz |
34:edda6a7238ec | 352 | /* If buf has the correct size */ |
Wolfgang Betz |
34:edda6a7238ec | 353 | #ifndef NDEBUG |
Wolfgang Betz |
34:edda6a7238ec | 354 | debug("\n\rTOO SMALL BUF\n\r"); |
Wolfgang Betz |
34:edda6a7238ec | 355 | #endif |
Wolfgang Betz |
34:edda6a7238ec | 356 | return 0; |
Wolfgang Betz |
34:edda6a7238ec | 357 | } else { |
Wolfgang Betz |
34:edda6a7238ec | 358 | /* Copies the packet received */ |
Wolfgang Betz |
34:edda6a7238ec | 359 | memcpy(buf, spirit_rx_buf, spirit_rx_len); |
Wolfgang Betz |
34:edda6a7238ec | 360 | |
Wolfgang Betz |
34:edda6a7238ec | 361 | bufsize = spirit_rx_len; |
Wolfgang Betz |
34:edda6a7238ec | 362 | CLEAR_RXBUF(); |
Wolfgang Betz |
34:edda6a7238ec | 363 | |
Wolfgang Betz |
34:edda6a7238ec | 364 | enable_spirit_irq(); |
Wolfgang Betz |
34:edda6a7238ec | 365 | |
Wolfgang Betz |
34:edda6a7238ec | 366 | return bufsize; |
Wolfgang Betz |
34:edda6a7238ec | 367 | } |
Wolfgang Betz |
34:edda6a7238ec | 368 | |
Wolfgang Betz |
34:edda6a7238ec | 369 | } |
Wolfgang Betz |
34:edda6a7238ec | 370 | |
Wolfgang Betz |
34:edda6a7238ec | 371 | int SimpleSpirit1::channel_clear(void) |
Wolfgang Betz |
34:edda6a7238ec | 372 | { |
Wolfgang Betz |
34:edda6a7238ec | 373 | float rssi_value; |
Wolfgang Betz |
34:edda6a7238ec | 374 | /* Local variable used to memorize the SPIRIT1 state */ |
Wolfgang Betz |
34:edda6a7238ec | 375 | uint8_t spirit_state = ON; |
Wolfgang Betz |
34:edda6a7238ec | 376 | |
Wolfgang Betz |
34:edda6a7238ec | 377 | if(spirit_on == OFF) { |
Wolfgang Betz |
34:edda6a7238ec | 378 | /* Wakes up the SPIRIT1 */ |
Wolfgang Betz |
34:edda6a7238ec | 379 | on(); |
Wolfgang Betz |
34:edda6a7238ec | 380 | spirit_state = OFF; |
Wolfgang Betz |
34:edda6a7238ec | 381 | } |
Wolfgang Betz |
34:edda6a7238ec | 382 | |
Wolfgang Betz |
34:edda6a7238ec | 383 | #ifndef NDEBUG |
Wolfgang Betz |
34:edda6a7238ec | 384 | if(SPIRIT1_STATUS() != SPIRIT1_STATE_RX) { |
Wolfgang Betz |
34:edda6a7238ec | 385 | debug("\n\rAssert failed in: %s (%d): state=%x\n\r", __func__, __LINE__, last_state>>1); |
Wolfgang Betz |
34:edda6a7238ec | 386 | } |
Wolfgang Betz |
34:edda6a7238ec | 387 | #endif |
Wolfgang Betz |
34:edda6a7238ec | 388 | |
Wolfgang Betz |
34:edda6a7238ec | 389 | disable_spirit_irq(); |
Wolfgang Betz |
34:edda6a7238ec | 390 | |
Wolfgang Betz |
34:edda6a7238ec | 391 | /* Reset State to Ready */ |
Wolfgang Betz |
34:edda6a7238ec | 392 | set_ready_state(); |
Wolfgang Betz |
34:edda6a7238ec | 393 | |
Wolfgang Betz |
34:edda6a7238ec | 394 | /* Stores the RSSI value */ |
Wolfgang Betz |
34:edda6a7238ec | 395 | rssi_value = qi_get_rssi_dbm(); |
Wolfgang Betz |
34:edda6a7238ec | 396 | |
Wolfgang Betz |
34:edda6a7238ec | 397 | enable_spirit_irq(); |
Wolfgang Betz |
34:edda6a7238ec | 398 | |
Wolfgang Betz |
34:edda6a7238ec | 399 | /* Puts the SPIRIT1 in its previous state */ |
Wolfgang Betz |
34:edda6a7238ec | 400 | if(spirit_state==OFF) { |
Wolfgang Betz |
34:edda6a7238ec | 401 | off(); |
Wolfgang Betz |
34:edda6a7238ec | 402 | #ifndef NDEBUG |
Wolfgang Betz |
34:edda6a7238ec | 403 | #ifdef USE_STANDBY_STATE |
Wolfgang Betz |
34:edda6a7238ec | 404 | if(SPIRIT1_STATUS() != SPIRIT1_STATE_STANDBY) { |
Wolfgang Betz |
34:edda6a7238ec | 405 | #else |
Wolfgang Betz |
34:edda6a7238ec | 406 | if(SPIRIT1_STATUS() != SPIRIT1_STATE_READY) { |
Wolfgang Betz |
34:edda6a7238ec | 407 | #endif |
Wolfgang Betz |
34:edda6a7238ec | 408 | debug("\n\rAssert failed in: %s (%d): state=%x\n\r", __func__, __LINE__, last_state>>1); |
Wolfgang Betz |
34:edda6a7238ec | 409 | } |
Wolfgang Betz |
34:edda6a7238ec | 410 | #endif |
Wolfgang Betz |
34:edda6a7238ec | 411 | } else { |
Wolfgang Betz |
34:edda6a7238ec | 412 | disable_spirit_irq(); |
Wolfgang Betz |
34:edda6a7238ec | 413 | |
Wolfgang Betz |
34:edda6a7238ec | 414 | set_ready_state(); |
Wolfgang Betz |
34:edda6a7238ec | 415 | |
Wolfgang Betz |
34:edda6a7238ec | 416 | cmd_strobe(SPIRIT1_STROBE_RX); |
Wolfgang Betz |
34:edda6a7238ec | 417 | BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, STATE_TIMEOUT); |
Wolfgang Betz |
34:edda6a7238ec | 418 | if((last_state & SPIRIT1_STATE_STATEBITS) != SPIRIT1_STATE_RX) { |
Wolfgang Betz |
34:edda6a7238ec | 419 | error("\n\rSpirit1: (#2) failed to enter rx (%x) => retry\n\r", last_state>>1); |
Wolfgang Betz |
34:edda6a7238ec | 420 | } |
Wolfgang Betz |
34:edda6a7238ec | 421 | |
Wolfgang Betz |
34:edda6a7238ec | 422 | enable_spirit_irq(); |
Wolfgang Betz |
34:edda6a7238ec | 423 | |
Wolfgang Betz |
34:edda6a7238ec | 424 | #ifndef NDEBUG |
Wolfgang Betz |
34:edda6a7238ec | 425 | if(SPIRIT1_STATUS() != SPIRIT1_STATE_RX) { |
Wolfgang Betz |
34:edda6a7238ec | 426 | debug("\n\rAssert failed in: %s (%d): state=%x\n\r", __func__, __LINE__, last_state>>1); |
Wolfgang Betz |
34:edda6a7238ec | 427 | } |
Wolfgang Betz |
34:edda6a7238ec | 428 | #endif |
Wolfgang Betz |
34:edda6a7238ec | 429 | } |
Wolfgang Betz |
34:edda6a7238ec | 430 | |
Wolfgang Betz |
34:edda6a7238ec | 431 | /* Checks the RSSI value with the threshold */ |
Wolfgang Betz |
34:edda6a7238ec | 432 | if(rssi_value<CCA_THRESHOLD) { |
Wolfgang Betz |
34:edda6a7238ec | 433 | return 0; |
Wolfgang Betz |
34:edda6a7238ec | 434 | } else { |
Wolfgang Betz |
34:edda6a7238ec | 435 | return 1; |
Wolfgang Betz |
34:edda6a7238ec | 436 | } |
Wolfgang Betz |
34:edda6a7238ec | 437 | } |
Wolfgang Betz |
34:edda6a7238ec | 438 | |
Wolfgang Betz |
34:edda6a7238ec | 439 | int SimpleSpirit1::get_pending_packet(void) |
Wolfgang Betz |
34:edda6a7238ec | 440 | { |
Wolfgang Betz |
34:edda6a7238ec | 441 | return !IS_RXBUF_EMPTY(); |
Wolfgang Betz |
34:edda6a7238ec | 442 | } |
Wolfgang Betz |
34:edda6a7238ec | 443 | |
Wolfgang Betz |
34:edda6a7238ec | 444 | /** Spirit Irq Callback **/ |
Wolfgang Betz |
57:8cc871dc6cac | 445 | /* betzw - TODO: use threaded interrupt handling when `MBED_CONF_RTOS_PRESENT` is defined (see `atmel-rf-driver`) */ |
Wolfgang Betz |
34:edda6a7238ec | 446 | void SimpleSpirit1::IrqHandler() { |
Wolfgang Betz |
34:edda6a7238ec | 447 | st_lib_spirit_irqs x_irq_status; |
Wolfgang Betz |
34:edda6a7238ec | 448 | |
Wolfgang Betz |
34:edda6a7238ec | 449 | /* get interrupt source from radio */ |
Wolfgang Betz |
34:edda6a7238ec | 450 | irq_get_status(&x_irq_status); |
Wolfgang Betz |
34:edda6a7238ec | 451 | |
Wolfgang Betz |
45:2d01cc9bc761 | 452 | /* The IRQ_TX_DATA_SENT notifies the packet received. Puts the SPIRIT1 in RX */ |
Wolfgang Betz |
45:2d01cc9bc761 | 453 | if(x_irq_status.IRQ_TX_DATA_SENT) { |
Wolfgang Betz |
34:edda6a7238ec | 454 | #ifdef DEBUG_IRQ |
Wolfgang Betz |
34:edda6a7238ec | 455 | uint32_t *tmp = (uint32_t*)&x_irq_status; |
Wolfgang Betz |
45:2d01cc9bc761 | 456 | debug_if(!_spirit_tx_started, "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__); |
Wolfgang Betz |
45:2d01cc9bc761 | 457 | debug_if(!((*tmp) & IRQ_TX_DATA_SENT_MASK), "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__); |
Wolfgang Betz |
45:2d01cc9bc761 | 458 | debug_if(tx_fifo_remaining != 0, "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__); |
Wolfgang Betz |
34:edda6a7238ec | 459 | #endif |
Wolfgang Betz |
45:2d01cc9bc761 | 460 | |
Wolfgang Betz |
45:2d01cc9bc761 | 461 | tx_fifo_buffer = NULL; |
Wolfgang Betz |
45:2d01cc9bc761 | 462 | _spirit_tx_started = false; |
Wolfgang Betz |
45:2d01cc9bc761 | 463 | |
Wolfgang Betz |
45:2d01cc9bc761 | 464 | /* call user callback */ |
Wolfgang Betz |
45:2d01cc9bc761 | 465 | if(_current_irq_callback) { |
Wolfgang Betz |
45:2d01cc9bc761 | 466 | _current_irq_callback(TX_DONE); |
Wolfgang Betz |
34:edda6a7238ec | 467 | } |
Wolfgang Betz |
40:343254875d89 | 468 | |
Wolfgang Betz |
45:2d01cc9bc761 | 469 | /* Disable handling of other TX flags */ |
Wolfgang Betz |
46:d104e58c5caf | 470 | x_irq_status.IRQ_TX_FIFO_ALMOST_EMPTY = S_RESET; |
Wolfgang Betz |
45:2d01cc9bc761 | 471 | } |
Wolfgang Betz |
45:2d01cc9bc761 | 472 | |
Wolfgang Betz |
47:3a30b960a8c2 | 473 | #ifndef RX_FIFO_THR_WA |
Wolfgang Betz |
45:2d01cc9bc761 | 474 | /* The IRQ_TX_FIFO_ALMOST_EMPTY notifies an nearly empty TX fifo */ |
Wolfgang Betz |
45:2d01cc9bc761 | 475 | if(x_irq_status.IRQ_TX_FIFO_ALMOST_EMPTY) { |
Wolfgang Betz |
45:2d01cc9bc761 | 476 | #ifdef DEBUG_IRQ |
Wolfgang Betz |
45:2d01cc9bc761 | 477 | uint32_t *tmp = (uint32_t*)&x_irq_status; |
Wolfgang Betz |
45:2d01cc9bc761 | 478 | debug_if(!((*tmp) & IRQ_TX_FIFO_ALMOST_EMPTY_MASK), "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__); |
Wolfgang Betz |
45:2d01cc9bc761 | 479 | debug_if(!_spirit_tx_started, "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__); |
Wolfgang Betz |
45:2d01cc9bc761 | 480 | debug_if(tx_fifo_buffer == NULL, "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__); |
Wolfgang Betz |
45:2d01cc9bc761 | 481 | #endif |
Wolfgang Betz |
45:2d01cc9bc761 | 482 | |
Wolfgang Betz |
45:2d01cc9bc761 | 483 | int8_t fifo_available = SPIRIT_MAX_FIFO_LEN/2; // fill-up half fifo |
Wolfgang Betz |
45:2d01cc9bc761 | 484 | int8_t to_send = (tx_fifo_remaining > fifo_available) ? fifo_available : tx_fifo_remaining; |
Wolfgang Betz |
45:2d01cc9bc761 | 485 | |
Wolfgang Betz |
45:2d01cc9bc761 | 486 | tx_fifo_remaining -= to_send; |
Wolfgang Betz |
45:2d01cc9bc761 | 487 | |
Wolfgang Betz |
45:2d01cc9bc761 | 488 | /* Fill FIFO Buffer */ |
Wolfgang Betz |
45:2d01cc9bc761 | 489 | if(to_send > 0) { |
Wolfgang Betz |
45:2d01cc9bc761 | 490 | spi_write_linear_fifo(to_send, (uint8_t*)&tx_fifo_buffer[tx_buffer_pos]); |
Wolfgang Betz |
45:2d01cc9bc761 | 491 | } |
Wolfgang Betz |
45:2d01cc9bc761 | 492 | tx_buffer_pos += to_send; |
Wolfgang Betz |
34:edda6a7238ec | 493 | } |
Wolfgang Betz |
47:3a30b960a8c2 | 494 | #endif // !RX_FIFO_THR_WA |
Wolfgang Betz |
34:edda6a7238ec | 495 | |
Wolfgang Betz |
34:edda6a7238ec | 496 | /* Transmission error */ |
Wolfgang Betz |
34:edda6a7238ec | 497 | if(x_irq_status.IRQ_TX_FIFO_ERROR) { |
Wolfgang Betz |
34:edda6a7238ec | 498 | #ifdef DEBUG_IRQ |
Wolfgang Betz |
34:edda6a7238ec | 499 | uint32_t *tmp = (uint32_t*)&x_irq_status; |
Wolfgang Betz |
43:a512f909514a | 500 | debug("\n\r%s (%d): irq=%x\n\r", __func__, __LINE__, *tmp); |
Wolfgang Betz |
43:a512f909514a | 501 | debug_if(!((*tmp) & IRQ_TX_FIFO_ERROR_MASK), "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__); |
Wolfgang Betz |
34:edda6a7238ec | 502 | #endif |
Wolfgang Betz |
34:edda6a7238ec | 503 | if(_spirit_tx_started) { |
Wolfgang Betz |
34:edda6a7238ec | 504 | _spirit_tx_started = false; |
Wolfgang Betz |
34:edda6a7238ec | 505 | /* call user callback */ |
Wolfgang Betz |
34:edda6a7238ec | 506 | if(_current_irq_callback) { |
Wolfgang Betz |
34:edda6a7238ec | 507 | _current_irq_callback(TX_ERR); |
Wolfgang Betz |
34:edda6a7238ec | 508 | } |
Wolfgang Betz |
34:edda6a7238ec | 509 | } |
Wolfgang Betz |
40:343254875d89 | 510 | |
Wolfgang Betz |
45:2d01cc9bc761 | 511 | /* reset data still to be sent */ |
Wolfgang Betz |
45:2d01cc9bc761 | 512 | tx_fifo_remaining = 0; |
Wolfgang Betz |
34:edda6a7238ec | 513 | } |
Wolfgang Betz |
34:edda6a7238ec | 514 | |
Wolfgang Betz |
34:edda6a7238ec | 515 | /* The IRQ_RX_DATA_READY notifies a new packet arrived */ |
Wolfgang Betz |
34:edda6a7238ec | 516 | if(x_irq_status.IRQ_RX_DATA_READY) { |
Wolfgang Betz |
42:92a60a905ee7 | 517 | #ifdef DEBUG_IRQ |
Wolfgang Betz |
42:92a60a905ee7 | 518 | uint32_t *tmp = (uint32_t*)&x_irq_status; |
Wolfgang Betz |
43:a512f909514a | 519 | debug_if(!((*tmp) & IRQ_RX_DATA_READY_MASK), "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__); |
Wolfgang Betz |
42:92a60a905ee7 | 520 | #endif |
Wolfgang Betz |
34:edda6a7238ec | 521 | |
Wolfgang Betz |
44:aedd63cb0ce3 | 522 | if(!_is_receiving) { // spurious irq?!? (betzw: see comments on macro 'RX_FIFO_THR_WA'!) |
Wolfgang Betz |
44:aedd63cb0ce3 | 523 | #ifdef HEAVY_DEBUG |
Wolfgang Betz |
43:a512f909514a | 524 | debug("\n\r%s (%d): irq=%x\n\r", __func__, __LINE__, *tmp); |
Wolfgang Betz |
43:a512f909514a | 525 | #endif |
Wolfgang Betz |
43:a512f909514a | 526 | } else { |
Wolfgang Betz |
43:a512f909514a | 527 | _is_receiving = false; // Finished receiving |
Wolfgang Betz |
43:a512f909514a | 528 | stop_rx_timeout(); |
Wolfgang Betz |
43:a512f909514a | 529 | |
Wolfgang Betz |
43:a512f909514a | 530 | spirit_rx_len = pkt_basic_get_received_pkt_length(); |
Wolfgang Betz |
34:edda6a7238ec | 531 | |
Wolfgang Betz |
34:edda6a7238ec | 532 | #ifdef DEBUG_IRQ |
Wolfgang Betz |
48:373e1b7e424f | 533 | debug_if(!(spirit_rx_len <= MAX_PACKET_LEN), "\n\r%s (%d): irq=%x\n\r", __func__, __LINE__, *tmp); |
Wolfgang Betz |
34:edda6a7238ec | 534 | #endif |
Wolfgang Betz |
34:edda6a7238ec | 535 | |
Wolfgang Betz |
48:373e1b7e424f | 536 | if(spirit_rx_len <= MAX_PACKET_LEN) { |
Wolfgang Betz |
43:a512f909514a | 537 | uint8_t to_receive = spirit_rx_len - _spirit_rx_pos; |
Wolfgang Betz |
43:a512f909514a | 538 | if(to_receive > 0) { |
Wolfgang Betz |
43:a512f909514a | 539 | spi_read_linear_fifo(to_receive, &spirit_rx_buf[_spirit_rx_pos]); |
Wolfgang Betz |
43:a512f909514a | 540 | _spirit_rx_pos += to_receive; |
Wolfgang Betz |
43:a512f909514a | 541 | } |
Wolfgang Betz |
34:edda6a7238ec | 542 | } |
Wolfgang Betz |
43:a512f909514a | 543 | |
Wolfgang Betz |
43:a512f909514a | 544 | cmd_strobe(SPIRIT1_STROBE_FRX); |
Wolfgang Betz |
43:a512f909514a | 545 | |
Wolfgang Betz |
43:a512f909514a | 546 | last_rssi = qi_get_rssi(); //MGR |
Wolfgang Betz |
43:a512f909514a | 547 | last_sqi = qi_get_sqi(); //MGR |
Wolfgang Betz |
43:a512f909514a | 548 | |
Wolfgang Betz |
43:a512f909514a | 549 | /* call user callback */ |
Wolfgang Betz |
48:373e1b7e424f | 550 | if((_spirit_rx_pos == spirit_rx_len) && _current_irq_callback) { |
Wolfgang Betz |
43:a512f909514a | 551 | _current_irq_callback(RX_DONE); |
Wolfgang Betz |
43:a512f909514a | 552 | } |
Wolfgang Betz |
43:a512f909514a | 553 | |
Wolfgang Betz |
43:a512f909514a | 554 | /* Disable handling of other RX flags */ |
Wolfgang Betz |
46:d104e58c5caf | 555 | x_irq_status.IRQ_RX_FIFO_ALMOST_FULL = S_RESET; |
Wolfgang Betz |
40:343254875d89 | 556 | } |
Wolfgang Betz |
43:a512f909514a | 557 | } |
Wolfgang Betz |
34:edda6a7238ec | 558 | |
Wolfgang Betz |
47:3a30b960a8c2 | 559 | #ifndef RX_FIFO_THR_WA |
Wolfgang Betz |
43:a512f909514a | 560 | /* RX FIFO almost full */ |
Wolfgang Betz |
43:a512f909514a | 561 | if(x_irq_status.IRQ_RX_FIFO_ALMOST_FULL) { |
Wolfgang Betz |
43:a512f909514a | 562 | #ifdef DEBUG_IRQ |
Wolfgang Betz |
43:a512f909514a | 563 | uint32_t *tmp = (uint32_t*)&x_irq_status; |
Wolfgang Betz |
43:a512f909514a | 564 | debug_if(!((*tmp) & IRQ_RX_FIFO_ALMOST_FULL_MASK), "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__); |
Wolfgang Betz |
43:a512f909514a | 565 | #endif |
Wolfgang Betz |
43:a512f909514a | 566 | if(!_is_receiving) { // spurious irq?!? |
Wolfgang Betz |
43:a512f909514a | 567 | #ifdef DEBUG_IRQ |
Wolfgang Betz |
43:a512f909514a | 568 | debug("\n\r%s (%d): irq=%x\n\r", __func__, __LINE__, *tmp); |
Wolfgang Betz |
43:a512f909514a | 569 | #endif |
Wolfgang Betz |
43:a512f909514a | 570 | } else { |
Wolfgang Betz |
43:a512f909514a | 571 | uint8_t fifo_available = linear_fifo_read_num_elements_rx_fifo(); |
Wolfgang Betz |
48:373e1b7e424f | 572 | if((fifo_available + _spirit_rx_pos) <= MAX_PACKET_LEN) { |
Wolfgang Betz |
48:373e1b7e424f | 573 | spi_read_linear_fifo(fifo_available, &spirit_rx_buf[_spirit_rx_pos]); |
Wolfgang Betz |
48:373e1b7e424f | 574 | _spirit_rx_pos += fifo_available; |
Wolfgang Betz |
48:373e1b7e424f | 575 | } else { |
Wolfgang Betz |
48:373e1b7e424f | 576 | #ifdef DEBUG_IRQ |
Wolfgang Betz |
48:373e1b7e424f | 577 | debug("\n\r%s (%d): irq=%x\n\r", __func__, __LINE__, *tmp); |
Wolfgang Betz |
48:373e1b7e424f | 578 | #endif |
Wolfgang Betz |
48:373e1b7e424f | 579 | } |
Wolfgang Betz |
45:2d01cc9bc761 | 580 | } |
Wolfgang Betz |
45:2d01cc9bc761 | 581 | } |
Wolfgang Betz |
47:3a30b960a8c2 | 582 | #endif // !RX_FIFO_THR_WA |
Wolfgang Betz |
43:a512f909514a | 583 | |
Wolfgang Betz |
45:2d01cc9bc761 | 584 | /* Reception errors */ |
Wolfgang Betz |
45:2d01cc9bc761 | 585 | if((x_irq_status.IRQ_RX_FIFO_ERROR) || (x_irq_status.IRQ_RX_DATA_DISC)) { |
Wolfgang Betz |
45:2d01cc9bc761 | 586 | #ifdef DEBUG_IRQ |
Wolfgang Betz |
45:2d01cc9bc761 | 587 | uint32_t *tmp = (uint32_t*)&x_irq_status; |
Wolfgang Betz |
45:2d01cc9bc761 | 588 | debug("\n\r%s (%d): irq=%x\n\r", __func__, __LINE__, *tmp); |
Wolfgang Betz |
45:2d01cc9bc761 | 589 | debug_if(!((*tmp) & (IRQ_RX_FIFO_ERROR_MASK | IRQ_RX_DATA_DISC_MASK)), "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__); |
Wolfgang Betz |
45:2d01cc9bc761 | 590 | #endif |
Wolfgang Betz |
45:2d01cc9bc761 | 591 | rx_timeout_handler(); |
Wolfgang Betz |
45:2d01cc9bc761 | 592 | if(_spirit_tx_started) { |
Wolfgang Betz |
45:2d01cc9bc761 | 593 | _spirit_tx_started = false; |
Wolfgang Betz |
45:2d01cc9bc761 | 594 | /* call user callback */ |
Wolfgang Betz |
45:2d01cc9bc761 | 595 | if(_current_irq_callback) { |
Wolfgang Betz |
45:2d01cc9bc761 | 596 | _current_irq_callback(TX_ERR); |
Wolfgang Betz |
45:2d01cc9bc761 | 597 | } |
Wolfgang Betz |
34:edda6a7238ec | 598 | } |
Wolfgang Betz |
34:edda6a7238ec | 599 | } |
Wolfgang Betz |
34:edda6a7238ec | 600 | |
Wolfgang Betz |
34:edda6a7238ec | 601 | /* The IRQ_VALID_SYNC is used to notify a new packet is coming */ |
Wolfgang Betz |
34:edda6a7238ec | 602 | if(x_irq_status.IRQ_VALID_SYNC) { |
Wolfgang Betz |
42:92a60a905ee7 | 603 | #ifdef DEBUG_IRQ |
Wolfgang Betz |
42:92a60a905ee7 | 604 | uint32_t *tmp = (uint32_t*)&x_irq_status; |
Wolfgang Betz |
43:a512f909514a | 605 | debug_if(!((*tmp) & IRQ_VALID_SYNC_MASK), "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__); |
Wolfgang Betz |
42:92a60a905ee7 | 606 | #endif |
Wolfgang Betz |
39:75481c4c6655 | 607 | /* betzw - NOTE: there is a race condition between Spirit1 receiving packets and |
Wolfgang Betz |
39:75481c4c6655 | 608 | * the MCU trying to send a packet, which gets resolved in favor of |
Wolfgang Betz |
39:75481c4c6655 | 609 | * sending. |
Wolfgang Betz |
39:75481c4c6655 | 610 | */ |
Wolfgang Betz |
39:75481c4c6655 | 611 | if(_spirit_tx_started) { |
Wolfgang Betz |
34:edda6a7238ec | 612 | #ifdef DEBUG_IRQ |
Wolfgang Betz |
43:a512f909514a | 613 | debug("\n\r%s (%d): irq=%x\n\r", __func__, __LINE__, *tmp); |
Wolfgang Betz |
34:edda6a7238ec | 614 | #endif |
Wolfgang Betz |
39:75481c4c6655 | 615 | } else { |
Wolfgang Betz |
39:75481c4c6655 | 616 | _is_receiving = true; |
Wolfgang Betz |
39:75481c4c6655 | 617 | start_rx_timeout(); |
Wolfgang Betz |
39:75481c4c6655 | 618 | } |
Wolfgang Betz |
34:edda6a7238ec | 619 | } |
Wolfgang Betz |
34:edda6a7238ec | 620 | } |