local for mbed5
sx126x-hal.cpp
- Committer:
- GregCr
- Date:
- 2016-10-12
- Revision:
- 3:7e3595a9ebe0
- Parent:
- 2:4ff11ea92fbe
- Child:
- 4:c6ef863d0b07
File content as of revision 3:7e3595a9ebe0:
/* / _____) _ | | ( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| (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 "sx126x-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 ){ } SX126xHal::SX126xHal( 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 )( IrqTimeoutCode_t timeoutCode ), void ( *rxError )( IrqErrorCode_t errorCode ), void ( *cadDone )( bool channelActivityDetected ), void ( *onDioIrq )( ) ) : SX126x( txDone, rxDone, rxPblSyncWordHeader, rxTxTimeout, rxError, 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; } SX126xHal::SX126xHal( 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 )( IrqTimeoutCode_t timeoutCode ), void ( *rxError )( IrqErrorCode_t errorCode ), void ( *cadDone )( bool channelActivityDetected ), void ( *onDioIrq )( ) ) : SX126x( txDone, rxDone, rxPblSyncWordHeader, rxTxTimeout, rxError, cadDone, onDioIrq ), RadioNss( NC ), RadioReset( rst ), BUSY( busy ), DIO1( dio1 ), DIO2( dio2 ), DIO3( dio3 ) { RadioSpi = NULL; RadioUart = new Serial( tx, rx ); RadioReset = 1; } void SX126xHal::SpiInit( void ) { RadioNss = 1; RadioSpi->format( 8, 0 ); RadioSpi->frequency( SX126x_SPI_FREQ_DEFAULT ); wait( 0.1 ); } void SX126xHal::UartInit( void ) { RadioUart->format( 9, SerialBase::Even, 1 ); // 8 data bits + 1 even parity bit + 1 stop bit RadioUart->baud( 115200 ); // By default the SX126x 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 SX126xHal::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 SX126xHal::Reset( void ) { __disable_irq( ); wait( 0.05 ); RadioReset = 0; wait( 0.1 ); RadioReset = 1; wait( 0.05 ); __enable_irq( ); } void SX126xHal::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 SX126xHal::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 SX126xHal::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 SX126xHal::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 SX126xHal::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 SX126xHal::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 SX126xHal::WriteRegister( uint16_t address, uint8_t value ) { WriteRegister( address, &value, 1 ); } void SX126xHal::WriteRegisterNoBusy( uint16_t address, uint8_t value ) { WriteRegisterNoBusy( address, &value, 1 ); } void SX126xHal::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 SX126xHal::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 SX126xHal::ReadRegister( uint16_t address ) { uint8_t data; ReadRegister( address, &data, 1 ); return data; } uint8_t SX126xHal::ReadRegisterNoBusy( uint16_t address ) { uint8_t data; ReadRegisterNoBusy( address, &data, 1 ); return data; } void SX126xHal::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 SX126xHal::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 SX126xHal::GetDioStatus( void ) { return ( DIO3 << 3 ) | ( DIO2 << 2 ) | ( DIO1 << 1 ) | ( BUSY << 0 ); }