basic working sx126x skeleton
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
module lilygot3s3sx128x
|
||||
|
||||
go 1.26.2
|
||||
|
||||
require tinygo.org/x/drivers v0.34.0
|
||||
|
||||
require github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
|
||||
replace tinygo.org/x/drivers => /Users/jwetzell/Projects/drivers
|
||||
@@ -0,0 +1,2 @@
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
@@ -0,0 +1,287 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"tinygo.org/x/drivers/lora"
|
||||
"tinygo.org/x/drivers/sx126x"
|
||||
)
|
||||
|
||||
func main() {
|
||||
time.Sleep(3 * time.Second)
|
||||
led := machine.GPIO37
|
||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
spi := machine.SPI0
|
||||
spi.Configure(machine.SPIConfig{
|
||||
Mode: 0,
|
||||
Frequency: 8 * 1e6,
|
||||
SDO: machine.GPIO6,
|
||||
SDI: machine.GPIO3,
|
||||
SCK: machine.GPIO5,
|
||||
})
|
||||
|
||||
nssPin := machine.GPIO7
|
||||
nssPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
nssPin.Set(true)
|
||||
|
||||
resetPin := machine.GPIO8
|
||||
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
resetPin.Set(true)
|
||||
|
||||
busyPin := machine.GPIO34
|
||||
busyPin.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||
|
||||
button := machine.GPIO0
|
||||
button.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||
button.SetInterrupt(machine.PinFalling, func(machine.Pin) {
|
||||
println("button interrupt")
|
||||
})
|
||||
|
||||
println("initializing radio...")
|
||||
|
||||
radio := sx126x.New(
|
||||
spi,
|
||||
nssPin,
|
||||
resetPin,
|
||||
busyPin,
|
||||
)
|
||||
|
||||
dio1 := machine.GPIO33
|
||||
var txDone atomic.Bool
|
||||
txDone.Store(true)
|
||||
var rxDone atomic.Bool
|
||||
rxDone.Store(true)
|
||||
var timeout atomic.Bool
|
||||
timeout.Store(true)
|
||||
|
||||
dio1.Configure(machine.PinConfig{Mode: machine.PinInputPulldown})
|
||||
dio1.SetInterrupt(machine.PinRising, func(machine.Pin) {
|
||||
irqStatus := radio.GetIrqStatus()
|
||||
println("irq status:", irqStatus)
|
||||
|
||||
if irqStatus&sx126x.IRQ_TX_DONE_MASK != 0 {
|
||||
println("tx done")
|
||||
txDone.Store(true)
|
||||
timeout.Store(false)
|
||||
led.Set(false)
|
||||
}
|
||||
if irqStatus&sx126x.IRQ_RX_DONE_MASK != 0 {
|
||||
println("rx done")
|
||||
rxDone.Store(true)
|
||||
timeout.Store(false)
|
||||
led.Set(true)
|
||||
}
|
||||
if irqStatus&sx126x.IRQ_TIMEOUT_MASK != 0 {
|
||||
println("timeout")
|
||||
txDone.Store(true)
|
||||
rxDone.Store(true)
|
||||
timeout.Store(true)
|
||||
}
|
||||
})
|
||||
|
||||
loraConfig := lora.Config{
|
||||
Freq: lora.MHZ_915_0,
|
||||
Bw: lora.Bandwidth_125_0,
|
||||
Sf: lora.SpreadingFactor9,
|
||||
Cr: lora.CodingRate4_7,
|
||||
HeaderType: lora.HeaderExplicit,
|
||||
Preamble: 8,
|
||||
Ldr: lora.LowDataRateOptimizeOff,
|
||||
Iq: lora.IQStandard,
|
||||
Crc: lora.CRCOff,
|
||||
SyncWord: 0x1424,
|
||||
LoraTxPowerDBm: 2,
|
||||
}
|
||||
|
||||
radio.WaitWhileBusy()
|
||||
SetupLora(radio, loraConfig)
|
||||
|
||||
for {
|
||||
// if txDone.Load() {
|
||||
// txDone.Store(false)
|
||||
// println("cleaning up prior to transmit...")
|
||||
// radio.ClearIrqStatus(sx126x.IRQ_ALL_MASK)
|
||||
// checkStatus(radio, "ClearIrqStatus")
|
||||
// radio.SetStandby(sx126x.STANDBY_RC)
|
||||
// checkStatus(radio, "SetStandby")
|
||||
// println("waiting 1s before transmitting...")
|
||||
// time.Sleep(1000 * time.Millisecond)
|
||||
// led.Set(true)
|
||||
// err := Tx(radio, loraConfig, []byte("hello world"))
|
||||
// if err != nil {
|
||||
// println("failed to enter transmit:", err)
|
||||
// }
|
||||
// println("transmit started")
|
||||
// }
|
||||
|
||||
if rxDone.Load() {
|
||||
rxDone.Store(false)
|
||||
if !timeout.Load() {
|
||||
println("receive completed without timeout, reading buffer...")
|
||||
rxLength, rxPointer := radio.GetRxBufferStatus()
|
||||
println("rx length:", rxLength, "rx pointer:", rxPointer)
|
||||
rxData := radio.ReadBuffer(rxPointer, rxLength)
|
||||
println("rx data:", string(rxData))
|
||||
led.Set(false)
|
||||
} else {
|
||||
println("receive timed out")
|
||||
}
|
||||
Rx(radio, loraConfig)
|
||||
println("receive started")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SetupLora(radio *sx126x.Device, config lora.Config) {
|
||||
// Switch to standby prior to configuration changes
|
||||
|
||||
chipMode, _ := radio.GetStatus()
|
||||
if chipMode != sx126x.CHIP_MODE_STBY_RC {
|
||||
radio.SetStandby(sx126x.STANDBY_RC)
|
||||
checkStatus(radio, "SetStandby")
|
||||
}
|
||||
radio.ClearDeviceErrors()
|
||||
// Clear errors, disable radio interrupts for the moment
|
||||
radio.SetPacketType(sx126x.PACKET_TYPE_LORA)
|
||||
checkStatus(radio, "SetPacketType")
|
||||
radio.SetRfFrequency(config.Freq)
|
||||
checkStatus(radio, "SetRfFrequency")
|
||||
radio.SetModulationParamsLoRa(spreadingFactor(config.Sf), bandwidth(config.Bw), codingRate(config.Cr), config.Ldr)
|
||||
checkStatus(radio, "SetModulationParamsLoRa")
|
||||
radio.SetPaConfig(0x04, 0x07, sx126x.DEVICE_SEL_SX1262)
|
||||
checkStatus(radio, "SetPaConfig")
|
||||
radio.SetTxParams(config.LoraTxPowerDBm, sx126x.RADIO_RAMP_200U)
|
||||
checkStatus(radio, "SetTxParams")
|
||||
var syncWord [2]uint8
|
||||
syncWord[0] = uint8(config.SyncWord >> 8)
|
||||
syncWord[1] = uint8(config.SyncWord & 0x00FF)
|
||||
|
||||
radio.WriteRegister(sx126x.REG_LORA_SYNC_WORD_MSB, syncWord[:])
|
||||
checkStatus(radio, "WriteRegister")
|
||||
radio.SetRxTxFallbackMode(sx126x.FALLBACK_MODE_STDBY_RC)
|
||||
checkStatus(radio, "SetRxTxFallbackMode")
|
||||
radio.SetDIO2AsRfSwitchCtrl(true)
|
||||
checkStatus(radio, "SetDIO2AsRfSwitchCtrl")
|
||||
radio.SetDIO3AsTCXOCtrl(sx126x.TCXO_VOLTAGE_1_6V, 5000)
|
||||
checkStatus(radio, "SetDIO3AsTCXOCtrl")
|
||||
}
|
||||
|
||||
func printRegister(radio *sx126x.Device, address uint16) {
|
||||
data := radio.ReadRegister(address)
|
||||
println("register:", address, "data:", data)
|
||||
}
|
||||
|
||||
func checkStatus(radio *sx126x.Device, prefix string) {
|
||||
chipMode, commandStatus := radio.GetStatus()
|
||||
if commandStatus == sx126x.COMMAND_STATUS_COMMAND_PROCESSING_ERROR || commandStatus == sx126x.COMMAND_STATUS_COMMAND_TIMEOUT || commandStatus == sx126x.COMMAND_STATUS_FAILURE_TO_EXECUTE_COMMAND {
|
||||
println(prefix, "->", "command failed with status:", commandStatus)
|
||||
}
|
||||
if chipMode != sx126x.CHIP_MODE_STBY_RC && chipMode != sx126x.CHIP_MODE_STBY_XOSC {
|
||||
println(prefix, "->", "exited standby:", chipMode)
|
||||
}
|
||||
}
|
||||
|
||||
func checkDeviceErrors(radio *sx126x.Device, prefix string) {
|
||||
err := radio.GetDeviceErrors()
|
||||
if err == 0 {
|
||||
return
|
||||
}
|
||||
println(prefix, "->", "error:", err)
|
||||
}
|
||||
|
||||
func Tx(radio *sx126x.Device, loraConfig lora.Config, data []byte) error {
|
||||
radio.SetStandby(sx126x.STANDBY_RC)
|
||||
radio.SetBufferBaseAddress(0, 0)
|
||||
radio.SetDioIrqParams(sx126x.IRQ_TX_DONE_MASK|sx126x.IRQ_TIMEOUT_MASK, sx126x.IRQ_TX_DONE_MASK|sx126x.IRQ_TIMEOUT_MASK, 0x00, 0x00)
|
||||
if len(data) > 255 {
|
||||
return nil
|
||||
}
|
||||
radio.SetPacketParamsLoRa(loraConfig.Preamble, loraConfig.HeaderType, uint8(len(data)&0xFF), loraConfig.Crc, loraConfig.Iq)
|
||||
radio.WriteBuffer(0, data)
|
||||
radio.ClearIrqStatus(sx126x.IRQ_ALL_MASK)
|
||||
radio.SetTx(1000)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Rx(radio *sx126x.Device, loraConfig lora.Config) {
|
||||
radio.SetStandby(sx126x.STANDBY_RC)
|
||||
radio.ClearIrqStatus(sx126x.IRQ_ALL_MASK)
|
||||
radio.SetBufferBaseAddress(0, 0)
|
||||
radio.SetRfFrequency(loraConfig.Freq)
|
||||
radio.SetPacketParamsLoRa(loraConfig.Preamble, loraConfig.HeaderType, 0xFF, loraConfig.Crc, loraConfig.Iq)
|
||||
radio.SetDioIrqParams(sx126x.IRQ_RX_DONE_MASK|sx126x.IRQ_TIMEOUT_MASK, sx126x.IRQ_RX_DONE_MASK|sx126x.IRQ_TIMEOUT_MASK, 0x00, 0x00)
|
||||
radio.SetRx(1000)
|
||||
}
|
||||
|
||||
func codingRate(cr uint8) uint8 {
|
||||
switch cr {
|
||||
case lora.CodingRate4_5:
|
||||
return sx126x.LORA_CR_4_5
|
||||
case lora.CodingRate4_6:
|
||||
return sx126x.LORA_CR_4_6
|
||||
case lora.CodingRate4_7:
|
||||
return sx126x.LORA_CR_4_7
|
||||
case lora.CodingRate4_8:
|
||||
return sx126x.LORA_CR_4_8
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func spreadingFactor(sf uint8) uint8 {
|
||||
switch sf {
|
||||
case lora.SpreadingFactor5:
|
||||
return sx126x.LORA_SF_5
|
||||
case lora.SpreadingFactor6:
|
||||
return sx126x.LORA_SF_6
|
||||
case lora.SpreadingFactor7:
|
||||
return sx126x.LORA_SF_7
|
||||
case lora.SpreadingFactor8:
|
||||
return sx126x.LORA_SF_8
|
||||
case lora.SpreadingFactor9:
|
||||
return sx126x.LORA_SF_9
|
||||
case lora.SpreadingFactor10:
|
||||
return sx126x.LORA_SF_10
|
||||
case lora.SpreadingFactor11:
|
||||
return sx126x.LORA_SF_11
|
||||
case lora.SpreadingFactor12:
|
||||
return sx126x.LORA_SF_12
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func bandwidth(bw uint8) uint8 {
|
||||
switch bw {
|
||||
case lora.Bandwidth_7_8:
|
||||
return sx126x.LORA_BW_7
|
||||
case lora.Bandwidth_10_4:
|
||||
return sx126x.LORA_BW_10
|
||||
case lora.Bandwidth_15_6:
|
||||
return sx126x.LORA_BW_15
|
||||
case lora.Bandwidth_20_8:
|
||||
return sx126x.LORA_BW_20
|
||||
case lora.Bandwidth_31_25:
|
||||
return sx126x.LORA_BW_31
|
||||
case lora.Bandwidth_41_7:
|
||||
return sx126x.LORA_BW_41
|
||||
case lora.Bandwidth_62_5:
|
||||
return sx126x.LORA_BW_62
|
||||
case lora.Bandwidth_125_0:
|
||||
return sx126x.LORA_BW_125
|
||||
case lora.Bandwidth_250_0:
|
||||
return sx126x.LORA_BW_250
|
||||
case lora.Bandwidth_500_0:
|
||||
return sx126x.LORA_BW_500
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func timeoutMsToRtcSteps(timeoutMs uint32) uint32 {
|
||||
r := uint32(timeoutMs * (64000 / 1000))
|
||||
return r
|
||||
}
|
||||
Reference in New Issue
Block a user