This commit is contained in:
Laila van Reenen 2025-04-19 22:08:57 +02:00
parent ef76d8e35f
commit 9959e0bd01
Signed by: LailaTheElf
GPG Key ID: 8A3EF0226518C12D
4 changed files with 208 additions and 36 deletions

View File

@ -16,14 +16,17 @@ set(PICO_CXX_ENABLE_RTTI 1)
pico_sdk_init() pico_sdk_init()
add_executable(stofzuiger src/main.c) add_executable(stofzuiger src/main.c)
pico_generate_pio_header(stofzuiger ${CMAKE_CURRENT_LIST_DIR}/src/ws2812.pio OUTPUT_DIR ${CMAKE_CURRENT_LIST_DIR}/src/generated)
target_link_libraries(stofzuiger target_link_libraries(stofzuiger
pico_stdlib pico_stdlib
hardware_sleep hardware_sleep
hardware_pio
hardware_pwm
) )
pico_enable_stdio_uart(stofzuiger 0) pico_enable_stdio_uart(stofzuiger 0)
pico_enable_stdio_usb(stofzuiger 1) pico_enable_stdio_usb(stofzuiger 0)
# create map/bin/hex/uf2 file in addition to ELF. # create map/bin/hex/uf2 file in addition to ELF.
pico_add_extra_outputs(stofzuiger) pico_add_extra_outputs(stofzuiger)

View File

@ -0,0 +1,66 @@
// -------------------------------------------------- //
// This file is autogenerated by pioasm; do not edit! //
// -------------------------------------------------- //
#pragma once
#if !PICO_NO_HARDWARE
#include "hardware/pio.h"
#endif
// ------ //
// ws2812 //
// ------ //
#define ws2812_wrap_target 0
#define ws2812_wrap 3
#define ws2812_pio_version 0
#define ws2812_T1 3
#define ws2812_T2 3
#define ws2812_T3 4
static const uint16_t ws2812_program_instructions[] = {
// .wrap_target
0x6321, // 0: out x, 1 side 0 [3]
0x1223, // 1: jmp !x, 3 side 1 [2]
0x1200, // 2: jmp 0 side 1 [2]
0xa242, // 3: nop side 0 [2]
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program ws2812_program = {
.instructions = ws2812_program_instructions,
.length = 4,
.origin = -1,
.pio_version = ws2812_pio_version,
#if PICO_PIO_VERSION > 0
.used_gpio_ranges = 0x0
#endif
};
static inline pio_sm_config ws2812_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + ws2812_wrap_target, offset + ws2812_wrap);
sm_config_set_sideset(&c, 1, false, false);
return c;
}
#include "hardware/clocks.h"
static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin, float freq, bool rgbw) {
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);
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);
}
#endif

View File

@ -1,25 +1,28 @@
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <pico/stdlib.h> #include <pico/stdlib.h>
#include <hardware/pio.h>
#include <hardware/clocks.h> #include <hardware/clocks.h>
#include <hardware/pwm.h>
#include <pico/sleep.h> #include <pico/sleep.h>
#include "generated/ws2812.pio.h"
#define IS_RGBW false #define IS_RGBW false
#define NUM_PIXELS 1 #define NUM_PIXELS 1
#define WS2812_PIN 16 #define WS2812_PIN 16
#define PIN_LED_MODE_RED 0 #define PIN_LED_MODE_GREEN 3
#define PIN_LED_MODE_GREEN 1 #define PIN_LED_MODE_RED 4
#define PIN_LED_BATT1 2 #define PIN_LED_BATT1 5
#define PIN_LED_BATT2 3 #define PIN_LED_BATT2 6
#define PIN_LED_BATT3 4 #define PIN_LED_BATT3 7
#define PIN_BTN 5 #define PIN_BTN 2
#define PIN_MOTOR_IO1 6
#define PIN_MOTOR_IO2 7
#define PIN_MOTOR_PWM 8 #define PIN_MOTOR_PWM 8
#define PIN_MOTOR_IO1 9
#define PIN_MOTOR_IO2 10
typedef enum { typedef enum {
STATE_OFF, STATE_OFF,
@ -27,33 +30,22 @@ typedef enum {
STATE_LOW STATE_LOW
} mainState_t; } mainState_t;
mainState_t mainState; mainState_t mainState;
bool btn_pressed = false;
void update_state(mainState_t state) static inline void put_pixel(PIO pio, uint sm, uint32_t pixel_grb) {
{ pio_sm_put_blocking(pio, sm, pixel_grb << 8u);
switch (state) }
{
case STATE_OFF:
gpio_put(PIN_MOTOR_IO1, 0);
gpio_put(PIN_MOTOR_IO2, 0);
break;
case STATE_HIGE:
gpio_put(PIN_MOTOR_IO1, 1);
gpio_put(PIN_MOTOR_IO2, 0);
break;
case STATE_LOW:
gpio_put(PIN_MOTOR_IO1, 0);
gpio_put(PIN_MOTOR_IO2, 1);
break;
static inline uint32_t urgb_u32(uint8_t r, uint8_t g, uint8_t b) {
} return ((uint32_t) (r) << 16) | ((uint32_t) (g) << 8) | (uint32_t) (b);
} }
int main() { int main() {
//set_sys_clock_48(); //set_sys_clock_48();
stdio_init_all(); // stdio_init_all();
mainState = STATE_OFF; mainState = STATE_OFF;
uint pwm_out;
// init gpio outputs // init gpio outputs
gpio_init(PIN_LED_MODE_RED); gpio_init(PIN_LED_MODE_RED);
@ -71,31 +63,89 @@ int main() {
gpio_init(PIN_LED_BATT3); gpio_init(PIN_LED_BATT3);
gpio_set_dir(PIN_LED_BATT3, GPIO_OUT); gpio_set_dir(PIN_LED_BATT3, GPIO_OUT);
gpio_put(PIN_LED_BATT3, 0); gpio_put(PIN_LED_BATT3, 0);
gpio_init(PIN_MOTOR_IO1);
gpio_set_dir(PIN_MOTOR_IO1, GPIO_OUT); gpio_set_dir(PIN_MOTOR_IO1, GPIO_OUT);
gpio_put(PIN_MOTOR_IO1, 0); gpio_put(PIN_MOTOR_IO1, 0);
gpio_init(PIN_MOTOR_IO2);
gpio_set_dir(PIN_MOTOR_IO2, GPIO_OUT); gpio_set_dir(PIN_MOTOR_IO2, GPIO_OUT);
gpio_put(PIN_MOTOR_IO2, 0); gpio_put(PIN_MOTOR_IO2, 0);
// gpio_init(PIN_MOTOR_PWM);
gpio_set_function(PIN_MOTOR_PWM, GPIO_FUNC_PWM);
pwm_out = pwm_gpio_to_slice_num(PIN_MOTOR_PWM);
pwm_config config = pwm_get_default_config();
// set to about 25 kHz
pwm_config_set_clkdiv(&config, 255.f);
pwm_config_set_wrap(&config, 19);
pwm_init(pwm_out, &config, true);
pwm_set_gpio_level(PIN_MOTOR_PWM, 0);
// init gpio inputs // init gpio inputs
gpio_init(PIN_BTN); gpio_init(PIN_BTN);
gpio_set_dir(PIN_BTN, GPIO_IN); gpio_set_dir(PIN_BTN, GPIO_IN);
gpio_set_pulls(PIN_BTN, false, true);
// gpio_set_irq_enabled_with_callback(PIN_BTN, GPIO_IRQ_EDGE_FALL, true, &switch_state);
// todo get free sm
PIO pio;
uint sm;
uint offset;
pio_claim_free_sm_and_add_program_for_gpio_range(&ws2812_program, &pio, &sm, &offset, WS2812_PIN, 1, false);
ws2812_program_init(pio, sm, offset, WS2812_PIN, 800000, false);
put_pixel(pio, sm, urgb_u32(0, 0, 0));
// pio_remove_program_and_unclaim_sm(&ws2812_program, pio, sm, offset);
mainState = STATE_OFF;
uint8_t counter = 0;
bool last_state = true;
while (true) while (true)
{ {
mainState = STATE_OFF; // sleep_run_from_xosc();
update_state(STATE_OFF); // sleep_goto_dormant_until_pin(PIN_BTN, true, false); // falling edge
sleep_goto_dormant_until_edge_high(PIN_BTN); // sleep_goto_sleep_for(100, &switch_state); // debounce
mainState = STATE_HIGE; // sleep_power_up();
while (mainState != STATE_OFF)
{ bool new_state;
while ((new_state = gpio_get(PIN_BTN)) == last_state) {
tight_loop_contents();
}
sleep_ms(100);
last_state = new_state;
if (new_state) {
switch (mainState) { switch (mainState) {
case STATE_OFF:
mainState = STATE_HIGE;
gpio_put(PIN_MOTOR_IO1, 0);
gpio_put(PIN_MOTOR_IO2, 1);
gpio_put(PIN_LED_MODE_RED, 1);
gpio_put(PIN_LED_MODE_GREEN, 0);
pwm_set_gpio_level(PIN_MOTOR_PWM, 19);
put_pixel(pio, sm, urgb_u32(50, 0, 0));
break;
case STATE_HIGE: case STATE_HIGE:
mainState = STATE_LOW; mainState = STATE_LOW;
gpio_put(PIN_MOTOR_IO1, 0);
gpio_put(PIN_MOTOR_IO2, 1);
gpio_put(PIN_LED_MODE_RED, 0);
gpio_put(PIN_LED_MODE_GREEN, 1);
pwm_set_gpio_level(PIN_MOTOR_PWM, 12);
put_pixel(pio, sm, urgb_u32(0, 50, 0));
break; break;
case STATE_LOW: case STATE_LOW:
mainState = STATE_OFF; mainState = STATE_OFF;
gpio_put(PIN_MOTOR_IO1, 0);
gpio_put(PIN_MOTOR_IO2, 0);
gpio_put(PIN_LED_MODE_RED, 0);
gpio_put(PIN_LED_MODE_GREEN, 0);
pwm_set_gpio_level(PIN_MOTOR_PWM, 0);
put_pixel(pio, sm, urgb_u32(0, 0, 50));
break; break;
} }
update_state(mainState);
} }
} }
return 0; return 0;

53
src/ws2812.pio Normal file
View File

@ -0,0 +1,53 @@
;
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
;
; SPDX-License-Identifier: BSD-3-Clause
;
.pio_version 0 // only requires PIO version 0
.program ws2812
.side_set 1
; The following constants are selected for broad compatibility with WS2812,
; WS2812B, and SK6812 LEDs. Other constants may support higher bandwidths for
; specific LEDs, such as (7,10,8) for WS2812B LEDs.
.define public T1 3
.define public T2 3
.define public T3 4
.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
% c-sdk {
#include "hardware/clocks.h"
static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin, float freq, bool rgbw) {
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);
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);
}
%}