Skip to content

Commit

Permalink
support for Raspberry Pi Pico added
Browse files Browse the repository at this point in the history
  • Loading branch information
jandelgado committed Feb 13, 2021
1 parent 64b268a commit e43f426
Show file tree
Hide file tree
Showing 12 changed files with 293 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# JLed changelog (github.com/jandelgado/jled)

## [2021-02-02] 4.7.0

* new: support for Raspberry Pi Pico added

## [2021-02-02] 4.6.1

* fix: `Forever()` on sequence had no effect (#68)
Expand Down
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# this CMakeLists.txt file is needed to include JLed in raspi pico projects
add_library (JLed src/jled_base.cpp)
target_include_directories (JLed PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)

2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ all:
pio run

lint:
cpplint --extensions=cpp,h,ino $(shell find . \( ! -regex '.*/\..*' \) \
cpplint --extensions=cpp,h,ino $(shell find . -maxdepth 3 \( ! -regex '.*/\..*' \) \
-type f -a \( -name "*\.cpp" -o -name "*\.h" -o -name "*\.ino" \) )

ci:
Expand Down
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and someone did a [video tutorial for JLed](https://youtu.be/x5V2vdpZq1w) - Tha
<p float="left">
<a href="examples/multiled"><img alt="breathing, blinking, fadeon and -off at the same time" height=200 src="doc/jled.gif"></a>
<a href="https://jandelgado.github.io/jled-wasm"><img alt="jled running in the browser" height=200 src="doc/jled-wasm.png"></a>
(click on the image for a demo)
</p>

## Example
Expand Down Expand Up @@ -73,6 +74,7 @@ void loop() {
* [ESP32](#esp32)
* [STM32](#stm32)
* [Arduino framework](#arduino-framework)
* [Raspberry Pi Pico](#raspberry-pi-pico)
* [Example sketches](#example-sketches)
* [PlatformIO](#platformio-1)
* [Arduino IDE](#arduino-ide-1)
Expand All @@ -96,8 +98,9 @@ void loop() {
* supports inverted polarity of LED
* easy configuration using fluent interface
* can control groups of LEDs sequentially or in parallel
* Portable: Arduino, ESP8266, ESP32, Mbed etc platform compatible, runs even in the [browser](https://jandelgado.github.io/jled-wasm)
* supports Arduino and [mbed](www.mbed.com) frameworks
* Portable: Arduino, ESP8266, ESP32, Mbed, Raspberry Pi Pico and more platform
compatible, runs even in the [browser](https://jandelgado.github.io/jled-wasm)
* supports Arduino, [mbed](www.mbed.com) and Raspberry Pi Pico SDKs
* well [tested](https://coveralls.io/github/jandelgado/jled)

## Cheat Sheet
Expand Down Expand Up @@ -484,6 +487,12 @@ core](https://github.com/rogerclarkmelbourne/Arduino_STM32/tree/master/STM32F4)
and compiling examples from the Arduino IDE. Note that the `stlink` is
necessary to upload sketches to the microcontroller.

### Raspberry Pi Pico

When using JLed on a Raspberry Pi Pico, the Pico-SDK and tools must be
installed. The Pico supports up to 16 PWM channels in parallel. See
[pico-demo](examples/pico-demo) for an example and build instructions.

## Example sketches

Example sketches are provided in the [examples](examples/) directory.
Expand All @@ -501,6 +510,7 @@ Example sketches are provided in the [examples](examples/) directory.
* [Morsecode example](examples/morse)
* [Custom HAL example](examples/custom_hal)
* [JLed compiled for WASM and running in the browser](https://jandelgado.github.io/jled-wasm)
* [Raspberry Pi Pico Demo](examples/raspi_pico)

### PlatformIO

Expand Down
15 changes: 15 additions & 0 deletions examples/raspi_pico/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
CMakeFiles/
elf2uf2/
cmake_install.cmake/
generated/
pico-sdk/
build/
CMakeCache.txt
Makefile
cmake_install.cmake
*.bin
*.dis
*.elf
*.map
*.hex
*.uf2
39 changes: 39 additions & 0 deletions examples/raspi_pico/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Generated Cmake Pico project file
cmake_minimum_required(VERSION 3.13)

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

# initalize pico_sdk from installed location
# (note this can come from environment, CMake cache etc)
#set(PICO_SDK_PATH "/home/paco/src/pico-sdk")

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

project(pico_demo C CXX ASM)

# Initialise the Pico SDK
pico_sdk_init()

# Add executable. Default name is the project name, version 0.1

add_executable(pico_demo pico_demo.cpp )

pico_set_program_name(pico_demo "pico_demo")
pico_set_program_version(pico_demo "0.1")

pico_enable_stdio_uart(pico_demo 1)
pico_enable_stdio_usb(pico_demo 0)

# Add the standard library to the build
target_link_libraries(pico_demo pico_stdlib hardware_pwm JLed)

pico_add_extra_outputs(pico_demo)

#add_library(jled STATIC ${CMAKE_CURRENT_SOURCE_DIR}/../jled/src)
#include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../jled/src)
#add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../jled build)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../..src)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../.. build)

21 changes: 21 additions & 0 deletions examples/raspi_pico/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# JLed for the Raspberry Pi Pico

This examples demonstrates how to use JLed on the Raspberry Pi Pico. The
built-in LED and a LED on GPIO 16 will be faded.

You need the [pico-sdk](https://github.com/raspberrypi/pico-sdk) and
necessary tools to compile everything installed.

The `PICO_SDK_PATH` environment variable must point to the installation
directory of the SDK.

* to compile the demo sketch, run `cmake . && make`
* To deploy the demo sketch, press and hold `BOOTSEL` on the Pico and connect
the Pico to your PC. The Pico will now be mounted as an external drive. Copy
the file `pico_demo.uf2` to the mount point. The sketch should now start
automatically.

## Author

(c) Copyright 2021 by Jan Delgado, License: MIT

17 changes: 17 additions & 0 deletions examples/raspi_pico/pico_demo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// JLed demo for the Raspberry Pi Pico
// Copyright 2021 by Jan Delgado. All rights reserved.
// https://github.com/jandelgado/jled
#include "pico/stdlib.h" // NOLINT
#include "jled.h" // NOLINT

int main() {
constexpr auto LED_PIN = 25;

auto led1 = JLed(LED_PIN).FadeOff(2000).DelayAfter(1000).Forever();
auto led2 = JLed(16).FadeOn(2000).DelayAfter(1000).Forever();

while (true) {
led1.Update();
led2.Update();
}
}
62 changes: 62 additions & 0 deletions examples/raspi_pico/pico_sdk_import.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# 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 ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG master
)
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})
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=JLed
version=4.6.1
version=4.7.0
author=Jan Delgado <jdelgado[at]gmx.net>
maintainer=Jan Delgado <jdelgado[at]gmx.net>
sentence=An Arduino library to control LEDs
Expand Down
5 changes: 4 additions & 1 deletion src/jled.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@

#include "jled_base.h" // NOLINT

#if defined(__MBED__) && !defined(ARDUINO_API_VERSION)
#ifdef PICO_SDK_VERSION_MAJOR
#include "pico_hal.h" // NOLINT
namespace jled {using JLedHalType = PicoHal;}
#elif defined(__MBED__) && !defined(ARDUINO_API_VERSION)
#include "mbed_hal.h" // NOLINT
namespace jled {using JLedHalType = MbedHal;}
#elif ESP32
Expand Down
113 changes: 113 additions & 0 deletions src/pico_hal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright (c) 2021 Jan Delgado <jdelgado[at]gmx.net>
// https://github.com/jandelgado/jled
// HAL for the Raspi Pico
// This HAL uses the Raspi Pico SDK: https://github.com/raspberrypi/pico-sdk
//
// Adapted from https://pastebin.com/uVMigyFN (Scott Beasley) and
// https://github.com/raspberrypi/micropython/blob/pico/ports/rp2/machine_pwm.c
// (Copyright (c) 2020 Damien P. George)
//
// 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.
//
#ifndef SRC_PICO_HAL_H_
#define SRC_PICO_HAL_H_

namespace jled {

#include "hardware/clocks.h"
#include "hardware/pwm.h"
#include "pico/time.h"

class PicoHal {
static constexpr auto TOP_MAX = 65534;
static constexpr auto DUTY_100_PCT = 65535;
static constexpr auto DEFAULT_FREQ_HZ = 5000;

static int set_pwm_freq(uint slice, int freq, uint32_t *div,
uint32_t *top_) {
// Set the frequency, making "top_" as large as possible for maximum
// resolution.
*div = (uint32_t)(16 * clock_get_hz(clk_sys) / (uint32_t)freq);
*top_ = 1;
for (;;) {
// Try a few small prime factors to get close to the desired
// frequency.
if (*div >= 16 * 5 && *div % 5 == 0 && *top_ * 5 <= TOP_MAX) {
*div /= 5;
*top_ *= 5;
} else if (*div >= 16 * 3 && *div % 3 == 0 &&
*top_ * 3 <= TOP_MAX) {
*div /= 3;
*top_ *= 3;
} else if (*div >= 16 * 2 && *top_ * 2 <= TOP_MAX) {
*div /= 2;
*top_ *= 2;
} else {
break;
}
}

if (*div < 16) {
*div = 0;
*top_ = 0;
return -1; // freq too large
} else if (*div >= 256 * 16) {
*div = 0;
*top_ = 0;
return -2; // freq too small
}

return 0;
}

static void set_pwm_duty(uint slice, uint channel, uint32_t top,
uint32_t duty) {
const uint32_t cc = duty * (top + 1) / 65535;
pwm_set_chan_level(slice, channel, cc);
pwm_set_enabled(slice, true);
}

public:
using PinType = uint8_t;

explicit PicoHal(PinType pin) noexcept {
slice_num_ = pwm_gpio_to_slice_num(pin);
channel_ = pwm_gpio_to_channel(pin);
gpio_set_function(pin, GPIO_FUNC_PWM);

uint32_t div = 0;
set_pwm_freq(slice_num_, DEFAULT_FREQ_HZ, &div, &top_);
// TODO(jd) check return value?

pwm_set_wrap(slice_num_, top_);
}

void analogWrite(uint8_t val) const {
set_pwm_duty(slice_num_, channel_, top_,
(uint32_t)(DUTY_100_PCT / 255) * val);
}

uint32_t millis() const { return to_ms_since_boot(get_absolute_time()); }

private:
uint slice_num_, channel_;
uint32_t top_ = 0;
};
} // namespace jled
#endif // SRC_PICO_HAL_H_

0 comments on commit e43f426

Please sign in to comment.