SX1261 and sx1262 common library
Dependents: SX126xDevKit SX1262PingPong SX126X_TXonly SX126X_PingPong_Demo ... more
Fork of SX126xLib by
Diff: sx126x-hal.cpp
- Revision:
- 0:deaafdfde3bb
- Child:
- 1:35d34672a089
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sx126x-hal.cpp Tue Sep 06 06:56:46 2016 +0000 @@ -0,0 +1,506 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2016 Semtech + +Description: Handling of the node configuration protocol + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainer: Miguel Luis, Gregory Cristian and Matthieu Verdy +*/ +#include "sx1261-hal.h" + +#define V1A_WORKAROUNDS + +/*! + * \brief Used to block execution waiting for low state on radio busy pin. + * Essentially used in SPI communications + */ +#define WaitBusy( ) while( BUSY == 1 ){ } + + + +/*! + * \brief Blocking routine for waiting the UART to be writeable + * + */ +#define WaitUartWritable( ) while( RadioUart->writeable( ) == false ){ } + +/*! + * \brief Blocking routine for waiting the UART to be readable + * + */ +#define WaitUartReadable( ) while( RadioUart->readable( ) == false ){ } + +SX1261Hal::SX1261Hal( PinName mosi, PinName miso, PinName sclk, PinName nss, PinName busy, PinName dio1, PinName dio2, PinName dio3, PinName rst, + void ( *txDone )( ), void ( *rxDone )( ), void ( *rxPblSyncWordHeader )( IrqPblSyncHeaderCode_t val ), + void ( *rxTxTimeout )( ), void ( *rxError )( IrqErrorCode_t errorCode ), void ( *rangingDone )( IrqRangingCode_t val ), + void ( *cadDone )( bool channelActivityDetected ), + void ( *onDioIrq )( ) ) + : SX1261( txDone, rxDone, rxPblSyncWordHeader, rxTxTimeout, rxError, rangingDone, cadDone, onDioIrq ), + RadioNss( nss ), + RadioReset( rst ), + BUSY( busy ), + DIO1( dio1 ), + DIO2( dio2 ), + DIO3( dio3 ) +{ + RadioSpi = new SPI( mosi, miso, sclk ); + RadioUart = NULL; + + RadioNss = 1; + RadioReset = 1; +} + +SX1261Hal::SX1261Hal( PinName tx, PinName rx, PinName busy, PinName dio1, PinName dio2, PinName dio3, PinName rst, + void ( *txDone )( ), void ( *rxDone )( ), void ( *rxPblSyncWordHeader )( IrqPblSyncHeaderCode_t val ), + void ( *rxTxTimeout )( ), void ( *rxError )( IrqErrorCode_t errorCode ), void ( *rangingDone )( IrqRangingCode_t val ), + void ( *cadDone )( bool channelActivityDetected ), + void ( *onDioIrq )( ) ) + : SX1261( txDone, rxDone, rxPblSyncWordHeader, rxTxTimeout, rxError, rangingDone, cadDone, onDioIrq ), + RadioNss( NC ), + RadioReset( rst ), + BUSY( busy ), + DIO1( dio1 ), + DIO2( dio2 ), + DIO3( dio3 ) +{ + RadioSpi = NULL; + RadioUart = new Serial( tx, rx ); + RadioReset = 1; +} + +void SX1261Hal::SpiInit( void ) +{ + RadioNss = 1; + RadioSpi->format( 8, 0 ); + RadioSpi->frequency( SX1261_SPI_FREQ_DEFAULT ); + + wait( 0.1 ); +} + +void SX1261Hal::UartInit( void ) +{ + RadioUart->format( 9, SerialBase::Even, 1 ); // 8 data bits + 1 even parity bit + 1 stop bit + RadioUart->baud( 115200 ); + + // By default the SX1261 UART is setup to handle bytes MSB first. + // In order to setup the radio to use the UART standard way we first send + // the equivalent of a WriteRegister with reversed bit order in order to + // change the endianness. + //@todo + /*uint8_t regVal = 0; + RadioUart->putc( 0x98 ); // Reversed opcode for read register (0x19) + RadioUart->putc( 0x10 ); // Reversed MSB register address (0x08) + RadioUart->putc( 0x18 ); // Reversed LSB register address (0x18) + RadioUart->putc( 0x80 ); // Reversed value for reading only 1 byte (0x01) + regVal = RadioUart->getc( )& 0xF3; // Read reversed value and mask it + + RadioUart->putc( 0x18 ); // Reversed opcode for read register (0x18) + RadioUart->putc( 0x10 ); // Reversed MSB register address (0x08) + RadioUart->putc( 0x18 ); // Reversed LSB register address (0x18) + RadioUart->putc( 0x80 ); // Reversed value for writing only 1 byte (0x01) + RadioUart->putc( regVal ); // The new value of the register*/ + + // After this point, the UART is running standard mode: 8 data bit, 1 even + // parity bit, 1 stop bit, 115200 baud, LSB first + wait_us( 10 ); +} + +void SX1261Hal::IoIrqInit( DioIrqHandler irqHandler ) +{ + assert_param( RadioSpi != 0 || RadioUart != 0 ); + if( RadioSpi != NULL ) + { + SpiInit( ); + } + if( RadioUart != NULL ) + { + UartInit( ); + } + + BUSY.mode( PullDown ); + DIO1.mode( PullDown ); + DIO2.mode( PullDown ); + DIO3.mode( PullDown ); + + DIO1.rise( this, static_cast <Trigger>( irqHandler ) ); + DIO2.rise( this, static_cast <Trigger>( irqHandler ) ); + DIO3.rise( this, static_cast <Trigger>( irqHandler ) ); +} + +void SX1261Hal::Reset( void ) +{ + __disable_irq( ); + wait( 0.05 ); + RadioReset = 0; + wait( 0.1 ); + RadioReset = 1; + wait( 0.05 ); + __enable_irq( ); +} + +void SX1261Hal::ClearInstructionRam( void ) +{ + // Clearing the instruction RAM is writing 0x00s on every bytes of the + // instruction RAM + WaitBusy( ); + + if( RadioSpi != NULL ) + { + RadioNss = 0; + RadioSpi->write( RADIO_WRITE_REGISTER ); // Send write register opcode + RadioSpi->write( ( IRAM_START_ADDRESS >> 8 ) & 0x00FF ); // Send MSB of the first byte address + RadioSpi->write( IRAM_START_ADDRESS & 0x00FF ); // Send LSB of the first byte address + + for( uint16_t address = IRAM_START_ADDRESS; address < ( IRAM_START_ADDRESS + IRAM_SIZE ); address++ ) + { + RadioSpi->write( 0x00 ); + } + RadioNss = 1; + } + if( RadioUart != NULL ) + { + // We can't erase the whole instruction RAM in one shot with UART + // because we need to send the length of register to erase + // and this length is coded on 1 byte. + for( uint16_t address = IRAM_START_ADDRESS; address < ( IRAM_START_ADDRESS + IRAM_SIZE ); address++ ) + { + WriteRegister( address, 0 ); + } + } + + WaitBusy( ); +} + +void SX1261Hal::Wakeup( void ) +{ + __disable_irq( ); + + //Don't wait for DIO0 here + + if( RadioSpi != NULL ) + { + RadioNss = 0; + RadioSpi->write( RADIO_GET_STATUS ); + RadioSpi->write( 0 ); + RadioNss = 1; + } + if( RadioUart != NULL ) + { + RadioUart->putc( RADIO_GET_STATUS ); + WaitUartReadable( ); + RadioUart->getc( ); + } + + // Wait for chip to be ready. + WaitBusy( ); + + #ifdef V1A_WORKAROUNDS + //V1a workaround: rc64k not enabled after warm_start, rtc_wake_up=0 + WriteRegister(0x91e, ReadRegister(0x91e) | 0x40); + //rc13m enable bug + uint8_t txFallbackFunc[2]; + //set to ModeTx2Rc addr = 0fce, so rc is not enabled before ramp down + txFallbackFunc[0] = 0x0f; + txFallbackFunc[1] = 0xce; + WriteRegister(0x00CC, txFallbackFunc, 2); + #endif + + __enable_irq( ); +} + +void SX1261Hal::WriteCommand( RadioCommands_t command, uint8_t *buffer, uint16_t size ) +{ + WaitBusy( ); + + if( RadioSpi != NULL ) + { + RadioNss = 0; + RadioSpi->write( ( uint8_t )command ); + for( uint16_t i = 0; i < size; i++ ) + { + RadioSpi->write( buffer[i] ); + } + RadioNss = 1; + } + if( RadioUart != NULL ) + { + RadioUart->putc( command ); + if( size > 0 ) + { + RadioUart->putc( size ); + for( uint16_t i = 0; i < size; i++ ) + { + RadioUart->putc( buffer[i] ); + } + } + } + + if( command != RADIO_SET_SLEEP ) + { + WaitBusy( ); + } +} + +void SX1261Hal::ReadCommand( RadioCommands_t command, uint8_t *buffer, uint16_t size ) +{ + WaitBusy( ); + + if( RadioSpi != NULL ) + { + RadioNss = 0; + RadioSpi->write( ( uint8_t )command ); + RadioSpi->write( 0 ); + for( uint16_t i = 0; i < size; i++ ) + { + buffer[i] = RadioSpi->write( 0 ); + } + RadioNss = 1; + } + else if( RadioUart != NULL ) + { + RadioUart->putc( command ); + + // Behavior on the UART is different depending of the opcode command + if( ( command == RADIO_GET_PACKETTYPE ) || + ( command == RADIO_GET_RXBUFFERSTATUS ) || + ( command == RADIO_GET_RSSIINST ) || + ( command == RADIO_GET_PACKETSTATUS ) || + ( command == RADIO_GET_IRQSTATUS ) ) + { + RadioUart->putc( size ); + } + + WaitUartReadable( ); + for( uint16_t i = 0; i < size; i++ ) + { + buffer[i] = RadioUart->getc( ); + } + } + else + { + buffer[0] = 0xFF; + } + + WaitBusy( ); +} + +void SX1261Hal::WriteRegister( uint16_t address, uint8_t *buffer, uint16_t size ) +{ + WaitBusy( ); + + if( RadioSpi != NULL ) + { + RadioNss = 0; + RadioSpi->write( RADIO_WRITE_REGISTER ); + RadioSpi->write( ( address & 0xFF00 ) >> 8 ); + RadioSpi->write( address & 0x00FF ); + for( uint16_t i = 0; i < size; i++ ) + { + RadioSpi->write( buffer[i] ); + } + RadioNss = 1; + } + if( RadioUart != NULL ) + { + RadioUart->putc( RADIO_WRITE_REGISTER ); + RadioUart->putc( ( address & 0xFF00 ) >> 8 ); + RadioUart->putc( address & 0x00FF ); + RadioUart->putc( size ); + for( uint16_t i = 0; i < size; i++ ) + { + RadioUart->putc( buffer[i] ); + } + } + + WaitBusy( ); +} + +void SX1261Hal::WriteRegisterNoBusy( uint16_t address, uint8_t *buffer, uint16_t size ) +{ + if( RadioSpi != NULL ) + { + RadioNss = 0; + RadioSpi->write( RADIO_WRITE_REGISTER ); + RadioSpi->write( ( address & 0xFF00 ) >> 8 ); + RadioSpi->write( address & 0x00FF ); + for( uint16_t i = 0; i < size; i++ ) + { + RadioSpi->write( buffer[i] ); + } + RadioNss = 1; + } + if( RadioUart != NULL ) + { + RadioUart->putc( RADIO_WRITE_REGISTER ); + RadioUart->putc( ( address & 0xFF00 ) >> 8 ); + RadioUart->putc( address & 0x00FF ); + RadioUart->putc( size ); + for( uint16_t i = 0; i < size; i++ ) + { + RadioUart->putc( buffer[i] ); + } + } +} + +void SX1261Hal::WriteRegister( uint16_t address, uint8_t value ) +{ + WriteRegister( address, &value, 1 ); +} + +void SX1261Hal::WriteRegisterNoBusy( uint16_t address, uint8_t value ) +{ + WriteRegisterNoBusy( address, &value, 1 ); +} + +void SX1261Hal::ReadRegister( uint16_t address, uint8_t *buffer, uint16_t size ) +{ + WaitBusy( ); + + if( RadioSpi != NULL ) + { + RadioNss = 0; + RadioSpi->write( RADIO_READ_REGISTER ); + RadioSpi->write( ( address & 0xFF00 ) >> 8 ); + RadioSpi->write( address & 0x00FF ); + RadioSpi->write( 0 ); + for( uint16_t i = 0; i < size; i++ ) + { + buffer[i] = RadioSpi->write( 0 ); + } + RadioNss = 1; + } + if( RadioUart != NULL ) + { + RadioUart->putc( RADIO_READ_REGISTER ); + RadioUart->putc( ( address & 0xFF00 ) >> 8 ); + RadioUart->putc( address & 0x00FF ); + RadioUart->putc( size ); + WaitUartReadable( ); + for( uint16_t i = 0; i < size; i++ ) + { + buffer[i] = RadioUart->getc( ); + } + } + + WaitBusy( ); +} + +void SX1261Hal::ReadRegisterNoBusy( uint16_t address, uint8_t *buffer, uint16_t size ) +{ + + if( RadioSpi != NULL ) + { + RadioNss = 0; + RadioSpi->write( RADIO_READ_REGISTER ); + RadioSpi->write( ( address & 0xFF00 ) >> 8 ); + RadioSpi->write( address & 0x00FF ); + RadioSpi->write( 0 ); + for( uint16_t i = 0; i < size; i++ ) + { + buffer[i] = RadioSpi->write( 0 ); + } + RadioNss = 1; + } + if( RadioUart != NULL ) + { + RadioUart->putc( RADIO_READ_REGISTER ); + RadioUart->putc( ( address & 0xFF00 ) >> 8 ); + RadioUart->putc( address & 0x00FF ); + RadioUart->putc( size ); + WaitUartReadable( ); + for( uint16_t i = 0; i < size; i++ ) + { + buffer[i] = RadioUart->getc( ); + } + } + +} + +uint8_t SX1261Hal::ReadRegister( uint16_t address ) +{ + uint8_t data; + + ReadRegister( address, &data, 1 ); + return data; +} + +uint8_t SX1261Hal::ReadRegisterNoBusy( uint16_t address ) +{ + uint8_t data; + + ReadRegisterNoBusy( address, &data, 1 ); + return data; +} + +void SX1261Hal::WriteBuffer( uint8_t offset, uint8_t *buffer, uint8_t size ) +{ + WaitBusy( ); + + if( RadioSpi != NULL ) + { + RadioNss = 0; + RadioSpi->write( RADIO_WRITE_BUFFER ); + RadioSpi->write( offset ); + for( uint16_t i = 0; i < size; i++ ) + { + RadioSpi->write( buffer[i] ); + } + RadioNss = 1; + } + if( RadioUart != NULL ) + { + RadioUart->putc( RADIO_WRITE_BUFFER ); + RadioUart->putc( offset ); + RadioUart->putc( size ); + for( uint16_t i = 0; i < size; i++ ) + { + RadioUart->putc( buffer[i] ); + } + } + + WaitBusy( ); +} + +void SX1261Hal::ReadBuffer( uint8_t offset, uint8_t *buffer, uint8_t size ) +{ + WaitBusy( ); + + if( RadioSpi != NULL ) + { + RadioNss = 0; + RadioSpi->write( RADIO_READ_BUFFER ); + RadioSpi->write( offset ); + RadioSpi->write( 0 ); + for( uint16_t i = 0; i < size; i++ ) + { + buffer[i] = RadioSpi->write( 0 ); + } + RadioNss = 1; + } + if( RadioUart != NULL ) + { + RadioUart->putc( RADIO_READ_BUFFER ); + RadioUart->putc( offset ); + RadioUart->putc( size ); + WaitUartReadable( ); + for( uint16_t i = 0; i < size; i++ ) + { + buffer[i] = RadioUart->getc( ); + } + } + + WaitBusy( ); +} + +uint8_t SX1261Hal::GetDioStatus( void ) +{ + return ( DIO3 << 3 ) | ( DIO2 << 2 ) | ( DIO1 << 1 ) | ( BUSY << 0 ); +} + +