|
|
@ -1,47 +1,45 @@ |
|
|
|
#include "cppmain.h" |
|
|
|
#include "init.h" |
|
|
|
#include "usbd_cdc_if.h" |
|
|
|
//#include "usb_device.h"
|
|
|
|
//#include "cmsis_os.h"
|
|
|
|
#include "utils.h" |
|
|
|
|
|
|
|
#include <cmath> |
|
|
|
#include <bitset> |
|
|
|
#include "limits" |
|
|
|
#include <sstream> |
|
|
|
|
|
|
|
#define SAMPLE_FREQ 44200 |
|
|
|
#define SAMPLE_MAX 4096 |
|
|
|
#define DOUBLE_BUFFER_SIZE 16 |
|
|
|
#define BUFFER_SIZE 8 |
|
|
|
#include <iomanip> |
|
|
|
#include <array> |
|
|
|
|
|
|
|
const double pi{ std::acos(-1) }; |
|
|
|
static u32 double_buffer[DOUBLE_BUFFER_SIZE]; |
|
|
|
static u64 time{ 0 }; |
|
|
|
static volatile bool dma_to_dac_half_complete{ false }; |
|
|
|
static volatile bool dma_to_dac_complete{ false }; |
|
|
|
static volatile int freq = 100; |
|
|
|
|
|
|
|
namespace Heck { |
|
|
|
bool debug_suspend_active = false; |
|
|
|
|
|
|
|
void debug_suspend_continue() |
|
|
|
{ |
|
|
|
debug_suspend_active = false; |
|
|
|
} |
|
|
|
constexpr u32 SAMPLE_FREQ = 42000U; |
|
|
|
constexpr u32 SAMPLE_MIN = 0U; |
|
|
|
constexpr u32 SAMPLE_MAX = 4095U; |
|
|
|
constexpr float SAMPLE_MIN_FLOAT = -1.0f; |
|
|
|
constexpr float SAMPLE_MAX_FLOAT = 1.0f; |
|
|
|
constexpr u32 BUFFER_SIZE = 128; |
|
|
|
constexpr u32 BLOCK_SIZE = BUFFER_SIZE / 2; |
|
|
|
|
|
|
|
// Serial Logging
|
|
|
|
// --------------
|
|
|
|
void log(std::string msg) |
|
|
|
{ |
|
|
|
std::string out{ msg }; |
|
|
|
out.append("\r\n"); |
|
|
|
CDC_Transmit_FS((uint8_t *)out.data(), out.size()); |
|
|
|
} |
|
|
|
|
|
|
|
// Buffer and block
|
|
|
|
static std::array<u32, BUFFER_SIZE> audio_buffer; |
|
|
|
static u32 *block = &audio_buffer[0]; |
|
|
|
|
|
|
|
// DAC
|
|
|
|
// ---
|
|
|
|
static std::array<float, BLOCK_SIZE> block_float; |
|
|
|
static volatile bool process_block{ true }; |
|
|
|
|
|
|
|
// Pots
|
|
|
|
constexpr u32 POTCOUNT = 3; |
|
|
|
static u32 pot_nr_current = 0; |
|
|
|
static std::array<float, POTCOUNT> pot = {}; |
|
|
|
|
|
|
|
// time
|
|
|
|
static u64 sample_clock{ 0 }; |
|
|
|
|
|
|
|
namespace ut = Heck::Utils; |
|
|
|
|
|
|
|
|
|
|
|
namespace Heck { |
|
|
|
// LED
|
|
|
|
// ---
|
|
|
|
void led_green_toggle() |
|
|
@ -59,12 +57,10 @@ namespace Heck { |
|
|
|
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// CALLBACKS
|
|
|
|
void irq1_cb() |
|
|
|
{ |
|
|
|
debug_suspend_continue(); |
|
|
|
freq += 10; |
|
|
|
ut::debug_suspend_continue(); |
|
|
|
} |
|
|
|
|
|
|
|
void timer3_cb() |
|
|
@ -72,8 +68,7 @@ namespace Heck { |
|
|
|
led_green_toggle(); |
|
|
|
} |
|
|
|
|
|
|
|
// dont forget to start the DAC
|
|
|
|
// HAL_DAC_Start(&hdac, DAC_CHANNEL_1);
|
|
|
|
|
|
|
|
void bytebeat() |
|
|
|
{ |
|
|
|
long t{ 0 }; |
|
|
@ -86,103 +81,185 @@ namespace Heck { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
u32 random(u32 max) |
|
|
|
void buffer_init_noise() |
|
|
|
{ |
|
|
|
ut::log("buffer_init_noise()"); |
|
|
|
for (int i = 0; i < BUFFER_SIZE; i++) { |
|
|
|
u32 val = ut::random(SAMPLE_MAX); |
|
|
|
audio_buffer[i] = val; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void block_fill_saw() |
|
|
|
{ |
|
|
|
u32 *b = block; |
|
|
|
u32 step = (SAMPLE_MAX - (SAMPLE_MAX / 4)) / BLOCK_SIZE; |
|
|
|
for (int i = 0; i < BLOCK_SIZE; i++) { |
|
|
|
u32 val = i * step; |
|
|
|
b[i] = val; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void block_float_saw_unipolar() |
|
|
|
{ |
|
|
|
float step = SAMPLE_MAX_FLOAT / BLOCK_SIZE; |
|
|
|
for (int i = 0; i < BLOCK_SIZE; i++) { |
|
|
|
float val = (float)i * step; |
|
|
|
block_float[i] = val; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void buffer_init_sin() |
|
|
|
{ |
|
|
|
ut::log("buffer_init_sin()"); |
|
|
|
for (int i = 0; i < BUFFER_SIZE; i++) { |
|
|
|
float p = float(i) / (float)BUFFER_SIZE - 0.5; |
|
|
|
u32 val = sin(p) * SAMPLE_MAX; |
|
|
|
audio_buffer[i] = val; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void buffer_div(int div) |
|
|
|
{ |
|
|
|
ut::log("init_scale()"); |
|
|
|
for (int i = 0; i < BUFFER_SIZE; i++) { |
|
|
|
u32 val = audio_buffer[i] / div; |
|
|
|
audio_buffer[i] = val; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void buffer_randomize(int max) |
|
|
|
{ |
|
|
|
ut::log("buffer_randomize()"); |
|
|
|
u32 buf_index = ut::random(BUFFER_SIZE); |
|
|
|
u32 buf_val = ut::random(max); |
|
|
|
audio_buffer[buf_index] = buf_val; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
u32 hz_to_samps(float hz) |
|
|
|
{ |
|
|
|
return (u32)floor((float)SAMPLE_FREQ / (float)hz); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
u32 saw(u64 t, float freq_hz) |
|
|
|
{ |
|
|
|
u32 ret{ 0 }; |
|
|
|
HAL_RNG_GenerateRandomNumber(&hrng, &ret); |
|
|
|
ret %= max; |
|
|
|
u32 samps = hz_to_samps(freq_hz); |
|
|
|
u32 normalizing_factor = SAMPLE_MAX / samps; |
|
|
|
|
|
|
|
ret = t % samps; |
|
|
|
ret *= normalizing_factor; |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
//
|
|
|
|
// void buffer_init_noise()
|
|
|
|
// {
|
|
|
|
// log("buffer_init_noise()");
|
|
|
|
// for (int i = 0; i < DOUBLE_BUFFER_SIZE; i++) {
|
|
|
|
// u32 val = random(SAMPLE_MAX);
|
|
|
|
// double_buffer[i] = val;
|
|
|
|
// log(std::to_string(val));
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// void buffer_init_sin()
|
|
|
|
// {
|
|
|
|
// log("buffer_init_sin()");
|
|
|
|
// for (int i = 0; i < DOUBLE_BUFFER_SIZE; i++) {
|
|
|
|
// float p = float(i) / (float)DOUBLE_BUFFER_SIZE - 0.5;
|
|
|
|
// u32 val = sin(p) * SAMPLE_MAX;
|
|
|
|
// double_buffer[i] = val;
|
|
|
|
// log(std::to_string(val));
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// void buffer_div(int div)
|
|
|
|
// {
|
|
|
|
// log("init_scale()");
|
|
|
|
// for (int i = 0; i < DOUBLE_BUFFER_SIZE; i++) {
|
|
|
|
// u32 val = double_buffer[i] / div;
|
|
|
|
// double_buffer[i] = val;
|
|
|
|
// log(std::to_string(val));
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// void buffer_randomize(int max)
|
|
|
|
// {
|
|
|
|
// log("buffer_randomize()");
|
|
|
|
// u32 buf_index = random(DOUBLE_BUFFER_SIZE);
|
|
|
|
// u32 buf_val = random(max);
|
|
|
|
// double_buffer[buf_index] = buf_val;
|
|
|
|
// log("i:" + std::to_string(buf_index) + " v:" + std::to_string(buf_val));
|
|
|
|
// }
|
|
|
|
|
|
|
|
std::string reg_to_string(uint32_t val) |
|
|
|
|
|
|
|
std::string block_to_string() |
|
|
|
{ |
|
|
|
u32 *b = block; |
|
|
|
std::stringstream ss{}; |
|
|
|
const std::bitset<32> x{ val }; |
|
|
|
ss << "0b" << x.to_string(); |
|
|
|
ss << " - "; |
|
|
|
ss << std::to_string(val); |
|
|
|
for (int i = 0; i < BLOCK_SIZE; i++) { |
|
|
|
ss << std::setw(4) << b[i] << " "; |
|
|
|
} |
|
|
|
return ss.str(); |
|
|
|
} |
|
|
|
|
|
|
|
u32 hz_to_samps(float hz) |
|
|
|
|
|
|
|
void u12_to_float(u32 &in, float &out) |
|
|
|
{ |
|
|
|
return (u32)floor((float)SAMPLE_FREQ / (float)hz); |
|
|
|
out = static_cast<float>(in) / 4095.f; |
|
|
|
} |
|
|
|
|
|
|
|
void float_to_u12(float &in, u32 &out) |
|
|
|
{ |
|
|
|
out = static_cast<u32>(in * 4095.f); |
|
|
|
} |
|
|
|
|
|
|
|
void calculate_audio(u32 *buffer) |
|
|
|
void saw_next_samp(float *out, float freq) |
|
|
|
{ |
|
|
|
log("calculate_audio time: "); |
|
|
|
u64 t = time; |
|
|
|
u32 samps = hz_to_samps(freq); |
|
|
|
static float val{ 0 }; |
|
|
|
val += SAMPLE_MAX_FLOAT / SAMPLE_FREQ * freq; |
|
|
|
val = std::fmod(val, 1.0); |
|
|
|
*out = val; |
|
|
|
} |
|
|
|
|
|
|
|
for (int i = 0; i < BUFFER_SIZE; i++) { |
|
|
|
buffer[i] = t % samps; |
|
|
|
t++; |
|
|
|
void sine_from_saw(float *sig) |
|
|
|
{ |
|
|
|
*sig = sin(*sig * 2.f * pi) / 2.f + 0.5f; |
|
|
|
} |
|
|
|
|
|
|
|
void waveshape(float *sig, float amt) |
|
|
|
{ |
|
|
|
*sig = std::tanh(*sig * amt); |
|
|
|
} |
|
|
|
|
|
|
|
void calculate_block_float() |
|
|
|
{ |
|
|
|
float *sig = &block_float[0]; |
|
|
|
for (int i = 0; i < BLOCK_SIZE; i++) { |
|
|
|
sig = &block_float[i]; |
|
|
|
saw_next_samp(sig, pot[0] * 1000.f); |
|
|
|
sine_from_saw(sig); |
|
|
|
waveshape(sig, pot[1] * 2.f); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void pot_select_current(u32 pot_nr) |
|
|
|
{ |
|
|
|
if (pot_nr != pot_nr_current) { |
|
|
|
adc2_select_channel(pot_nr); |
|
|
|
pot_nr_current = pot_nr; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void pot_read() |
|
|
|
{ |
|
|
|
HAL_ADC_Start(&hadc1); |
|
|
|
// HAL_ADC_PollForConversion(&hadc1, 1);
|
|
|
|
u32 pot1_tmp = HAL_ADC_GetValue(&hadc1); |
|
|
|
// Fixme: add stabilization
|
|
|
|
u12_to_float(pot1_tmp, pot[pot_nr_current]); |
|
|
|
|
|
|
|
// HAL_ADC_Stop(&hadc1);
|
|
|
|
// ut::log("pot[" + std::to_string(pot_nr_current) + "]: " + std::to_string(pot[pot_nr_current]));
|
|
|
|
} |
|
|
|
|
|
|
|
void read_next_pot() |
|
|
|
{ |
|
|
|
pot_select_current(pot_nr_current); |
|
|
|
pot_read(); |
|
|
|
pot_nr_current++; |
|
|
|
pot_nr_current %= POTCOUNT; |
|
|
|
} |
|
|
|
|
|
|
|
void main() |
|
|
|
{ |
|
|
|
heck_debug_suspend(); |
|
|
|
log("Starting..."); |
|
|
|
ut::log("Starting..."); |
|
|
|
|
|
|
|
HAL_TIM_Base_Start_IT(&htim_blinky_led); |
|
|
|
HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1, (u32 *)double_buffer, DOUBLE_BUFFER_SIZE, DAC_ALIGN_12B_R); |
|
|
|
HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1, audio_buffer.data(), BUFFER_SIZE, DAC_ALIGN_12B_R); |
|
|
|
HAL_TIM_Base_Start_IT(&htim_dac1); |
|
|
|
|
|
|
|
log("Entering MainLoop..."); |
|
|
|
ut::log("Entering MainLoop..."); |
|
|
|
while (true) { |
|
|
|
if (dma_to_dac_half_complete) { |
|
|
|
calculate_audio(&double_buffer[0]); |
|
|
|
time += BUFFER_SIZE; |
|
|
|
dma_to_dac_half_complete = false; |
|
|
|
} |
|
|
|
if (dma_to_dac_complete) { |
|
|
|
|
|
|
|
calculate_audio(&double_buffer[BUFFER_SIZE]); |
|
|
|
time += BUFFER_SIZE; |
|
|
|
dma_to_dac_complete = false; |
|
|
|
if (process_block) { |
|
|
|
process_block = false; |
|
|
|
|
|
|
|
calculate_block_float(); |
|
|
|
|
|
|
|
u32 *b = block; |
|
|
|
for (int i = 0; i < BLOCK_SIZE; i++) { |
|
|
|
float_to_u12(block_float[i], b[i]); |
|
|
|
} |
|
|
|
|
|
|
|
sample_clock += BLOCK_SIZE; |
|
|
|
if (process_block == true) { |
|
|
|
ut::log("UNDERRUN!"); |
|
|
|
} |
|
|
|
} else { |
|
|
|
read_next_pot(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -193,15 +270,6 @@ namespace Heck { |
|
|
|
// C Linkage (Bridging)
|
|
|
|
// ----------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
extern "C" void heck_debug_suspend(void) |
|
|
|
{ |
|
|
|
Heck::debug_suspend_active = true; |
|
|
|
while (Heck::debug_suspend_active == true) { |
|
|
|
Heck::log("debug_suspend..."); |
|
|
|
HAL_Delay(10); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
extern "C" void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) |
|
|
|
{ |
|
|
|
if (GPIO_Pin == GPIO_PIN_0) { |
|
|
@ -215,63 +283,33 @@ extern "C" void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) |
|
|
|
// Heck::log(
|
|
|
|
// "TIM2 timer: instance: " + std::to_string(reinterpret_cast<u32>(htim->Instance)) +
|
|
|
|
// " channel: " + std::to_string(htim->Channel));
|
|
|
|
// Heck::log(std::to_string(time));
|
|
|
|
} else if (htim->Instance == TIM3) { |
|
|
|
Heck::log( |
|
|
|
ut::log( |
|
|
|
"TIM3 timer: instance: " + std::to_string(reinterpret_cast<u32>(htim->Instance)) + |
|
|
|
" channel: " + std::to_string(htim->Channel)); |
|
|
|
Heck::timer3_cb(); |
|
|
|
} else { |
|
|
|
Heck::log( |
|
|
|
ut::log( |
|
|
|
"UNKNOWN timer: instance: " + std::to_string(reinterpret_cast<u32>(htim->Instance)) + |
|
|
|
" channel: " + std::to_string(htim->Channel)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
extern "C" void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef *hdac) |
|
|
|
{ |
|
|
|
Heck::log("HAL_DAC_ConvHalfCpltCallbackCh1"); |
|
|
|
dma_to_dac_half_complete = true; |
|
|
|
// Heck::log("HAL_DAC_ConvHalfCpltCallbackCh1");
|
|
|
|
block = &audio_buffer[0]; |
|
|
|
process_block = true; |
|
|
|
} |
|
|
|
|
|
|
|
extern "C" void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef *hdac) |
|
|
|
{ |
|
|
|
Heck::log("HAL_DAC_ConvCpltCallbackCh1"); |
|
|
|
dma_to_dac_complete = true; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
extern "C" void heck_log(char *msg) |
|
|
|
{ |
|
|
|
Heck::log(std::string(msg)); |
|
|
|
// Heck::log("HAL_DAC_ConvCpltCallbackCh1");
|
|
|
|
block = &audio_buffer[BLOCK_SIZE]; |
|
|
|
process_block = true; |
|
|
|
} |
|
|
|
|
|
|
|
extern "C" void heck_cppmain(void) |
|
|
|
{ |
|
|
|
Heck::main(); |
|
|
|
} |
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Reports the name of the source file and the source line number |
|
|
|
* where the assert_param error has occurred. |
|
|
|
* @param file: pointer to the source file name |
|
|
|
* @param line: assert_param error line source number |
|
|
|
* @retval None |
|
|
|
*/ |
|
|
|
extern "C" void assert_failed(uint8_t *file, uint32_t line) |
|
|
|
{ |
|
|
|
/* User can add his own implementation to report the file name and line number,
|
|
|
|
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ |
|
|
|
int str_size = 1024; |
|
|
|
char str[str_size]; |
|
|
|
snprintf(str, str_size, "assert failed: %s:%d", file, line); |
|
|
|
heck_log(str); |
|
|
|
} |
|
|
|
|
|
|
|
extern "C" void Error_Handler(void) |
|
|
|
{ |
|
|
|
heck_log("Error_Handler StR1keZ!"); |
|
|
|
__disable_irq(); |
|
|
|
while (1) {} |
|
|
|
} |
|
|
|