/******************************************************************************* * @fn cc115LTxIdle * * @brief Radio state is switched from TX to IDLE * * input parameters * * @param none * * output parameters * * @return void */ static void cc115LTxIdle(void) { /* Disable pin interrupt */ trxDisableInt(); /* Strobe IDLE */ trxSpiCmdStrobe(CC115L_SIDLE); /* Wait until chip is in IDLE */ while(trxSpiCmdStrobe(CC115L_SNOP) & 0xF0); /* Flush the TX FIFO */ trxSpiCmdStrobe(CC110L_SFTX); /* Clear pin interrupt flag */ trxClearIntFlag(); return; }
/****************************************************************************** * @fn cc120x_sniffModeRegConfig * * @brief Writes packet and modem settings to registers * * input parameters * * output parameters * * @return void */ void cc120x_sniffModeRegConfig(uint16_t deviceName) { uint8 writeByte; // Reset radio trxSpiCmdStrobe(CC120X_SRES); // Write registers to radio for(uint16 i = 0; i < (sizeof(simpleLinkTestSniffCC120x)/sizeof(radioSetting_t)); i++) { writeByte = simpleLinkTestSniffCC120x[i].data; cc120xSpiWriteReg( simpleLinkTestSniffCC120x[i].addr, &writeByte, 1); } // Put radio in powerdown to save power trxSpiCmdStrobe(CC120X_SPWD); }
/******************************************************************************* * @fn cc1120cc1190RxIdle * * @brief Radio state is switched from RX to IDLE * * input parameters * * @param none * * output parameters * * @return void */ static void cc1120cc1190RxIdle(void) { /* Disable pin interrupt */ trxDisableInt(); /* Strobe IDLE */ trxSpiCmdStrobe(CC112X_SIDLE); /* Wait until chip is in IDLE */ while(trxSpiCmdStrobe(CC112X_SNOP) & 0xF0); //Disable LNA perCC1120CC1190LnaDisable(); /* Flush the Receive FIFO */ trxSpiCmdStrobe(CC112X_SFRX); /* Clear pin interrupt flag */ trxClearIntFlag(); return; }
static void runTX(char c1, char c2, char c3, char c4) { // Initialize packet buffer of size PKTLEN + 1 uint8 txBuffer[PKTLEN+1] = {0}; P2SEL &= ~0x40; // P2SEL bit 6 (GDO0) set to one as default. Set to zero (I/O) // connect ISR function to GPIO0, interrupt on falling edge trxIsrConnect(GPIO_0, FALLING_EDGE, &radioRxTxISR); // enable interrupt from GPIO_0 trxEnableInt(GPIO_0); // create a random packet with PKTLEN + 2 byte packet counter + n x random bytes createPacket(txBuffer, c1, c2, c3, c4); // write packet to tx fifo cc11xLSpiWriteTxFifo(txBuffer,sizeof(txBuffer)); // strobe TX to send packet trxSpiCmdStrobe(CC110L_STX); // wait for interrupt that packet has been sent. // (Assumes the GPIO connected to the radioRxTxISR function is set // to GPIOx_CFG = 0x06) while(!packetSemaphore); // clear semaphore flag packetSemaphore = ISR_IDLE; halLedToggle(LED1); __delay_cycles(250000); halLedToggle(LED1); }
/****************************************************************************** * @fn perCC115LEnterSleep * * @brief Enters Sleep. Function is used to abstract the cc11xLRadioTxIdle * functionality away from the lower-level radio interface. * Note: assumes chip is ready * * input parameters * * @param none * * output parameters * * @return void */ void perCC115LEnterSleep(void) { cc115LTxIdle(); trxSpiCmdStrobe(CC115L_SPWD); /* Only important to differ between TX and IDLE */ cc115LRadioTxIdle = CC115L_STATE_IDLE; return; }
/****************************************************************************** * @fn perCC1120CC1190EnterSleep * * @brief Enters Sleep. Function is used to abstract the cc1120cc1190RadioTxRx * functionality away from the lower-level radio interface. * Note: assumes chip is ready * * input parameters * * @param none * * output parameters * * @return void */ void perCC1120CC1190EnterSleep(void) { cc1120cc1190RxIdle(); trxSpiCmdStrobe(CC112X_SPWD); /* Only important to differ between RX/TX and IDLE */ cc1120cc1190RadioTxRx = CC112X_STATE_IDLE; return; }
/******************************************************************************* * @fn cc1120cc1190IdleRx * * @brief Radio state is switched from Idle to RX. Function assumes that * radio is in IDLE when called. * * input parameters * * @param none * * output parameters * * @return void */ static void cc1120cc1190IdleRx(void) { trxClearIntFlag(); //perCC1190HgmEnable(); perCC1120CC1190PaDisable(); perCC1120CC1190LnaEnable(); trxSpiCmdStrobe(CC112X_SRX); trxEnableInt(); return; }
/******************************************************************************* * @fn registerConfig * * @brief Write register settings as given by SmartRF Studio found in * cc120x_easy_link_reg_config.h * * @param none * * @return none */ static void registerConfig(void){ uint8 writeByte; // Reset radio trxSpiCmdStrobe(CC120X_SRES); // Write registers to radio for(uint16 i = 0; i < (sizeof preferredSettings/sizeof(registerSetting_t)); i++) { writeByte = preferredSettings[i].data; cc120xSpiWriteReg( preferredSettings[i].addr, &writeByte, 1); } }
/****************************************************************************** * @fn cc120x_FreqConfig * * @brief Writes frequency word depending on user input * * input index * * output none * * @return void */ uint8 cc120x_FreqConfig(uint16 index) { // Set frequency cc120xSpiWriteReg(CC120X_FS_CFG,&cc120xFsCfgs[index],1); cc120xSpiWriteReg(CC120X_FREQ2,freqSettings40Mhz[index],3); // Put radio in powerdown to save power trxSpiCmdStrobe(CC120X_SPWD); //Insert Carrier Sense threshold warning in Sniff Test Menu drawInfo(); return SNIFF_RETURN_SUCCESS; }
/******************************************************************************* * @fn syncReceivedISR * * @brief Function running every time a sync word has been received * * @param none * * @return none */ static void syncReceivedISR(void) { uint8 numRxBytes; uint8 writeByte; // After the sync word is received one needs to wait for the two // length bytes to be put in the RX FIFO do { cc112xSpiReadReg(CC112X_NUM_RXBYTES, &numRxBytes, 1); } while (numRxBytes < 2); // Read the length byte and store it in the packetLength variable cc112xSpiReadRxFifo(rxBuffer, 2); pBufferIndex += 2; packetLength = (uint16)(((uint16)(rxBuffer[0] << 8)) | rxBuffer[1]); // Make sure that the packet length is in the correct range, update // variables and enable interrupt on falling edge of GPIO3 (PKT_SYNC_RXTX) if ((packetLength > MAX_VARIABLE_LENGTH) && (packetLength <= PACKET_LENGTH)) { bytesLeft = packetLength + 2; fixedPacketLength = bytesLeft % (MAX_VARIABLE_LENGTH + 1); writeByte = fixedPacketLength; cc112xSpiWriteReg(CC112X_PKT_LEN, &writeByte, 1); // Clear interrupt flag and enable GPIO3 ioPinIntClear(IO_PIN_PORT_1, GPIO3); ioPinIntEnable(IO_PIN_PORT_1, GPIO3); } else { // Exit RX and flush RX FIFO due to length byte being out of range trxSpiCmdStrobe(CC112X_SIDLE); trxSpiCmdStrobe(CC112X_SFRX); state = RX_START; } // Clear ISR flag ioPinIntClear(IO_PIN_PORT_1, GPIO2); }
static void registerConfig(void) { uint8 writeByte; uint16 i; #ifdef PA_TABLE uint8 paTable[] = PA_TABLE; #endif // reset radio trxSpiCmdStrobe(CC110L_SRES); // write registers to radio for(i = 0; i < (sizeof preferredSettings/sizeof(registerSetting_t)); i++) { writeByte = preferredSettings[i].data; cc11xLSpiWriteReg( preferredSettings[i].addr, &writeByte, 1); } #ifdef PA_TABLE // write PA_TABLE cc11xLSpiWriteReg(CC11xL_PA_TABLE0,paTable, sizeof(paTable)); #endif }
/****************************************************************************** * @fn perCC1120CC1190SendPacket * * @brief Sends the contents that pData points to which has the * following structure: * * txArray[0] = length byte * txArray[n] = payload[n] * | n<[sizeOf(RXFIFO)-2], variable packet length is assumed. * * The radio state after completing TX is dependant on the * CC112X_RFEND_CFG0 register setting. For PG10 this register * dictates IDLE after TX. For PG.0 this function must be * re-implemented since the 2way PER test relies on RX after TX. * This function enables SYNC interrupt. This means that * an interrupt will fire when a packet has been sent, i.e sync * signal transitions from high to low. * * The One-Way PER test disables the sync pin interrupt when TX * finishes, while the Two-Way PER test doesn't to enable quick * reception of Slave ACK. * * Note: Assumes chip is ready * * input parameters * * @param *pData - pointer to data array that starts with length byte * and followed by payload. * output parameters * * @return void */ void perCC1120CC1190SendPacket(uint8 *pData) { uint8 len = *pData; /* PG1.0 errate fix: Before entering TX, the frequency word must be altered from that of RX */ /* This means in general that TX from Idle is the only option, not TX from RX */ perCC1120CC1190EnterIdle(); /* Will only try to transmit if the whole packet can fit i RXFIFO * and we're not currently sending a packet. */ if(!(len > (PER_MAX_DATA-2)) && (cc1120cc1190RadioTxRx != CC112X_STATE_TX) ) { cc112xSpiWriteTxFifo(pData,(len+1)); /* Indicate state to the ISR and issue the TX strobe */ trxEnableInt(); /* Enable PA on CC1190 and be sure LNA is off */ //perCC1190HgmEnable(); perCC1120CC1190LnaDisable(); perCC1120CC1190PaEnable(); cc1120cc1190RadioTxRx = CC112X_STATE_TX; trxSpiCmdStrobe(CC112X_STX); /* Wait until packet is sent before doing anything else */ __low_power_mode_3(); /* This function will not return before the complete packet * is sent and the radio is back in IDLE. The MSP will be * be sleeping while the packet is beeing sent unless waken * by button presses. */ while(cc1120cc1190RadioTxRx == CC112X_STATE_TX); if(perSettings.linkTopology == LINK_1_WAY) { /* Back in Idle*/ trxDisableInt(); /* Turn off PA on CC1190 */ perCC1120CC1190PaDisable(); } } return; }
/****************************************************************************** * @fn perCC115LSendPacket * * @brief Sends the contents that pData points to. pData has the * following structure: * * txArray[0] = length byte * txArray[n] = payload[n] * | n<[sizeOf(RXFIFO)-2], variable packet length is assumed. * * The radio state after completing TX is dependant on the * MCSM1 register setting. This function enables SYNC interrupt. * This means that an interrupt will go off when a packet * has been sent, i.e sync signal transitions from high to low. * MSP will be in low power mode until packet has been sent given * that no other interrupts go off. * * The One-Way PER test disables the sync pin interrupt when TX * finishes, while the Two-Way PER test doesn't to enable quick * reception of Slave ACK. * * Note: Assumes chip is ready * * input parameters * * @param *pData - pointer to data array that starts with length byte * and followed by payload. * output parameters * * @return void */ void perCC115LSendPacket(uint8 *pData) { uint8 len = *pData; /* Will only try to transmit if the whole packet can fit i TXFIFO * and we're not currently sending a packet. */ if(!(len > (PER_MAX_DATA-2)) && (cc115LRadioTxIdle != CC115L_STATE_TX) ) { cc11xLSpiWriteTxFifo(pData,(len+1)); /* Indicate state to the ISR and issue the TX strobe */ trxEnableInt(); cc115LRadioTxIdle = CC115L_STATE_TX; trxSpiCmdStrobe(CC115L_STX); /* Wait until packet is sent before doing anything else */ __low_power_mode_3(); while(cc115LRadioTxIdle == CC115L_STATE_TX); if(perSettings.linkTopology == LINK_1_WAY) { /* Back in Idle*/ trxDisableInt(); } } return; }
/****************************************************************************** * @fn trxDetectCC1101Crystal() * * @brief This function estimates the crystal frequency if a NextGen * radio is detected. * SPI init must be applied before this function * can be called. * * @param none * * @return none */ static uint8 trxDetectCC1101Crystal() { // Write CLOCK_XOSC/192 to GDO2 uint8 writeByte = 0x3F; trx8BitRegAccess(CC1101_WRITE_BURST, CC1101_IOCFG2, &writeByte, 1); //Wait for crystal to be stable (CHIP_RDYn) while((trxSpiCmdStrobe(CC1101_SNOP)& 0xF0) != 0x00); //Get current system clock frequency uint32_t systemClockBak = bspSysClockSpeedGet(); //set system clock frequency up to 25 MHz for accurate sampling bspSysClockSpeedSet(BSP_SYS_CLK_25MHZ); // initialize timerA to capture rising edges on CLOCK XOSC cc1101InitTimerA(); // Setting up time out in case we hang wating for capture interrupt halTimer32kIntConnect(&timeOutISR); halTimer32kSetIntFrequency(1); // 1 sec timeout halTimer32kIntEnable(); // wait for interrupt on timer capture or timeout while((!timerSemaphore) && (!timeoutSemaphore)); // stop timeuot timer halTimer32kIntDisable(); // stop timer disableTimerA(); if(timerSemaphore) { // assuming 50% duty cycle. Period time = time between rising and // falling edge x 2 capturePeriod = (captureTable[1] - captureTable[0])*2; //check for negative number and set absolute value capturePeriod= (capturePeriod<0)?(0-capturePeriod):capturePeriod; // Claculate XOSC frequency in MHz: // system clock frequency / capturePeriod // times clock xosc divider (192) floatingEstimate = (((25.0*192.0)/capturePeriod)); //Round up/down estimated frequency and truncate to int xoscFreqEstimate = (uint8) (floatingEstimate + 0.5); } else { xoscFreqEstimate = XOSC_FREQ_NONE; } //set system clock frequency back to standard bspSysClockSpeedSet(systemClockBak); //reset radio trxSpiCmdStrobe(CC1101_SRES); return xoscFreqEstimate; }
/****************************************************************************** * @fn cc120x_masterStartApp * * @brief * * input parameters * * @param pDummy - pointer to pointer to void. Not used * * output parameters * * @return SNIFF_RETURN_SUCCESS */ uint8 cc120x_masterStartApp(void) { static uint8 marcState; // Set first packet number pkt = 1; // Set up GPIO pins. For debug cc112xSpiWriteReg(CC120X_IOCFG3,&cc120x_gpioConfigMaster[0],4); //Display while configuring radios* lcdBufferClear(0); lcdBufferPrintString(0," RX Sniff Test ",0,eLcdPage0); lcdBufferSetHLine(0,0,LCD_COLS-1,eLcdPage7); lcdBufferPrintString(0," Radio in TX ",0,eLcdPage2); lcdBufferPrintString(0," ",0,eLcdPage3); lcdBufferPrintString(0," Press right button ",0,eLcdPage4); lcdBufferPrintString(0," to send packet ",0,eLcdPage5); lcdBufferPrintString(0," 1 Abort Master Mode ",0,eLcdPage7); lcdBufferSetHLine(0,0,LCD_COLS-1,55); lcdBufferInvertPage(0,0,LCD_COLS,eLcdPage7); lcdSendBuffer(0); // Calibrate radio trxSpiCmdStrobe(CC120X_SCAL); // Wait for calibration to be done (radio back in IDLE state) do { cc120xSpiReadReg(CC120X_MARCSTATE, &marcState, 1); } while (marcState != 0x41); // Put MCU to sleep __low_power_mode_3(); while(1) { if(buttonPressed = bspKeyPushed(BSP_KEY_ALL)) { if(buttonPressed == BSP_KEY_LEFT) { // Left button pressed. Abort function // Put radio in powerdown to save power trxSpiCmdStrobe(CC120X_SPWD); //Insert Carrier Sense threshold warning in Sniff Test Menu drawInfo(); return SNIFF_RETURN_FAILURE; } else if (buttonPressed == BSP_KEY_RIGHT) { //Right button pressed, send packet lcdBufferClear(0); // build packet comArray[0] = PKTLEN; // length field comArray[1] = 0x00; // address field comArray[2] = pkt>>24; // payload comArray[3] = pkt>>16; comArray[4] = pkt>>8; comArray[5] = pkt; // Update LCD lcdBufferPrintString(0," RX Sniff Test ",0,eLcdPage0); lcdBufferSetHLine(0,0,LCD_COLS-1,eLcdPage7); lcdBufferPrintString(0,"Sent Pkt number:",0,eLcdPage3); lcdBufferPrintInt(0,pkt,70,eLcdPage4); lcdBufferPrintString(0," 1 Abort Master Mode ",0,eLcdPage7); lcdBufferSetHLine(0,0,LCD_COLS-1,55); lcdBufferInvertPage(0,0,LCD_COLS,eLcdPage7); lcdSendBuffer(0); // Update packet counter pkt++; // Strobe IDLE and fill TX FIFO trxSpiCmdStrobe(CC120X_SIDLE); // wait for radio to enter IDLE state while((trxSpiCmdStrobe(CC112X_SNOP)& 0xF0) != 0x00); cc112xSpiWriteTxFifo(comArray,PKTLEN+1); // Send packet trxSpiCmdStrobe(CC120X_STX); // Wait for radio to finish sending packet while((trxSpiCmdStrobe(CC120X_SNOP)& 0xF0) != 0x00); // Put radio in powerdown to save power trxSpiCmdStrobe(CC120X_SPWD); //Put MCU to sleep __low_power_mode_3(); } } }
/******************************************************************************* * @fn runRX * * @brief Puts radio in RX and waits for packets. Function assumes * that status bytes are appended in the RX_FIFO * Update packet counter and display for each packet received. * * @param none * * @return none */ static void runRX(void) { uint8 rxBuffer[128] = {0}; uint8 rxBytes; uint8 marcState; // Connect ISR function to GPIO2 ioPinIntRegister(IO_PIN_PORT_1, GPIO2, &radioRxISR); // Interrupt on falling edge ioPinIntTypeSet(IO_PIN_PORT_1, GPIO2, IO_PIN_FALLING_EDGE); // Clear ISR flag ioPinIntClear(IO_PIN_PORT_1, GPIO2); // Enable interrupt ioPinIntEnable(IO_PIN_PORT_1, GPIO2); // Update LCD updateLcd(); // Set radio in RX trxSpiCmdStrobe(CC120X_SRX); // Infinite loop while(TRUE) { // Wait for packet received interrupt if(packetSemaphore == ISR_ACTION_REQUIRED) { // Read number of bytes in RX FIFO cc120xSpiReadReg(CC120X_NUM_RXBYTES, &rxBytes, 1); // Check that we have bytes in FIFO if(rxBytes != 0) { // Read MARCSTATE to check for RX FIFO error cc120xSpiReadReg(CC120X_MARCSTATE, &marcState, 1); // Mask out MARCSTATE bits and check if we have a RX FIFO error if((marcState & 0x1F) == RX_FIFO_ERROR) { // Flush RX FIFO trxSpiCmdStrobe(CC120X_SFRX); } else { // Read n bytes from RX FIFO cc120xSpiReadRxFifo(rxBuffer, rxBytes); // Check CRC ok (CRC_OK: bit7 in second status byte) // This assumes status bytes are appended in RX_FIFO // (PKT_CFG1.APPEND_STATUS = 1) // If CRC is disabled the CRC_OK field will read 1 if(rxBuffer[rxBytes - 1] & 0x80) { // Update packet counter packetCounter++; } } } // Update LCD updateLcd(); // Reset packet semaphore packetSemaphore = ISR_IDLE; // Set radio back in RX trxSpiCmdStrobe(CC120X_SRX); } } }
/****************************************************************************** * @fn runRX * * @brief puts radio in RX and waits for packets. Function assumes * that status bytes are appended in the RX_FIFO * Update packet counter and display for each packet received. * * @param none * * @return none */ void cc120xRunRX(void){ uint8 rxBuffer[128] = {0}; uint8 rxBytes; uint8 marcStatus; // Write radio registers registerConfig(); // Connect ISR function to GPIO0, interrupt on falling edge trxIsrConnect(&radioRxTxISR); // Enable interrupt from GPIO_0 trxEnableInt(); // Update LCD updateLcd(); // Set radio in RX trxSpiCmdStrobe(CC120X_SRX); // Loop until left button is pushed (exits application) while(BSP_KEY_LEFT != bspKeyPushed(BSP_KEY_ALL)){ // Wait for packet received interrupt if(packetSemaphore == ISR_ACTION_REQUIRED){ // Read number of bytes in rx fifo cc120xSpiReadReg(CC120X_NUM_RXBYTES, &rxBytes, 1); // Check that we have bytes in fifo if(rxBytes != 0){ // Read marcstate to check for RX FIFO error cc120xSpiReadReg(CC120X_MARCSTATE, &marcStatus, 1); // Mask out marcstate bits and check if we have a RX FIFO error if((marcStatus & 0x1F) == RX_FIFO_ERROR){ // Flush RX Fifo trxSpiCmdStrobe(CC120X_SFRX); } else{ // Read n bytes from rx fifo cc120xSpiReadRxFifo(rxBuffer, rxBytes); // Check CRC ok (CRC_OK: bit7 in second status byte) // This assumes status bytes are appended in RX_FIFO // (PKT_CFG1.APPEND_STATUS = 1.) // If CRC is disabled the CRC_OK field will read 1 if(rxBuffer[rxBytes-1] & 0x80){ // Update packet counter packetCounter++; } } } // Update LCD updateLcd(); // Reset packet semaphore packetSemaphore = ISR_IDLE; // Set radio back in RX trxSpiCmdStrobe(CC120X_SRX); } } // Reset packet counter packetCounter = 0; // Put radio to sleep and exit application trxSpiCmdStrobe(CC120X_SPWD); }
/******************************************************************************* * @fn main * * @brief Runs the main routine * * @param none * * @return none */ void main(void) { uint8 writeByte; // Initialize MCU and peripherals initMCU(); // Write radio registers (preferred settings from SmartRF Studio) registerConfig(); // Application specific registers // FIFO_THR = 120 // GPIO0 = RXFIFO_THR // GPIO2 = PKT_SYNC_RXTX // GPIO3 = PKT_SYNC_RXTX writeByte = INFINITE_PACKET_LENGTH_MODE; cc112xSpiWriteReg(CC112X_PKT_CFG0, &writeByte, 1); writeByte = 0x78; cc112xSpiWriteReg(CC112X_FIFO_CFG, &writeByte, 1); writeByte = 0x00; cc112xSpiWriteReg(CC112X_IOCFG0, &writeByte, 1); writeByte = 0x06; cc112xSpiWriteReg(CC112X_IOCFG2, &writeByte, 1); writeByte = 0x06; cc112xSpiWriteReg(CC112X_IOCFG3, &writeByte, 1); bspLedSet(BSP_LED_ALL); // Calibrate the radio according to the errata note manualCalibration(); // Connect ISR function to GPIO0 ioPinIntRegister(IO_PIN_PORT_1, GPIO0, &rxFifoAboveThresholdISR); // Interrupt on falling edge ioPinIntTypeSet(IO_PIN_PORT_1, GPIO0, IO_PIN_RISING_EDGE); // Clear interrupt ioPinIntClear(IO_PIN_PORT_1, GPIO0); // Enable interrupt ioPinIntEnable(IO_PIN_PORT_1, GPIO0); // Connect ISR function to GPIO2 ioPinIntRegister(IO_PIN_PORT_1, GPIO2, &syncReceivedISR); // Interrupt on falling edge ioPinIntTypeSet(IO_PIN_PORT_1, GPIO2, IO_PIN_RISING_EDGE); // Clear interrupt ioPinIntClear(IO_PIN_PORT_1, GPIO2); // Enable interrupt ioPinIntEnable(IO_PIN_PORT_1, GPIO2); // Set up interrupt on GPIO3 (PKT_SYNC_RXTX) ioPinIntRegister(IO_PIN_PORT_1, GPIO3, &packetReceivedISR); // Interrupt on falling edge ioPinIntTypeSet(IO_PIN_PORT_1, GPIO3, IO_PIN_FALLING_EDGE); printWelcomeMessage(); while (TRUE) { switch (state) { //------------------------------------------------------------------ case RX_START: //------------------------------------------------------------------ trxSpiCmdStrobe(CC112X_SRX); pBufferIndex = rxBuffer; // Disable interrupt on GPIO3 ioPinIntDisable(IO_PIN_PORT_1, GPIO3); state = RX_WAIT; //------------------------------------------------------------------ case RX_WAIT: //------------------------------------------------------------------ if (packetReceived) { packetReceived = FALSE; // Check CRC and update LCD if CRC OK if ((rxBuffer[packetLength + 3]) & CRC_OK) updateLcd(); // Change to infinite packet length mode pktFormat = INFINITE; writeByte = INFINITE_PACKET_LENGTH_MODE; cc112xSpiWriteReg(CC112X_PKT_CFG0, &writeByte, 1); state = RX_START; } break; //------------------------------------------------------------------ default: //------------------------------------------------------------------ break; } } }
/****************************************************************************** * * @fn cc1101GetRxStatus(void) * * @brief * This function transmits a No Operation Strobe (SNOP) with the * read bit set to get the status of the radio and the number of * available bytes in the RXFIFO. * * Status byte: * * -------------------------------------------------------------------------------- * | | | | * | CHIP_RDY | STATE[2:0] | FIFO_BYTES_AVAILABLE (available bytes in the RX FIFO | * | | | | * -------------------------------------------------------------------------------- * * NOTE: * When reading a status register over the SPI interface while the * register is updated by the radio hardware, there is a small, but * finite, probability that the result is corrupt. This also applies * to the chip status byte. The CC1100 and CC1101 errata notes explain * the problem and propose several work arounds. * * input parameters * * @param none * * output parameters * * @return rfStatus_t * */ rfStatus_t cc1101GetRxStatus(void) { return(trxSpiCmdStrobe(CC1101_SNOP | RADIO_READ_ACCESS)); }
/****************************************************************************** * @fn cc1101GetTxStatus(void) * * @brief This function transmits a No Operation Strobe (SNOP) to get the * status of the radio and the number of free bytes in the TX FIFO. * * Status byte: * * --------------------------------------------------------------------------- * | | | | * | CHIP_RDY | STATE[2:0] | FIFO_BYTES_AVAILABLE (free bytes in the TX FIFO | * | | | | * --------------------------------------------------------------------------- * * NOTE: * When reading a status register over the SPI interface while the * register is updated by the radio hardware, there is a small, but * finite, probability that the result is corrupt. This also applies * to the chip status byte. The CC1100 and CC1101 errata notes explain * the problem and propose several work arounds. * * input parameters * * @param none * * output parameters * * @return rfStatus_t * */ rfStatus_t cc1101GetTxStatus(void) { return(trxSpiCmdStrobe(CC1101_SNOP)); }
/******************************************************************************* * @fn manualCalibration * * @brief Perform manual calibration according to the errata note * @param none * * @return none */ static void manualCalibration(void) { uint8 original_fs_cal2; uint8 calResults_for_vcdac_start_high[3]; uint8 calResults_for_vcdac_start_mid[3]; uint8 marcstate; uint8 writeByte; // 1) Set VCO cap-array to 0 (FS_VCO2 = 0x00) writeByte = 0x00; cc112xSpiWriteReg(CC112X_FS_VCO2, &writeByte, 1); // 2) Start with high VCDAC (original VCDAC_START + 2): cc112xSpiReadReg(CC112X_FS_CAL2, &original_fs_cal2, 1); writeByte = original_fs_cal2 + VCDAC_START_OFFSET; cc112xSpiWriteReg(CC112X_FS_CAL2, &writeByte, 1); // 3) Calibrate and wait for calibration to be done (radio back in IDLE state) trxSpiCmdStrobe(CC112X_SCAL); do { cc112xSpiReadReg(CC112X_MARCSTATE, &marcstate, 1); } while (marcstate != 0x41); // 4) Read FS_VCO2, FS_VCO4 and FS_CHP register obtained with high VCDAC_START value cc112xSpiReadReg(CC112X_FS_VCO2, &calResults_for_vcdac_start_high[FS_VCO2_INDEX], 1); cc112xSpiReadReg(CC112X_FS_VCO4, &calResults_for_vcdac_start_high[FS_VCO4_INDEX], 1); cc112xSpiReadReg(CC112X_FS_CHP, &calResults_for_vcdac_start_high[FS_CHP_INDEX], 1); // 5) Set VCO cap-array to 0 (FS_VCO2 = 0x00) writeByte = 0x00; cc112xSpiWriteReg(CC112X_FS_VCO2, &writeByte, 1); // 6) Continue with mid VCDAC (original VCDAC_START): writeByte = original_fs_cal2; cc112xSpiWriteReg(CC112X_FS_CAL2, &writeByte, 1); // 7) Calibrate and wait for calibration to be done (radio back in IDLE state) trxSpiCmdStrobe(CC112X_SCAL); do { cc112xSpiReadReg(CC112X_MARCSTATE, &marcstate, 1); } while (marcstate != 0x41); // 8) Read FS_VCO2, FS_VCO4 and FS_CHP register obtained with mid VCDAC_START value cc112xSpiReadReg(CC112X_FS_VCO2, &calResults_for_vcdac_start_mid[FS_VCO2_INDEX], 1); cc112xSpiReadReg(CC112X_FS_VCO4, &calResults_for_vcdac_start_mid[FS_VCO4_INDEX], 1); cc112xSpiReadReg(CC112X_FS_CHP, &calResults_for_vcdac_start_mid[FS_CHP_INDEX], 1); // 9) Write back highest FS_VCO2 and corresponding FS_VCO and FS_CHP result if (calResults_for_vcdac_start_high[FS_VCO2_INDEX] > calResults_for_vcdac_start_mid[FS_VCO2_INDEX]) { writeByte = calResults_for_vcdac_start_high[FS_VCO2_INDEX]; cc112xSpiWriteReg(CC112X_FS_VCO2, &writeByte, 1); writeByte = calResults_for_vcdac_start_high[FS_VCO4_INDEX]; cc112xSpiWriteReg(CC112X_FS_VCO4, &writeByte, 1); writeByte = calResults_for_vcdac_start_high[FS_CHP_INDEX]; cc112xSpiWriteReg(CC112X_FS_CHP, &writeByte, 1); } else { writeByte = calResults_for_vcdac_start_mid[FS_VCO2_INDEX]; cc112xSpiWriteReg(CC112X_FS_VCO2, &writeByte, 1); writeByte = calResults_for_vcdac_start_mid[FS_VCO4_INDEX]; cc112xSpiWriteReg(CC112X_FS_VCO4, &writeByte, 1); writeByte = calResults_for_vcdac_start_mid[FS_CHP_INDEX]; cc112xSpiWriteReg(CC112X_FS_CHP, &writeByte, 1); } }
/****************************************************************************** * @fn trxDetectCC112xCrystal() * * @brief This function estimates the crystal frequency if a CC112x * is detected. * SPI init must be applied before this function * can be called. * * @param none * * @return none */ static uint8 trxDetectCC112xCrystal() { // Write EXT CLOCK to IOCFG3 and IOCFG2 uint8 writeBytes1[2] = {0x31, 0x31}; trx8BitRegAccess(CC112X_WRITE_BURST, CC112X_IOCFG3, writeBytes1, 2); // set external clock divider to 32 writeBytes1[0] = 0x00; trx16BitRegAccess(CC112X_WRITE_BURST,CC112X_EXT_MEM_ACCESS,CC112X_ECG_CFG,writeBytes1,1); //wait for crystal to be stable (CHIP_RDYn) while((trxSpiCmdStrobe(CC112X_SNOP)& 0xF0) != 0x00); //get system clock frequency uint32_t systemClockBak = bspSysClockSpeedGet(); //set system clock frequency up to 25 MHz for accurate sampling bspSysClockSpeedSet(BSP_SYS_CLK_25MHZ); // initialize timerA to capture rising and falling edges on EXT CLOCK cc112xInitTimerA(); // Setting up time out in case we hang wating for capture interrupt halTimer32kIntConnect(&timeOutISR); halTimer32kSetIntFrequency(1); // 1 sec timeout halTimer32kIntEnable(); // wait for interrupt on timer capture or timeout while((!timerSemaphore) && (!timeoutSemaphore)); // stop timeuot timer halTimer32kIntDisable(); // stop timer disableTimerA(); if(timerSemaphore) { // assuming 50% duty cycle. Period time = time between rising and // falling edge x 2 capturePeriod = (captureTable[1] - captureTable[0])*2; //check for negative number and set absolute value capturePeriod= (capturePeriod<0)?(0-capturePeriod):capturePeriod; // Claculate XOSC frequency in MHz: // system clock frequency / capturePeriod // times external clock divider (32) // times digital clock divider (2) floatingEstimate = (((25.0*32.0*2.0)/capturePeriod)); //Round up/down estimated frequency and truncate to int xoscFreqEstimate = (uint8) (floatingEstimate + 0.5); } else { xoscFreqEstimate = XOSC_FREQ_NONE; } //set system clock frequency back to standard bspSysClockSpeedSet(systemClockBak); //reset radio trxSpiCmdStrobe(CC112X_SRES); return xoscFreqEstimate; }