back to where we began, now with rpi
This commit is contained in:
parent
d4f8c94cd4
commit
90915b89f6
6 changed files with 211 additions and 86 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "lib/pico-ssd1306"]
|
||||
path = lib/pico-ssd1306
|
||||
url = https://github.com/Harbys/pico-ssd1306
|
||||
|
|
@ -23,11 +23,17 @@ add_executable(clock
|
|||
pico_enable_stdio_usb(clock 1)
|
||||
pico_enable_stdio_uart(clock 0)
|
||||
|
||||
target_include_directories(clock PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/lib)
|
||||
|
||||
add_subdirectory(lib/pico-ssd1306)
|
||||
|
||||
# Pull in standard library and hardware abstraction
|
||||
target_link_libraries(clock
|
||||
pico_stdlib
|
||||
hardware_gpio
|
||||
hardware_i2c
|
||||
pico_multicore
|
||||
pico_ssd1306
|
||||
)
|
||||
|
||||
# Create the .uf2 file
|
||||
|
|
|
|||
|
|
@ -1,47 +1,35 @@
|
|||
#ifndef GLOBALS_H
|
||||
#define GLOBALS_H
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include <cstdint>
|
||||
|
||||
static constexpr uint8_t OUT_1_PIN = 0;
|
||||
static constexpr uint8_t OUT_2_PIN = 2;
|
||||
static constexpr uint8_t OUT_3_PIN = 4;
|
||||
static constexpr uint8_t OUT_4_PIN = 6;
|
||||
static constexpr uint8_t OUT_5_PIN = 8;
|
||||
static constexpr uint8_t OUT_6_PIN = 10;
|
||||
static constexpr uint8_t OUT_7_PIN = 12;
|
||||
static constexpr uint8_t OUT_8_PIN = 14;
|
||||
|
||||
static constexpr uint8_t SCREEN_SCL_PIN = 18;
|
||||
static constexpr uint8_t SCREEN_SDA_PIN = 19;
|
||||
|
||||
static constexpr uint8_t ENCODER_CLK_PIN = 20;
|
||||
static constexpr uint8_t ENCODER_DT_PIN = 21;
|
||||
static constexpr uint8_t ENCODER_SW_PIN = 22;
|
||||
|
||||
extern volatile uint8_t BPM;
|
||||
|
||||
static constexpr uint32_t MINUTE_US = 60000000;
|
||||
static constexpr uint8_t PPQN = 96;
|
||||
|
||||
inline uint32_t millis() {
|
||||
return to_ms_since_boot(get_absolute_time());
|
||||
}
|
||||
|
||||
inline uint32_t micros() {
|
||||
return to_us_since_boot(get_absolute_time());
|
||||
}
|
||||
#endif // GLOBALS_H
|
||||
|
||||
/*
|
||||
TODO:
|
||||
|
||||
PRE-DAC:
|
||||
[x] Figure out multiplicative beats X2 X4 X8 X16 X32?
|
||||
[ ] Swing/Phase (same thing)
|
||||
[x] Probability
|
||||
[ ] Humanization
|
||||
[ ] Euclidian Rhythms
|
||||
[ ] Steps - # of steps for a full pattern
|
||||
[ ] Hits - how many hits across the steps, must be less than steps
|
||||
[ ] Offset - move the starting point of the pattern
|
||||
[ ] Logic (NO | AND | OR | XOR)
|
||||
[ ] Mute
|
||||
[ ] Save
|
||||
[ ] Load
|
||||
|
||||
POST-DAC:
|
||||
[ ] Different Wave Forms
|
||||
[ ] Different Voltage levels
|
||||
[ ] v/oct?
|
||||
|
||||
100BPM
|
||||
4800BPM
|
||||
|
||||
POSSIBLE DIVISIONS:
|
||||
1: x48
|
||||
16: x32
|
||||
32: x16
|
||||
40: x8
|
||||
44: x4
|
||||
46: x2
|
||||
---
|
||||
48*1: 1 ** THIS NEEDS TO BE PASSED IN AS DIVIDE MODE
|
||||
48*2 = 96: /2
|
||||
48*4 = 192: /4
|
||||
48*8 = /8
|
||||
48*16 = /16
|
||||
|
||||
*/
|
||||
|
|
|
|||
1
lib/pico-ssd1306
Submodule
1
lib/pico-ssd1306
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 2cec467a06bb8cd89363e12091bfd2318f7feab6
|
||||
12
src/Gate.cpp
12
src/Gate.cpp
|
|
@ -32,10 +32,10 @@ void Gate::setLen(uint32_t currentPeriod) {
|
|||
|
||||
void Gate::setDiv(uint16_t modifier, uint8_t divide) {
|
||||
if (divide == 1) {
|
||||
div = ppqn * modifier;
|
||||
div = PPQN * modifier;
|
||||
divString = "/" + std::to_string(modifier);
|
||||
} else {
|
||||
div = ppqn / modifier;
|
||||
div = PPQN / modifier;
|
||||
divString = "x" + std::to_string(modifier);
|
||||
}
|
||||
divideMode = divide;
|
||||
|
|
@ -45,9 +45,9 @@ void Gate::setDiv(uint16_t modifier, uint8_t divide) {
|
|||
void Gate::setWidth(uint16_t newWidth) {
|
||||
width = newWidth;
|
||||
if (divideMode == 1) {
|
||||
len = (uint32_t)((double)(minute / BPM) * (width / 100.0) / 1000.0);
|
||||
len = (uint32_t)((double)(MINUTE_US / BPM) * (width / 100.0) / 1000.0);
|
||||
} else {
|
||||
len = (uint32_t)((double)(minute / BPM / modifier) * (width / 100.0) / 1000.0);
|
||||
len = (uint32_t)((double)(MINUTE_US / BPM / modifier) * (width / 100.0) / 1000.0);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ void Gate::turnOn() {
|
|||
|
||||
if (pRes == 1) {
|
||||
state = 1;
|
||||
digitalWrite(pin, state);
|
||||
gpio_put(pin, state);
|
||||
dur = millis();
|
||||
}
|
||||
cycle = 0;
|
||||
|
|
@ -79,7 +79,7 @@ void Gate::turnOn() {
|
|||
void Gate::turnOff() {
|
||||
if (state == 1 && millis() - dur >= len) {
|
||||
state = 0;
|
||||
digitalWrite(pin, state);
|
||||
gpio_put(pin, state);
|
||||
dur = 0;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
205
src/main.cpp
205
src/main.cpp
|
|
@ -1,37 +1,24 @@
|
|||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <stdio.h>
|
||||
#include "hardware/i2c.h"
|
||||
#include "hardware/structs/rosc.h"
|
||||
#include "pico/multicore.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/time.h"
|
||||
#include <cstdint>
|
||||
|
||||
#include "pico-ssd1306/ssd1306.h"
|
||||
#include "pico-ssd1306/textRenderer/TextRenderer.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "Gate.h"
|
||||
|
||||
static constexpr uint8_t OUT_1_PIN = 0;
|
||||
static constexpr uint8_t OUT_2_PIN = 2;
|
||||
static constexpr uint8_t OUT_3_PIN = 4;
|
||||
static constexpr uint8_t OUT_4_PIN = 6;
|
||||
static constexpr uint8_t OUT_5_PIN = 8;
|
||||
static constexpr uint8_t OUT_6_PIN = 10;
|
||||
static constexpr uint8_t OUT_7_PIN = 12;
|
||||
static constexpr uint8_t OUT_8_PIN = 14;
|
||||
|
||||
static constexpr uint8_t SCREEN_SCL_PIN = 18;
|
||||
static constexpr uint8_t SCREEN_SDA_PIN = 19;
|
||||
|
||||
static constexpr uint8_t ENCODER_CLK_PIN = 20;
|
||||
static constexpr uint8_t ENCODER_DT_PIN = 21;
|
||||
static constexpr uint8_t ENCODER_SW_PIN = 22;
|
||||
struct repeating_timer bpm_timer = {0};
|
||||
|
||||
volatile uint8_t BPM = 60;
|
||||
volatile uint8_t PLAY = 1;
|
||||
volatile uint8_t BPM = 100;
|
||||
|
||||
static constexpr uint32_t MINUTE_US = 60000000;
|
||||
static constexpr uint8_t PPQN = 96;
|
||||
volatile uint32_t period_us = 0;
|
||||
|
||||
struct repeating_timer bpm_timer;
|
||||
|
||||
volatile bool beatToggle = false;
|
||||
|
||||
Gate out1(OUT_1_PIN);
|
||||
|
|
@ -43,6 +30,13 @@ Gate out6(OUT_6_PIN);
|
|||
Gate out7(OUT_7_PIN);
|
||||
Gate out8(OUT_8_PIN);
|
||||
|
||||
volatile bool updateScreen = 1;
|
||||
pico_ssd1306::SSD1306* display = nullptr;
|
||||
|
||||
volatile uint8_t encoder_pos = 0;
|
||||
volatile bool button_pressed = 0;
|
||||
volatile uint16_t clk_last_state;
|
||||
|
||||
|
||||
bool timer_callback(struct repeating_timer *t) {
|
||||
if (PLAY == 1) {
|
||||
|
|
@ -64,33 +58,166 @@ void update_period() {
|
|||
}
|
||||
|
||||
|
||||
void update_BPM(bool up) {
|
||||
if (up) {
|
||||
BPM++;
|
||||
} else {
|
||||
BPM--;
|
||||
}
|
||||
|
||||
update_period();
|
||||
}
|
||||
|
||||
|
||||
void gpio_callback(uint gpio, uint32_t events) {
|
||||
if (gpio == ENCODER_SW_PIN) { // handle button press
|
||||
|
||||
} else if (gpio == ENCODER_CLK_PIN || gpio == ENCODER_DT_PIN) { // handle encoder turn
|
||||
uint16_t clk_state = gpio_get(ENCODER_CLK_PIN);
|
||||
uint16_t dt_state = gpio_get(ENCODER_DT_PIN);
|
||||
|
||||
if (clk_state != clk_last_state && clk_state == 1)
|
||||
if (dt_state != clk_state) {
|
||||
encoder_pos++; // Clockwise
|
||||
update_BPM(1);
|
||||
} else {
|
||||
encoder_pos--; // Counter-clockwise
|
||||
update_BPM(0);
|
||||
}
|
||||
|
||||
updateScreen = 1;
|
||||
|
||||
clk_last_state = clk_state;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup_encoder() {
|
||||
gpio_init(ENCODER_SW_PIN);
|
||||
gpio_set_dir(ENCODER_SW_PIN, GPIO_IN);
|
||||
gpio_pull_up(ENCODER_SW_PIN);
|
||||
|
||||
gpio_init(ENCODER_CLK_PIN);
|
||||
gpio_set_dir(ENCODER_CLK_PIN, GPIO_IN);
|
||||
gpio_pull_up(ENCODER_CLK_PIN);
|
||||
|
||||
gpio_init(ENCODER_DT_PIN);
|
||||
gpio_set_dir(ENCODER_DT_PIN, GPIO_IN);
|
||||
gpio_pull_up(ENCODER_DT_PIN);
|
||||
|
||||
clk_last_state = gpio_get(ENCODER_CLK_PIN);
|
||||
|
||||
gpio_set_irq_enabled_with_callback(20, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &gpio_callback);
|
||||
gpio_set_irq_enabled(21, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true);
|
||||
gpio_set_irq_enabled(22, GPIO_IRQ_EDGE_FALL, true);
|
||||
}
|
||||
|
||||
|
||||
void setup_screen() {
|
||||
i2c_init(i2c1, 400 * 1000);
|
||||
|
||||
gpio_set_function(SCREEN_SDA_PIN, GPIO_FUNC_I2C);
|
||||
gpio_set_function(SCREEN_SCL_PIN, GPIO_FUNC_I2C);
|
||||
|
||||
gpio_pull_up(SCREEN_SDA_PIN);
|
||||
gpio_pull_up(SCREEN_SCL_PIN);
|
||||
|
||||
display = new pico_ssd1306::SSD1306(i2c1, 0x3C, pico_ssd1306::Size::W128xH64);
|
||||
display->setOrientation(0);
|
||||
}
|
||||
|
||||
|
||||
void core1_entry() {
|
||||
multicore_fifo_pop_blocking();
|
||||
|
||||
char buffer[32];
|
||||
|
||||
while (true) {
|
||||
if (updateScreen) {
|
||||
display->clear();
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "BPM: %u", BPM);
|
||||
pico_ssd1306::drawText(display, font_12x16, buffer, 0, 0);
|
||||
|
||||
display->sendBuffer();
|
||||
|
||||
updateScreen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup_outs() {
|
||||
Gate* my_outputs[] = {&out1, &out2, &out3, &out4, &out5, &out6, &out7, &out8};
|
||||
|
||||
for (auto g : my_outputs) {
|
||||
gpio_init(g->pin);
|
||||
gpio_set_dir(g->pin, GPIO_OUT);
|
||||
g->setLen(period_us);
|
||||
}
|
||||
|
||||
// manual setup
|
||||
out1.setDiv(8, 0);
|
||||
out1.setWidth(50);
|
||||
|
||||
out2.setDiv(4, 0);
|
||||
out2.setWidth(50);
|
||||
|
||||
out3.setDiv(2, 0);
|
||||
out3.setWidth(50);
|
||||
|
||||
out4.setDiv(1);
|
||||
out4.setWidth(50);
|
||||
|
||||
out5.setDiv(2);
|
||||
out5.setWidth(50);
|
||||
|
||||
out6.setDiv(4);
|
||||
out6.setWidth(50);
|
||||
|
||||
out7.setDiv(8);
|
||||
out7.setWidth(50);
|
||||
|
||||
out8.setDiv(16);
|
||||
out8.setWidth(50);
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
srand(rosc_hw->randombit);
|
||||
|
||||
gpio_init(out1.pin);
|
||||
gpio_init(out2.pin);
|
||||
gpio_init(out3.pin);
|
||||
gpio_init(out4.pin);
|
||||
gpio_init(out5.pin);
|
||||
gpio_init(out6.pin);
|
||||
gpio_init(out7.pin);
|
||||
gpio_init(out8.pin);
|
||||
setup_screen();
|
||||
multicore_launch_core1(core1_entry);
|
||||
multicore_fifo_push_blocking(1);
|
||||
|
||||
gpio_set_dir(out1.pin, GPIO_OUT);
|
||||
gpio_set_dir(out2.pin, GPIO_OUT);
|
||||
gpio_set_dir(out3.pin, GPIO_OUT);
|
||||
gpio_set_dir(out4.pin, GPIO_OUT);
|
||||
gpio_set_dir(out5.pin, GPIO_OUT);
|
||||
gpio_set_dir(out6.pin, GPIO_OUT);
|
||||
gpio_set_dir(out7.pin, GPIO_OUT);
|
||||
gpio_set_dir(out8.pin, GPIO_OUT);
|
||||
setup_encoder();
|
||||
setup_outs();
|
||||
|
||||
update_period();
|
||||
|
||||
while (true) {
|
||||
if (beatToggle) {
|
||||
out1.turnOn();
|
||||
out2.turnOn();
|
||||
out3.turnOn();
|
||||
out4.turnOn();
|
||||
out5.turnOn();
|
||||
out6.turnOn();
|
||||
out7.turnOn();
|
||||
out8.turnOn();
|
||||
|
||||
beatToggle = false;
|
||||
}
|
||||
|
||||
out1.turnOff();
|
||||
out2.turnOff();
|
||||
out3.turnOff();
|
||||
out4.turnOff();
|
||||
out5.turnOff();
|
||||
out6.turnOff();
|
||||
out7.turnOff();
|
||||
out8.turnOff();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue