Skip to content

Commit 3c065ec

Browse files
committed
[example] Adding SX128x LoRa example
1 parent bc014bb commit 3c065ec

File tree

2 files changed

+292
-0
lines changed

2 files changed

+292
-0
lines changed
Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
// coding: utf-8
2+
/*
3+
* Copyright (c) 2023, Rasmus Kleist Hørlyck Sørensen
4+
*
5+
* This file is part of the modm project.
6+
*
7+
* This Source Code Form is subject to the terms of the Mozilla Public
8+
* License, v. 2.0. If a copy of the MPL was not distributed with this
9+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
10+
*/
11+
// ----------------------------------------------------------------------------
12+
13+
#include <atomic>
14+
15+
#include <modm/board.hpp>
16+
#include <modm/debug/logger/logger.hpp>
17+
#include <modm/driver/radio/sx128x.hpp>
18+
#include <modm/platform.hpp>
19+
#include <modm/processing.hpp>
20+
21+
using Sck = GpioA5;
22+
using Miso = GpioA6;
23+
using Mosi = GpioA7;
24+
using SpiMaster = modm::platform::SpiMaster1;
25+
26+
namespace
27+
{
28+
29+
namespace rx
30+
{
31+
std::atomic_bool dio1 = false;
32+
std::atomic_bool dio2 = false;
33+
std::atomic_bool dio3 = false;
34+
}
35+
36+
namespace tx
37+
{
38+
std::atomic_bool dio1 = false;
39+
std::atomic_bool dio2 = false;
40+
std::atomic_bool dio3 = false;
41+
}
42+
43+
static constexpr modm::sx128x::LoRa::ModulationParams modulationParams = {
44+
spreadingFactor : modm::sx128x::LoRa::ModulationParams::SpreadingFactor::Sf9,
45+
bandwidth : modm::sx128x::LoRa::ModulationParams::Bandwidth::Bw400,
46+
codingRate : modm::sx128x::LoRa::ModulationParams::CodingRate::Cr_Li_4_7
47+
};
48+
49+
static constexpr modm::sx128x::LoRa::PacketParams packetParams = {
50+
preambleLength : 12,
51+
headerType : modm::sx128x::LoRa::PacketParams::HeaderType::Explicit,
52+
payloadLength : 4,
53+
crc : modm::sx128x::LoRa::PacketParams::Crc::Enable,
54+
invertIq : modm::sx128x::LoRa::PacketParams::InvertIq::Standard
55+
};
56+
57+
}
58+
59+
class RxThread : public modm::sx128x, public modm::pt::Protothread
60+
{
61+
using Reset = GpioB3;
62+
using Busy = GpioB4;
63+
using Dio1 = GpioB5;
64+
using Dio2 = GpioB6;
65+
using Dio3 = GpioB7;
66+
67+
using Nss = GpioD2;
68+
using Transport = modm::Sx128xTransportSpi<SpiMaster, Nss>;
69+
70+
public:
71+
RxThread() {}
72+
73+
inline bool
74+
run()
75+
{
76+
PT_BEGIN();
77+
78+
Nss::setOutput(modm::Gpio::High);
79+
Reset::setOutput(modm::Gpio::Low);
80+
Busy::setInput(modm::platform::Gpio::InputType::PullDown);
81+
82+
Dio1::setInput(modm::platform::Gpio::InputType::PullDown);
83+
Exti::connect<Dio1>(Exti::Trigger::RisingEdge, [](uint8_t) { rx::dio1 = true; });
84+
85+
Dio2::setInput(modm::platform::Gpio::InputType::PullDown);
86+
Exti::connect<Dio2>(Exti::Trigger::RisingEdge, [](uint8_t) { rx::dio2 = true; });
87+
88+
Dio3::setInput(modm::platform::Gpio::InputType::PullDown);
89+
Exti::connect<Dio3>(Exti::Trigger::RisingEdge, [](uint8_t) { rx::dio3 = true; });
90+
91+
PT_CALL(radio.reset());
92+
PT_CALL(radio.setStandby());
93+
94+
// Initialize the sx128x
95+
PT_CALL(radio.setPacketType(PacketType::LoRa));
96+
PT_CALL(radio.setRfFrequency(2457_MHz / radio.frequencyLsb));
97+
PT_CALL(radio.setRegulatorMode(RegulatorMode::Ldo));
98+
PT_CALL(radio.setBufferBaseAddress(0, 0));
99+
PT_CALL(radio.setModulationParams(modulationParams));
100+
PT_CALL(radio.writeRegister(Register::SfAdditionalConfiguration, 0x32));
101+
PT_CALL(radio.writeRegister(Register::FrequencyErrorCorrection, 0x01));
102+
PT_CALL(radio.setPacketParams(packetParams));
103+
PT_CALL(radio.setDioIrqParams(Irq::RxDone | Irq::RxTxTimeout, Irq::RxDone, Irq::RxTxTimeout));
104+
PT_CALL(radio.setRx(sx128x::PeriodBase::ms1, 1000));
105+
106+
MODM_LOG_DEBUG << "Sx128x initialization complete!" << modm::endl;
107+
108+
while (true)
109+
{
110+
if (rx::dio1.exchange(false))
111+
{
112+
PT_CALL(radio.getIrqStatus(&irqStatus));
113+
if (irqStatus.any(Irq::RxDone))
114+
{
115+
PT_CALL(radio.clearIrqStatus(Irq::RxDone | Irq::RxTxTimeout));
116+
PT_CALL(radio.setRx(sx128x::PeriodBase::ms1, 1000));
117+
118+
PT_CALL(radio.getRxBufferStatus(&rxBufferStatus));
119+
PT_CALL(radio.getPacketStatus(&packetStatus));
120+
PT_CALL(radio.readBuffer(rxBufferStatus.rxStartBufferPointer, std::span{buffer, rxBufferStatus.rxPayloadLength}));
121+
122+
/// TODO: read frequency error indicator (FEI) from register 0x0954 (MSB) 0x0955, 0x0956 (LSB).
123+
124+
MODM_LOG_DEBUG << "Received Message" << modm::endl;
125+
MODM_LOG_DEBUG << "Counter: " << reinterpret_cast<uint32_t*>(buffer)[0] << modm::endl;
126+
MODM_LOG_DEBUG << modm::endl;
127+
}
128+
}
129+
130+
if (rx::dio2.exchange(false))
131+
{
132+
PT_CALL(radio.getIrqStatus(&irqStatus));
133+
if (irqStatus.any(Irq::RxTxTimeout))
134+
{
135+
// RxTxTimeout Interrupt recieved!
136+
// Clear irq and set to rx again.
137+
PT_CALL(radio.clearIrqStatus(Irq::RxTxTimeout));
138+
PT_CALL(radio.setRx(sx128x::PeriodBase::ms1, 1000));
139+
MODM_LOG_DEBUG << "RxTxTimeout Interrupt!" << modm::endl;
140+
}
141+
}
142+
PT_YIELD();
143+
}
144+
PT_END();
145+
}
146+
147+
private:
148+
Irq_t irqStatus;
149+
PacketStatus packetStatus;
150+
RxBufferStatus rxBufferStatus;
151+
152+
modm::Sx128x< Transport, Reset, Busy > radio;
153+
154+
private:
155+
156+
static constexpr uint8_t bufferSize = 124;
157+
uint8_t buffer[bufferSize];
158+
} rxThread;
159+
160+
class TxThread : public modm::sx128x, public modm::pt::Protothread
161+
{
162+
using Reset = modm::platform::GpioC2;
163+
using Busy = modm::platform::GpioC3;
164+
using Dio1 = modm::platform::GpioA0;
165+
using Dio2 = modm::platform::GpioA1;
166+
using Dio3 = modm::platform::GpioA2;
167+
168+
using Nss = modm::platform::GpioC1;
169+
using Transport = modm::Sx128xTransportSpi<SpiMaster, Nss>;
170+
171+
public:
172+
TxThread() : timer(std::chrono::milliseconds(500)) {}
173+
174+
inline bool
175+
run()
176+
{
177+
PT_BEGIN();
178+
179+
Nss::setOutput(modm::Gpio::High);
180+
Reset::setOutput(modm::Gpio::Low);
181+
Busy::setInput(modm::platform::Gpio::InputType::PullDown);
182+
183+
Dio1::setInput(modm::platform::Gpio::InputType::PullDown);
184+
Exti::connect<Dio1>(Exti::Trigger::RisingEdge, [](uint8_t) { tx::dio1 = true; });
185+
186+
Dio2::setInput(modm::platform::Gpio::InputType::PullDown);
187+
Exti::connect<Dio2>(Exti::Trigger::RisingEdge, [](uint8_t) { tx::dio2 = true; });
188+
189+
Dio3::setInput(modm::platform::Gpio::InputType::PullDown);
190+
Exti::connect<Dio3>(Exti::Trigger::RisingEdge, [](uint8_t) { tx::dio3 = true; });
191+
192+
193+
PT_CALL(radio.reset());
194+
PT_CALL(radio.setStandby());
195+
196+
// Initialize the sx128x
197+
PT_CALL(radio.setPacketType(PacketType::LoRa));
198+
PT_CALL(radio.setRfFrequency(2457_MHz / radio.frequencyLsb));
199+
PT_CALL(radio.setRegulatorMode(RegulatorMode::Ldo));
200+
PT_CALL(radio.setBufferBaseAddress(0, 0));
201+
PT_CALL(radio.setModulationParams(modulationParams));
202+
PT_CALL(radio.writeRegister(Register::SfAdditionalConfiguration, 0x32));
203+
PT_CALL(radio.writeRegister(Register::FrequencyErrorCorrection, 0x01));
204+
PT_CALL(radio.setPacketParams(packetParams));
205+
PT_CALL(radio.setDioIrqParams(Irq::TxDone | Irq::RxTxTimeout, Irq::TxDone, Irq::RxTxTimeout));
206+
207+
MODM_LOG_DEBUG << "Sx128x initialization complete!" << modm::endl;
208+
209+
while (true)
210+
{
211+
if (tx::dio1.exchange(false))
212+
{
213+
PT_CALL(radio.getIrqStatus(&irqStatus));
214+
if (irqStatus.any(Irq::TxDone))
215+
{
216+
PT_CALL(radio.clearIrqStatus(Irq::TxDone));
217+
irqStatus.reset(Irq::TxDone);
218+
219+
MODM_LOG_DEBUG << "Message sent" << modm::endl;
220+
MODM_LOG_DEBUG << "Counter: " << counter << modm::endl;
221+
counter++;
222+
}
223+
}
224+
225+
if (tx::dio2.exchange(false))
226+
{
227+
PT_CALL(radio.getIrqStatus(&irqStatus));
228+
if (irqStatus.any(Irq::RxTxTimeout))
229+
{
230+
PT_CALL(radio.clearIrqStatus(Irq::RxTxTimeout));
231+
irqStatus.reset(Irq::RxTxTimeout);
232+
233+
MODM_LOG_DEBUG << "Received a timeout" << modm::endl;
234+
}
235+
}
236+
237+
if (timer.execute())
238+
{
239+
PT_CALL(radio.writeBuffer(0, std::span<const uint8_t>{(uint8_t *) &counter, sizeof(counter)}));
240+
PT_CALL(radio.setTx(PeriodBase::ms1, 100));
241+
}
242+
PT_YIELD();
243+
}
244+
245+
PT_END();
246+
}
247+
248+
private:
249+
Irq_t irqStatus;
250+
modm::Sx128x< Transport, Reset, Busy > radio;
251+
252+
uint32_t counter = 0;
253+
modm::PeriodicTimer timer;
254+
};
255+
256+
int
257+
main()
258+
{
259+
Board::initialize();
260+
261+
SpiMaster::connect<Mosi::Mosi, Mosi::Mosi, Sck::Sck>();
262+
SpiMaster::initialize<Board::SystemClock, 21.5_MHz>();
263+
264+
MODM_LOG_INFO << "==========SX128x Test==========" << modm::endl;
265+
MODM_LOG_DEBUG << "Debug logging here" << modm::endl;
266+
MODM_LOG_INFO << "Info logging here" << modm::endl;
267+
MODM_LOG_WARNING << "Warning logging here" << modm::endl;
268+
MODM_LOG_ERROR << "Error logging here" << modm::endl;
269+
MODM_LOG_INFO << "===============================" << modm::endl;
270+
271+
while (true)
272+
{
273+
rxThread.run();
274+
}
275+
276+
return 0;
277+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<library>
2+
<extends>modm:nucleo-g474re</extends>
3+
<options>
4+
<option name="modm:build:build.path">../../../build/nucleo_g474re/sx128x_lora</option>
5+
</options>
6+
<modules>
7+
<module>modm:driver:sx128x</module>
8+
<module>modm:platform:exti</module>
9+
<module>modm:platform:gpio</module>
10+
<module>modm:platform:spi:1</module>
11+
<module>modm:processing:protothread</module>
12+
<module>modm:processing:timer</module>
13+
<module>modm:build:scons</module>
14+
</modules>
15+
</library>

0 commit comments

Comments
 (0)