[SX126x] Implemented LoRa transmit method

This commit is contained in:
jgromes 2019-05-13 15:05:02 +02:00
parent 7780c499a1
commit 58d3ca3984
3 changed files with 125 additions and 79 deletions

View file

@ -2,24 +2,23 @@
SX126x::SX126x(Module* mod) : PhysicalLayer(SX126X_CRYSTAL_FREQ, SX126X_DIV_EXPONENT) { SX126x::SX126x(Module* mod) : PhysicalLayer(SX126X_CRYSTAL_FREQ, SX126X_DIV_EXPONENT) {
_mod = mod; _mod = mod;
_bw = SX126X_LORA_BW_125_0;
_bwKhz = 125.0;
_sf = 9;
_cr = SX126X_LORA_CR_4_7;
_ldro = 0x00;
_payloadLength = 255;
_crcType = SX126X_LORA_CRC_ON;
_preambleLength = 8;
} }
int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint16_t preambleLength) { int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint16_t preambleLength) {
// set module properties // set module properties
_mod->init(USE_SPI, INT_BOTH); _mod->init(USE_SPI, INT_BOTH);
pinMode(_mod->getRx(), INPUT); pinMode(_mod->getRx(), INPUT);
pinMode(_mod->getTx(), INPUT);
// reset module // BW in kHz and SF are required in order to calculate LDRO for setModulationParams
reset(); _bwKhz = bw;
_sf = sf;
// initialize dummy configuration variables
_bw = SX126X_LORA_BW_125_0;
_cr = SX126X_LORA_CR_4_7;
_ldro = 0x00;
_crcType = SX126X_LORA_CRC_ON;
_preambleLength = preambleLength;
// get status and errors // get status and errors
getStatus(); getStatus();
@ -32,12 +31,12 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint1
config(); config();
// configure publicly accessible settings // configure publicly accessible settings
int16_t state = setBandwidth(bw); int16_t state = setSpreadingFactor(sf);
if(state != ERR_NONE) { if(state != ERR_NONE) {
return(state); return(state);
} }
state = setSpreadingFactor(sf); state = setBandwidth(bw);
if(state != ERR_NONE) { if(state != ERR_NONE) {
return(state); return(state);
} }
@ -61,7 +60,79 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint1
} }
int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) {
// set mode to standby
int16_t state = standby();
// get currently active modem
uint8_t modem = getPacketType();
if(modem == SX126X_PACKET_TYPE_LORA) {
// check packet length
if(len >= 256) {
return(ERR_PACKET_TOO_LONG);
}
// calculate timeout (150% of expected time-on-air)
float symbolLength = (float)(uint32_t(1) << _sf) / (float)_bwKhz;
float sfCoeff1 = 4.25;
float sfCoeff2 = 8.0;
if(_sf == 5 || _sf == 6) {
sfCoeff1 = 6.25;
sfCoeff2 = 0.0;
}
uint8_t sfDivisor = 4*_sf;
if(symbolLength >= 16.0) {
sfDivisor = 4*(_sf - 2);
}
float nSymbol = _preambleLength + sfCoeff1 + 8 + ceil(max(8.0 * len + (_crcType * 16.0) - 4.0 * _sf + sfCoeff2 + 20.0, 0.0) / sfDivisor) * (_cr + 4);
uint32_t timeout = (uint32_t)(symbolLength * nSymbol * 1.5);
DEBUG_PRINTLN(timeout);
// set DIO mapping
setDioIrqParams(SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT, SX126X_IRQ_TX_DONE);
// set packet length
setPacketParams(_preambleLength, _crcType, len);
// set buffer pointers
setBufferBaseAddress();
// write packet to buffer
writeBuffer(data, len);
// clear interrupt flags
clearIrqStatus();
// start transmission
uint32_t timeoutValue = (uint32_t)((float)timeout / 0.015625);
setTx(timeoutValue);
//DEBUG_PRINTLN(digitalRead(_mod->getRx()));
// wait for BUSY to go low (= PA ramp up done)
while(digitalRead(_mod->getRx()));
// wait for packet transmission or timeout
uint32_t start = millis();
while(!digitalRead(_mod->getInt0())) {
if(millis() - start > timeout) {
clearIrqStatus();
return(ERR_TX_TIMEOUT);
}
}
uint32_t elapsed = millis() - start;
// update data rate
_dataRate = (len*8.0)/((float)elapsed/1000.0);
// clear interrupt flags
clearIrqStatus();
return(ERR_NONE);
} else if(modem == SX126X_PACKET_TYPE_GFSK) {
}
return(ERR_UNKNOWN);
} }
int16_t SX126x::receive(uint8_t* data, size_t len) { int16_t SX126x::receive(uint8_t* data, size_t len) {
@ -100,16 +171,6 @@ int16_t SX126x::standby(uint8_t mode) {
return(ERR_NONE); return(ERR_NONE);
} }
void SX126x::reset() {
delay(10);
pinMode(_mod->getTx(), OUTPUT);
digitalWrite(_mod->getTx(), LOW);
delay(20);
digitalWrite(_mod->getTx(), HIGH);
pinMode(_mod->getTx(), INPUT);
delay(10);
}
int16_t SX126x::setBandwidth(float bw) { int16_t SX126x::setBandwidth(float bw) {
// check active modem // check active modem
if(getPacketType() != SX126X_PACKET_TYPE_LORA) { if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
@ -205,12 +266,12 @@ int16_t SX126x::setCurrentLimit(float currentLimit) {
int16_t SX126x::setPreambleLength(uint16_t preambleLength) { int16_t SX126x::setPreambleLength(uint16_t preambleLength) {
// update packet parameters // update packet parameters
_preambleLength = preambleLength; _preambleLength = preambleLength;
setPacketParams(_preambleLength, _payloadLength, _crcType); setPacketParams(_preambleLength, _crcType);
return(ERR_NONE); return(ERR_NONE);
} }
float SX126x::getDataRate() { float SX126x::getDataRate() {
return(_dataRate);
} }
int16_t SX126x::setFrequencyDeviation(float freqDev) { int16_t SX126x::setFrequencyDeviation(float freqDev) {
@ -246,6 +307,14 @@ void SX126x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
delete[] dat; delete[] dat;
} }
void SX126x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) {
uint8_t* dat = new uint8_t[1 + numBytes];
dat[0] = offset;
memcpy(dat + 1, data, numBytes);
SPIwriteCommand(SX126X_CMD_WRITE_BUFFER, data, 1 + numBytes);
delete[] dat;
}
void SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) { void SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) {
uint8_t data[8] = {(uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF), uint8_t data[8] = {(uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF),
(uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF), (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF),
@ -292,46 +361,20 @@ void SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldr
SPIwriteCommand(SX126X_CMD_SET_MODULATION_PARAMS, data, 4); SPIwriteCommand(SX126X_CMD_SET_MODULATION_PARAMS, data, 4);
} }
void SX126x::setPacketParams(uint16_t preambleLength, uint8_t payloadLength, uint8_t crcType, uint8_t headerType, uint8_t invertIQ) { void SX126x::setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength, uint8_t headerType, uint8_t invertIQ) {
uint8_t data[6] = {(uint8_t)((preambleLength >> 8) & 0xFF), (uint8_t)(preambleLength & 0xFF), headerType, payloadLength, crcType, invertIQ}; uint8_t data[6] = {(uint8_t)((preambleLength >> 8) & 0xFF), (uint8_t)(preambleLength & 0xFF), headerType, payloadLength, crcType, invertIQ};
SPIwriteCommand(SX126X_CMD_SET_PACKET_PARAMS, data, 6); SPIwriteCommand(SX126X_CMD_SET_PACKET_PARAMS, data, 6);
} }
void SX126x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) {
uint8_t data[2] = {txBaseAddress, rxBaseAddress};
SPIwriteCommand(SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2);
}
uint8_t SX126x::getStatus() { uint8_t SX126x::getStatus() {
/*uint8_t data[1]; uint8_t data[1];
SPIreadCommand(SX126X_CMD_GET_STATUS, data, 1); SPIreadCommand(SX126X_CMD_GET_STATUS, data, 1);
return(data[0]);*/ return(data[0]);
// get pointer to used SPI interface
SPIClass* spi = _mod->getSpi();
// ensure BUSY is low (state meachine ready)
// TODO timeout
while(digitalRead(_mod->getRx()));
// start transfer
digitalWrite(_mod->getCs(), LOW);
spi->beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
// send command byte
spi->transfer(SX126X_CMD_GET_STATUS);
DEBUG_PRINT(SX126X_CMD_GET_STATUS, HEX);
DEBUG_PRINT('\t');
// get status
uint8_t status = spi->transfer(SX126X_CMD_NOP) & 0b01111110;
DEBUG_PRINTLN(status, HEX);
// stop transfer
spi->endTransaction();
digitalWrite(_mod->getCs(), HIGH);
// wait for BUSY to go high and then low
// TODO timeout
delayMicroseconds(1);
while(digitalRead(_mod->getRx()));
return(status);
} }
uint8_t SX126x::getRssiInt() { uint8_t SX126x::getRssiInt() {
@ -382,25 +425,19 @@ int16_t SX126x::setFrequencyRaw(float freq, bool calibrate) {
} }
int16_t SX126x::config() { int16_t SX126x::config() {
// set DIO2 as RF switch // set DIO2 as IRQ
uint8_t* data = new uint8_t[1]; uint8_t* data = new uint8_t[1];
data[0] = SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL; data[0] = SX126X_DIO2_AS_IRQ;
SPIwriteCommand(SX126X_DIO2_AS_RF_SWITCH, data, 1); SPIwriteCommand(SX126X_DIO2_AS_RF_SWITCH, data, 1);
// set regulator mode // set regulator mode
data[0] = SX126X_REGULATOR_DC_DC; data[0] = SX126X_REGULATOR_DC_DC;
SPIwriteCommand(SX126X_CMD_SET_REGULATOR_MODE, data, 1); SPIwriteCommand(SX126X_CMD_SET_REGULATOR_MODE, data, 1);
// set buffer base address // reset buffer base address
delete[] data; setBufferBaseAddress();
data = new uint8_t[2];
data[0] = 0x00;
data[1] = 0x00;
SPIwriteCommand(SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2);
// set LoRa mode // set LoRa mode
delete[] data;
data = new uint8_t[1];
data[0] = SX126X_PACKET_TYPE_LORA; data[0] = SX126X_PACKET_TYPE_LORA;
SPIwriteCommand(SX126X_CMD_SET_PACKET_TYPE, data, 1); SPIwriteCommand(SX126X_CMD_SET_PACKET_TYPE, data, 1);
@ -420,6 +457,12 @@ int16_t SX126x::config() {
data[6] = 0x00; data[6] = 0x00;
SPIwriteCommand(SX126X_CMD_SET_CAD_PARAMS, data, 7); SPIwriteCommand(SX126X_CMD_SET_CAD_PARAMS, data, 7);
// clear IRQ
clearIrqStatus();
setDioIrqParams(SX126X_IRQ_NONE, SX126X_IRQ_NONE);
delete[] data;
return(ERR_NONE); return(ERR_NONE);
} }

View file

@ -330,7 +330,6 @@ class SX126x: public PhysicalLayer {
int16_t receiveDirect(); int16_t receiveDirect();
int16_t sleep(); int16_t sleep();
int16_t standby(uint8_t mode = SX126X_STANDBY_RC); int16_t standby(uint8_t mode = SX126X_STANDBY_RC);
void reset();
// configuration methods // configuration methods
int16_t setBandwidth(float bw); int16_t setBandwidth(float bw);
@ -349,13 +348,15 @@ class SX126x: public PhysicalLayer {
void setCad(); void setCad();
void setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = SX126X_PA_CONFIG_PA_LUT); void setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = SX126X_PA_CONFIG_PA_LUT);
void writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); void writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes);
void setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask = 0x0000); void writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00);
void setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = SX126X_IRQ_NONE, uint16_t dio3Mask = SX126X_IRQ_NONE);
void clearIrqStatus(uint16_t clearIrqParams = 0xFFFF); void clearIrqStatus(uint16_t clearIrqParams = 0xFFFF);
void setRfFrequency(uint32_t frf); void setRfFrequency(uint32_t frf);
uint8_t getPacketType(); uint8_t getPacketType();
void setTxParams(uint8_t power, uint8_t rampTime = SX126X_PA_RAMP_40U); void setTxParams(uint8_t power, uint8_t rampTime = SX126X_PA_RAMP_200U);
void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro = 0xFF); void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro = 0xFF);
void setPacketParams(uint16_t preambleLength, uint8_t payloadLength, uint8_t crcType, uint8_t headerType = SX126X_LORA_HEADER_EXPLICIT, uint8_t invertIQ = SX126X_LORA_IQ_INVERTED); void setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength = 0xFF, uint8_t headerType = SX126X_LORA_HEADER_EXPLICIT, uint8_t invertIQ = SX126X_LORA_IQ_INVERTED);
void setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00);
uint8_t getStatus(); uint8_t getStatus();
uint8_t getRssiInt(); uint8_t getRssiInt();
uint16_t getDeviceErrors(); uint16_t getDeviceErrors();
@ -366,10 +367,12 @@ class SX126x: public PhysicalLayer {
private: private:
Module* _mod; Module* _mod;
uint8_t _bw, _sf, _cr, _ldro, _payloadLength, _crcType; uint8_t _bw, _sf, _cr, _ldro, _crcType;
uint16_t _preambleLength; uint16_t _preambleLength;
float _bwKhz; float _bwKhz;
float _dataRate;
int16_t config(); int16_t config();
// common low-level SPI interface // common low-level SPI interface