YAHAL
Yet Another Hardware Abstraction Library
Loading...
Searching...
No Matches
ws2812_rp2350.cpp
1// ---------------------------------------------
2// This file is part of
3// _ _ __ _ _ __ __
4// ( \/ ) /__\ ( )_( ) /__\ ( )
5// \ / /(__)\ ) _ ( /(__)\ )(__
6// (__)(__)(__)(_) (_)(__)(__)(____)
7//
8// Yet Another HW Abstraction Library
9// Copyright (C) Andreas Terstegge
10// BSD Licensed (see file LICENSE)
11//
12// ---------------------------------------------
13//
14#include "ws2812_rp2350.h"
15#include "pio/ws2812.pio.h"
16#include "RP2350.h"
17#include "task.h"
18#include <cassert>
19
20using namespace _IO_BANK0_;
21
22// LED implementation
24
25void ws2812_rp2350::LED::on() {
26 _color = _on_color;
27 _ws2812_rp2350->update(_index);
28}
29
30void ws2812_rp2350::LED::off() {
31 _color = 0;
32 _ws2812_rp2350->update(_index);
33}
34
35void ws2812_rp2350::LED::toggle() {
36 _color = _color ? 0 : _on_color;
37 _ws2812_rp2350->update(_index);
38}
39
40bool ws2812_rp2350::LED::is_on() {
41 return _color;
42}
43
44void ws2812_rp2350::LED::set_color(uint32_t rgb) {
45 _color = _ws2812_rp2350->xRGB_to_GRBx(rgb);
46 _ws2812_rp2350->update(_index);
47}
48
49void ws2812_rp2350::LED::set_on_color(uint32_t rgb) {
50 _on_color = _ws2812_rp2350->xRGB_to_GRBx(rgb);
51}
52
53// ws2812_rp2040 implementation
55ws2812_rp2350::ws2812_rp2350(gpio_pin_t pin,
56 uint16_t size)
57: _gpio(pin), _size(size) {
58 // Allocate LED array and set base class pointers
59 _leds = new LED[_size];
60 for(uint16_t i=0; i < _size; ++i) {
61 _leds[i]._ws2812_rp2350 = this;
62 _leds[i]._index = i;
63 }
64}
65
66ws2812_rp2350::~ws2812_rp2350() {
67 delete [] _leds;
68 _leds = nullptr;
69 _gpio.setSEL(GPIO_CTRL_FUNCSEL__null);
70}
71
72void ws2812_rp2350::init() {
73 // configure GPIO pin to use PIO0 output
74 _gpio.setSEL(GPIO_CTRL_FUNCSEL__pio0);
75 // Set up the PIO state machine
76 _sm = pio_rp2350::pio0.loadProgram(ws2812_program);
77 configure_SM(_sm, _gpio.getGpio() );
78 _sm->enable();
79 // set flag
80 _init = true;
81}
82
83void ws2812_rp2350::set_colors(uint32_t * values, uint16_t size) {
84 assert(size <= _size);
85 for(uint16_t i=0; i < size; ++i) {
86 _leds[i]._color = xRGB_to_GRBx(values[i]);
87 }
88 update(size-1);
89}
90
91uint32_t ws2812_rp2350::xRGB_to_GRBx(uint32_t rgb) {
92 // WS2812 needs colors in GRB, and PIO
93 // expects the upper 24 bits to be set
94 // Shift green to MSB
95 rgb |= (rgb & 0x0000ff00) << 16;
96 // Zero-out blue
97 rgb &= 0xffff00ff;
98 // Shift blue one byte up
99 rgb |= (rgb & 0x000000ff) << 8;
100 return rgb;
101}
102
103void ws2812_rp2350::update(uint16_t index) {
104 if (!_init) init();
105 // The PIO buffers the data in the FIFO (8 entries).
106 // Sending the whole FIFO takes 80us. The reset time
107 // for a WS2812 is at least 280us, so we wait approx.
108 // 400us before sending a new packet.
109
110 // Make sure that writing the WS2812 data is atomic
111 task::enterCritical();
112 // Wait for 1ms without multitasking (sleep_ms not working)
113 uint64_t now = task::millis();
114 while (task::millis() < now+1) ;
115 // Write WS2812 data
116 for(uint16_t i=0; i <= index; ++i) {
117 _sm->writeTxFifo(_leds[i]._color);
118 }
119 // Leave the critical section
120 task::leaveCritical();
121}