Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

examples: NonArduino: Raspberry Pi Pico #941

Merged
merged 1 commit into from
Jan 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/NonArduino/Pico/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build/
33 changes: 33 additions & 0 deletions examples/NonArduino/Pico/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
cmake_minimum_required(VERSION 3.18)

# Pull in SDK (must be before project)
include(pico_sdk_import.cmake)

project(pico-sx1276 C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

# Initialize the SDK
pico_sdk_init()

add_compile_options(
-Wall
-Wno-format
-Wno-unused-function
)

add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib")

add_executable(${PROJECT_NAME}
main.cpp
)

# Pull in common dependencies
target_link_libraries(${PROJECT_NAME} pico_stdlib hardware_spi hardware_gpio hardware_timer RadioLib)


pico_enable_stdio_usb(${PROJECT_NAME} 1)
pico_enable_stdio_uart(${PROJECT_NAME} 0)

# Create map/bin/hex file etc.
pico_add_extra_outputs(${PROJECT_NAME})
142 changes: 142 additions & 0 deletions examples/NonArduino/Pico/PicoHal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#ifndef PICO_HAL_H
#define PICO_HAL_H

// include RadioLib
#include <RadioLib.h>

// include the necessary Pico libraries
#include <pico/stdlib.h>
#include "hardware/spi.h"
#include "hardware/timer.h"

// create a new Raspberry Pi Pico hardware abstraction
// layer using the Pico SDK
// the HAL must inherit from the base RadioLibHal class
// and implement all of its virtual methods
class PicoHal : public RadioLibHal {
public:
PicoHal(spi_inst_t *spiChannel, uint32_t misoPin, uint32_t mosiPin, uint32_t sckPin, uint32_t spiSpeed = 500 * 1000)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default SPI speed is quite low (500 kHz vs 2 MHz in Arduino). Is there a specific reason for that? Asking because of #938.

: RadioLibHal(GPIO_IN, GPIO_OUT, 0, 1, GPIO_IRQ_EDGE_RISE, GPIO_IRQ_EDGE_FALL),
_spiChannel(spiChannel),
_spiSpeed(spiSpeed),
_misoPin(misoPin),
_mosiPin(mosiPin),
_sckPin(sckPin) {
}

void init() override {
stdio_init_all();
spiBegin();
}

void term() override {
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_set_dir(pin, mode);
}

void digitalWrite(uint32_t pin, uint32_t value) override {
if (pin == RADIOLIB_NC) {
return;
}

gpio_put(pin, (bool)value);
}

uint32_t digitalRead(uint32_t pin) override {
if (pin == RADIOLIB_NC) {
return 0;
}

return gpio_get(pin);
}

void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override {
if (interruptNum == RADIOLIB_NC) {
return;
}

gpio_set_irq_enabled_with_callback(interruptNum, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, (gpio_irq_callback_t)interruptCb);
}

void detachInterrupt(uint32_t interruptNum) override {
if (interruptNum == RADIOLIB_NC) {
return;
}

gpio_set_irq_enabled_with_callback(interruptNum, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, NULL);
}

void delay(unsigned long ms) override {
sleep_ms(ms);
}

void delayMicroseconds(unsigned long us) override {
sleep_us(us);
}

unsigned long millis() override {
return to_ms_since_boot(get_absolute_time());
}

unsigned long micros() override {
return to_us_since_boot(get_absolute_time());
}

long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override {
if (pin == RADIOLIB_NC) {
return 0;
}

this->pinMode(pin, GPIO_IN);
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() {
spi_init(_spiChannel, _spiSpeed);
spi_set_format(_spiChannel, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);

gpio_set_function(_sckPin, GPIO_FUNC_SPI);
gpio_set_function(_mosiPin, GPIO_FUNC_SPI);
gpio_set_function(_misoPin, GPIO_FUNC_SPI);
}

void spiBeginTransaction() {}

void spiTransfer(uint8_t *out, size_t len, uint8_t *in) {
spi_write_read_blocking(_spiChannel, out, in, len);
}

void spiEndTransaction() {}

void spiEnd() {
spi_deinit(_spiChannel);
}

private:
// the HAL can contain any additional private members
spi_inst_t *_spiChannel;
uint32_t _spiSpeed;
uint32_t _misoPin;
uint32_t _mosiPin;
uint32_t _sckPin;
};

#endif
102 changes: 102 additions & 0 deletions examples/NonArduino/Pico/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
RadioLib Non-Arduino Raspberry Pi Pico library example

Licensed under the MIT License

Copyright (c) 2024 Cameron Goddard

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

// define pins to be used
#define SPI_PORT spi0
#define SPI_MISO 4
#define SPI_MOSI 3
#define SPI_SCK 2

#define RFM_NSS 26
#define RFM_RST 22
#define RFM_DIO0 14
#define RFM_DIO1 15

#include <pico/stdlib.h>

// include the library
#include <RadioLib.h>

// include the hardware abstraction layer
#include "PicoHal.h"

// create a new instance of the HAL class
PicoHal* hal = new PicoHal(SPI_PORT, SPI_MISO, SPI_MOSI, SPI_SCK);

// now we can create the radio module
// NSS pin: 26
// DIO0 pin: 14
// RESET pin: 22
// DIO1 pin: 15
SX1276 radio = new Module(hal, RFM_NSS, RFM_DIO0, RFM_RST, RFM_DIO1);


int main() {
stdio_init_all();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably not needed to call this here, as stdio_init_all() is called from PicoHal::init(), which is in turn called in Module::init() as the first step in radio.begin()


gpio_init(RFM_NSS);
gpio_init(RFM_RST);

gpio_set_dir(RFM_NSS, GPIO_OUT);
gpio_set_dir(RFM_RST, GPIO_OUT);
Comment on lines +60 to +64
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pin direction configuration is handled by the library. However, if it requires a call to gpio_init, I would propose to move this call to PicoHal::pinMode.


// reset the RF module

sleep_ms(10);
gpio_put(RFM_RST, 0);
sleep_ms(10);
gpio_put(RFM_RST, 1);
Comment on lines +66 to +71
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this is not needed, the module will be reset during radio.begin().

Just trying to remove the redundant portions of code ;)


// initialize just like with Arduino
printf("[SX1276] Initializing ... ");
int state = radio.begin();
if (state != RADIOLIB_ERR_NONE) {
printf("failed, code %d\n", state);
return(1);
}
printf("success!\n");

// loop forever
for(;;) {
// send a packet
printf("[SX1276] Transmitting packet ... ");
state = radio.transmit("Hello World!");
if(state == RADIOLIB_ERR_NONE) {
// the packet was successfully transmitted
printf("success!\n");

// wait for a second before transmitting again
hal->delay(1000);

} else {
printf("failed, code %d\n", state);

}

}

return(0);
}
73 changes: 73 additions & 0 deletions examples/NonArduino/Pico/pico_sdk_import.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake

# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()

if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()

if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()

if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()

set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")

if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT)
include(FetchContent)
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
if (PICO_SDK_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif ()
# GIT_SUBMODULES_RECURSE was added in 3.17
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG master
GIT_SUBMODULES_RECURSE FALSE
)
else ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG master
)
endif ()

if (NOT pico_sdk)
message("Downloading Raspberry Pi Pico SDK")
FetchContent_Populate(pico_sdk)
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
endif ()
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
else ()
message(FATAL_ERROR
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
)
endif ()
endif ()

get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()

set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
endif ()

set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)

include(${PICO_SDK_INIT_CMAKE_FILE})
Loading