kopia lustrzana https://github.com/pimoroni/pimoroni-pico
commit
852fdcaa45
|
@ -743,6 +743,13 @@ namespace pimoroni {
|
|||
return encoder_offset[channel] + value;
|
||||
}
|
||||
|
||||
void IOExpander::clear_rotary_encoder(uint8_t channel) {
|
||||
channel -= 1;
|
||||
encoder_last[channel] = 0;
|
||||
uint8_t reg = ENC_COUNT[channel];
|
||||
i2c->reg_write_uint8(address, reg, 0);
|
||||
}
|
||||
|
||||
uint8_t IOExpander::get_bit(uint8_t reg, uint8_t bit) {
|
||||
// Returns the specified bit (nth position from right) from a register
|
||||
return i2c->reg_read_uint8(address, reg) & (1 << bit);
|
||||
|
|
|
@ -214,6 +214,7 @@ namespace pimoroni {
|
|||
|
||||
void setup_rotary_encoder(uint8_t channel, uint8_t pin_a, uint8_t pin_b, uint8_t pin_c = 0, bool count_microsteps = false);
|
||||
int16_t read_rotary_encoder(uint8_t channel);
|
||||
void clear_rotary_encoder(uint8_t channel);
|
||||
|
||||
private:
|
||||
uint8_t i2c_reg_read_uint8(uint8_t reg);
|
||||
|
|
|
@ -16,6 +16,8 @@ add_subdirectory(breakout_msa301)
|
|||
add_subdirectory(breakout_bme688)
|
||||
add_subdirectory(breakout_bmp280)
|
||||
add_subdirectory(breakout_bme280)
|
||||
add_subdirectory(breakout_as7262)
|
||||
add_subdirectory(breakout_bh1745)
|
||||
|
||||
add_subdirectory(pico_display)
|
||||
add_subdirectory(pico_unicorn)
|
||||
|
@ -30,5 +32,5 @@ add_subdirectory(pico_tof_display)
|
|||
add_subdirectory(pico_trackball_display)
|
||||
add_subdirectory(pico_audio)
|
||||
add_subdirectory(pico_wireless)
|
||||
add_subdirectory(breakout_as7262)
|
||||
add_subdirectory(breakout_bh1745)
|
||||
|
||||
add_subdirectory(plasma_2040)
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
include(plasma2040_rotary.cmake)
|
||||
include(plasma2040_rainbow.cmake)
|
|
@ -0,0 +1,10 @@
|
|||
add_executable(plasma2040_rainbow plasma2040_rainbow.cpp)
|
||||
|
||||
target_link_libraries(plasma2040_rainbow
|
||||
pico_stdlib
|
||||
plasma2040
|
||||
rgbled
|
||||
button
|
||||
)
|
||||
|
||||
pico_add_extra_outputs(plasma2040_rainbow)
|
|
@ -0,0 +1,66 @@
|
|||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <cstdint>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#include "plasma2040.hpp"
|
||||
|
||||
#include "common/pimoroni_common.hpp"
|
||||
#include "rgbled.hpp"
|
||||
#include "button.hpp"
|
||||
|
||||
/*
|
||||
Press "B" to speed up the LED cycling effect.
|
||||
Press "A" to slow it down again.
|
||||
*/
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
// Set how many LEDs you have
|
||||
const uint N_LEDS = 30;
|
||||
|
||||
// Pick *one* LED type by uncommenting the relevant line below:
|
||||
|
||||
// APA102-style LEDs with Data/Clock lines. AKA DotStar
|
||||
//plasma::APA102 led_strip(N_LEDS, pio0, 0, plasma::PIN_DAT, plasma::PIN_CLK);
|
||||
|
||||
// WS28X-style LEDs with a single signal line. AKA NeoPixel
|
||||
// by default the WS2812 LED strip will be 400KHz, RGB with no white element
|
||||
plasma::WS2812 led_strip(N_LEDS, pio0, 0, plasma::PIN_DAT);
|
||||
|
||||
Button button_a(plasma::BUTTON_A, Polarity::ACTIVE_LOW, 50);
|
||||
Button button_b(plasma::BUTTON_B, Polarity::ACTIVE_LOW, 50);
|
||||
RGBLED led(plasma::LED_R, plasma::LED_G, plasma::LED_B);
|
||||
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
led_strip.start(60);
|
||||
|
||||
int speed = 10;
|
||||
float offset = 0.0f;
|
||||
|
||||
while (true) {
|
||||
bool a = button_a.read();
|
||||
bool b = button_b.read();
|
||||
|
||||
if(a) speed--;
|
||||
if(b) speed++;
|
||||
speed = std::min((int)255, std::max((int)1, speed));
|
||||
|
||||
offset += float(speed) / 2000.0f;
|
||||
|
||||
for(auto i = 0u; i < led_strip.num_leds; ++i) {
|
||||
float hue = float(i) / led_strip.num_leds;
|
||||
led_strip.set_hsv(i, hue + offset, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
led.set_rgb(speed, 0, 255 - speed);
|
||||
|
||||
// Sleep time controls the rate at which the LED buffer is updated
|
||||
// but *not* the actual framerate at which the buffer is sent to the LEDs
|
||||
sleep_ms(1000 / 60);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
add_executable(plasma2040_rotary plasma2040_rotary.cpp)
|
||||
|
||||
target_link_libraries(plasma2040_rotary
|
||||
pico_stdlib
|
||||
plasma2040
|
||||
breakout_encoder
|
||||
pimoroni_i2c
|
||||
rgbled
|
||||
button
|
||||
)
|
||||
|
||||
pico_add_extra_outputs(plasma2040_rotary)
|
|
@ -0,0 +1,152 @@
|
|||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <cstdint>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#include "plasma2040.hpp"
|
||||
|
||||
#include "common/pimoroni_common.hpp"
|
||||
#include "breakout_encoder.hpp"
|
||||
#include "rgbled.hpp"
|
||||
#include "button.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
// Set how many LEDs you have
|
||||
const uint N_LEDS = 30;
|
||||
|
||||
// Pick *one* LED type by uncommenting the relevant line below:
|
||||
|
||||
// APA102-style LEDs with Data/Clock lines. AKA DotStar
|
||||
//plasma::APA102 led_strip(N_LEDS, pio0, 0, plasma::PIN_DAT, plasma::PIN_CLK);
|
||||
|
||||
// WS28X-style LEDs with a single signal line. AKA NeoPixel
|
||||
plasma::WS2812 led_strip(N_LEDS, pio0, 0, plasma::PIN_DAT);
|
||||
|
||||
|
||||
|
||||
Button button_a(plasma::BUTTON_A);
|
||||
Button button_b(plasma::BUTTON_B);
|
||||
|
||||
RGBLED led(plasma::LED_R, plasma::LED_G, plasma::LED_B);
|
||||
|
||||
I2C i2c(BOARD::PICO_EXPLORER);
|
||||
BreakoutEncoder enc(&i2c);
|
||||
|
||||
enum ENCODER_MODE {
|
||||
COLOUR,
|
||||
ANGLE,
|
||||
BRIGHTNESS,
|
||||
TIME
|
||||
};
|
||||
|
||||
|
||||
void colour_cycle(float hue, float t, float angle) {
|
||||
t /= 200.0f;
|
||||
|
||||
for (auto i = 0u; i < led_strip.num_leds; ++i) {
|
||||
float offset = (M_PI * i) / led_strip.num_leds;
|
||||
offset = sinf(offset + t) * angle;
|
||||
led_strip.set_hsv(i, (hue + offset) / 360.0f, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void gauge(uint v, uint vmax = 100) {
|
||||
uint light_pixels = led_strip.num_leds * v / vmax;
|
||||
|
||||
for (auto i = 0u; i < led_strip.num_leds; ++i) {
|
||||
if(i < light_pixels) {
|
||||
led_strip.set_rgb(i, 0, 255, 0);
|
||||
} else {
|
||||
led_strip.set_rgb(i, 255, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
led_strip.start(60);
|
||||
|
||||
bool encoder_detected = enc.init();
|
||||
enc.clear_interrupt_flag();
|
||||
|
||||
int speed = 50;
|
||||
float hue = 0;
|
||||
int angle = 120;
|
||||
int8_t brightness = 16;
|
||||
bool cycle = true;
|
||||
ENCODER_MODE mode = ENCODER_MODE::COLOUR;
|
||||
while (true) {
|
||||
uint32_t t = millis();
|
||||
if(encoder_detected) {
|
||||
if(enc.get_interrupt_flag()) {
|
||||
int count = enc.read();
|
||||
enc.clear_interrupt_flag();
|
||||
enc.clear();
|
||||
|
||||
cycle = false;
|
||||
switch(mode) {
|
||||
case ENCODER_MODE::COLOUR:
|
||||
hue += count;
|
||||
brightness = std::min((int8_t)359, brightness);
|
||||
brightness = std::max((int8_t)0, brightness);
|
||||
colour_cycle(hue, 0, (float)angle);
|
||||
break;
|
||||
case ENCODER_MODE::ANGLE:
|
||||
angle += count;
|
||||
angle = std::min((int)359, angle);
|
||||
angle = std::max((int)0, angle);
|
||||
colour_cycle(hue, 0, (float)angle);
|
||||
break;
|
||||
case ENCODER_MODE::BRIGHTNESS:
|
||||
brightness += count;
|
||||
brightness = std::min((int8_t)31, brightness);
|
||||
brightness = std::max((int8_t)0, brightness);
|
||||
led_strip.set_brightness(brightness);
|
||||
gauge(brightness, 31);
|
||||
break;
|
||||
case ENCODER_MODE::TIME:
|
||||
speed += count;
|
||||
speed = std::min((int)100, speed);
|
||||
speed = std::max((int)0, speed);
|
||||
gauge(speed, 100);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool a_pressed = button_a.read();
|
||||
bool b_pressed = button_b.read();
|
||||
|
||||
if(b_pressed) cycle = true;
|
||||
|
||||
switch(mode) {
|
||||
case ENCODER_MODE::COLOUR:
|
||||
led.set_rgb(255, 0, 0);
|
||||
if(a_pressed) mode = ENCODER_MODE::ANGLE;
|
||||
break;
|
||||
case ENCODER_MODE::ANGLE:
|
||||
led.set_rgb(255, 255, 0);
|
||||
if(a_pressed) mode = ENCODER_MODE::BRIGHTNESS;
|
||||
break;
|
||||
case ENCODER_MODE::BRIGHTNESS:
|
||||
led.set_rgb(0, 255, 0);
|
||||
if(a_pressed) mode = ENCODER_MODE::TIME;
|
||||
break;
|
||||
case ENCODER_MODE::TIME:
|
||||
led.set_rgb(0, 0, 255);
|
||||
if(a_pressed) mode = ENCODER_MODE::COLOUR;
|
||||
break;
|
||||
}
|
||||
|
||||
if(cycle) colour_cycle(hue, t * speed / 100, (float)angle);
|
||||
|
||||
auto first_led = led_strip.get(0);
|
||||
enc.set_led(first_led.r, first_led.g, first_led.b);
|
||||
|
||||
// Sleep time controls the rate at which the LED buffer is updated
|
||||
// but *not* the actual framerate at which the buffer is sent to the LEDs
|
||||
sleep_ms(1000 / 60);
|
||||
}
|
||||
}
|
|
@ -22,3 +22,4 @@ add_subdirectory(pico_scroll)
|
|||
add_subdirectory(pico_explorer)
|
||||
add_subdirectory(pico_rgb_keypad)
|
||||
add_subdirectory(pico_wireless)
|
||||
add_subdirectory(plasma2040)
|
||||
|
|
|
@ -87,6 +87,10 @@ namespace pimoroni {
|
|||
return (ioe.get_interrupt_flag() > 0);
|
||||
}
|
||||
|
||||
void BreakoutEncoder::clear() {
|
||||
ioe.clear_rotary_encoder(ENC_CHANNEL);
|
||||
}
|
||||
|
||||
int16_t BreakoutEncoder::read() {
|
||||
int16_t count = ioe.read_rotary_encoder(ENC_CHANNEL);
|
||||
if(direction != DIRECTION_CW)
|
||||
|
|
|
@ -23,7 +23,6 @@ namespace pimoroni {
|
|||
static const uint8_t DEFAULT_I2C_ADDRESS = 0x0F;
|
||||
static constexpr float DEFAULT_BRIGHTNESS = 1.0f; //Effectively the maximum fraction of the period that the LED will be on
|
||||
static const Direction DEFAULT_DIRECTION = DIRECTION_CW;
|
||||
static const uint8_t PIN_UNUSED = UINT8_MAX;
|
||||
static const uint32_t DEFAULT_TIMEOUT = 1;
|
||||
|
||||
private:
|
||||
|
@ -90,6 +89,7 @@ namespace pimoroni {
|
|||
|
||||
bool available();
|
||||
int16_t read();
|
||||
void clear();
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
include(plasma2040.cmake)
|
|
@ -0,0 +1,98 @@
|
|||
#include "apa102.hpp"
|
||||
|
||||
namespace plasma {
|
||||
|
||||
APA102::APA102(uint num_leds, PIO pio, uint sm, uint pin_dat, uint pin_clk, uint freq, RGB* buffer) : buffer(buffer), num_leds(num_leds), pio(pio), sm(sm) {
|
||||
uint offset = pio_add_program(pio, &apa102_program);
|
||||
|
||||
pio_sm_set_pins_with_mask(pio, sm, 0, (1u << pin_clk) | (1u << pin_dat));
|
||||
pio_sm_set_pindirs_with_mask(pio, sm, ~0u, (1u << pin_clk) | (1u << pin_dat));
|
||||
pio_gpio_init(pio, pin_clk);
|
||||
pio_gpio_init(pio, pin_dat);
|
||||
|
||||
pio_sm_config c = apa102_program_get_default_config(offset);
|
||||
sm_config_set_out_pins(&c, pin_dat, 1);
|
||||
sm_config_set_sideset_pins(&c, pin_clk);
|
||||
|
||||
sm_config_set_out_shift(&c, false, true, 32);
|
||||
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
||||
|
||||
// The PIO program transmits 1 bit every 2 execution cycles
|
||||
float div = (float)clock_get_hz(clk_sys) / (2 * freq);
|
||||
sm_config_set_clkdiv(&c, div);
|
||||
|
||||
pio_sm_init(pio, sm, offset, &c);
|
||||
pio_sm_set_enabled(pio, sm, true);
|
||||
|
||||
dma_channel = dma_claim_unused_channel(true);
|
||||
dma_channel_config config = dma_channel_get_default_config(dma_channel);
|
||||
channel_config_set_bswap(&config, true);
|
||||
channel_config_set_dreq(&config, pio_get_dreq(pio, sm, true));
|
||||
channel_config_set_transfer_data_size(&config, DMA_SIZE_32);
|
||||
channel_config_set_read_increment(&config, true);
|
||||
dma_channel_configure(dma_channel, &config, &pio->txf[sm], NULL, 0, false);
|
||||
|
||||
if(this->buffer == nullptr) {
|
||||
this->buffer = new RGB[num_leds];
|
||||
}
|
||||
}
|
||||
|
||||
bool APA102::dma_timer_callback(struct repeating_timer *t) {
|
||||
((APA102*)t->user_data)->update();
|
||||
return true;
|
||||
}
|
||||
|
||||
void APA102::update(bool blocking) {
|
||||
if(dma_channel_is_busy(dma_channel) && !blocking) return;
|
||||
while(dma_channel_is_busy(dma_channel)) {}; // Block waiting for DMA finish
|
||||
pio->txf[sm] = 0x00000000; // Output the APA102 start-of-frame bytes
|
||||
dma_channel_set_trans_count(dma_channel, num_leds, false);
|
||||
dma_channel_set_read_addr(dma_channel, buffer, true);
|
||||
if (!blocking) return;
|
||||
while(dma_channel_is_busy(dma_channel)) {}; // Block waiting for DMA finish
|
||||
}
|
||||
|
||||
bool APA102::start(uint fps) {
|
||||
add_repeating_timer_ms(-(1000 / fps), dma_timer_callback, (void*)this, &timer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool APA102::stop() {
|
||||
return cancel_repeating_timer(&timer);
|
||||
}
|
||||
|
||||
void APA102::clear() {
|
||||
for (auto i = 0u; i < num_leds; ++i) {
|
||||
set_rgb(i, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void APA102::set_hsv(uint32_t index, float h, float s, float v) {
|
||||
float i = floor(h * 6.0f);
|
||||
float f = h * 6.0f - i;
|
||||
v *= 255.0f;
|
||||
uint8_t p = v * (1.0f - s);
|
||||
uint8_t q = v * (1.0f - f * s);
|
||||
uint8_t t = v * (1.0f - (1.0f - f) * s);
|
||||
|
||||
switch (int(i) % 6) {
|
||||
case 0: set_rgb(index, v, t, p); break;
|
||||
case 1: set_rgb(index, q, v, p); break;
|
||||
case 2: set_rgb(index, p, v, t); break;
|
||||
case 3: set_rgb(index, p, q, v); break;
|
||||
case 4: set_rgb(index, t, p, v); break;
|
||||
case 5: set_rgb(index, v, p, q); break;
|
||||
}
|
||||
}
|
||||
|
||||
void APA102::set_rgb(uint32_t index, uint8_t r, uint8_t g, uint8_t b) {
|
||||
buffer[index].rgb(r, g, b);
|
||||
}
|
||||
|
||||
void APA102::set_brightness(uint8_t b) {
|
||||
for (auto i = 0u; i < num_leds; ++i) {
|
||||
buffer[i].brightness(b);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/*
|
||||
This code is significantly modified from the PIO apa102 example
|
||||
found here: https://github.com/raspberrypi/pico-examples/tree/master/pio/apa102
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math.h>
|
||||
#include <cstdint>
|
||||
|
||||
#include "apa102.pio.h"
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/pio.h"
|
||||
#include "hardware/dma.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "hardware/clocks.h"
|
||||
#include "hardware/timer.h"
|
||||
|
||||
namespace plasma {
|
||||
|
||||
class APA102 {
|
||||
public:
|
||||
static const uint DEFAULT_SERIAL_FREQ = 20 * 1000 * 1000; // 20MHz
|
||||
#pragma pack(push, 1)
|
||||
union alignas(4) RGB {
|
||||
struct {
|
||||
uint8_t sof = 0b11101111;
|
||||
uint8_t b;
|
||||
uint8_t g;
|
||||
uint8_t r;
|
||||
} ;
|
||||
uint32_t srgb;
|
||||
void operator=(uint32_t v) {
|
||||
srgb = v;
|
||||
};
|
||||
void brightness(uint8_t b) {
|
||||
sof = 0b11100000 | b;
|
||||
};
|
||||
void rgb(uint8_t r, uint8_t g, uint8_t b) {
|
||||
this->r = r;
|
||||
this->g = g;
|
||||
this->b = b;;
|
||||
}
|
||||
RGB() : sof(0b11101111), b(0), g(0), r(0) {};
|
||||
};
|
||||
#pragma pack(pop)
|
||||
RGB *buffer;
|
||||
uint32_t num_leds;
|
||||
|
||||
APA102(uint num_leds, PIO pio, uint sm, uint pin_dat, uint pin_clk, uint freq=DEFAULT_SERIAL_FREQ, RGB* buffer=nullptr);
|
||||
~APA102() {
|
||||
stop();
|
||||
clear();
|
||||
update(true);
|
||||
dma_channel_unclaim(dma_channel);
|
||||
pio_sm_unclaim(pio, sm);
|
||||
delete[] buffer;
|
||||
}
|
||||
bool start(uint fps=60);
|
||||
bool stop();
|
||||
void update(bool blocking=false);
|
||||
void clear();
|
||||
void set_hsv(uint32_t index, float h, float s, float v);
|
||||
void set_rgb(uint32_t index, uint8_t r, uint8_t g, uint8_t b);
|
||||
void set_brightness(uint8_t b);
|
||||
RGB get(uint32_t index) {return buffer[index];};
|
||||
|
||||
static bool dma_timer_callback(struct repeating_timer *t);
|
||||
|
||||
private:
|
||||
uint32_t fps;
|
||||
PIO pio;
|
||||
uint sm;
|
||||
int dma_channel;
|
||||
struct repeating_timer timer;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
;
|
||||
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
;
|
||||
; SPDX-License-Identifier: BSD-3-Clause
|
||||
;
|
||||
|
||||
.program apa102
|
||||
.side_set 1
|
||||
out pins, 1 side 0 ; Stall here when no data (still asserts clock low)
|
||||
nop side 1
|
|
@ -0,0 +1,17 @@
|
|||
add_library(plasma2040 INTERFACE)
|
||||
|
||||
target_sources(plasma2040 INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/apa102.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/ws2812.cpp
|
||||
)
|
||||
|
||||
target_include_directories(plasma2040 INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
target_link_libraries(plasma2040 INTERFACE
|
||||
pico_stdlib
|
||||
hardware_pio
|
||||
hardware_dma
|
||||
)
|
||||
|
||||
pico_generate_pio_header(plasma2040 ${CMAKE_CURRENT_LIST_DIR}/apa102.pio)
|
||||
pico_generate_pio_header(plasma2040 ${CMAKE_CURRENT_LIST_DIR}/ws2812.pio)
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#include "apa102.hpp"
|
||||
#include "ws2812.hpp"
|
||||
|
||||
namespace plasma {
|
||||
const uint LED_R = 16;
|
||||
const uint LED_G = 17;
|
||||
const uint LED_B = 18;
|
||||
|
||||
const uint BUTTON_A = 12;
|
||||
const uint BUTTON_B = 13;
|
||||
|
||||
const uint PIN_CLK = 14; // Used only for APA102
|
||||
const uint PIN_DAT = 15; // Used for both APA102 and WS2812
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
#include "ws2812.hpp"
|
||||
|
||||
namespace plasma {
|
||||
|
||||
WS2812::WS2812(uint num_leds, PIO pio, uint sm, uint pin, uint freq, bool rgbw, COLOR_ORDER color_order, RGB* buffer) : buffer(buffer), num_leds(num_leds), color_order(color_order), pio(pio), sm(sm) {
|
||||
uint offset = pio_add_program(pio, &ws2812_program);
|
||||
|
||||
pio_gpio_init(pio, pin);
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
|
||||
|
||||
pio_sm_config c = ws2812_program_get_default_config(offset);
|
||||
sm_config_set_sideset_pins(&c, pin);
|
||||
|
||||
sm_config_set_out_shift(&c, false, true, rgbw ? 32 : 24); // Discard first (APA102 global brightness) byte. TODO support RGBW WS281X LEDs
|
||||
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
||||
|
||||
int cycles_per_bit = ws2812_T1 + ws2812_T2 + ws2812_T3;
|
||||
float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit);
|
||||
sm_config_set_clkdiv(&c, div);
|
||||
|
||||
pio_sm_init(pio, sm, offset, &c);
|
||||
pio_sm_set_enabled(pio, sm, true);
|
||||
|
||||
dma_channel = dma_claim_unused_channel(true);
|
||||
dma_channel_config config = dma_channel_get_default_config(dma_channel);
|
||||
channel_config_set_bswap(&config, true);
|
||||
channel_config_set_dreq(&config, pio_get_dreq(pio, sm, true));
|
||||
channel_config_set_transfer_data_size(&config, DMA_SIZE_32);
|
||||
channel_config_set_read_increment(&config, true);
|
||||
dma_channel_set_trans_count(dma_channel, num_leds, false);
|
||||
dma_channel_set_read_addr(dma_channel, (uint32_t *)buffer, false);
|
||||
dma_channel_configure(dma_channel, &config, &pio->txf[sm], NULL, 0, false);
|
||||
|
||||
if(!this->buffer) {
|
||||
this->buffer = new RGB[num_leds];
|
||||
}
|
||||
}
|
||||
|
||||
bool WS2812::dma_timer_callback(struct repeating_timer *t) {
|
||||
((WS2812*)t->user_data)->update();
|
||||
return true;
|
||||
}
|
||||
|
||||
void WS2812::update(bool blocking) {
|
||||
if(dma_channel_is_busy(dma_channel) && !blocking) return;
|
||||
while(dma_channel_is_busy(dma_channel)) {}; // Block waiting for DMA finish
|
||||
dma_channel_set_trans_count(dma_channel, num_leds, false);
|
||||
dma_channel_set_read_addr(dma_channel, buffer, true);
|
||||
if (!blocking) return;
|
||||
while(dma_channel_is_busy(dma_channel)) {}; // Block waiting for DMA finish
|
||||
}
|
||||
|
||||
bool WS2812::start(uint fps) {
|
||||
add_repeating_timer_ms(-(1000 / fps), dma_timer_callback, (void*)this, &timer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WS2812::stop() {
|
||||
return cancel_repeating_timer(&timer);
|
||||
}
|
||||
|
||||
void WS2812::clear() {
|
||||
for (auto i = 0u; i < num_leds; ++i) {
|
||||
set_rgb(i, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812::set_hsv(uint32_t index, float h, float s, float v) {
|
||||
float i = floor(h * 6.0f);
|
||||
float f = h * 6.0f - i;
|
||||
v *= 255.0f;
|
||||
uint8_t p = v * (1.0f - s);
|
||||
uint8_t q = v * (1.0f - f * s);
|
||||
uint8_t t = v * (1.0f - (1.0f - f) * s);
|
||||
|
||||
switch (int(i) % 6) {
|
||||
case 0: set_rgb(index, v, t, p); break;
|
||||
case 1: set_rgb(index, q, v, p); break;
|
||||
case 2: set_rgb(index, p, v, t); break;
|
||||
case 3: set_rgb(index, p, q, v); break;
|
||||
case 4: set_rgb(index, t, p, v); break;
|
||||
case 5: set_rgb(index, v, p, q); break;
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812::set_rgb(uint32_t index, uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
|
||||
switch(color_order) {
|
||||
case COLOR_ORDER::RGB:
|
||||
buffer[index].rgb(r, g, b, w);
|
||||
break;
|
||||
case COLOR_ORDER::RBG:
|
||||
buffer[index].rgb(r, b, g, w);
|
||||
break;
|
||||
case COLOR_ORDER::GRB:
|
||||
buffer[index].rgb(g, r, b, w);
|
||||
break;
|
||||
case COLOR_ORDER::GBR:
|
||||
buffer[index].rgb(g, b, r, w);
|
||||
break;
|
||||
case COLOR_ORDER::BRG:
|
||||
buffer[index].rgb(b, r, g, w);
|
||||
break;
|
||||
case COLOR_ORDER::BGR:
|
||||
buffer[index].rgb(b, g, r, w);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812::set_brightness(uint8_t b) {
|
||||
// WS2812 LEDs have no global brightness
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/*
|
||||
This code is significantly modified from the PIO apa102 example
|
||||
found here: https://github.com/raspberrypi/pico-examples/tree/master/pio/ws2812
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math.h>
|
||||
#include <cstdint>
|
||||
|
||||
#include "ws2812.pio.h"
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/pio.h"
|
||||
#include "hardware/dma.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "hardware/clocks.h"
|
||||
#include "hardware/timer.h"
|
||||
|
||||
namespace plasma {
|
||||
|
||||
class WS2812 {
|
||||
public:
|
||||
static const uint SERIAL_FREQ_400KHZ = 400000;
|
||||
static const uint SERIAL_FREQ_800KHZ = 800000;
|
||||
static const uint DEFAULT_SERIAL_FREQ = SERIAL_FREQ_400KHZ;
|
||||
enum class COLOR_ORDER {
|
||||
RGB,
|
||||
RBG,
|
||||
GRB,
|
||||
GBR,
|
||||
BRG,
|
||||
BGR
|
||||
};
|
||||
#pragma pack(push, 1)
|
||||
union alignas(4) RGB {
|
||||
struct {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
uint8_t w = 0b00000000;
|
||||
} ;
|
||||
uint32_t srgb;
|
||||
void operator=(uint32_t v) {
|
||||
srgb = v;
|
||||
};
|
||||
void rgb(uint8_t r, uint8_t g, uint8_t b, uint8_t w=0) {
|
||||
this->r = r;
|
||||
this->g = g;
|
||||
this->b = b;
|
||||
this->w = w;
|
||||
};
|
||||
RGB() : r(0), g(0), b(0), w(0) {};
|
||||
};
|
||||
#pragma pack(pop)
|
||||
RGB *buffer;
|
||||
uint32_t num_leds;
|
||||
COLOR_ORDER color_order;
|
||||
|
||||
WS2812(uint num_leds, PIO pio, uint sm, uint pin, uint freq=DEFAULT_SERIAL_FREQ, bool rgbw=false, COLOR_ORDER color_order=COLOR_ORDER::RGB, RGB* buffer=nullptr);
|
||||
~WS2812() {
|
||||
stop();
|
||||
clear();
|
||||
update(true);
|
||||
dma_channel_unclaim(dma_channel);
|
||||
pio_sm_unclaim(pio, sm);
|
||||
delete[] buffer;
|
||||
}
|
||||
bool start(uint fps=60);
|
||||
bool stop();
|
||||
void update(bool blocking=false);
|
||||
void clear();
|
||||
void set_hsv(uint32_t index, float h, float s, float v);
|
||||
void set_rgb(uint32_t index, uint8_t r, uint8_t g, uint8_t b, uint8_t w=0);
|
||||
void set_brightness(uint8_t b);
|
||||
RGB get(uint32_t index) {return buffer[index];};
|
||||
|
||||
static bool dma_timer_callback(struct repeating_timer *t);
|
||||
|
||||
private:
|
||||
uint32_t fps;
|
||||
PIO pio;
|
||||
uint sm;
|
||||
int dma_channel;
|
||||
struct repeating_timer timer;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
;
|
||||
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
;
|
||||
; SPDX-License-Identifier: BSD-3-Clause
|
||||
;
|
||||
|
||||
.program ws2812
|
||||
.side_set 1
|
||||
|
||||
.define public T1 2
|
||||
.define public T2 5
|
||||
.define public T3 3
|
||||
|
||||
.lang_opt python sideset_init = pico.PIO.OUT_HIGH
|
||||
.lang_opt python out_init = pico.PIO.OUT_HIGH
|
||||
.lang_opt python out_shiftdir = 1
|
||||
|
||||
.wrap_target
|
||||
bitloop:
|
||||
out x, 1 side 0 [T3 - 1] ; Side-set still takes place when instruction stalls
|
||||
jmp !x do_zero side 1 [T1 - 1] ; Branch on the bit we shifted out. Positive pulse
|
||||
do_one:
|
||||
jmp bitloop side 1 [T2 - 1] ; Continue driving high, for a long pulse
|
||||
do_zero:
|
||||
nop side 0 [T2 - 1] ; Or drive low, for a short pulse
|
||||
.wrap
|
|
@ -0,0 +1,19 @@
|
|||
import plasma
|
||||
import time
|
||||
|
||||
NUM_LEDS = 30
|
||||
|
||||
# WS2812 / NeoPixel™ LEDs
|
||||
led_strip = plasma.WS2812(NUM_LEDS, 0, 0, 15)
|
||||
# APA102 / DotStar™ LEDs
|
||||
# led_strip = plasma.APA102(NUM_LEDS, 0, 0, 15, 14)
|
||||
|
||||
# Start updating the LED strip
|
||||
led_strip.start()
|
||||
|
||||
# Make rainbows
|
||||
while True:
|
||||
t = time.ticks_ms() / 1000.0 / 5.0
|
||||
for i in range(NUM_LEDS):
|
||||
led_strip.set_hsv(i, t + (i / NUM_LEDS))
|
||||
time.sleep(1.0 / 60)
|
|
@ -0,0 +1,21 @@
|
|||
import time
|
||||
|
||||
# Import pin constants from plasma
|
||||
from plasma import PIN_LED_R, PIN_LED_G, PIN_LED_B, PIN_BUTTON_A, PIN_BUTTON_B
|
||||
|
||||
# Import helpers for RGB LEDs and Buttons
|
||||
from pimoroni import RGBLED, Button
|
||||
|
||||
led = RGBLED(PIN_LED_R, PIN_LED_G, PIN_LED_B)
|
||||
led.set_rgb(255, 0, 0)
|
||||
|
||||
button_a = Button(PIN_BUTTON_A)
|
||||
button_b = Button(PIN_BUTTON_B)
|
||||
|
||||
while True:
|
||||
if button_a.read():
|
||||
print("Pressed A - {}".format(time.ticks_ms()))
|
||||
led.set_rgb(0, 255, 0)
|
||||
if button_b.read():
|
||||
print("Pressed B - {}".format(time.ticks_ms()))
|
||||
led.set_rgb(0, 0, 255)
|
|
@ -32,4 +32,5 @@ include(pico_unicorn/micropython)
|
|||
include(pico_display/micropython)
|
||||
include(pico_explorer/micropython)
|
||||
include(pico_wireless/micropython)
|
||||
include(plasma_2040/micropython)
|
||||
include(ulab/code/micropython)
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
# Plasma <!-- omit in toc -->
|
||||
|
||||
The Plasma library is intended to drive APA102 / DotStar™ or WS2812 / NeoPixel™ LEDs on the Plasma 2040 board, though it can be used with your own custom pins/wiring.
|
||||
|
||||
- [Notes On PIO Limitations](#notes-on-pio-limitations)
|
||||
- [WS2812](#ws2812)
|
||||
- [Getting Started](#getting-started)
|
||||
- [RGBW and Setting Colour Order](#rgbw-and-setting-colour-order)
|
||||
- [Set An LED](#set-an-led)
|
||||
- [RGB](#rgb)
|
||||
- [HSV](#hsv)
|
||||
- [Set Brightness](#set-brightness)
|
||||
- [APA102](#apa102)
|
||||
- [Getting Started](#getting-started-1)
|
||||
- [Set An LED](#set-an-led-1)
|
||||
- [RGB](#rgb-1)
|
||||
- [HSV](#hsv-1)
|
||||
- [Using the Buttons & RGB LED](#using-the-buttons--rgb-led)
|
||||
- [Buttons](#buttons)
|
||||
- [RGBLED](#rgbled)
|
||||
|
||||
## Notes On PIO Limitations
|
||||
|
||||
The WS2812 and APA102 drivers use the PIO hardware on the RP2040. There are only two PIOs with four state machines each, placing a hard limit on how many separate LED strips you can drive.
|
||||
|
||||
In most cases you'll use `0` for PIO and `0` for PIO state-machine, but you should change these if you plan on running different strand types together, or if you're using something else that uses PIO.
|
||||
|
||||
## WS2812
|
||||
|
||||
### Getting Started
|
||||
|
||||
Construct a new `WS2812` instance, specifying the number of LEDs, PIO, PIO state-machine and GPIO pin.
|
||||
|
||||
```python
|
||||
import plasma
|
||||
|
||||
LEDS = 30
|
||||
FPS = 60
|
||||
|
||||
led_strip = plasma.WS2812(LEDS, 0, 0, 15)
|
||||
```
|
||||
|
||||
Start the LED strip by calling `start`. This sets up a timer which tells the RP2040 to DMA the pixel data into the PIO (a fast, asyncronous memory->peripheral copy) at the specified framerate.
|
||||
|
||||
```python
|
||||
led_strip.start(FPS)
|
||||
```
|
||||
|
||||
### RGBW and Setting Colour Order
|
||||
|
||||
Some WS2812-style LED strips have varying colour orders and support an additional white element. Two keyword arguments are supplied to configure this:
|
||||
|
||||
```
|
||||
import plasma
|
||||
|
||||
LEDS = 30
|
||||
FPS = 60
|
||||
|
||||
led_strip = plasma.WS2812(LEDS, 0, 0, 15, rgbw=True, color_order=plasma.COLOR_ORDER_GRB)
|
||||
```
|
||||
|
||||
The available orders are defined as constants in `plasma`:
|
||||
|
||||
* `COLOR_ORDER_RGB`
|
||||
* `COLOR_ORDER_RBG`
|
||||
* `COLOR_ORDER_GRB`
|
||||
* `COLOR_ORDER_GBR`
|
||||
* `COLOR_ORDER_BRG`
|
||||
* `COLOR_ORDER_BGR`
|
||||
|
||||
### Set An LED
|
||||
|
||||
You can set the colour of an LED in either the RGB colourspace, or HSV (Hue, Saturation, Value). HSV is useful for creating rainbow patterns.
|
||||
|
||||
#### RGB
|
||||
|
||||
Set the first LED - `0` - to Purple `255, 0, 255`:
|
||||
|
||||
```python
|
||||
led_strip.set_led(0, 255, 0, 255)
|
||||
```
|
||||
|
||||
#### HSV
|
||||
|
||||
Set the first LED - `0` - to Red `0.0`:
|
||||
|
||||
```python
|
||||
led_strip.set_hsv(0, 0.0, 1.0, 1.0)
|
||||
```
|
||||
|
||||
### Set Brightness
|
||||
|
||||
APA102 pixels support global brightness, allowing their brightness to be specified independent of their colour. You can set the overall brightness of your strip by calling:
|
||||
|
||||
```python
|
||||
led_strip.set_brightness(15)
|
||||
```
|
||||
|
||||
You can set brightness from `0` to `31`. This directly maps to the 5-bit brightness value sent to the APA102 LEDs.
|
||||
|
||||
## APA102
|
||||
|
||||
### Getting Started
|
||||
|
||||
Construct a new `APA102` instance, specifying the number of LEDs, PIO, PIO state-machine and GPIO data/clock pins.
|
||||
|
||||
```python
|
||||
import plasma
|
||||
|
||||
LEDS = 30
|
||||
FPS = 60
|
||||
|
||||
led_strip = plasma.APA102(LEDS, 0, 0, 15, 14)
|
||||
```
|
||||
|
||||
Start the LED strip by calling `start`. This sets up a timer which tells the RP2040 to DMA the pixel data into the PIO (a fast, asyncronous memory->peripheral copy) at the specified framerate.
|
||||
|
||||
```python
|
||||
led_strip.start(FPS)
|
||||
```
|
||||
|
||||
### Set An LED
|
||||
|
||||
You can set the colour of an LED in either the RGB colourspace, or HSV (Hue, Saturation, Value). HSV is useful for creating rainbow patterns.
|
||||
|
||||
#### RGB
|
||||
|
||||
Set the first LED - `0` - to Purple `255, 0, 255`:
|
||||
|
||||
```python
|
||||
led_strip.set_led(0, 255, 0, 255)
|
||||
```
|
||||
|
||||
#### HSV
|
||||
|
||||
Set the first LED - `0` - to Red `0.0`:
|
||||
|
||||
```python
|
||||
led_strip.set_hsv(0, 0.0, 1.0, 1.0)
|
||||
```
|
||||
|
||||
## Using the Buttons & RGB LED
|
||||
|
||||
The `pimoroni` module contains `Button` and `RGBLED` classes to simplify button debounce, auto-repeat and PWM'ing an RGB LED.
|
||||
|
||||
```python
|
||||
Button(button, invert=True, repeat_time=200, hold_time=1000)
|
||||
```
|
||||
|
||||
```python
|
||||
RGBLED(r, g, b, invert=True)
|
||||
```
|
||||
|
||||
The `plasma` module contains constants for the LED and button pins:
|
||||
|
||||
* `plasma.PIN_LED_R` = 16
|
||||
* `plasma.PIN_LED_G` = 17
|
||||
* `plasma.PIN_LED_B` = 18
|
||||
* `plasma.PIN_BUTTON_A` = 12
|
||||
* `plasma.PIN_BUTTON_B` = 13
|
||||
|
||||
### Buttons
|
||||
|
||||
Import the `Button` class from the `pimoroni` module and the pin constants for the buttons:
|
||||
|
||||
```python
|
||||
from pimoroni import Button
|
||||
from plasma import PIN_BUTTON_A, PIN_BUTTON_B
|
||||
```
|
||||
|
||||
Set up an instance of `Button` for each button:
|
||||
|
||||
```python
|
||||
button_a = Button(PIN_BUTTON_A)
|
||||
button_b = Button(PIN_BUTTON_B)
|
||||
```
|
||||
|
||||
To get the button state, call `.read()`. If the button is held down, then this will return `True` at the interval specified by `repeat_time` until `hold_time` is reached, at which point it will return `True` every `hold_time / 3` milliseconds. This is useful for rapidly increasing/decreasing values such as hue:
|
||||
|
||||
```python
|
||||
state = button_a.read()
|
||||
```
|
||||
|
||||
### RGBLED
|
||||
|
||||
Import the `RGBLED` class from `pimoroni` and the pin constants for the buttons:
|
||||
|
||||
```python
|
||||
from pimoroni import RGBLED
|
||||
from plasma import PIN_LED_R, PIN_LED_G, PIN_LED_B
|
||||
```
|
||||
|
||||
And set up an instance of `RGBLED` for the LED:
|
||||
|
||||
```python
|
||||
led = RGBLED(PIN_LED_R, PIN_LED_G, PIN_LED_B)
|
||||
```
|
||||
|
||||
To set the LED colour, call `.set_rgb(r, g, b)`. Each value should be between 0 and 255:
|
||||
|
||||
```python
|
||||
led.set_rgb(255, 0, 0) # Full red
|
||||
led.set_rgb(0, 255, 0) # Full green
|
||||
led.set_rgb(0, 0, 255) # Full blue
|
||||
```
|
|
@ -0,0 +1,23 @@
|
|||
set(MOD_NAME plasma_2040)
|
||||
string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER)
|
||||
add_library(usermod_${MOD_NAME} INTERFACE)
|
||||
|
||||
target_sources(usermod_${MOD_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/plasma2040/apa102.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/plasma2040/ws2812.cpp
|
||||
)
|
||||
pico_generate_pio_header(usermod_${MOD_NAME} ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/plasma2040/apa102.pio)
|
||||
pico_generate_pio_header(usermod_${MOD_NAME} ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/plasma2040/ws2812.pio)
|
||||
|
||||
target_include_directories(usermod_${MOD_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/plasma2040/
|
||||
)
|
||||
|
||||
target_compile_definitions(usermod_${MOD_NAME} INTERFACE
|
||||
MODULE_PLASMA_ENABLED=1
|
||||
)
|
||||
|
||||
target_link_libraries(usermod INTERFACE usermod_${MOD_NAME})
|
|
@ -0,0 +1,89 @@
|
|||
#include "plasma_2040.h"
|
||||
|
||||
|
||||
/***** Methods *****/
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(PlasmaAPA102___del___obj, PlasmaAPA102___del__);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaAPA102_set_rgb_obj, 5, PlasmaAPA102_set_rgb);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaAPA102_set_hsv_obj, 3, PlasmaAPA102_set_hsv);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaAPA102_set_brightness_obj, 2, PlasmaAPA102_set_brightness);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaAPA102_start_obj, 1, PlasmaAPA102_start);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(PlasmaAPA102_clear_obj, PlasmaAPA102_clear);
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(PlasmaWS2812___del___obj, PlasmaWS2812___del__);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaWS2812_set_rgb_obj, 5, PlasmaWS2812_set_rgb);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaWS2812_set_hsv_obj, 3, PlasmaWS2812_set_hsv);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(PlasmaWS2812_start_obj, 1, PlasmaWS2812_start);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(PlasmaWS2812_clear_obj, PlasmaWS2812_clear);
|
||||
|
||||
/***** Binding of Methods *****/
|
||||
STATIC const mp_rom_map_elem_t PlasmaAPA102_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&PlasmaAPA102___del___obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_rgb), MP_ROM_PTR(&PlasmaAPA102_set_rgb_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_hsv), MP_ROM_PTR(&PlasmaAPA102_set_hsv_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_brightness), MP_ROM_PTR(&PlasmaAPA102_set_brightness_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&PlasmaAPA102_start_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&PlasmaAPA102_clear_obj) },
|
||||
};
|
||||
STATIC const mp_rom_map_elem_t PlasmaWS2812_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&PlasmaWS2812___del___obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_rgb), MP_ROM_PTR(&PlasmaWS2812_set_rgb_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_hsv), MP_ROM_PTR(&PlasmaWS2812_set_hsv_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&PlasmaWS2812_start_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&PlasmaWS2812_clear_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(PlasmaAPA102_locals_dict, PlasmaAPA102_locals_dict_table);
|
||||
STATIC MP_DEFINE_CONST_DICT(PlasmaWS2812_locals_dict, PlasmaWS2812_locals_dict_table);
|
||||
|
||||
/***** Class Definition *****/
|
||||
const mp_obj_type_t PlasmaAPA102_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_plasma_apa102,
|
||||
.print = PlasmaAPA102_print,
|
||||
.make_new = PlasmaAPA102_make_new,
|
||||
.locals_dict = (mp_obj_dict_t*)&PlasmaAPA102_locals_dict,
|
||||
};
|
||||
|
||||
const mp_obj_type_t PlasmaWS2812_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_plasma_ws2812,
|
||||
.print = PlasmaWS2812_print,
|
||||
.make_new = PlasmaWS2812_make_new,
|
||||
.locals_dict = (mp_obj_dict_t*)&PlasmaWS2812_locals_dict,
|
||||
};
|
||||
|
||||
typedef struct _mp_obj_float_t {
|
||||
mp_obj_base_t base;
|
||||
mp_float_t value;
|
||||
} mp_obj_float_t;
|
||||
mp_obj_float_t shunt_resistor = {{&mp_type_float}, 0.015f};
|
||||
|
||||
/***** Globals Table *****/
|
||||
STATIC const mp_map_elem_t plasma_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_plasma) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_APA102), (mp_obj_t)&PlasmaAPA102_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WS2812), (mp_obj_t)&PlasmaWS2812_type },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PIN_LED_R), MP_ROM_INT(16) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PIN_LED_G), MP_ROM_INT(17) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PIN_LED_B), MP_ROM_INT(18) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PIN_BUTTON_A), MP_ROM_INT(12) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PIN_BUTTON_B), MP_ROM_INT(13) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_COLOR_ORDER_RGB), MP_ROM_INT(0x00) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_COLOR_ORDER_RBG), MP_ROM_INT(0x01) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_COLOR_ORDER_GRB), MP_ROM_INT(0x02) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_COLOR_ORDER_GBR), MP_ROM_INT(0x03) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_COLOR_ORDER_BRG), MP_ROM_INT(0x04) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_COLOR_ORDER_BGR), MP_ROM_INT(0x05) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_SHUNT_RESISTOR), MP_ROM_PTR(&shunt_resistor) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ADC_GAIN), MP_ROM_INT(50) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_plasma_globals, plasma_globals_table);
|
||||
|
||||
/***** Module Definition *****/
|
||||
const mp_obj_module_t plasma_user_cmodule = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_plasma_globals,
|
||||
};
|
||||
MP_REGISTER_MODULE(MP_QSTR_plasma, plasma_user_cmodule, MODULE_PLASMA_ENABLED);
|
|
@ -0,0 +1,359 @@
|
|||
#include "libraries/plasma2040/plasma2040.hpp"
|
||||
#include <cstdio>
|
||||
|
||||
#define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o))
|
||||
|
||||
// SDA/SCL on even/odd pins, I2C0/I2C1 on even/odd pairs of pins.
|
||||
#define IS_VALID_SCL(i2c, pin) (((pin) & 1) == 1 && (((pin) & 2) >> 1) == (i2c))
|
||||
#define IS_VALID_SDA(i2c, pin) (((pin) & 1) == 0 && (((pin) & 2) >> 1) == (i2c))
|
||||
|
||||
|
||||
using namespace plasma;
|
||||
|
||||
extern "C" {
|
||||
#include "plasma_2040.h"
|
||||
#include "py/builtin.h"
|
||||
|
||||
typedef struct _mp_obj_float_t {
|
||||
mp_obj_base_t base;
|
||||
mp_float_t value;
|
||||
} mp_obj_float_t;
|
||||
|
||||
const mp_obj_float_t const_float_1 = {{&mp_type_float}, 1.0f};
|
||||
|
||||
/********** WS2812 **********/
|
||||
|
||||
/***** Variables Struct *****/
|
||||
typedef struct _PlasmaWS2812_obj_t {
|
||||
mp_obj_base_t base;
|
||||
WS2812* ws2812;
|
||||
void *buf;
|
||||
} _PlasmaWS2812_obj_t;
|
||||
|
||||
|
||||
/***** Print *****/
|
||||
void PlasmaWS2812_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
(void)kind; //Unused input parameter
|
||||
_PlasmaWS2812_obj_t *self = MP_OBJ_TO_PTR2(self_in, _PlasmaWS2812_obj_t);
|
||||
mp_print_str(print, "WS2812(");
|
||||
|
||||
mp_print_str(print, "num_leds = ");
|
||||
mp_obj_print_helper(print, mp_obj_new_int(self->ws2812->num_leds), PRINT_REPR);
|
||||
|
||||
mp_print_str(print, ")");
|
||||
}
|
||||
|
||||
/***** Destructor ******/
|
||||
mp_obj_t PlasmaWS2812___del__(mp_obj_t self_in) {
|
||||
_PlasmaWS2812_obj_t *self = MP_OBJ_TO_PTR2(self_in, _PlasmaWS2812_obj_t);
|
||||
delete self->ws2812;
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
/***** Constructor *****/
|
||||
mp_obj_t PlasmaWS2812_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
_PlasmaWS2812_obj_t *self = nullptr;
|
||||
|
||||
enum {
|
||||
ARG_num_leds,
|
||||
ARG_pio,
|
||||
ARG_sm,
|
||||
ARG_dat,
|
||||
ARG_freq,
|
||||
ARG_buffer,
|
||||
ARG_rgbw,
|
||||
ARG_color_order
|
||||
};
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_num_leds, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_pio, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_sm, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_dat, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_freq, MP_ARG_INT, {.u_int = WS2812::DEFAULT_SERIAL_FREQ} },
|
||||
{ MP_QSTR_buffer, MP_ARG_OBJ, {.u_obj = nullptr} },
|
||||
{ MP_QSTR_rgbw, MP_ARG_BOOL, {.u_bool = false} },
|
||||
{ MP_QSTR_color_order, MP_ARG_INT, {.u_int = (uint8_t)WS2812::COLOR_ORDER::RGB} },
|
||||
};
|
||||
|
||||
// Parse args.
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
int num_leds = args[ARG_num_leds].u_int;
|
||||
PIO pio = args[ARG_pio].u_int == 0 ? pio0 : pio1;
|
||||
int sm = args[ARG_sm].u_int;
|
||||
int dat = args[ARG_dat].u_int;
|
||||
int freq = args[ARG_freq].u_int;
|
||||
bool rgbw = args[ARG_rgbw].u_bool;
|
||||
WS2812::COLOR_ORDER color_order = (WS2812::COLOR_ORDER)args[ARG_color_order].u_int;
|
||||
|
||||
void *buffer = nullptr;
|
||||
|
||||
if (args[ARG_buffer].u_obj) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW);
|
||||
buffer = bufinfo.buf;
|
||||
if(bufinfo.len < (size_t)(num_leds * 4)) {
|
||||
mp_raise_ValueError("Supplied buffer is too small for LED count!");
|
||||
}
|
||||
}
|
||||
|
||||
self = m_new_obj_with_finaliser(_PlasmaWS2812_obj_t);
|
||||
self->base.type = &PlasmaWS2812_type;
|
||||
self->buf = buffer;
|
||||
|
||||
self->ws2812 = new WS2812(num_leds, pio, sm, dat, freq, rgbw, color_order, (WS2812::RGB *)buffer);
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
mp_obj_t PlasmaWS2812_clear(mp_obj_t self_in) {
|
||||
_PlasmaWS2812_obj_t *self = MP_OBJ_TO_PTR2(self_in, _PlasmaWS2812_obj_t);
|
||||
self->ws2812->clear();
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t PlasmaWS2812_start(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_fps };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_fps, MP_ARG_INT, {.u_int = 60} }
|
||||
};
|
||||
|
||||
// Parse args.
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
_PlasmaWS2812_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _PlasmaWS2812_obj_t);
|
||||
self->ws2812->start(args[ARG_fps].u_int);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
|
||||
mp_obj_t PlasmaWS2812_set_rgb(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_index, ARG_r, ARG_g, ARG_b };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_index, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT }
|
||||
};
|
||||
|
||||
// Parse args.
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
int index = args[ARG_index].u_int;
|
||||
int r = args[ARG_r].u_int;
|
||||
int g = args[ARG_g].u_int;
|
||||
int b = args[ARG_b].u_int;
|
||||
|
||||
_PlasmaWS2812_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _PlasmaWS2812_obj_t);
|
||||
self->ws2812->set_rgb(index, r, g, b);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t PlasmaWS2812_set_hsv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_index, ARG_h, ARG_s, ARG_v };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_index, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_hue, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_sat, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&const_float_1)} },
|
||||
{ MP_QSTR_val, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&const_float_1)} }
|
||||
};
|
||||
|
||||
// Parse args.
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
int index = args[ARG_index].u_int;
|
||||
float h = mp_obj_get_float(args[ARG_h].u_obj);
|
||||
float s = mp_obj_get_float(args[ARG_s].u_obj);
|
||||
float v = mp_obj_get_float(args[ARG_v].u_obj);
|
||||
|
||||
_PlasmaWS2812_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _PlasmaWS2812_obj_t);
|
||||
self->ws2812->set_hsv(index, h, s, v);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
/********** APA102 **********/
|
||||
|
||||
/***** Variables Struct *****/
|
||||
typedef struct _PlasmaAPA102_obj_t {
|
||||
mp_obj_base_t base;
|
||||
APA102* apa102;
|
||||
void *buf;
|
||||
} _PlasmaAPA102_obj_t;
|
||||
|
||||
|
||||
/***** Print *****/
|
||||
void PlasmaAPA102_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
(void)kind; //Unused input parameter
|
||||
_PlasmaAPA102_obj_t *self = MP_OBJ_TO_PTR2(self_in, _PlasmaAPA102_obj_t);
|
||||
mp_print_str(print, "APA102(");
|
||||
|
||||
mp_print_str(print, "num_leds = ");
|
||||
mp_obj_print_helper(print, mp_obj_new_int(self->apa102->num_leds), PRINT_REPR);
|
||||
|
||||
mp_print_str(print, ")");
|
||||
}
|
||||
|
||||
/***** Destructor ******/
|
||||
mp_obj_t PlasmaAPA102___del__(mp_obj_t self_in) {
|
||||
_PlasmaAPA102_obj_t *self = MP_OBJ_TO_PTR2(self_in, _PlasmaAPA102_obj_t);
|
||||
delete self->apa102;
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
/***** Constructor *****/
|
||||
mp_obj_t PlasmaAPA102_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
_PlasmaAPA102_obj_t *self = nullptr;
|
||||
|
||||
enum {
|
||||
ARG_num_leds,
|
||||
ARG_pio,
|
||||
ARG_sm,
|
||||
ARG_dat,
|
||||
ARG_clk,
|
||||
ARG_freq,
|
||||
ARG_buffer
|
||||
};
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_num_leds, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_pio, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_sm, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_dat, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_clk, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_freq, MP_ARG_INT, {.u_int = APA102::DEFAULT_SERIAL_FREQ} },
|
||||
{ MP_QSTR_buffer, MP_ARG_OBJ, {.u_obj = nullptr} },
|
||||
};
|
||||
|
||||
// Parse args.
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
int num_leds = args[ARG_num_leds].u_int;
|
||||
PIO pio = args[ARG_pio].u_int == 0 ? pio0 : pio1;
|
||||
int sm = args[ARG_sm].u_int;
|
||||
int dat = args[ARG_dat].u_int;
|
||||
int clk = args[ARG_clk].u_int;
|
||||
int freq = args[ARG_freq].u_int;
|
||||
|
||||
void *buffer = nullptr;
|
||||
|
||||
if (args[ARG_buffer].u_obj) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW);
|
||||
buffer = bufinfo.buf;
|
||||
if(bufinfo.len < (size_t)(num_leds * 4)) {
|
||||
mp_raise_ValueError("Supplied buffer is too small for LED count!");
|
||||
}
|
||||
}
|
||||
|
||||
self = m_new_obj_with_finaliser(_PlasmaAPA102_obj_t);
|
||||
self->base.type = &PlasmaAPA102_type;
|
||||
self->buf = buffer;
|
||||
|
||||
self->apa102 = new APA102(num_leds, pio, sm, dat, clk, freq, (APA102::RGB *)buffer);
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
mp_obj_t PlasmaAPA102_clear(mp_obj_t self_in) {
|
||||
_PlasmaAPA102_obj_t *self = MP_OBJ_TO_PTR2(self_in, _PlasmaAPA102_obj_t);
|
||||
self->apa102->clear();
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t PlasmaAPA102_start(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_fps };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_fps, MP_ARG_INT, {.u_int = 60} }
|
||||
};
|
||||
|
||||
// Parse args.
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
_PlasmaAPA102_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _PlasmaAPA102_obj_t);
|
||||
self->apa102->start(args[ARG_fps].u_int);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t PlasmaAPA102_set_brightness(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_brightness };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_brightness, MP_ARG_REQUIRED | MP_ARG_INT }
|
||||
};
|
||||
|
||||
// Parse args.
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
int brightness = args[ARG_brightness].u_int;
|
||||
|
||||
_PlasmaAPA102_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _PlasmaAPA102_obj_t);
|
||||
self->apa102->set_brightness(brightness);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t PlasmaAPA102_set_rgb(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_index, ARG_r, ARG_g, ARG_b };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_index, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT }
|
||||
};
|
||||
|
||||
// Parse args.
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
int index = args[ARG_index].u_int;
|
||||
int r = args[ARG_r].u_int;
|
||||
int g = args[ARG_g].u_int;
|
||||
int b = args[ARG_b].u_int;
|
||||
|
||||
_PlasmaAPA102_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _PlasmaAPA102_obj_t);
|
||||
self->apa102->set_rgb(index, r, g, b);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t PlasmaAPA102_set_hsv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_index, ARG_h, ARG_s, ARG_v };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_index, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_hue, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_sat, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&const_float_1)} },
|
||||
{ MP_QSTR_val, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&const_float_1)} }
|
||||
};
|
||||
|
||||
// Parse args.
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
int index = args[ARG_index].u_int;
|
||||
float h = mp_obj_get_float(args[ARG_h].u_obj);
|
||||
float s = mp_obj_get_float(args[ARG_s].u_obj);
|
||||
float v = mp_obj_get_float(args[ARG_v].u_obj);
|
||||
|
||||
_PlasmaAPA102_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _PlasmaAPA102_obj_t);
|
||||
self->apa102->set_hsv(index, h, s, v);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// Include MicroPython API.
|
||||
#include "py/runtime.h"
|
||||
|
||||
/***** Extern of Class Definition *****/
|
||||
extern const mp_obj_type_t PlasmaAPA102_type;
|
||||
extern const mp_obj_type_t PlasmaWS2812_type;
|
||||
|
||||
/***** Extern of Class Methods *****/
|
||||
extern void PlasmaAPA102_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
|
||||
extern mp_obj_t PlasmaAPA102_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
|
||||
extern mp_obj_t PlasmaAPA102___del__(mp_obj_t self_in);
|
||||
extern mp_obj_t PlasmaAPA102_start(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t PlasmaAPA102_set_rgb(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t PlasmaAPA102_set_hsv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t PlasmaAPA102_set_brightness(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t PlasmaAPA102_clear(mp_obj_t self_in);
|
||||
|
||||
extern void PlasmaWS2812_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
|
||||
extern mp_obj_t PlasmaWS2812_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
|
||||
extern mp_obj_t PlasmaWS2812___del__(mp_obj_t self_in);
|
||||
extern mp_obj_t PlasmaWS2812_start(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t PlasmaWS2812_set_rgb(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t PlasmaWS2812_set_hsv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t PlasmaWS2812_clear(mp_obj_t self_in);
|
||||
|
||||
extern bool Pimoroni_mp_obj_to_i2c(mp_obj_t in, void *out);
|
|
@ -1,5 +1,21 @@
|
|||
import time
|
||||
from machine import Pin, PWM
|
||||
from machine import Pin, PWM, ADC
|
||||
|
||||
|
||||
class Analog:
|
||||
def __init__(self, pin, amplifier_gain=1, resistor=0):
|
||||
self.gain = amplifier_gain
|
||||
self.resistor = resistor
|
||||
self.pin = ADC(pin)
|
||||
|
||||
def read_voltage(self):
|
||||
return self.pin.read_u16() * 3.3 / 65535 / self.gain
|
||||
|
||||
def read_current(self):
|
||||
if self.resistor > 0:
|
||||
return self.read_voltage() / self.resistor
|
||||
else:
|
||||
return self.read_voltage()
|
||||
|
||||
|
||||
class Button:
|
||||
|
|
Ładowanie…
Reference in New Issue