New ui, global settings.

This commit is contained in:
Daniele Lacamera 2020-04-13 11:11:17 +02:00
parent b949063b6a
commit d4749d2fe9
15 changed files with 253 additions and 82 deletions

View file

@ -5,7 +5,7 @@ VERSION?=1
OBJS:=startup.o main.o system.o mem.o led.o \ OBJS:=startup.o main.o system.o mem.o led.o \
i2c.o display.o font_twisted.o button.o systick.o newlib.o uart.o ui.o timer.o\ i2c.o display.o font_twisted.o button.o systick.o newlib.o uart.o ui.o timer.o\
mutex.o ui_drone.o adc.o spi.o pot.o dac.o sound.o drone.o mutex.o ui_drone.o adc.o spi.o pot.o dac.o sound.o drone.o settings.o
UMX:=lib/unicore-mx/lib/libucmx_stm32f4.a UMX:=lib/unicore-mx/lib/libucmx_stm32f4.a

View file

@ -39,7 +39,7 @@ enum button_state {
#endif #endif
#define BUTTON_DEBOUNCE_TIME 50 #define BUTTON_DEBOUNCE_TIME 50
#define BUTTON_HOLD_TIME 1500 #define BUTTON_HOLD_TIME 200

View file

@ -19,6 +19,12 @@ static struct drone_slot drone_pattern[MAX_PATTERN_LEN] = {
{ 40, 10 }, { 40, 10}, {36, 10}, {32,10} { 40, 10 }, { 40, 10}, {36, 10}, {32,10}
}; };
void drone_mute(void)
{
pot_set(0, 0xFF);
pot_set(1, 0x0);
}
void drone_beat(int pattern_pos) void drone_beat(int pattern_pos)
{ {
struct drone_slot *key = &drone_pattern[pattern_pos]; struct drone_slot *key = &drone_pattern[pattern_pos];

View file

@ -3,6 +3,8 @@
#define DRONE_H_INCLUDED #define DRONE_H_INCLUDED
#include <stdint.h> #include <stdint.h>
void drone_mute(void);
struct __attribute__((packed)) drone_slot { struct __attribute__((packed)) drone_slot {
uint8_t pitch; uint8_t pitch;
uint8_t env; uint8_t env;

5
led.c
View file

@ -84,10 +84,11 @@ void led_toggle(int led)
void led_beat(int b) void led_beat(int b)
{ {
if (b < 1 || b > 8) if (b < 0 || b > 8)
return; return;
gpio_clear(GPIOB, BANK_B_LD); gpio_clear(GPIOB, BANK_B_LD);
gpio_clear(GPIOE, BANK_E_LD); gpio_clear(GPIOE, BANK_E_LD);
led_on(b); if (b != 0)
led_on(b);
} }

12
main.c
View file

@ -15,6 +15,12 @@
#include "ui.h" #include "ui.h"
#include "button.h" #include "button.h"
#include "adc.h" #include "adc.h"
#include "pot.h"
#include "settings.h"
#include "drums.h"
#include "drone.h"
#include "uart.h"
#include "timer.h"
extern uint32_t cpu_freq; extern uint32_t cpu_freq;
#define BLINK_INTERVAL 500 #define BLINK_INTERVAL 500
@ -39,9 +45,6 @@ static void bootlevel_0(void)
printf("Buttons initialized.\r\n"); printf("Buttons initialized.\r\n");
} }
extern int timer_init(uint32_t bpm);
extern int timer_start();
extern int timer_stop();
static void bootlevel_1(void) static void bootlevel_1(void)
{ {
@ -66,7 +69,7 @@ static void bootlevel_1(void)
printf("Displaying splash screen...\r\n"); printf("Displaying splash screen...\r\n");
ui_init(); ui_init();
printf("UI initialized.\r\n"); printf("UI initialized.\r\n");
timer_init(140); timer_init();
drums_init(); drums_init();
drums_start(); drums_start();
@ -106,6 +109,7 @@ void process_button(uint8_t press, int hold)
process_input_callback(press, hold); process_input_callback(press, hold);
else else
ui_button_press(press, hold); ui_button_press(press, hold);
} }
extern void gettime(uint32_t *s, uint32_t *us); extern void gettime(uint32_t *s, uint32_t *us);

40
pot.c
View file

@ -4,10 +4,11 @@
#include "system.h" #include "system.h"
#include "led.h" #include "led.h"
#include "pinout.h" #include "pinout.h"
#include "settings.h"
#include "pot.h"
extern volatile uint32_t jiffies; extern volatile uint32_t jiffies;
uint32_t p1_lvl, p0_lvl, master_lvl;
static int pot_cs[3] = { 8, 7, 6 }; // PC6, PC7, PC8 static int pot_cs[3] = { 8, 7, 6 }; // PC6, PC7, PC8
@ -18,13 +19,11 @@ static int pot_cs[3] = { 8, 7, 6 }; // PC6, PC7, PC8
#define POTINC GPIO14 // D14 #define POTINC GPIO14 // D14
#define POTUD GPIO15 // D15 #define POTUD GPIO15 // D15
#define NUM_POTS 3
#define POT_CS_PINS (POT0 | POT1 | POTM) #define POT_CS_PINS (POT0 | POT1 | POTM)
#define POT_CTRL_PINS (POTINC | POTUD) #define POT_CTRL_PINS (POTINC | POTUD)
static int HWLevel[3] = {0, 0, 0};
static uint32_t Pots[NUM_POTS] = { POT0, POT1, POTM }; static uint32_t Pots[NUM_POTS] = { POT0, POT1, POTM };
static int Levels[NUM_POTS] = { 0, 0, 0 };
static void p_offset(int p, int offset) static void p_offset(int p, int offset)
@ -64,21 +63,21 @@ static void p_offset(int p, int offset)
;; ;;
} }
Levels[p] += offset; HWLevel[p] += offset;
if (Levels[p] > 100) if (HWLevel[p] > 100)
Levels[p] = 100; HWLevel[p] = 100;
if (Levels[p] < 0) if (HWLevel[p] < 0)
Levels[p] = 0; HWLevel[p] = 0;
} }
void pot_offset(int p, int offset) void pot_offset(int p, int offset)
{ {
if ((Levels[p] + offset) > 100) { if ((HWLevel[p] + offset) > 100) {
offset = 100 - Levels[p]; offset = 100 - HWLevel[p];
} }
if ((Levels[p] + offset) < 0) { if ((HWLevel[p] + offset) < 0) {
offset = 0 - Levels[p]; offset = 0 - HWLevel[p];
} }
if (offset == 0) if (offset == 0)
@ -108,20 +107,31 @@ void pot_init(void)
} }
void pot_sync(int p)
{
pot_set(p, Settings.levels[p]);
}
int pot_get(int p) int pot_get(int p)
{ {
return Levels[p]; return HWLevel[p];
} }
void pot_set(int p, int val) void pot_set(int p, int val)
{ {
int old = Levels[p]; int old = HWLevel[p];
int new = val;
int off; int off;
if (val < 0) if (val < 0)
val = 0; val = 0;
if (val > 100) if (val > 100)
val = 100; val = 100;
Settings.levels[p] = val;
off = val - old; off = val - old;
if (off == 0) if (off == 0)
return; return;

1
pot.h
View file

@ -11,5 +11,6 @@ void pot_offset(int p, int offset);
#define pot_get_master() pot_get(2) #define pot_get_master() pot_get(2)
#define pot_set_master(x) pot_set(2,x) #define pot_set_master(x) pot_set(2,x)
#define NUM_POTS 3
#endif #endif

6
settings.c Normal file
View file

@ -0,0 +1,6 @@
#include "settings.h"
struct settings Settings = {
.bpm = 125,
};

14
settings.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef SETTINGS_H_INCLUDED
#define SETTINGS_H_INCLUDED
#include <stdint.h>
#include "pot.h"
struct settings {
int levels[NUM_POTS];
#define master_vol levels[2]
int bpm;
int sequencer_on;
};
extern struct settings Settings;
#endif

22
timer.c
View file

@ -3,11 +3,11 @@
#include "led.h" #include "led.h"
#include "timer.h" #include "timer.h"
#include <stdlib.h> #include <stdlib.h>
#include "settings.h"
#define S_PER_MINUTE (60) #define S_PER_MINUTE (60)
extern uint32_t cpu_freq; extern uint32_t cpu_freq;
static uint32_t sys_bpm = 75;
void (*beat_callback)(uint32_t b) = NULL; void (*beat_callback)(uint32_t b) = NULL;
@ -21,19 +21,13 @@ void timer_clear_beat_callback(void)
timer_set_beat_callback(NULL); timer_set_beat_callback(NULL);
} }
int timer_set_bpm(void)
uint32_t timer_get_bpm(void)
{
return sys_bpm;
}
int timer_set_bpm(uint32_t bpm)
{ {
uint32_t val = 0; uint32_t val = 0;
uint32_t psc = 1; uint32_t psc = 1;
uint32_t err = 0; uint32_t err = 0;
uint32_t reg = 0; uint32_t reg = 0;
uint32_t clock = (cpu_freq / (4 * bpm)) * (S_PER_MINUTE);; uint32_t clock = (cpu_freq / (4 * Settings.bpm)) * (S_PER_MINUTE);;
while (psc < 65535) { while (psc < 65535) {
val = clock / psc; val = clock / psc;
@ -52,7 +46,6 @@ int timer_set_bpm(uint32_t bpm)
TIM4_PSC = psc; TIM4_PSC = psc;
TIM4_ARR = val; TIM4_ARR = val;
TIM4_CNT = val - 1; TIM4_CNT = val - 1;
sys_bpm = bpm;
return 0; return 0;
} }
@ -64,8 +57,8 @@ int timer_start(void)
int timer_stop(void) int timer_stop(void)
{ {
TIM4_CR1 |= TIM_CR1_CLOCK_ENABLE; TIM4_CR1 &= ~TIM_CR1_CLOCK_ENABLE;
TIM4_DIER |= TIM_DIER_UIE; TIM4_DIER &= ~TIM_DIER_UIE;
} }
static void timer_irq_setup(void) static void timer_irq_setup(void)
@ -79,12 +72,11 @@ static void timer_irq_setup(void)
} }
int timer_init(uint32_t bpm) int timer_init(void)
{ {
timer_stop(); timer_stop();
timer_irq_setup(); timer_irq_setup();
timer_set_bpm(bpm); timer_set_bpm();
timer_start();
return 0; return 0;
} }

View file

@ -1,11 +1,10 @@
#ifndef TIMER_H_INCLUDED #ifndef TIMER_H_INCLUDED
#define TIMER_H_INCLUDED #define TIMER_H_INCLUDED
uint32_t timer_get_bpm(void); int timer_set_bpm(void);
int timer_set_bpm(uint32_t bpm);
int timer_start(void); int timer_start(void);
int timer_stop(void); int timer_stop(void);
int timer_init(uint32_t bpm); int timer_init(void);
void timer_set_beat_callback(void (*b_cb)(uint32_t)); void timer_set_beat_callback(void (*b_cb)(uint32_t));
void timer_clear_beat_callback(void); void timer_clear_beat_callback(void);

151
ui.c
View file

@ -22,8 +22,9 @@
//#define DEVICE_INITIALIZATION //#define DEVICE_INITIALIZATION
static const char welcome_message0[]= " Waveblender "; static const char welcome_message0[]= " Waveblender ";
static const char welcome_message1[]= " (c) 2020 "; static const char welcome_message1[]= "(c) danielinux ";
static const char welcome_message2[]= " danielinux "; static const char welcome_message2[]= " GPL v.2 ";
static const char welcome_message3[]= "src: wb.vado.li";
static uint32_t last_action = 0; static uint32_t last_action = 0;
static uint32_t offset = 0; static uint32_t offset = 0;
@ -88,6 +89,7 @@ static void ui_display_menu_refresh(void)
const struct display_menu *menu = CurrentMenu; const struct display_menu *menu = CurrentMenu;
uint8_t vline; uint8_t vline;
int i; int i;
char txt[16];
display_scroll(NULL, display_cur_v); display_scroll(NULL, display_cur_v);
display_clear(NULL); display_clear(NULL);
@ -95,10 +97,74 @@ static void ui_display_menu_refresh(void)
vline = i + 4; vline = i + 4;
if (vline > 7) if (vline > 7)
vline -= 8; vline -= 8;
switch (menu->entry[i].type) {
case ENTRY_TYPE_TEXT:
strncpy(txt, menu->entry[i].label, 15);
break;
case ENTRY_TYPE_HEX:
{
int x = *menu->entry[i].var ;
int j;
strncpy(txt, menu->entry[i].label, 11);
for (j = strlen(menu->entry[i].label); j < 12; j++)
txt[j] = ' ';
if (x > 0xFF) {
if (((x >> 8) & 0x0F) > 9)
txt[12] = (((x >> 8) & 0x0F) - 10) + 'A';
else
txt[12] = ((x >> 8) & 0x0F) + '0';
} else
txt[12] = ' ';
if (x > 0x0F) {
if (((x >> 4) & 0x0F) > 9)
txt[13] = (((x >> 4) & 0x0F) - 10) + 'A';
else
txt[13] = ((x >> 4) & 0x0F) + '0';
} else
txt[13] = ' ';
if ((x & 0x0F) > 9)
txt[14] = ((x & 0x0F) - 10) + 'A';
else
txt[14] = (x & 0x0F) + '0';
}
break;
case ENTRY_TYPE_BOOL:
{
int x = *menu->entry[i].var ;
int j;
strncpy(txt, menu->entry[i].label, 10);
for (j = strlen(menu->entry[i].label); j < 12; j++)
txt[j] = ' ';
if (x)
strcpy(txt + 10, "[ ON]");
else
strcpy(txt + 10, "[OFF]");
}
break;
case ENTRY_TYPE_DEC:
{
int x = *menu->entry[i].var ;
int j;
strncpy(txt, menu->entry[i].label, 11);
for (j = strlen(menu->entry[i].label); j < 12; j++)
txt[j] = ' ';
if (x > 99) {
txt[12] = (x / 100) + '0';
} else
txt[12] = ' ';
if (x > 9) {
txt[13] = ((x % 100)/10) + '0';
} else
txt[13] = ' ';
txt[14] = (x % 10) + '0';
}
break;
}
if (i == menu_selection) if (i == menu_selection)
display_text_inverse(vline, menu->entry[i].title); display_text_inverse(vline, txt);
else else
display_text(vline, menu->entry[i].title); display_text(vline, txt);
} }
WFI(); WFI();
} }
@ -115,32 +181,52 @@ void ui_display_menu(const struct display_menu *menu)
void ui_button_press(uint8_t b, int hold) void ui_button_press(uint8_t b, int hold)
{ {
if (b == '+') { int n = menu_selection;
int n = menu_selection; struct display_menu_entry e;
menu_selection = 0; switch (b) {
if (CurrentMenu->entry[n].action) { case 'U':
display_cur_v = 0; if (menu_selection > 0) {
display_clear(NULL); menu_selection--;
display_scroll(NULL, display_cur_v); ui_menu_autoscroll();
CurrentMenu->entry[n].action( ui_display_menu_refresh();
CurrentMenu->entry[n].arg); }
break;
} case 'D':
return; if (menu_selection < CurrentMenu->entry_n - 1) {
} menu_selection++;
if (b == 'U') { ui_menu_autoscroll();
if (menu_selection > 0) { ui_display_menu_refresh();
menu_selection--; }
ui_menu_autoscroll(); break;
ui_display_menu_refresh(); default:
} e = CurrentMenu->entry[n];
} int changed = 0;
if (b == 'D') { /* Default actions for '-', '+', '*' */
if (menu_selection < CurrentMenu->entry_n - 1) { if (e.var && (e.type == ENTRY_TYPE_BOOL)) {
menu_selection++; if ((*e.var) && ((b == '-') || (b == '*'))) {
ui_menu_autoscroll(); *e.var = 0;
ui_display_menu_refresh(); changed = 1;
} } else if ((!(*e.var)) && ((b == '+') || (b == '*'))) {
*e.var = 1;
changed = 1;
}
} else if ((e.min != e.max) && e.var && ((e.type == ENTRY_TYPE_DEC) || (e.type == ENTRY_TYPE_DEC))) {
if ((*e.var > e.min) && (b == '-')) {
*e.var -= e.step;
changed = 1;
} else if ((*e.var < e.max) && (b == '+')) {
*e.var += e.step;
changed = 1;
}
}
/* Custom actions for '-', '+', '*' (after changes are applied) */
if (b != 0 && e.action) {
e.action(&e, b);
changed = 1;
}
if (changed) {
ui_display_menu_refresh();
}
} }
} }
@ -152,16 +238,17 @@ void ui_init(void)
display_text(0, welcome_message0); display_text(0, welcome_message0);
display_text(1, welcome_message1); display_text(1, welcome_message1);
display_text(2, welcome_message2); display_text(2, welcome_message2);
display_text(3, welcome_message3);
now = jiffies; now = jiffies;
for (i = 0x3f; i >= 0x20; i--) { for (i = 0x3f; i >= 0x20; i--) {
display_scroll(NULL, i); display_scroll(NULL, i);
while ((jiffies - now) < 30) while ((jiffies - now) < 20)
WFI(); WFI();
now = jiffies; now = jiffies;
} }
for (i = display_getcontrast(NULL); i >= 0; i--) { for (i = display_getcontrast(NULL); i >= 0; i--) {
display_setcontrast(NULL, i); display_setcontrast(NULL, i);
while ((jiffies - now) < 10) while ((jiffies - now) < 16)
WFI(); WFI();
now = jiffies; now = jiffies;
} }

18
ui.h
View file

@ -4,14 +4,26 @@
void ui_init(void); void ui_init(void);
#define ENTRY_TYPE_TEXT 0
#define ENTRY_TYPE_BOOL 1
#define ENTRY_TYPE_DEC 2
#define ENTRY_TYPE_HEX 3
#define MAX_ENTRY 8
struct display_menu { struct display_menu {
struct display_menu *next; struct display_menu *next;
int entry_n; int entry_n;
struct display_menu_entry { struct display_menu_entry {
char title[16]; int type;
void (*action)(const void *arg); char label[16];
void (*action)(struct display_menu_entry *item, uint8_t button);
int min, max, step;
int *var;
const void *arg; const void *arg;
} entry[8]; } entry[MAX_ENTRY];
}; };

View file

@ -7,6 +7,9 @@
#include "unicore-mx/stm32/gpio.h" #include "unicore-mx/stm32/gpio.h"
#include "unicore-mx/stm32/rcc.h" #include "unicore-mx/stm32/rcc.h"
#include "pot.h" #include "pot.h"
#include "dac.h"
#include "settings.h"
#include "timer.h"
#define CENTER_X ((int)(52)) #define CENTER_X ((int)(52))
#define CENTER_Y ((int)(50)) #define CENTER_Y ((int)(50))
@ -16,7 +19,7 @@ struct display_menu *CurrentMenu = &MainMenu;
extern volatile uint32_t jiffies; extern volatile uint32_t jiffies;
static uint32_t drone_xy_gain = 1; static uint32_t drone_xy_gain = 1;
#if 0
static void ui_return(uint8_t press, int hold) static void ui_return(uint8_t press, int hold)
{ {
display_clear(NULL); display_clear(NULL);
@ -192,7 +195,7 @@ static void ui_bpm_input(uint8_t press, int hold)
if (press == 'U') { if (press == 'U') {
if (sys_bpm < 300) { if (sys_bpm < 300) {
timer_stop(); timer_stop();
timer_set_bpm(sys_bpm + 1); timer_set_bpm();
led_beat(1); led_beat(1);
timer_set_beat(1); timer_set_beat(1);
timer_start(); timer_start();
@ -208,7 +211,7 @@ static void ui_bpm_input(uint8_t press, int hold)
timer_start(); timer_start();
} }
} }
if (press == '+') { if (press == '*') {
display_clear(NULL); display_clear(NULL);
clear_input_callback(); clear_input_callback();
ui_display_menu(&MainMenu); ui_display_menu(&MainMenu);
@ -294,15 +297,49 @@ const struct display_menu SettingsMenu = {
} }
}; };
#endif
static void ui_sequencer_action(struct display_menu_entry *e, uint8_t b)
{
if (Settings.sequencer_on) {
timer_set_beat(1);
timer_start();
} else {
led_beat(0);
drone_mute();
timer_stop();
}
}
static void ui_master_action(struct display_menu_entry *e, uint8_t b)
{
pot_sync(2);
}
static void ui_bpm_action(struct display_menu_entry *e, uint8_t b)
{
timer_stop();
timer_set_bpm();
led_beat(1);
timer_set_beat(1);
timer_start();
}
const struct display_menu MainMenu = { const struct display_menu MainMenu = {
.entry_n = 5, .entry_n = 3,
.entry = { .entry = {
{ "Master Volume ", ui_mastervol, NULL }, /* TYPE, label, action, min, max, var, arg */
{ ENTRY_TYPE_BOOL, "Sequencer", ui_sequencer_action, 0, 0, 0, &Settings.sequencer_on, NULL },
{ ENTRY_TYPE_DEC, "Volume: ", ui_master_action, 0, 100, 2, &Settings.levels[2], NULL },
{ ENTRY_TYPE_DEC, "BPM: ", ui_bpm_action, 30, 300, 1, &Settings.bpm, NULL },
/*
{ "BPM" , ui_bpm, NULL}, { "BPM" , ui_bpm, NULL},
{ "Pattern ", ui_submenu, &PatternMenu }, { "Pattern ", ui_submenu, &PatternMenu },
{ "Drone ", ui_submenu, &DroneMenu}, { "Drone ", ui_submenu, &DroneMenu},
{ "Bytebeat ", ui_bytebeat }, { "Bytebeat ", ui_bytebeat },
{ "", NULL, NULL} */
{0, "", NULL, 0,0,0,NULL,NULL}
} }
}; };