Skip to content

Commit 1ca571f

Browse files
feat: Add SubGhz object to access SubGhz signals
This allows accessing some of the signals internally connected to the SubGhz radio (that would have been GPIO signals if the radio was external). This also allocates and exposes the SPI object connected to the SubGhz radio block. Note that the busy signal is *not* exposed, since there is no way to read it directly (and indirectly reading it through the IRQ pending flag does not work in all cases).
1 parent 6a220b3 commit 1ca571f

File tree

4 files changed

+169
-4
lines changed

4 files changed

+169
-4
lines changed

libraries/SPI/src/SPI.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -423,8 +423,6 @@ void SPIClass::detachInterrupt(void)
423423
}
424424

425425
#if defined(SUBGHZSPI_BASE)
426-
SUBGHZSPIClass SubGHZ_SPI;
427-
428426
void SUBGHZSPIClass::begin(uint8_t _pin)
429427
{
430428
if (_pin != CS_PIN_CONTROLLED_BY_USER) {

libraries/SPI/src/SPI.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,8 +330,6 @@ class SUBGHZSPIClass : public SPIClass {
330330
void transfer(byte _pin, void *_bufout, void *_bufin, size_t _count, SPITransferMode _mode = SPI_LAST);
331331
void enableDebugPins(void);
332332
};
333-
334-
extern SUBGHZSPIClass SubGHZ_SPI;
335333
#endif
336334

337335
#endif /* _SPI_H_INCLUDED */

libraries/SPI/src/SubGhz.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// TODO: License headers, include guards, etc.
2+
#include <stm32_def.h>
3+
4+
#include "SubGhz.h"
5+
6+
SubGhzClass SubGhz;
7+
8+
extern "C" void SUBGHZ_Radio_IRQHandler(void)
9+
{
10+
SubGhz.handleIrq();
11+
}
12+
13+
void SubGhzClass::handleIrq() {
14+
if (callback)
15+
callback();
16+
}
17+
18+
void SubGhzClass::attachInterrupt(callback_function_t callback) {
19+
this->callback = callback;
20+
HAL_NVIC_ClearPendingIRQ(SUBGHZ_Radio_IRQn);
21+
enableInterrupt();
22+
}
23+
24+
void SubGhzClass::detachInterrupt() {
25+
disableInterrupt();
26+
this->callback = nullptr;
27+
}
28+
29+
bool SubGhzClass::hasInterrupt() {
30+
return (bool)this->callback;
31+
}
32+
33+
void SubGhzClass::enableInterrupt() {
34+
HAL_NVIC_EnableIRQ(SUBGHZ_Radio_IRQn);
35+
}
36+
37+
void SubGhzClass::disableInterrupt() {
38+
HAL_NVIC_DisableIRQ(SUBGHZ_Radio_IRQn);
39+
}
40+
41+
void SubGhzClass::clearPendingInterrupt() {
42+
HAL_NVIC_ClearPendingIRQ(SUBGHZ_Radio_IRQn);
43+
}
44+
45+
bool SubGhzClass::isInterruptPending() {
46+
HAL_NVIC_GetPendingIRQ(SUBGHZ_Radio_IRQn);
47+
}
48+
49+
void SubGhzClass::writeNSS(uint32_t value) {
50+
if (value == LOW)
51+
LL_PWR_SelectSUBGHZSPI_NSS();
52+
else
53+
LL_PWR_UnselectSUBGHZSPI_NSS();
54+
}
55+
56+
uint32_t SubGhzClass::readNSS() {
57+
return LL_PWR_IsSUBGHZSPI_NSS_Selected() ? LOW : HIGH;
58+
}
59+
60+
void SubGhzClass::writeReset(uint32_t value) {
61+
if (value == LOW)
62+
LL_RCC_RF_EnableReset();
63+
else
64+
LL_RCC_RF_DisableReset();
65+
}
66+
67+
uint32_t SubGhzClass::readReset() {
68+
return LL_RCC_RF_IsEnabledReset() ? LOW : HIGH;
69+
}
70+
71+
uint32_t SubGhzClass::readBusy() {
72+
// TODO: Or should we use LL_PWR_IsActiveFlag_RFBUSYMS() ?
73+
return(LL_PWR_IsActiveFlag_RFBUSYS());
74+
}

libraries/SPI/src/SubGhz.h

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// TODO: License headers, include guards, etc.
2+
// TODO: Where should this live? Maybe in its own library?
3+
#pragma once
4+
5+
#include <functional>
6+
#include <stdint.h>
7+
#include <SPI.h>
8+
9+
extern "C" void SUBGHZ_Radio_IRQHandler();
10+
11+
/**
12+
* Singleton class to manage the SubGHZ ISR and internal signals
13+
*/
14+
class SubGhzClass {
15+
public:
16+
using callback_function_t = std::function<void(void)>;
17+
18+
// Attach the passed handler to be called (from ISR context) when
19+
// the radio IRQ triggers, then clear any pending IRQs and enable
20+
// it.
21+
//
22+
// Note that the radio IRQ is *level* triggered, so the callback
23+
// should either disable directly process the IRQ and clear the IRQ
24+
// flags in the radio (so the radio module clears its DIO lines
25+
// before the ISR returns), or the callback should disable the IRQ
26+
// to prevent it from being triggered over and over again.
27+
void attachInterrupt(callback_function_t callback);
28+
29+
// Detach the interrupt handler, disabling the IRQ too.
30+
void detachInterrupt();
31+
32+
// Return whether an interrupt callback is currently attached
33+
bool hasInterrupt();
34+
35+
// Enable the interrupt agani if it was previously disabled using
36+
// disableInterrupt(). This does *not* clear any pending interrupts,
37+
// so if the IRQ was triggered while it was disabled, this will
38+
// cause the callback (previously registered with attachInterrupt)
39+
// to fire directly.
40+
void enableInterrupt();
41+
42+
// Temporarily disable interrupt processing by disabling the IRQ in
43+
// the NVIC.
44+
void disableInterrupt();
45+
46+
// Clear the interrupt pending flag (to suppress an IRQs that
47+
// happened while the interrupt was disabled).
48+
void clearPendingInterrupt();
49+
50+
// Returns whether the interrupt is currently pending (useful when
51+
// the interrupt is disabled, or while some higher priority
52+
// interrupt is currently running).
53+
bool isInterruptPending();
54+
55+
// Update the NSS signal that is internally connected to the radio
56+
// SPI block.
57+
// This signal is active-low, so passing LOW activates
58+
// the block, HIGH deactivates it.
59+
// TODO: Should this just pass a bool and be inverted?
60+
void writeNSS(uint32_t value);
61+
62+
// Read back the value written to NSS
63+
uint32_t readNSS();
64+
65+
// Update the RESET signal that is internally connected to the
66+
// radio.
67+
// This signal is active-low, so passing LOW resets the radio and
68+
// HIGH releases it.
69+
// TODO: Should this just pass a bool and be inverted?
70+
void writeReset(uint32_t value);
71+
72+
// Read back the value written to RESET
73+
uint32_t readReset();
74+
75+
// Return the state of busy signal exported by the radio module.
76+
// Returns HIGH when busy, or LOW when idle.
77+
// TODO: Should this just return a bool?
78+
uint32_t readBusy();
79+
80+
// The SPI object that can be used to talk to the radio. Works
81+
// like regular SPI objects, except that writeNSS() above must be
82+
// used to controll the (internal) NSS "pin".
83+
SUBGHZSPIClass SPI;
84+
85+
protected:
86+
// To access handleIrq()
87+
friend void SUBGHZ_Radio_IRQHandler();
88+
void handleIrq();
89+
90+
private:
91+
callback_function_t callback;
92+
};
93+
94+
// Singleton instance, no other instances should be created
95+
extern SubGhzClass SubGhz;

0 commit comments

Comments
 (0)