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_usb(clock 1)
|
||||||
pico_enable_stdio_uart(clock 0)
|
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
|
# Pull in standard library and hardware abstraction
|
||||||
target_link_libraries(clock
|
target_link_libraries(clock
|
||||||
pico_stdlib
|
pico_stdlib
|
||||||
hardware_gpio
|
hardware_gpio
|
||||||
hardware_i2c
|
hardware_i2c
|
||||||
|
pico_multicore
|
||||||
|
pico_ssd1306
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create the .uf2 file
|
# Create the .uf2 file
|
||||||
|
|
|
||||||
|
|
@ -1,47 +1,35 @@
|
||||||
#ifndef GLOBALS_H
|
#ifndef GLOBALS_H
|
||||||
#define GLOBALS_H
|
#define GLOBALS_H
|
||||||
|
|
||||||
|
#include "pico/stdlib.h"
|
||||||
#include <cstdint>
|
#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
|
#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) {
|
void Gate::setDiv(uint16_t modifier, uint8_t divide) {
|
||||||
if (divide == 1) {
|
if (divide == 1) {
|
||||||
div = ppqn * modifier;
|
div = PPQN * modifier;
|
||||||
divString = "/" + std::to_string(modifier);
|
divString = "/" + std::to_string(modifier);
|
||||||
} else {
|
} else {
|
||||||
div = ppqn / modifier;
|
div = PPQN / modifier;
|
||||||
divString = "x" + std::to_string(modifier);
|
divString = "x" + std::to_string(modifier);
|
||||||
}
|
}
|
||||||
divideMode = divide;
|
divideMode = divide;
|
||||||
|
|
@ -45,9 +45,9 @@ void Gate::setDiv(uint16_t modifier, uint8_t divide) {
|
||||||
void Gate::setWidth(uint16_t newWidth) {
|
void Gate::setWidth(uint16_t newWidth) {
|
||||||
width = newWidth;
|
width = newWidth;
|
||||||
if (divideMode == 1) {
|
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 {
|
} 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) {
|
if (pRes == 1) {
|
||||||
state = 1;
|
state = 1;
|
||||||
digitalWrite(pin, state);
|
gpio_put(pin, state);
|
||||||
dur = millis();
|
dur = millis();
|
||||||
}
|
}
|
||||||
cycle = 0;
|
cycle = 0;
|
||||||
|
|
@ -79,7 +79,7 @@ void Gate::turnOn() {
|
||||||
void Gate::turnOff() {
|
void Gate::turnOff() {
|
||||||
if (state == 1 && millis() - dur >= len) {
|
if (state == 1 && millis() - dur >= len) {
|
||||||
state = 0;
|
state = 0;
|
||||||
digitalWrite(pin, state);
|
gpio_put(pin, state);
|
||||||
dur = 0;
|
dur = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
205
src/main.cpp
205
src/main.cpp
|
|
@ -1,37 +1,24 @@
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdio>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include "hardware/i2c.h"
|
||||||
#include "hardware/structs/rosc.h"
|
#include "hardware/structs/rosc.h"
|
||||||
|
#include "pico/multicore.h"
|
||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
#include "pico/time.h"
|
#include "pico/time.h"
|
||||||
#include <cstdint>
|
|
||||||
|
#include "pico-ssd1306/ssd1306.h"
|
||||||
|
#include "pico-ssd1306/textRenderer/TextRenderer.h"
|
||||||
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "Gate.h"
|
#include "Gate.h"
|
||||||
|
|
||||||
static constexpr uint8_t OUT_1_PIN = 0;
|
struct repeating_timer bpm_timer = {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;
|
|
||||||
|
|
||||||
|
volatile uint8_t BPM = 60;
|
||||||
volatile uint8_t PLAY = 1;
|
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;
|
volatile uint32_t period_us = 0;
|
||||||
|
|
||||||
struct repeating_timer bpm_timer;
|
|
||||||
|
|
||||||
volatile bool beatToggle = false;
|
volatile bool beatToggle = false;
|
||||||
|
|
||||||
Gate out1(OUT_1_PIN);
|
Gate out1(OUT_1_PIN);
|
||||||
|
|
@ -43,6 +30,13 @@ Gate out6(OUT_6_PIN);
|
||||||
Gate out7(OUT_7_PIN);
|
Gate out7(OUT_7_PIN);
|
||||||
Gate out8(OUT_8_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) {
|
bool timer_callback(struct repeating_timer *t) {
|
||||||
if (PLAY == 1) {
|
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() {
|
int main() {
|
||||||
stdio_init_all();
|
stdio_init_all();
|
||||||
|
|
||||||
srand(rosc_hw->randombit);
|
srand(rosc_hw->randombit);
|
||||||
|
|
||||||
gpio_init(out1.pin);
|
setup_screen();
|
||||||
gpio_init(out2.pin);
|
multicore_launch_core1(core1_entry);
|
||||||
gpio_init(out3.pin);
|
multicore_fifo_push_blocking(1);
|
||||||
gpio_init(out4.pin);
|
|
||||||
gpio_init(out5.pin);
|
|
||||||
gpio_init(out6.pin);
|
|
||||||
gpio_init(out7.pin);
|
|
||||||
gpio_init(out8.pin);
|
|
||||||
|
|
||||||
gpio_set_dir(out1.pin, GPIO_OUT);
|
setup_encoder();
|
||||||
gpio_set_dir(out2.pin, GPIO_OUT);
|
setup_outs();
|
||||||
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);
|
|
||||||
|
|
||||||
update_period();
|
update_period();
|
||||||
|
|
||||||
while (true) {
|
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