RadioLib update to v7.1.2

This commit is contained in:
lewisxhe 2025-01-13 10:28:08 +08:00
commit 24815c6cdc
93 changed files with 1143 additions and 1305 deletions

View file

@ -0,0 +1,322 @@
#ifndef ESP_HAL_H
#define ESP_HAL_H
// include RadioLib
#include <RadioLib.h>
// this example only works on ESP32 and is unlikely to work on ESP32S2/S3 etc.
// if you need high portability, you should probably use Arduino anyway ...
#if CONFIG_IDF_TARGET_ESP32 == 0
#error This example HAL only supports ESP32 targets. Support for ESP32S2/S3 etc. can be added by adjusting this file to user needs.
#endif
// include all the dependencies
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp32/rom/gpio.h"
#include "soc/rtc.h"
#include "soc/dport_reg.h"
#include "soc/spi_reg.h"
#include "soc/spi_struct.h"
#include "driver/gpio.h"
#include "hal/gpio_hal.h"
#include "esp_timer.h"
#include "esp_log.h"
// define Arduino-style macros
#define LOW (0x0)
#define HIGH (0x1)
#define INPUT (0x01)
#define OUTPUT (0x03)
#define RISING (0x01)
#define FALLING (0x02)
#define NOP() asm volatile ("nop")
#define MATRIX_DETACH_OUT_SIG (0x100)
#define MATRIX_DETACH_IN_LOW_PIN (0x30)
// all of the following is needed to calculate SPI clock divider
#define ClkRegToFreq(reg) (apb_freq / (((reg)->clkdiv_pre + 1) * ((reg)->clkcnt_n + 1)))
typedef union {
uint32_t value;
struct {
uint32_t clkcnt_l: 6;
uint32_t clkcnt_h: 6;
uint32_t clkcnt_n: 6;
uint32_t clkdiv_pre: 13;
uint32_t clk_equ_sysclk: 1;
};
} spiClk_t;
uint32_t getApbFrequency() {
rtc_cpu_freq_config_t conf;
rtc_clk_cpu_freq_get_config(&conf);
if(conf.freq_mhz >= 80) {
return(80 * MHZ);
}
return((conf.source_freq_mhz * MHZ) / conf.div);
}
uint32_t spiFrequencyToClockDiv(uint32_t freq) {
uint32_t apb_freq = getApbFrequency();
if(freq >= apb_freq) {
return SPI_CLK_EQU_SYSCLK;
}
const spiClk_t minFreqReg = { 0x7FFFF000 };
uint32_t minFreq = ClkRegToFreq((spiClk_t*) &minFreqReg);
if(freq < minFreq) {
return minFreqReg.value;
}
uint8_t calN = 1;
spiClk_t bestReg = { 0 };
int32_t bestFreq = 0;
while(calN <= 0x3F) {
spiClk_t reg = { 0 };
int32_t calFreq;
int32_t calPre;
int8_t calPreVari = -2;
reg.clkcnt_n = calN;
while(calPreVari++ <= 1) {
calPre = (((apb_freq / (reg.clkcnt_n + 1)) / freq) - 1) + calPreVari;
if(calPre > 0x1FFF) {
reg.clkdiv_pre = 0x1FFF;
} else if(calPre <= 0) {
reg.clkdiv_pre = 0;
} else {
reg.clkdiv_pre = calPre;
}
reg.clkcnt_l = ((reg.clkcnt_n + 1) / 2);
calFreq = ClkRegToFreq(&reg);
if(calFreq == (int32_t) freq) {
memcpy(&bestReg, &reg, sizeof(bestReg));
break;
} else if(calFreq < (int32_t) freq) {
if(RADIOLIB_ABS(freq - calFreq) < RADIOLIB_ABS(freq - bestFreq)) {
bestFreq = calFreq;
memcpy(&bestReg, &reg, sizeof(bestReg));
}
}
}
if(calFreq == (int32_t) freq) {
break;
}
calN++;
}
return(bestReg.value);
}
// create a new ESP-IDF hardware abstraction layer
// the HAL must inherit from the base RadioLibHal class
// and implement all of its virtual methods
// this is pretty much just copied from Arduino ESP32 core
class EspHal : public RadioLibHal {
public:
// default constructor - initializes the base HAL and any needed private members
EspHal(int8_t sck, int8_t miso, int8_t mosi)
: RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING),
spiSCK(sck), spiMISO(miso), spiMOSI(mosi) {
}
void init() override {
// we only need to init the SPI here
spiBegin();
}
void term() override {
// we only need to stop the SPI here
spiEnd();
}
// GPIO-related methods (pinMode, digitalWrite etc.) should check
// RADIOLIB_NC as an alias for non-connected pins
void pinMode(uint32_t pin, uint32_t mode) override {
if(pin == RADIOLIB_NC) {
return;
}
gpio_hal_context_t gpiohal;
gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0);
gpio_config_t conf = {
.pin_bit_mask = (1ULL<<pin),
.mode = (gpio_mode_t)mode,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = (gpio_int_type_t)gpiohal.dev->pin[pin].int_type,
};
gpio_config(&conf);
}
void digitalWrite(uint32_t pin, uint32_t value) override {
if(pin == RADIOLIB_NC) {
return;
}
gpio_set_level((gpio_num_t)pin, value);
}
uint32_t digitalRead(uint32_t pin) override {
if(pin == RADIOLIB_NC) {
return(0);
}
return(gpio_get_level((gpio_num_t)pin));
}
void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override {
if(interruptNum == RADIOLIB_NC) {
return;
}
gpio_install_isr_service((int)ESP_INTR_FLAG_IRAM);
gpio_set_intr_type((gpio_num_t)interruptNum, (gpio_int_type_t)(mode & 0x7));
// this uses function typecasting, which is not defined when the functions have different signatures
// untested and might not work
gpio_isr_handler_add((gpio_num_t)interruptNum, (void (*)(void*))interruptCb, NULL);
}
void detachInterrupt(uint32_t interruptNum) override {
if(interruptNum == RADIOLIB_NC) {
return;
}
gpio_isr_handler_remove((gpio_num_t)interruptNum);
gpio_wakeup_disable((gpio_num_t)interruptNum);
gpio_set_intr_type((gpio_num_t)interruptNum, GPIO_INTR_DISABLE);
}
void delay(unsigned long ms) override {
vTaskDelay(ms / portTICK_PERIOD_MS);
}
void delayMicroseconds(unsigned long us) override {
uint64_t m = (uint64_t)esp_timer_get_time();
if(us) {
uint64_t e = (m + us);
if(m > e) { // overflow
while((uint64_t)esp_timer_get_time() > e) {
NOP();
}
}
while((uint64_t)esp_timer_get_time() < e) {
NOP();
}
}
}
unsigned long millis() override {
return((unsigned long)(esp_timer_get_time() / 1000ULL));
}
unsigned long micros() override {
return((unsigned long)(esp_timer_get_time()));
}
long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override {
if(pin == RADIOLIB_NC) {
return(0);
}
this->pinMode(pin, INPUT);
uint32_t start = this->micros();
uint32_t curtick = this->micros();
while(this->digitalRead(pin) == state) {
if((this->micros() - curtick) > timeout) {
return(0);
}
}
return(this->micros() - start);
}
void spiBegin() {
// enable peripheral
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI2_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI2_RST);
// reset the control struct
this->spi->slave.trans_done = 0;
this->spi->slave.val = 0;
this->spi->pin.val = 0;
this->spi->user.val = 0;
this->spi->user1.val = 0;
this->spi->ctrl.val = 0;
this->spi->ctrl1.val = 0;
this->spi->ctrl2.val = 0;
this->spi->clock.val = 0;
this->spi->user.usr_mosi = 1;
this->spi->user.usr_miso = 1;
this->spi->user.doutdin = 1;
for(uint8_t i = 0; i < 16; i++) {
this->spi->data_buf[i] = 0x00000000;
}
// set SPI mode 0
this->spi->pin.ck_idle_edge = 0;
this->spi->user.ck_out_edge = 0;
// set bit order to MSB first
this->spi->ctrl.wr_bit_order = 0;
this->spi->ctrl.rd_bit_order = 0;
// set the clock
this->spi->clock.val = spiFrequencyToClockDiv(2000000);
// initialize pins
this->pinMode(this->spiSCK, OUTPUT);
this->pinMode(this->spiMISO, INPUT);
this->pinMode(this->spiMOSI, OUTPUT);
gpio_matrix_out(this->spiSCK, HSPICLK_OUT_IDX, false, false);
gpio_matrix_in(this->spiMISO, HSPIQ_OUT_IDX, false);
gpio_matrix_out(this->spiMOSI, HSPID_IN_IDX, false, false);
}
void spiBeginTransaction() {
// not needed - in ESP32 Arduino core, this function
// repeats clock div, mode and bit order configuration
}
uint8_t spiTransferByte(uint8_t b) {
this->spi->mosi_dlen.usr_mosi_dbitlen = 7;
this->spi->miso_dlen.usr_miso_dbitlen = 7;
this->spi->data_buf[0] = b;
this->spi->cmd.usr = 1;
while(this->spi->cmd.usr);
return(this->spi->data_buf[0] & 0xFF);
}
void spiTransfer(uint8_t* out, size_t len, uint8_t* in) {
for(size_t i = 0; i < len; i++) {
in[i] = this->spiTransferByte(out[i]);
}
}
void spiEndTransaction() {
// nothing needs to be done here
}
void spiEnd() {
// detach pins
gpio_matrix_out(this->spiSCK, MATRIX_DETACH_OUT_SIG, false, false);
gpio_matrix_in(this->spiMISO, MATRIX_DETACH_IN_LOW_PIN, false);
gpio_matrix_out(this->spiMOSI, MATRIX_DETACH_OUT_SIG, false, false);
}
private:
// the HAL can contain any additional private members
int8_t spiSCK;
int8_t spiMISO;
int8_t spiMOSI;
spi_dev_t * spi = (volatile spi_dev_t *)(DR_REG_SPI2_BASE);
};
#endif

View file

@ -17,7 +17,7 @@
#include <RadioLib.h>
// include the hardware abstraction layer
#include "hal/ESP-IDF/EspHal.h"
#include "EspHal.h"
// create a new instance of the HAL class
EspHal* hal = new EspHal(5, 19, 27);

View file

@ -50,7 +50,21 @@ add_executable(${PROJECT_NAME} main.cpp)
# The build system for libtock-c is a bit odd and the version of libraries
# built changes based on compiler version.
if (RISCV_BUILD)
if(EXISTS "$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0")
if(EXISTS "$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-14.1.0")
target_link_libraries(${PROJECT_NAME} PUBLIC
RadioLib
$ENV{LIBTOCK_C_DIRECTORY}/libtock/build/rv32imc/libtock.a
$ENV{LIBTOCK_C_DIRECTORY}/libtock-sync/build/rv32imc/libtocksync.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-14.1.0/riscv/lib/gcc/riscv64-unknown-elf/14.1.0/rv32i/ilp32/libgcc.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-14.1.0/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libstdc++.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.4.0.20231231/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.4.0.20231231/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libm.a
)
target_include_directories(RadioLib AFTER PUBLIC
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.3.0.20230120/riscv/riscv64-unknown-elf/include/
)
elseif(EXISTS "$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0")
target_link_libraries(${PROJECT_NAME} PUBLIC
RadioLib
$ENV{LIBTOCK_C_DIRECTORY}/libtock/build/rv32imc/libtock.a
@ -80,7 +94,17 @@ if (RISCV_BUILD)
)
endif()
else()
if(EXISTS "$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0")
if (EXISTS "$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-14.1.0")
target_link_libraries(${PROJECT_NAME} PUBLIC
RadioLib
$ENV{LIBTOCK_C_DIRECTORY}/libtock/build/cortex-m4/libtock.a
$ENV{LIBTOCK_C_DIRECTORY}/libtock-sync/build/cortex-m4/libtocksync.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-14.1.0/arm/lib/gcc/arm-none-eabi/14.1.0/libgcc.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-14.1.0/arm/arm-none-eabi/lib/libstdc++.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.4.0.20231231/arm/arm-none-eabi/lib/libc.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.4.0.20231231/arm/arm-none-eabi/lib/libm.a
)
elseif(EXISTS "$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0")
target_link_libraries(${PROJECT_NAME} PUBLIC
RadioLib
$ENV{LIBTOCK_C_DIRECTORY}/libtock/build/cortex-m4/libtock.a

View file

@ -23,7 +23,7 @@ The RadioLib example can be built with:
$ git clone https://github.com/jgromes/RadioLib.git
$ cd RadioLib/examples/NonArduino/Tock/
$ git clone https://github.com/tock/libtock-c.git
$ cd libtock-c; git checkout dbee65a56d74b4bad166317f199e80b959f7c82c; cd ../
$ cd libtock-c; git checkout c0202f9ab78da4a6e95f136cf5250701e3778f63; cd ../
$ LIBTOCK_C_DIRECTORY="$(pwd)/libtock-c" ./build.sh
```

View file

@ -3,9 +3,9 @@ set -e
rm -rf ./build-*
cd libtock-c/examples/cxx_hello
pushd ${LIBTOCK_C_DIRECTORY}/examples/cxx_hello
make -j4
cd ../../../
popd
mkdir -p build-arm
cd build-arm

View file

@ -28,14 +28,14 @@
#include <RadioLib.h>
// include the hardware abstraction layer
#include "hal/Tock/libtockHal.h"
#include "RadioLib/libtockHal.h"
// the entry point for the program
int main(void) {
printf("[SX1261] Initialising Radio ... \r\n");
// create a new instance of the HAL class
TockHal* hal = new TockHal();
TockRadioLibHal* hal = new TockRadioLibHal();
// now we can create the radio module
// pinout corresponds to the SparkFun LoRa Thing Plus - expLoRaBLE
@ -43,7 +43,7 @@ int main(void) {
// DIO1 pin: 2
// NRST pin: 4
// BUSY pin: 1
Module* tock_module = new Module(hal, RADIO_NSS, RADIO_DIO_1, RADIO_RESET, RADIO_BUSY);
Module* tock_module = new Module(hal, RADIOLIB_RADIO_NSS, RADIOLIB_RADIO_DIO_1, RADIOLIB_RADIO_RESET, RADIOLIB_RADIO_BUSY);
SX1262* radio = new SX1262(tock_module);
// Setup the radio