Compare commits

...

4 Commits

  1. 2
      Src/tim.c
  2. 4
      User/dotmatrix.h
  3. 108
      User/font.h
  4. 11
      User/screendef.h
  5. 73
      User/scrolltext.c
  6. 13
      User/scrolltext.h
  7. 134
      User/user_main.c

@ -50,7 +50,7 @@ void MX_TIM3_Init(void)
htim3.Instance = TIM3; htim3.Instance = TIM3;
htim3.Init.Prescaler = 0; htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 3600; // MX: changed from 1800 htim3.Init.Period = 1800; // MX: changed from 1800
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
if (HAL_TIM_OC_Init(&htim3) != HAL_OK) if (HAL_TIM_OC_Init(&htim3) != HAL_OK)
{ {

@ -21,10 +21,6 @@ typedef struct {
uint32_t rows; /*!< Number of drivers vertically */ uint32_t rows; /*!< Number of drivers vertically */
} DotMatrix_Init; } DotMatrix_Init;
// global inst
extern DotMatrix_Cfg *dmtx;
DotMatrix_Cfg* dmtx_init(DotMatrix_Init *init); DotMatrix_Cfg* dmtx_init(DotMatrix_Init *init);
/** /**

@ -0,0 +1,108 @@
#ifndef FONT_H
#define FONT_H
#define FONT_MIN ' '
#define FONT_MAX '~'
#define FONT_WIDTH 6
const unsigned char font[96][6] = {
{0x00,0x00,0x00,0x00,0x00,0x00}, //
{0x5c,0x00,0x00,0x00,0x00,0x00}, // !
{0x06,0x00,0x06,0x00,0x00,0x00}, // "
{0x28,0x7c,0x28,0x7c,0x28,0x00}, // #
{0x5c,0x54,0xfe,0x54,0x74,0x00}, // $
{0x44,0x20,0x10,0x08,0x44,0x00}, // %
{0x28,0x54,0x54,0x20,0x50,0x00}, // &
{0x06,0x00,0x00,0x00,0x00,0x00}, // '
{0x38,0x44,0x00,0x00,0x00,0x00}, // (
{0x44,0x38,0x00,0x00,0x00,0x00}, // )
{0x02,0x07,0x02,0x00,0x00,0x00}, // *
{0x10,0x10,0x7c,0x10,0x10,0x00}, // +
{0xc0,0x00,0x00,0x00,0x00,0x00}, // ,
{0x10,0x10,0x10,0x10,0x10,0x00}, // -
{0x40,0x00,0x00,0x00,0x00,0x00}, // .
{0x60,0x10,0x0c,0x00,0x00,0x00}, // /
{0x7c,0x64,0x54,0x4c,0x7c,0x00}, // 0
{0x48,0x7c,0x40,0x00,0x00,0x00}, // 1
{0x64,0x54,0x54,0x54,0x48,0x00}, // 2
{0x44,0x54,0x54,0x54,0x6c,0x00}, // 3
{0x3c,0x20,0x70,0x20,0x20,0x00}, // 4
{0x5c,0x54,0x54,0x54,0x24,0x00}, // 5
{0x7c,0x54,0x54,0x54,0x74,0x00}, // 6
{0x04,0x04,0x64,0x14,0x0c,0x00}, // 7
{0x7c,0x54,0x54,0x54,0x7c,0x00}, // 8
{0x5c,0x54,0x54,0x54,0x7c,0x00}, // 9
{0x44,0x00,0x00,0x00,0x00,0x00}, // :
{0xc4,0x00,0x00,0x00,0x00,0x00}, // ;
{0x10,0x28,0x44,0x00,0x00,0x00}, // <
{0x28,0x28,0x28,0x28,0x28,0x00}, // =
{0x44,0x28,0x10,0x00,0x00,0x00}, // >
{0x08,0x04,0x54,0x08,0x00,0x00}, // ?
{0x7c,0x44,0x54,0x54,0x5c,0x00}, // @
{0x7c,0x24,0x24,0x24,0x7c,0x00}, // A
{0x7c,0x54,0x54,0x54,0x6c,0x00}, // B
{0x7c,0x44,0x44,0x44,0x44,0x00}, // C
{0x7c,0x44,0x44,0x44,0x38,0x00}, // D
{0x7c,0x54,0x54,0x54,0x44,0x00}, // E
{0x7c,0x14,0x14,0x14,0x04,0x00}, // F
{0x7c,0x44,0x44,0x54,0x74,0x00}, // G
{0x7c,0x10,0x10,0x10,0x7c,0x00}, // H
{0x44,0x44,0x7c,0x44,0x44,0x00}, // I
{0x60,0x40,0x40,0x44,0x7c,0x00}, // J
{0x7c,0x10,0x10,0x28,0x44,0x00}, // K
{0x7c,0x40,0x40,0x40,0x40,0x00}, // L
{0x7c,0x08,0x10,0x08,0x7c,0x00}, // M
{0x7c,0x08,0x10,0x20,0x7c,0x00}, // N
{0x38,0x44,0x44,0x44,0x38,0x00}, // O
{0x7c,0x14,0x14,0x14,0x08,0x00}, // P
{0x3c,0x24,0x64,0x24,0x3c,0x00}, // Q
{0x7c,0x14,0x14,0x14,0x68,0x00}, // R
{0x5c,0x54,0x54,0x54,0x74,0x00}, // S
{0x04,0x04,0x7c,0x04,0x04,0x00}, // T
{0x7c,0x40,0x40,0x40,0x7c,0x00}, // U
{0x0c,0x30,0x40,0x30,0x0c,0x00}, // V
{0x3c,0x40,0x30,0x40,0x3c,0x00}, // W
{0x44,0x28,0x10,0x28,0x44,0x00}, // X
{0x0c,0x10,0x60,0x10,0x0c,0x00}, // Y
{0x44,0x64,0x54,0x4c,0x44,0x00}, // Z
{0x7c,0x44,0x00,0x00,0x00,0x00}, // [
{0x0c,0x10,0x60,0x00,0x00,0x00}, // "\"
{0x44,0x7c,0x00,0x00,0x00,0x00}, // ]
{0x00,0x01,0x00,0x01,0x00,0x00}, // ^
{0x40,0x40,0x40,0x40,0x40,0x40}, // _
{0x00,0x01,0x00,0x00,0x00,0x00}, // `
{0x7c,0x24,0x24,0x24,0x7c,0x00}, // a
{0x7c,0x54,0x54,0x54,0x6c,0x00}, // b
{0x7c,0x44,0x44,0x44,0x44,0x00}, // c
{0x7c,0x44,0x44,0x44,0x38,0x00}, // d
{0x7c,0x54,0x54,0x54,0x44,0x00}, // e
{0x7c,0x14,0x14,0x14,0x04,0x00}, // f
{0x7c,0x44,0x44,0x54,0x74,0x00}, // g
{0x7c,0x10,0x10,0x10,0x7c,0x00}, // h
{0x44,0x44,0x7c,0x44,0x44,0x00}, // i
{0x60,0x40,0x40,0x44,0x7c,0x00}, // j
{0x7c,0x10,0x10,0x28,0x44,0x00}, // k
{0x7c,0x40,0x40,0x40,0x40,0x00}, // l
{0x7c,0x08,0x10,0x08,0x7c,0x00}, // m
{0x7c,0x08,0x10,0x20,0x7c,0x00}, // n
{0x38,0x44,0x44,0x44,0x38,0x00}, // o
{0x7c,0x14,0x14,0x14,0x08,0x00}, // p
{0x3c,0x24,0x64,0x24,0x3c,0x00}, // q
{0x7c,0x14,0x14,0x14,0x68,0x00}, // r
{0x5c,0x54,0x54,0x54,0x74,0x00}, // s
{0x04,0x04,0x7c,0x04,0x04,0x00}, // t
{0x7c,0x40,0x40,0x40,0x7c,0x00}, // u
{0x0c,0x30,0x40,0x30,0x0c,0x00}, // v
{0x3c,0x40,0x30,0x40,0x3c,0x00}, // w
{0x44,0x28,0x10,0x28,0x44,0x00}, // x
{0x0c,0x10,0x60,0x10,0x0c,0x00}, // y
{0x44,0x64,0x54,0x4c,0x44,0x00}, // z
{0x10,0x7c,0x44,0x00,0x00,0x00}, // {
{0x6c,0x00,0x00,0x00,0x00,0x00}, // |
{0x44,0x7c,0x10,0x00,0x00,0x00}, // }
{0x02,0x01,0x02,0x01,0x00,0x00}, // ~
{0x00,0x00,0x00,0x00,0x00,0x00}
};
#endif // FONT_H

@ -0,0 +1,11 @@
//
// Created by MightyPork on 2016/09/22.
//
#ifndef F107_FFT_SCREENDEF_H
#define F107_FFT_SCREENDEF_H
#define SCREEN_W 32
#define SCREEN_H 16
#endif //F107_FFT_SCREENDEF_H

@ -0,0 +1,73 @@
#include <string.h>
#include "scrolltext.h"
#include "font.h"
#include "screendef.h"
volatile bool text_moving;
/**
* Print text at coordinates
* @param text
* @param x
* @param y
*/
void printtext(DotMatrix_Cfg *disp, const char *text, int x, int y)
{
int totalX = 0;
for (int textX = 0; textX < (int)strlen(text); textX++) {
uint8_t ch = (uint8_t)text[textX];
if (ch < FONT_MIN) ch = '?';
if (ch > FONT_MAX) ch = '?';
ch -= ' '; // normalize for font table
if (ch == 0) { // space
totalX += 4;
continue;
}
// one letter
uint8_t blanks = 0;
// skip empty space on right
for (int charX = FONT_WIDTH-1; charX >= 0; charX--) {
uint8_t col = font[ch][charX];
if (col == 0x00) {
blanks++;
} else {
break;
}
}
for (int charX = 0; charX < FONT_WIDTH - blanks; charX++) {
uint8_t col = font[ch][charX];
for (int charY = 0; charY < 8; charY++) {
dmtx_set(disp, x + totalX, y + 8 - charY, (col >> charY) & 1);
}
totalX++;
}
totalX+= 2; // gap
}
}
/**
* Scroll text across the screen
* @param text
* @param step delay per step (ms)
*/
void scrolltext(DotMatrix_Cfg *disp, const char *text, ms_time_t step)
{
(void)step;
text_moving = true;
for (int i = 0; i < (int)strlen(text)*(FONT_WIDTH+1) + SCREEN_W-1; i++) {
if (i > 0) delay_ms(step);
dmtx_clear(disp);
printtext(disp, text, (SCREEN_W-1)-i, SCREEN_H/2-4);
dmtx_show(disp);
}
text_moving = false;
}

@ -0,0 +1,13 @@
#ifndef SCROLLTEXT_H
#define SCROLLTEXT_H
#include "dotmatrix.h"
#include "timebase.h"
volatile extern bool text_moving;
void printtext(DotMatrix_Cfg *disp, const char *text, int x, int y);
void scrolltext(DotMatrix_Cfg *disp, const char *text, ms_time_t step);
#endif // SCROLLTEXT_H

@ -13,6 +13,8 @@
#include "debounce.h" #include "debounce.h"
#include "debug.h" #include "debug.h"
#include "fft_windows.h" #include "fft_windows.h"
#include "screendef.h"
#include "scrolltext.h"
// 512 = show 0-5 kHz // 512 = show 0-5 kHz
// 256 = show 0-10 kHz // 256 = show 0-10 kHz
@ -21,8 +23,7 @@
#define BIN_COUNT (SAMPLE_COUNT/2) #define BIN_COUNT (SAMPLE_COUNT/2)
#define CFFT_INST arm_cfft_sR_f32_len256 #define CFFT_INST arm_cfft_sR_f32_len256
#define SCREEN_W 32 #define DEFAULT_BRIGHTNESS 3
#define SCREEN_H 16
// Pins // Pins
#define BTN_CENTER 0 #define BTN_CENTER 0
@ -32,9 +33,18 @@
#define BTN_DOWN 4 #define BTN_DOWN 4
// Y axis scaling factors // Y axis scaling factors
#define WAVEFORM_SCALE 0.007f #define WAVEFORM_SCALE 0.02
#define FFT_SCALE 0.25f * 0.3f #define FFT_PRELOG_SCALE 1.0
#define FFT_SPINDLE_SCALE_MULT 0.5f #define FFT_FINAL_SCALE 3.0
#define FFT_PREFFT_SCALE 0.4
#define VOL_STEP_TIME 50
#define VOL_STEP 0.05
#define VOL_STEP_LARGE 0.75
#define VOL_STEP_THRESH 0.01
#define VOL_STEP_SPEEDUP_TIME 750
#define SCROLL_STEP_MS 15
uint32_t audio_samples[SAMPLE_COUNT * 2]; // 2x size needed for complex FFT uint32_t audio_samples[SAMPLE_COUNT * 2]; // 2x size needed for complex FFT
float *audio_samples_f = (float *) audio_samples; float *audio_samples_f = (float *) audio_samples;
@ -42,6 +52,7 @@ float *audio_samples_f = (float *) audio_samples;
// counter for auto repeat // counter for auto repeat
ms_time_t updn_press_timer = 0; ms_time_t updn_press_timer = 0;
ms_time_t ltrt_press_timer = 0; ms_time_t ltrt_press_timer = 0;
ms_time_t updn_hold_ts;
/** Dot matrix display instance */ /** Dot matrix display instance */
DotMatrix_Cfg *disp; DotMatrix_Cfg *disp;
@ -50,13 +61,17 @@ DotMatrix_Cfg *disp;
volatile bool capture_pending = false; volatile bool capture_pending = false;
/** scale & brightness config fields. Initial values. */ /** scale & brightness config fields. Initial values. */
float y_scale = 5; float y_scale = 1;
uint8_t brightness = 3; uint8_t brightness = DEFAULT_BRIGHTNESS;
/** var used to signalize to MAIN that a banner should scroll */
static bool request_banner_text = false;
/** active rendering mode (visualisation preset) */ /** active rendering mode (visualisation preset) */
enum { enum {
MODE_SPECTRUM, MODE_SPECTRUM,
MODE_SPECTRUM2, MODE_SPECTRUM2,
MODE_LINEAR,
MODE_WAVEFORM, MODE_WAVEFORM,
MAX_MODE MAX_MODE
} render_mode; } render_mode;
@ -68,7 +83,7 @@ bool right_pressed = false;
static void display_wave(); static void display_wave();
static void calculate_fft(); static void calculate_fft(bool logmode);
static void display_fft(); static void display_fft();
@ -93,18 +108,28 @@ void capture_start()
/** This callback is called by HAL after the transfer is complete */ /** This callback is called by HAL after the transfer is complete */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{ {
if (text_moving || request_banner_text) {
capture_pending = false;
return;
}
switch (render_mode) { switch (render_mode) {
case MODE_WAVEFORM: case MODE_WAVEFORM:
display_wave(); display_wave();
break; break;
case MODE_LINEAR:
calculate_fft(false);
display_fft();
break;
case MODE_SPECTRUM: case MODE_SPECTRUM:
calculate_fft(); calculate_fft(true);
display_fft(); display_fft();
break; break;
case MODE_SPECTRUM2: case MODE_SPECTRUM2:
calculate_fft(); calculate_fft(true);
display_fft_spindle(); display_fft_spindle();
break; break;
} }
@ -171,12 +196,17 @@ void display_wave()
dmtx_show(disp); dmtx_show(disp);
} }
/** Calculate and display FFT */ /** Calculate FFT */
static void calculate_fft() static void calculate_fft(bool logmode)
{ {
float *bins = audio_samples_f; float *bins = audio_samples_f;
samples_to_float(); samples_to_float();
for (int i = 0; i < SAMPLE_COUNT; i++) {
bins[i] *= y_scale * FFT_PREFFT_SCALE; //win_hamming_512[i];
}
spread_samples_for_fft(); spread_samples_for_fft();
const arm_cfft_instance_f32 *S; const arm_cfft_instance_f32 *S;
@ -187,21 +217,28 @@ static void calculate_fft()
// Normalize & display // Normalize & display
start_render();
float factor = (1.0f / BIN_COUNT) * FFT_SCALE * y_scale;
for (int i = 0; i < BIN_COUNT; i++) { // +1 because bin 0 is always 0 for (int i = 0; i < BIN_COUNT; i++) { // +1 because bin 0 is always 0
bins[i] *= factor; float bin = bins[i] * (1.0f / BIN_COUNT) * FFT_PRELOG_SCALE;
if (logmode) {
bin = log2f(bin);
} else {
//
}
bins[i] = bin * FFT_FINAL_SCALE;
} }
} }
/** Render classic FFT */ /** Render classic FFT */
static void display_fft() static void display_fft()
{ {
start_render();
float *bins = audio_samples_f; float *bins = audio_samples_f;
for (int x = 0; x < SCREEN_W; x++) { for (int x = 0; x < SCREEN_W; x++) {
for (int j = 0; j < 1 + floorf(bins[x]); j++) { float bin = floorf(bins[x]);
if (bin<0) bin=0;
for (int j = 0; j < 1 + bin; j++) {
dmtx_set(disp, x, j, 1); dmtx_set(disp, x, j, 1);
} }
} }
@ -212,10 +249,14 @@ static void display_fft()
/** Render FFT "spindle" */ /** Render FFT "spindle" */
static void display_fft_spindle() static void display_fft_spindle()
{ {
start_render();
float *bins = audio_samples_f; float *bins = audio_samples_f;
for (int x = 0; x < SCREEN_W; x++) { for (int x = 0; x < SCREEN_W; x++) {
for (int j = 0; j < 1 + floorf(bins[x] * FFT_SPINDLE_SCALE_MULT); j++) { float bin = floorf(bins[x] * 0.5f);
if (bin<0) bin=0;
for (int j = 0; j < 1 + bin; j++) {
dmtx_set(disp, x, 7 + j, 1); dmtx_set(disp, x, 7 + j, 1);
dmtx_set(disp, x, 7 - j, 1); dmtx_set(disp, x, 7 - j, 1);
} }
@ -248,16 +289,20 @@ static void gamepad_button_cb(uint32_t btn, bool press)
case BTN_UP: case BTN_UP:
up_pressed = press; up_pressed = press;
if (press) { if (press) {
updn_hold_ts = ms_now();
updn_press_timer = 0; updn_press_timer = 0;
y_scale += 0.5f; y_scale += VOL_STEP;
} }
break; break;
case BTN_DOWN: case BTN_DOWN:
down_pressed = press; down_pressed = press;
if (press) { if (press) {
updn_hold_ts = ms_now();
updn_press_timer = 0; updn_press_timer = 0;
if (y_scale > 0.55) y_scale -= 0.5f; if (y_scale > VOL_STEP + VOL_STEP_THRESH) {
y_scale -= VOL_STEP;
}
} }
break; break;
@ -284,9 +329,11 @@ static void gamepad_button_cb(uint32_t btn, bool press)
if (++render_mode == MAX_MODE) { if (++render_mode == MAX_MODE) {
render_mode = 0; render_mode = 0;
} }
}
info("Switched to render mode %d", render_mode); info("Switched to render mode %d", render_mode);
request_banner_text = true;
}
break; break;
} }
} }
@ -364,6 +411,8 @@ void user_main()
user_init(); user_init();
request_banner_text = true;
ms_time_t counter1 = 0; ms_time_t counter1 = 0;
while (1) { while (1) {
if (ms_loop_elapsed(&counter1, 500)) { if (ms_loop_elapsed(&counter1, 500)) {
@ -373,19 +422,31 @@ void user_main()
// hold-to-repeat // hold-to-repeat
// This is not the correct way to do it, but good enough // This is not the correct way to do it, but good enough
if (ms_loop_elapsed(&updn_press_timer, 100)) { if (ms_loop_elapsed(&updn_press_timer, VOL_STEP_TIME)) {
if (up_pressed) { if (up_pressed) {
y_scale += 0.5; if (ms_now() - updn_hold_ts > VOL_STEP_SPEEDUP_TIME) {
y_scale += VOL_STEP_LARGE;
} else {
y_scale += VOL_STEP;
}
} }
if (down_pressed) { if (down_pressed) {
if (y_scale > 0.55) { if (ms_now() - updn_hold_ts > VOL_STEP_SPEEDUP_TIME) {
y_scale -= 0.5; if (y_scale > VOL_STEP_LARGE + VOL_STEP_THRESH) {
y_scale -= VOL_STEP_LARGE;
} else if (y_scale > VOL_STEP + VOL_STEP_THRESH) {
y_scale -= VOL_STEP;
}
} else {
if (y_scale > VOL_STEP + VOL_STEP_THRESH) {
y_scale -= VOL_STEP;
}
} }
} }
if (up_pressed || down_pressed) { if (up_pressed || down_pressed) {
dbg("scale = %.1f", y_scale); dbg("scale = %.2f", y_scale);
} }
} }
@ -407,6 +468,27 @@ void user_main()
} }
} }
if (request_banner_text) {
switch (render_mode) {
case MODE_SPECTRUM:
scrolltext(disp, "FFT LOG-Y", SCROLL_STEP_MS);
break;
case MODE_SPECTRUM2:
scrolltext(disp, "FFT LOG-Y MIRROR", SCROLL_STEP_MS);
break;
case MODE_LINEAR:
scrolltext(disp, "FFT LIN-Y", SCROLL_STEP_MS);
break;
case MODE_WAVEFORM:
scrolltext(disp, "WAVEFORM", SCROLL_STEP_MS);
break;
}
request_banner_text = false;
}
// capture a sample to update display // capture a sample to update display
if (!capture_pending) { if (!capture_pending) {
capture_start(); capture_start();

Loading…
Cancel
Save