1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
//! # Welcome to the neopixel library source code!
//! - By: Jonathan Zurita
//! - Date: 11/18/2024
//! - Version: 0.1.0
//!
//! ## What is the function of this library?
//! This library allows the user to call user-friendly functions
//! in order to manipulate WS2812 neopixels.
//!
//! ## IMPORTANT NOTES
//! Please edit the `pub const` variables as needed
//! - (e.g. change `NUM_LEDS` to 24 instead of default value of 8.)
//!
//! ## Why do use a watchdog timer as an argument?
//! I decided to include a watchdog timer in order
//! to protect against possible lockups in DMA transmission.
//! Thankfully utilizing a WDT requires minimal overhead. :)
//!
//! ## Release Notes
//! V0.1.0 - Released neopixel library to the public
// user defined includes
use esp_hal::{
delay::Delay,
spi::{master::{self, SpiDmaBus}, SpiMode},
peripherals::{self, Peripherals, SPI2, TIMG0},
timer::timg::Wdt, Blocking
};
use core::result::Result::Ok;
use core::result::Result::Err;
// IMPORTANT NOTE: Please edit these variables in order to best fit your
// neopixel array! :)
/// Desired number of neopixels to control
pub const NUM_LEDS: usize = 8;
/// Number of color bits per neopixel
pub const PACKET_SIZE: usize = 24;
/// ARR_SIZE = NUM_LEDS * PACKET_SIZE
pub const ARR_SIZE: usize = NUM_LEDS * PACKET_SIZE;
/// SPI generate waveforms (LOGIC_1)
pub const NEOPIXEL_LOGIC_0: u8 = 0x80;
/// SPI generate waveforms (LOGIC_0)
pub const NEOPIXEL_LOGIC_1: u8 = 0xF8;
/// Essentially hex color code for black (no light)
const TURN_OFF: u32 = 0x000000;
////////////////////////////// START OF NEOPIXEL FUNCTIONS /////////////////////////////////////////////
/// # <<< Click on me to see function desc!
/// # Purpose:
/// Sets a specific neopixel to a desired color code
/// - Has error checking such as wrong color code size and wrong position argument given
pub fn neopixel_set_data(rgb_color: u32, position: usize, arr: &mut [u8 ; ARR_SIZE]) -> Result<u8, &str>{
// error checking for RGB value
if rgb_color > 0xFFFFFF {
// color code exceeds RGB max value
return Err("MAX VAL EXCEEDED FOR RGB VALUE");
}
// subtract one because we are indexing from 0!
if position > (NUM_LEDS - 1) {
return Err("EXCEEDED NEOPIXEL POSITION BOUNDS");
}
let mut bit_mask: u32 = 0x800000;
let mut arr_idx = position * PACKET_SIZE;
let mut result: u32;
// iterate through every color bit in 24-bit RGB code
for _i in 0..24 {
result = rgb_color & bit_mask;
if result > 0 {
arr[arr_idx] = NEOPIXEL_LOGIC_1;
}
else {
arr[arr_idx] = NEOPIXEL_LOGIC_0;
}
arr_idx += 1; // increment to next element in array
bit_mask >>= 1; // shift to next bit
}
return Ok(0);
}
/// # <<< Click on me to see function desc!
/// # Purpose:
/// Sets the entire user-defined neopixel array a particular color code
/// - Has error checking such as wrong color code size and wrong position argument given
pub fn neopixel_set_entire_data(rgb_color: u32, arr: &mut [u8 ; ARR_SIZE]) {
for i in 0..NUM_LEDS {
neopixel_set_data(rgb_color, i, arr).unwrap();
}
}
/// # <<< Click on me to see function desc!
/// # Purpose:
/// Returns a mutable array that stores the data for the desired
/// number of neopixels (determine by `NUM_LEDS`)
pub fn neopixel_init_buffer() -> [u8; ARR_SIZE] {
// init to all zeroes
let mut arr: [u8 ; ARR_SIZE] = [0 ; ARR_SIZE];
// final init array stage is to prepare entire array with NEOPIXEL_LOGIC_0
for i in 0..ARR_SIZE {
arr[i] = NEOPIXEL_LOGIC_0;
}
return arr;
}
pub fn spi_dma_send_breathing(spi: &mut SpiDmaBus<SPI2, esp_hal::spi::FullDuplexMode, Blocking>,
arr: &mut [u8 ; ARR_SIZE],
delay: &mut Delay,
wdt: &mut Wdt<TIMG0>)
{
// declare rgb_val variable in order to synchronize what the color is for entire NeoPixel LED array
let mut rgb_val: u32 = 0x00;
// increment up from d0 to d20 and back down from d20 to d1
for _i in 0..20 {
neopixel_set_entire_data(rgb_val, arr);
spi_dma_send(spi, arr, wdt);
delay.delay_millis(125 as u32);
rgb_val += 1;
}
for _i in 0..20 {
neopixel_set_entire_data(rgb_val, arr);
spi_dma_send(spi, arr, wdt);
delay.delay_millis(100 as u32);
rgb_val -= 1;
}
// reset neoPixels back to zero state
neopixel_set_entire_data(TURN_OFF, arr);
spi_dma_send(spi, arr, wdt);
}
pub fn spi_dma_send(spi: &mut SpiDmaBus<SPI2, esp_hal::spi::FullDuplexMode, Blocking>,
arr: &mut [u8], wdt: &mut Wdt<TIMG0> )
{
// feed watchdog when spi transfer is complete!
match spi.write(arr) {
Ok(_t) => wdt.feed(),
Err(_e) => () ,
}
}