added spindle effect

master
Ondřej Hruška 8 years ago
parent 66df0d7378
commit fa652f942a
  1. 2
      CMakeLists.txt
  2. 2
      Src/tim.c
  3. 218
      User/user_main.c

@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.5.0)
file(GLOB_RECURSE USER_SOURCES "User/*.c") file(GLOB_RECURSE USER_SOURCES "User/*.c")
file(GLOB_RECURSE MX_SOURCES "Src/*.c") file(GLOB_RECURSE MX_SOURCES "Src/*.c")
file(GLOB_RECURSE HAL_SOURCES "Drivers/STM32F1xx_HAL_Driver/Src/*.c") file(GLOB_RECURSE HAL_SOURCES "Drivers/STM32F1xx_HAL_Driver/Src/*.c")
file(GLOB_RECURSE CMSIS_SOURCES "Drivers/CMSIS/DSP_Lib/Source/*.c") file(GLOB_RECURSE CMSIS_SOURCES "Drivers/CMSIS/DSP_Lib/Source/*.c" "Drivers/CMSIS/DSP_Lib/Source/*.S")
add_library(HAL ${HAL_SOURCES}) add_library(HAL ${HAL_SOURCES})
add_library(CMSIS ${CMSIS_SOURCES} add_library(CMSIS ${CMSIS_SOURCES}

@ -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 = 1800; htim3.Init.Period = 3600; //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)
{ {

@ -3,20 +3,22 @@
// //
#include <inttypes.h> #include <inttypes.h>
#include <arm_const_structs.h>
#include <arm_math.h> #include <arm_math.h>
#include <arm_const_structs.h>
#include <stm32f1xx_hal_gpio.h> #include <stm32f1xx_hal_gpio.h>
#include "dotmatrix.h" #include "dotmatrix.h"
#include "mxconstants.h"
#include "stm32f1xx_hal.h"
#include "adc.h" #include "adc.h"
#include "tim.h" #include "tim.h"
#include "user_main.h" #include "user_main.h"
#include "debounce.h" #include "debounce.h"
#include "debug.h" #include "debug.h"
#define SAMPLE_COUNT 256 // 512 = show 0-5 kHz
// 256 = show 0-10 kHz
// smaller range is OK since we have only a limited reception of higher frequencies anyway
#define SAMPLE_COUNT 512
#define BIN_COUNT (SAMPLE_COUNT/2) #define BIN_COUNT (SAMPLE_COUNT/2)
#define CFFT_INST arm_cfft_sR_f32_len256
#define SCREEN_W 32 #define SCREEN_W 32
#define SCREEN_H 16 #define SCREEN_H 16
@ -28,20 +30,51 @@
#define BTN_UP 3 #define BTN_UP 3
#define BTN_DOWN 4 #define BTN_DOWN 4
static uint32_t audio_samples[SAMPLE_COUNT * 2]; // 2x size needed for complex FFT // Y axis scaling factors
static float *audio_samples_f = (float *) audio_samples; #define WAVEFORM_SCALE 0.008f
#define FFT_SCALE 0.25f * 0.3f
#define FFT_SPINDLE_SCALE_MULT 0.5f
uint32_t audio_samples[SAMPLE_COUNT * 2]; // 2x size needed for complex FFT
float *audio_samples_f = (float *) audio_samples;
/** Dot matrix display instance */
DotMatrix_Cfg *disp;
/** Capture in progress flag */
volatile bool capture_pending = false;
static DotMatrix_Cfg *disp; /** scale & brightness config fields. Initial values. */
float y_scale = 3;
uint8_t brightness = 4;
static volatile bool capture_pending = false; /** active rendering mode (visualisation preset) */
enum {
MODE_WAVEFORM = 0,
MODE_SPECTRUM = 1,
MODE_SPECTRUM2 = 2,
} render_mode;
static float waveform_scale = 3; #define MODE_MAX MODE_SPECTRUM2
bool up_pressed = false;
bool down_pressed = false;
bool left_pressed = false;
bool right_pressed = false;
static void display_wave(); static void display_wave();
static void calculate_fft();
static void display_fft(); static void display_fft();
static void display_fft_spindle();
static void start_render();
// region Audio capture & display // region Audio capture & display
/** Start DMA to capture audio */
void capture_start() void capture_start()
{ {
if (capture_pending) return; if (capture_pending) return;
@ -56,7 +89,22 @@ 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)
{ {
display_wave(); switch (render_mode) {
case MODE_WAVEFORM:
display_wave();
break;
case MODE_SPECTRUM:
calculate_fft();
display_fft();
break;
case MODE_SPECTRUM2:
calculate_fft();
display_fft_spindle();
break;
}
capture_pending = false; capture_pending = false;
} }
@ -93,14 +141,12 @@ void spread_samples_for_fft()
/** Display waveform preview */ /** Display waveform preview */
void display_wave() void display_wave()
{ {
float wave_y_mult = 0.0078125f;
samples_to_float(); samples_to_float();
int x_offset = 0; int x_offset = 0;
for (int i = 1; i < SAMPLE_COUNT; i++) { for (int i = 1; i < SAMPLE_COUNT; i++) {
if (audio_samples_f[i] > 0 && audio_samples_f[i-1] < 0) { if (audio_samples_f[i] > 0 && audio_samples_f[i - 1] < 0) {
x_offset = i; x_offset = i;
break; break;
} }
@ -111,15 +157,18 @@ void display_wave()
x_offset = 0; x_offset = 0;
} }
dmtx_clear(disp); float totalmult = WAVEFORM_SCALE * y_scale;
start_render();
for (int i = 0; i < SCREEN_W; i++) { for (int i = 0; i < SCREEN_W; i++) {
dmtx_set(disp, i, 7 + roundf(audio_samples_f[i + x_offset] * wave_y_mult * waveform_scale), 1); dmtx_set(disp, i, 7 + roundf(audio_samples_f[i + x_offset] * totalmult), 1);
} }
dmtx_show(disp); dmtx_show(disp);
} }
/** Calculate and display FFT */ /** Calculate and display FFT */
static void display_fft() static void calculate_fft()
{ {
float *bins = audio_samples_f; float *bins = audio_samples_f;
@ -127,41 +176,66 @@ static void display_fft()
spread_samples_for_fft(); spread_samples_for_fft();
const arm_cfft_instance_f32 *S; const arm_cfft_instance_f32 *S;
S = &arm_cfft_sR_f32_len128; S = &CFFT_INST;
arm_cfft_f32(S, bins, 0, true); // bit reversed FFT arm_cfft_f32(S, bins, 0, true); // bit reversed FFT
arm_cmplx_mag_f32(bins, bins, BIN_COUNT); // get magnitude (extract real values) arm_cmplx_mag_f32(bins, bins, BIN_COUNT); // get magnitude (extract real values)
// Normalize & display // Normalize & display
dmtx_clear(dmtx); start_render();
float factor = (1.0f / BIN_COUNT) * 0.25f; 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; bins[i] *= factor;
} }
}
/** Render classic FFT */
static void display_fft()
{
float *bins = audio_samples_f;
// TODO implement offset using gamepad buttons (?)
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++) { for (int j = 0; j < 1 + floorf(bins[x]); j++) {
dmtx_set(dmtx, x, j, 1); dmtx_set(disp, x, j, 1);
}
}
dmtx_show(disp);
}
/** Render FFT "spindle" */
static void display_fft_spindle()
{
float *bins = audio_samples_f;
for (int x = 0; x < SCREEN_W; x++) {
for (int j = 0; j < 1 + floorf(bins[x] * FFT_SPINDLE_SCALE_MULT); j++) {
dmtx_set(disp, x, 7 + j, 1);
dmtx_set(disp, x, 7 - j, 1);
} }
} }
dmtx_show(dmtx); dmtx_show(disp);
} }
// endregion // endregion
// Increment timebase counter each ms // region UI
void HAL_SYSTICK_Callback(void)
/** Clear screen & render "HUD" - button feedback lights */
void start_render()
{ {
timebase_ms_cb(); dmtx_clear(disp);
}
bool up_pressed = false; if (up_pressed) dmtx_set(disp, SCREEN_W - 2, SCREEN_H - 1, 1);
bool down_pressed = false; if (down_pressed) dmtx_set(disp, SCREEN_W - 2, SCREEN_H - 3, 1);
if (left_pressed) dmtx_set(disp, SCREEN_W - 3, SCREEN_H - 2, 1);
if (right_pressed) dmtx_set(disp, SCREEN_W - 1, SCREEN_H - 2, 1);
}
/** Callback when button press state changes */
static void gamepad_button_cb(uint32_t btn, bool press) static void gamepad_button_cb(uint32_t btn, bool press)
{ {
dbg("Button press %d, state %d", btn, press); dbg("Button press %d, state %d", btn, press);
@ -170,13 +244,47 @@ static void gamepad_button_cb(uint32_t btn, bool press)
case BTN_UP: case BTN_UP:
up_pressed = press; up_pressed = press;
break; break;
case BTN_DOWN: case BTN_DOWN:
down_pressed = press; down_pressed = press;
break; break;
case BTN_LEFT:
left_pressed = press;
break;
case BTN_RIGHT:
right_pressed = press;
break;
case BTN_CENTER:
if (!press) {
// center button released
// cycle through modes
if (render_mode++ == MODE_MAX) {
render_mode = 0;
}
}
info("Switched to render mode %d", render_mode);
break;
} }
} }
void user_init() { // endregion
/**
* Increment timebase counter each ms.
* This is called by HAL, weak override.
*/
void HAL_SYSTICK_Callback(void)
{
timebase_ms_cb();
}
/** Init the application */
void user_init()
{
// Enable audio input // Enable audio input
HAL_GPIO_WritePin(AUDIO_NSTBY_GPIO_Port, AUDIO_NSTBY_Pin, 1); HAL_GPIO_WritePin(AUDIO_NSTBY_GPIO_Port, AUDIO_NSTBY_Pin, 1);
@ -189,7 +297,7 @@ void user_init() {
disp_init.SPIx = SPI1; disp_init.SPIx = SPI1;
disp = dmtx_init(&disp_init); disp = dmtx_init(&disp_init);
dmtx_intensity(disp, 7); dmtx_intensity(disp, brightness);
dmtx_clear(disp); dmtx_clear(disp);
dmtx_show(disp); dmtx_show(disp);
@ -229,7 +337,7 @@ void user_init() {
debo_register_pin(&debo); debo_register_pin(&debo);
} }
/** Main function, called from MX-generated main.c */
void user_main() void user_main()
{ {
banner("== USER CODE STARTING =="); banner("== USER CODE STARTING ==");
@ -237,30 +345,53 @@ void user_main()
user_init(); user_init();
ms_time_t counter1 = 0; ms_time_t counter1 = 0;
uint32_t counter2 = 0; ms_time_t counter2 = 0;
uint32_t btn_scale_cnt = 0; ms_time_t btn_scale_cnt = 0;
ms_time_t btn_brt_cnt = 0;
while (1) { while (1) {
if (ms_loop_elapsed(&counter1, 500)) { if (ms_loop_elapsed(&counter1, 500)) {
// Blink // Blink
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
} }
// hold-to-repeat for up/down buttons (sensitivity)
// This is not the correct way to do it, but good enough
if (ms_loop_elapsed(&btn_scale_cnt, 50)) { if (ms_loop_elapsed(&btn_scale_cnt, 50)) {
if (up_pressed) { if (up_pressed) {
waveform_scale += 0.1; y_scale += 0.1;
} }
if (down_pressed) { if (down_pressed) {
if (waveform_scale > 0.1) { if (y_scale > 0.1) {
waveform_scale -= 0.1; y_scale -= 0.1;
} }
} }
if (up_pressed || down_pressed) { if (up_pressed || down_pressed) {
dbg("scale = %.1f", waveform_scale); dbg("scale = %.1f", y_scale);
} }
} }
// hold-to-repeat for left/right buttons (brightness)
if (ms_loop_elapsed(&btn_brt_cnt, 200)) {
if (left_pressed) {
if (brightness > 0) {
brightness--;
}
}
if (right_pressed) {
if (brightness < 15) {
brightness++;
}
}
if (left_pressed || right_pressed) {
dmtx_intensity(disp, brightness);
}
}
// capture a sample to update display
if (!capture_pending) { if (!capture_pending) {
capture_start(); capture_start();
} }
@ -269,6 +400,7 @@ void user_main()
//region Error handlers //region Error handlers
/** Called from MX-generated HAL error handler */
void user_Error_Handler() void user_Error_Handler()
{ {
error("HAL error occurred.\n"); error("HAL error occurred.\n");
@ -276,12 +408,12 @@ void user_Error_Handler()
} }
/** /**
* @brief Reports the name of the source file and the source line number * @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred. * where the assert_param error has occurred.
* @param file: pointer to the source file name * @param file: pointer to the source file name
* @param line: assert_param error line source number * @param line: assert_param error line source number
* @retval None * @retval None
*/ */
void user_assert_failed(uint8_t *file, uint32_t line) void user_assert_failed(uint8_t *file, uint32_t line)
{ {
user_error_file_line("Assert failed", (const char *) file, line); user_error_file_line("Assert failed", (const char *) file, line);

Loading…
Cancel
Save