uint8_t Rfm12b::Send (uint8_t* Data, uint8_t Length) { uint8_t i; RFM12_INT_OFF(); if ((InputLength > 0) || (Rfm12bSpi.GetWord (RFM12B_STATUS_CMD) & RFM12B_STATUS_RSSI_PIN) != 0) { // either already receiving something or RFM12B detects a // signal, so don't send now RFM12_INT_ON(); return 0; } Rfm12bSpi.SendWord (RF_IDLE_MODE); // switch off receiver OutputData[LENGTH_BYTE] = Length + 2; // include 2 crc bytes in length memcpy ((void*) &OutputData[LENGTH_BYTE+1], Data, Length); OutputLength = Length + LENGTH_BYTE + 1; // include 4 preamble bytes + 1 Length byte // calculate crc and put it into output buffer Crc = ~0; for (i=0; i <= Length; i++) Crc = _crc16_update(Crc, OutputData[i+4]); OutputData[OutputLength++] = Crc & 0xFF; OutputData[OutputLength++] = Crc >> 8; // add trailer byte to end of packet to ensure last byte of data is transmitted completely OutputData[OutputLength] = PREAMBLE; // pre-load preamble byte into transmit buffer to get things going quickly Rfm12bSpi.SendWord (RFM12B_TX_CMD + PREAMBLE); // turn on transmitter Rfm12bSpi.SendWord (RF_XMITTER_ON); // bytes will be fed via interrupts RFM12_INT_ON(); return Length; }
void Rfm12b::Initialize () { Rfm12bSpi.SendWord (RFM12B_STATUS_CMD); // initial SPI transfer added to avoid power-up problem? Rfm12bSpi.SendWord (RF_IDLE_MODE); // disable clk pin Rfm12bSpi.SendWord (RFM12B_TX_CMD); // in case we're still in OOK mode Rfm12bSpi.SendWord (CONFIGURATION | (BAND << 4)); // EL (enable TX), EF (enable RX FIFO), 12.0pF, 915 MHz Rfm12bSpi.SendWord (RFM12B_DATARATE_CMD | DATARATE); // approx 49.2 Kbps, i.e. 10000/29/(1+6) Kbps Rfm12bSpi.SendWord (RX_CONFIG); // VDI, FAST, 134kHz, 0dBm, -91dBm Rfm12bSpi.SendWord (DATA_FILTER); // AL, !ml, DIG, DQD=4 Rfm12bSpi.SendWord (FIFO_CONFIG); // FIFO8, 2-SYNC, !ff, DR Rfm12bSpi.SendWord (AFC_CONFIG); // @PWR, NO RSTRIC, !st, !fi, OE, EN Rfm12bSpi.SendWord (TX_CONFIG); // !mp, 90kHz, MAX OUT Rfm12bSpi.SendWord (PLL_CONFIG); // force to POR for A1 version per manual (CC77) Rfm12bSpi.SendWord (RFM12B_WAKEUP_CMD); // Wake-Up Timer not used Rfm12bSpi.SendWord (RFM12B_DUTYCYCLE_CMD); // Low Duty-Cycle not used //memset ((void*) InputData, 0, 10); OutputIndex = OutputLength = InputLength = 0; Crc = ~0; DEBUG_INIT; RFM12_INT_ON(); sei(); // start receiving Rfm12bSpi.SendWord (RF_RECEIVER_ON); }
/** * Call a SW reset in case the module hangs (does not receive any data). */ void rfm12_sw_reset(void) { RFM12_INT_OFF(); rfm12_data(RFM12_CMD_RESET_FE); _delay_ms(200); // datasheet lists 150ms max. rfm12_data(RFM12_CMD_RESET_FF); _delay_ms(200); RFM12_INT_ON(); }
/** When enabling ASK tx mode, this function puts the internal state machine * into transmit mode and disables the interrupt. * Otherwise it will restore normale operation. * * \param [setting] Pass 1 to enable the raw mode, 0 to disable it. * \note You need to define RFM12_TRANSMIT_ASK as 1 to enable this. * \warning This will interfere with the wakeup timer feature. * \todo Use power management shadow register if the wakeup timer feature is enabled. * \see rfm12_tx_on() and rfm12_tx_off() */ void rfm12_ask_tx_mode(uint8_t setting) { if (setting) { #if 0 /* disable the receiver */ rfm12_data(RFM12_CMD_PWRMGT | PWRMGT_DEFAULT); /* fill preamble into buffer */ rfm12_data(RFM12_CMD_TX | PREAMBLE); rfm12_data(RFM12_CMD_TX | PREAMBLE); #endif ctrl.rfm12_state = STATE_TX; RFM12_INT_OFF(); } else { /* re-enable the receiver */ rfm12_data(RFM12_CMD_PWRMGT | PWRMGT_DEFAULT | RFM12_PWRMGT_ER); RFM12_INT_ON(); ctrl.rfm12_state = STATE_RX_IDLE; } }
/**This function takes care of all module initialization, including: * - Setup of the used frequency band and external capacitor * - Setting the exact frequency (channel) * - Setting the transmission data rate * - Configuring various module related rx parameters, including the amplification * - Enabling the digital data filter * - Enabling the use of the modules fifo, as well as enabling sync pattern detection * - Configuring the automatic frequency correction * - Setting the transmit power * * This initialization function also sets up various library internal configuration structs and * puts the module into receive mode before returning. * * \note Please note that the transmit power and receive amplification values are currently hard coded. * Have a look into rfm12_hw.h for possible settings. */ void rfm12_init(void) { RFM12_INT_OFF(); // in case rfm12_init is called twice, make sure rfm module does not interfere //initialize spi SS_RELEASE(); DDR_SS |= (1<<BIT_SS); spi_init(); //enable internal data register and fifo //setup selected band rfm12_data(RFM12_CMD_CFG | RFM12_CFG_EL | RFM12_CFG_EF | RFM12_BASEBAND | RFM12_XTAL_12PF); //set power default state (usually disable clock output) //do not write the power register two times in a short time //as it seems to need some recovery rfm12_data(RFM12_CMD_PWRMGT | PWRMGT_DEFAULT); //set frequency rfm12_data(RFM12_CMD_FREQUENCY | RFM12_FREQUENCY_CALC(FREQ) ); //set data rate rfm12_data(RFM12_CMD_DATARATE | DATARATE_VALUE ); //set rx parameters: int-in/vdi-out pin is vdi-out, //Bandwith, LNA, RSSI rfm12_data(RFM12_CMD_RXCTRL | RFM12_RXCTRL_P16_VDI | RFM12_RXCTRL_VDI_FAST | RFM12_RXCTRL_BW_400 | RFM12_RXCTRL_LNA_6 | RFM12_RXCTRL_RSSI_79 ); //automatic clock lock control(AL), digital Filter(!S), //Data quality detector value 3, slow clock recovery lock rfm12_data(RFM12_CMD_DATAFILTER | RFM12_DATAFILTER_AL | 3); //2 Byte Sync Pattern, Start fifo fill when sychron pattern received, //disable sensitive reset, Fifo filled interrupt at 8 bits rfm12_data(RFM12_CMD_FIFORESET | RFM12_FIFORESET_DR | (8<<4)); //set AFC to automatic, (+4 or -3)*2.5kHz Limit, fine mode, active and enabled rfm12_data(RFM12_CMD_AFC | RFM12_AFC_AUTO_KEEP | RFM12_AFC_LIMIT_4 | RFM12_AFC_FI | RFM12_AFC_OE | RFM12_AFC_EN); //set TX Power to -0dB, frequency shift = +-125kHz rfm12_data(RFM12_CMD_TXCONF | RFM12_TXCONF_POWER_0 | RFM12_TXCONF_FS_CALC(125000) ); //disable low dutycycle mode rfm12_data(RFM12_CMD_DUTYCYCLE); //disable wakeup timer rfm12_data(RFM12_CMD_WAKEUP); //store the syncronization pattern to the transmission buffer //the sync pattern is used by the receiver to distinguish noise from real transmissions //the sync pattern is hardcoded into the receiver rf_tx_buffer.sync[0] = SYNC_MSB; rf_tx_buffer.sync[1] = SYNC_LSB; //if receive mode is not disabled (default) #if !(RFM12_TRANSMIT_ONLY) //init buffer pointers ctrl.rf_buffer_out = &rf_rx_buffers[0]; ctrl.rf_buffer_in = &rf_rx_buffers[0]; //ctrl.buffer_in_num = 0; //ctrl.buffer_out_num = 0; #endif /* !(RFM12_TRANSMIT_ONLY) */ //low battery detector feature initialization #if RFM12_LOW_BATT_DETECTOR ctrl.low_batt = RFM12_BATT_OKAY; #endif /* RFM12_LOW_BATT_DETECTOR */ //enable rf receiver chain, if receiving is not disabled (default) //the magic is done via defines rfm12_data(RFM12_CMD_PWRMGT | PWRMGT_RECEIVE); //wakeup timer feature setup #if RFM12_USE_WAKEUP_TIMER //set power management shadow register to receiver chain enabled or disabled //the define correctly handles the transmit only mode ctrl.pwrmgt_shadow = (RFM12_CMD_PWRMGT | PWRMGT_RECEIVE); #endif /* RFM12_USE_WAKEUP_TIMER */ //ASK receive mode feature initialization #if RFM12_RECEIVE_ASK adc_init(); #endif //setup interrupt for falling edge trigger RFM12_INT_SETUP(); //clear int flag rfm12_read(RFM12_CMD_STATUS); RFM12_INT_FLAG |= (1<<RFM12_FLAG_BIT); //init receiver fifo, we now begin receiving. rfm12_data(CLEAR_FIFO); rfm12_data(ACCEPT_DATA); //activate the interrupt RFM12_INT_ON(); }
/** This function has to be called periodically. * It will read the rfm12 status register to check if a carrier is being received, * which would indicate activity on the chosen radio channel. \n * If there has been no activity for long enough, the channel is believed to be free. * * When there is a packet waiting for transmission and the collision avoidance * algorithm indicates that the air is free, then the interrupt control variables are * setup for packet transmission and the rfm12 is switched to transmit mode. * This function also fills the rfm12 tx fifo with a preamble. * * \warning Warning, if you do not call this function periodically, then no packet will get transmitted. * \see rfm12_tx() and rfm12_start_tx() */ void rfm12_tick(void) { //collision detection is enabled by default #if !(RFM12_NOCOLLISIONDETECTION) uint16_t status; //start with a channel free count of 16, this is necessary for the ASK receive feature to work static uint8_t channel_free_count = 16; //static local variables produce smaller code size than globals #endif //debug #if RFM12_UART_DEBUG static uint8_t oldstate; uint8_t state = ctrl.rfm12_state; if (oldstate != state) { uart_putstr ("mode change: "); switch (state) { case STATE_RX_IDLE: uart_putc ('i'); break; case STATE_RX_ACTIVE: uart_putc ('r'); break; case STATE_TX: uart_putc ('t'); break; default: uart_putc ('?'); } uart_putstr ("\r\n"); oldstate = state; } #endif //don't disturb RFM12 if transmitting or receiving if(ctrl.rfm12_state != STATE_RX_IDLE) { return; } //collision detection is enabled by default #if !(RFM12_NOCOLLISIONDETECTION) //disable the interrupt (as we're working directly with the transceiver now) //hint: we could be losing an interrupt here //solutions: check status flag if int is set, launch int and exit ... OR implement packet retransmission RFM12_INT_OFF(); status = rfm12_read(RFM12_CMD_STATUS); RFM12_INT_ON(); //check if we see a carrier if(status & RFM12_STATUS_RSSI) { //yes: reset free counter and return channel_free_count = CHANNEL_FREE_TIME; return; } //no: decrement counter channel_free_count--; //is the channel free long enough ? if(channel_free_count != 0) { return; } //reset the channel free count for the next decrement (during the next call..) channel_free_count = 1; #endif //do we have something to transmit? if(ctrl.txstate == STATUS_OCCUPIED) { //yes: start transmitting //disable the interrupt (as we're working directly with the transceiver now) //hint: we could be losing an interrupt here, too //we could also disturb an ongoing reception, //if it just started some cpu cycles ago //(as the check for this case is some lines (cpu cycles) above) //anyhow, we MUST transmit at some point... RFM12_INT_OFF(); //disable receiver - if you don't do this, tx packets will get lost //as the fifo seems to be in use by the receiver rfm12_data(RFM12_CMD_PWRMGT | PWRMGT_DEFAULT); //calculate number of bytes to be sent by ISR //2 sync bytes + len byte + type byte + checksum + message length + 1 dummy byte ctrl.num_bytes = rf_tx_buffer.len + 6; //reset byte sent counter ctrl.bytecount = 0; //set mode for interrupt handler ctrl.rfm12_state = STATE_TX; //wakeup timer feature #if RFM12_USE_WAKEUP_TIMER ctrl.pwrmgt_shadow = (RFM12_CMD_PWRMGT | PWRMGT_DEFAULT | RFM12_PWRMGT_ET); #endif /* RFM12_USE_WAKEUP_TIMER */ //fill 2byte 0xAA preamble into data register //the preamble helps the receivers AFC circuit to lock onto the exact frequency //(hint: the tx FIFO [if el is enabled] is two staged, so we can safely write 2 bytes before starting) rfm12_data(RFM12_CMD_TX | PREAMBLE); rfm12_data(RFM12_CMD_TX | PREAMBLE); //set ET in power register to enable transmission (hint: TX starts now) rfm12_data(RFM12_CMD_PWRMGT | PWRMGT_DEFAULT | RFM12_PWRMGT_ET); //enable the interrupt to continue the transmission RFM12_INT_ON(); } }