/************************************************************************************************** * @fn mrfiSpiCmdStrobe * * @brief Send command strobe to the radio. Returns status byte read during transfer * of strobe command. * * @param addr - address of register to strobe * * @return status byte of radio ************************************************************************************************** */ uint8_t mrfiSpiCmdStrobe(uint8_t addr) { uint8_t statusByte; mrfiSpiIState_t s; MRFI_SPI_ASSERT( MRFI_SPI_IS_INITIALIZED() ); /* SPI is not initialized */ MRFI_SPI_ASSERT((addr >= 0x30) && (addr <= 0x3D)); /* invalid address */ /* disable interrupts that use SPI */ MRFI_SPI_ENTER_CRITICAL_SECTION(s); /* turn chip select "off" and then "on" to clear any current SPI access */ MRFI_SPI_TURN_CHIP_SELECT_OFF(); MRFI_SPI_TURN_CHIP_SELECT_ON(); /* send the command strobe, wait for SPI access to complete */ MRFI_SPI_WRITE_BYTE(addr); MRFI_SPI_WAIT_DONE(); /* read the readio status byte returned by the command strobe */ statusByte = MRFI_SPI_READ_BYTE(); /* turn off chip select; enable interrupts that call SPI functions */ MRFI_SPI_TURN_CHIP_SELECT_OFF(); MRFI_SPI_EXIT_CRITICAL_SECTION(s); /* return the status byte */ return(statusByte); }
/*================================================================================================= * @fn spiRegAccess * * @brief This function performs a read or write. The * calling code must configure the read/write bit of the register's address byte. * This bit is set or cleared based on the type of access. * * @param regAddrByte - address byte of register; the read/write bit already configured * * @return register value *================================================================================================= */ static uint8_t spiRegAccess(uint8_t addrByte, uint8_t writeValue) { uint8_t readValue; mrfiSpiIState_t s; #ifdef MRFI_TIMER_ALWAYS_ACTIVE bool comm_state = sActiveSPI; // save comm state #endif MRFI_SPI_ASSERT( MRFI_SPI_IS_INITIALIZED() ); /* SPI is not initialized */ /* disable interrupts that use SPI */ MRFI_SPI_ENTER_CRITICAL_SECTION(s); #ifdef MRFI_TIMER_ALWAYS_ACTIVE sActiveSPI = true; // indicate active comm state #endif /* turn chip select "off" and then "on" to clear any current SPI access */ MRFI_SPI_TURN_CHIP_SELECT_OFF(); MRFI_SPI_TURN_CHIP_SELECT_ON(); /* send register address byte, the read/write bit is already configured */ MRFI_SPI_WRITE_BYTE(addrByte); MRFI_SPI_WAIT_DONE(); /* * Send the byte value to write. If this operation is a read, this value * is not used and is just dummy data. Wait for SPI access to complete. */ MRFI_SPI_WRITE_BYTE(writeValue); MRFI_SPI_WAIT_DONE(); /* * If this is a read operation, SPI data register now contains the register * value which will be returned. For a read operation, it contains junk info * that is not used. */ readValue = MRFI_SPI_READ_BYTE(); #ifdef MRFI_TIMER_ALWAYS_ACTIVE sActiveSPI = comm_state; // restore comm state #endif /* turn off chip select; enable interrupts that call SPI functions */ MRFI_SPI_TURN_CHIP_SELECT_OFF(); MRFI_SPI_EXIT_CRITICAL_SECTION(s); /* return the register value */ return(readValue); }
/************************************************************************************************** * @fn mrfiSpiCmdStrobe * * @brief Send command strobe to the radio. Returns status byte read during transfer * of strobe command. * * @param addr - address of register to strobe * * @return status byte of radio ************************************************************************************************** */ uint8_t mrfiSpiCmdStrobe(uint8_t addr) { uint8_t statusByte; mrfiSpiIState_t s; #ifdef DEBUG_SPI DEBUG("SPI!C# "); DEBUG_LN(cmdRegs[addr-SRES]); #endif #ifdef MRFI_TIMER_ALWAYS_ACTIVE bool comm_state = sActiveSPI; // save comm state #endif MRFI_SPI_ASSERT( MRFI_SPI_IS_INITIALIZED() ); /* SPI is not initialized */ MRFI_SPI_ASSERT((addr >= 0x30) && (addr <= 0x3D)); /* invalid address */ /* disable interrupts that use SPI */ MRFI_SPI_ENTER_CRITICAL_SECTION(s); #ifdef MRFI_TIMER_ALWAYS_ACTIVE sActiveSPI = true; // indicate active comm state #endif /* turn chip select "off" and then "on" to clear any current SPI access */ MRFI_SPI_TURN_CHIP_SELECT_OFF(); MRFI_SPI_TURN_CHIP_SELECT_ON(); /* send the command strobe, wait for SPI access to complete */ MRFI_SPI_WRITE_BYTE(addr); MRFI_SPI_WAIT_DONE(); /* read the readio status byte returned by the command strobe */ statusByte = MRFI_SPI_READ_BYTE(); #ifdef MRFI_TIMER_ALWAYS_ACTIVE sActiveSPI = comm_state; // restore comm state #endif /* turn off chip select; enable interrupts that call SPI functions */ MRFI_SPI_TURN_CHIP_SELECT_OFF(); MRFI_SPI_EXIT_CRITICAL_SECTION(s); /* return the status byte */ return(statusByte); }
/*================================================================================================= * @fn spiRegAccess * * @brief This function performs a read or write. The * calling code must configure the read/write bit of the register's address byte. * This bit is set or cleared based on the type of access. * * @param regAddrByte - address byte of register; the read/write bit already configured * * @return register value *================================================================================================= */ static uint8_t spiRegAccess(uint8_t addrByte, uint8_t writeValue) { uint8_t readValue; mrfiSpiIState_t s; MRFI_SPI_ASSERT( MRFI_SPI_IS_INITIALIZED() ); /* SPI is not initialized */ /* disable interrupts that use SPI */ MRFI_SPI_ENTER_CRITICAL_SECTION(s); /* make sure clock phase and polarity are correct for radio */ MRFI_SPI_CLK_CONFIG(); /* turn chip select "off" and then "on" to clear any current SPI access */ MRFI_SPI_TURN_CHIP_SELECT_OFF(); MRFI_SPI_TURN_CHIP_SELECT_ON(); /* send register address byte, the read/write bit is already configured */ MRFI_SPI_WRITE_BYTE(addrByte); MRFI_SPI_WAIT_DONE(); /* * Send the byte value to write. If this operation is a read, this value * is not used and is just dummy data. Wait for SPI access to complete. */ MRFI_SPI_WRITE_BYTE(writeValue); MRFI_SPI_WAIT_DONE(); /* * If this is a read operation, SPI data register now contains the register * value which will be returned. For a write operation, it contains junk info * that is not used. */ readValue = MRFI_SPI_READ_BYTE(); /* turn off chip select; enable interrupts that call SPI functions */ MRFI_SPI_TURN_CHIP_SELECT_OFF(); MRFI_SPI_EXIT_CRITICAL_SECTION(s); /* return the register value */ return(readValue); }
/*================================================================================================= * @fn spiBurstFifoAccess * * @brief Burst mode access used for reading or writing to radio FIFOs. * * For more efficient interrupt latency, this function does not keep interrupts * disabled for its entire execution. It is designed to recover if an interrupt * occurs that accesses SPI. See comments in code for further details. * * @param addrByte - first byte written to SPI, contains address and mode bits * @param pData - pointer to data to read or write * @param len - length of data in bytes * * @return true if an interrupt was detected during the transfer, false otherwise *================================================================================================= */ static bool spiBurstFifoAccess(uint8_t addrByte, uint8_t * pData, uint8_t len) { bool result = false; // initialize to successful status mrfiSpiIState_t s; #ifdef MRFI_TIMER_ALWAYS_ACTIVE bool comm_state = sActiveSPI; // save comm state #endif MRFI_SPI_ASSERT( MRFI_SPI_IS_INITIALIZED() ); /* SPI is not initialized */ MRFI_SPI_ASSERT(len != 0); /* zero length is not allowed */ MRFI_SPI_ASSERT(addrByte & BURST_BIT); /* only burst mode supported */ /* disable interrupts that use SPI */ MRFI_SPI_ENTER_CRITICAL_SECTION(s); #ifdef MRFI_TIMER_ALWAYS_ACTIVE sActiveSPI = true; // indicate active comm state #endif /* turn chip select "off" and then "on" to clear any current SPI access */ MRFI_SPI_TURN_CHIP_SELECT_OFF(); MRFI_SPI_TURN_CHIP_SELECT_ON(); /*------------------------------------------------------------------------------- * Main loop. If the SPI access is interrupted, execution comes back to * the start of this loop. Loop exits when nothing left to transfer. */ do { /* send FIFO access command byte, wait for SPI access to complete */ MRFI_SPI_WRITE_BYTE(addrByte); MRFI_SPI_WAIT_DONE(); /*------------------------------------------------------------------------------- * Inner loop. This loop executes as long as the SPI access is not interrupted. * Loop completes when nothing left to transfer. */ do { MRFI_SPI_WRITE_BYTE(*pData); /*------------------------------------------------------------------------------- * Use idle time. Perform increment/decrement operations before pending on * completion of SPI access. * * Decrement the length counter. Wait for SPI access to complete. */ len--; MRFI_SPI_WAIT_DONE(); /*------------------------------------------------------------------------------- * SPI data register holds data just read. If this is a read operation, * store the value into memory. */ if (addrByte & READ_BIT) { *pData = MRFI_SPI_READ_BYTE(); } /*------------------------------------------------------------------------------- * At least one byte of data has transferred. Briefly enable (and then disable) * interrupts that can call SPI functions. This provides a window for any timing * critical interrupts that might be pending. * * To improve latency, take care of pointer increment within the interrupt * enabled window. */ MRFI_SPI_EXIT_CRITICAL_SECTION(s); pData++; MRFI_SPI_ENTER_CRITICAL_SECTION(s); /*------------------------------------------------------------------------------- * If chip select is "off" the SPI access was interrupted (all SPI access * functions leave chip select in the "off" state). In this case, turn * back on chip select and break to the main loop. The main loop will * pick up where the access was interrupted. */ if (MRFI_SPI_CHIP_SELECT_IS_OFF()) { MRFI_SPI_TURN_CHIP_SELECT_ON(); result = true; // indicate interruption detected break; } /*------------------------------------------------------------------------------- */ } while (len); /* inner loop */ } while (len); /* main loop */ #ifdef MRFI_TIMER_ALWAYS_ACTIVE sActiveSPI = comm_state; // restore comm state #endif /* turn off chip select; enable interrupts that call SPI functions */ MRFI_SPI_TURN_CHIP_SELECT_OFF(); MRFI_SPI_EXIT_CRITICAL_SECTION(s); return result; }