mirror of
https://github.com/jhbruhn/eurorack.git
synced 2025-03-15 02:55:49 +00:00
Basic software prototype of stm32 stereo_mix finished
This commit is contained in:
parent
1349f134cb
commit
adfa464665
7 changed files with 3245 additions and 737 deletions
109
stereo_mix/drivers/adc.cc
Executable file
109
stereo_mix/drivers/adc.cc
Executable file
|
@ -0,0 +1,109 @@
|
|||
#include "stereo_mix/drivers/adc.h"
|
||||
|
||||
#include <stm32f0xx.h>
|
||||
|
||||
namespace stereo_mix {
|
||||
|
||||
void Adc::Init()
|
||||
{
|
||||
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
|
||||
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
|
||||
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
|
||||
|
||||
ADC_InitTypeDef adc_init;
|
||||
GPIO_InitTypeDef gpio_init;
|
||||
|
||||
gpio_init.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
|
||||
gpio_init.GPIO_Pin |= GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
|
||||
gpio_init.GPIO_Pin |= GPIO_Pin_6 | GPIO_Pin_7;
|
||||
gpio_init.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_AN;
|
||||
GPIO_Init(GPIOA, &gpio_init);
|
||||
|
||||
gpio_init.GPIO_Pin = GPIO_Pin_0;
|
||||
gpio_init.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_AN;
|
||||
GPIO_Init(GPIOB, &gpio_init);
|
||||
|
||||
// Configure the address lines for the MUX.
|
||||
gpio_init.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_OUT;
|
||||
gpio_init.GPIO_OType = GPIO_OType_PP;
|
||||
gpio_init.GPIO_Speed = GPIO_Speed_2MHz;
|
||||
gpio_init.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
||||
GPIO_Init(GPIOB, &gpio_init);
|
||||
GPIO_ResetBits(GPIOB, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14);
|
||||
this->mux_index_ = 0;
|
||||
|
||||
adc_init.ADC_Resolution = ADC_Resolution_12b;
|
||||
adc_init.ADC_ContinuousConvMode = ENABLE;
|
||||
adc_init.ADC_DataAlign = ADC_DataAlign_Left;
|
||||
adc_init.ADC_ScanDirection = ADC_ScanDirection_Upward;
|
||||
ADC_Init(ADC1, &adc_init);
|
||||
|
||||
ADC_ClockModeConfig(ADC1, ADC_ClockMode_SynClkDiv2);
|
||||
ADC_ChannelConfig(ADC1, ADC_Channel_0, ADC_SampleTime_239_5Cycles);
|
||||
ADC_ChannelConfig(ADC1, ADC_Channel_1, ADC_SampleTime_239_5Cycles);
|
||||
ADC_ChannelConfig(ADC1, ADC_Channel_2, ADC_SampleTime_239_5Cycles);
|
||||
ADC_ChannelConfig(ADC1, ADC_Channel_3, ADC_SampleTime_239_5Cycles);
|
||||
ADC_ChannelConfig(ADC1, ADC_Channel_4, ADC_SampleTime_239_5Cycles);
|
||||
ADC_ChannelConfig(ADC1, ADC_Channel_5, ADC_SampleTime_239_5Cycles);
|
||||
ADC_ChannelConfig(ADC1, ADC_Channel_6, ADC_SampleTime_239_5Cycles);
|
||||
ADC_ChannelConfig(ADC1, ADC_Channel_7, ADC_SampleTime_239_5Cycles);
|
||||
ADC_ChannelConfig(ADC1, ADC_Channel_8, ADC_SampleTime_239_5Cycles);
|
||||
|
||||
ADC_Cmd(ADC1, ENABLE);
|
||||
ADC_DMACmd(ADC1, ENABLE);
|
||||
|
||||
DMA_InitTypeDef dma_init;
|
||||
DMA_StructInit(&dma_init);
|
||||
dma_init.DMA_DIR = DMA_DIR_PeripheralSRC;
|
||||
dma_init.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
|
||||
dma_init.DMA_MemoryBaseAddr = (uint32_t)&values_[0];
|
||||
dma_init.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
|
||||
dma_init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
|
||||
dma_init.DMA_BufferSize = ADC_CHANNEL_NUM_DIRECT;
|
||||
dma_init.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
||||
dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
||||
dma_init.DMA_Mode = DMA_Mode_Circular;
|
||||
dma_init.DMA_Priority = DMA_Priority_High;
|
||||
dma_init.DMA_M2M = DMA_M2M_Disable;
|
||||
DMA_Init(DMA1_Channel1, &dma_init);
|
||||
|
||||
NVIC_EnableIRQ(DMA1_Channel1_IRQn);
|
||||
NVIC_SetPriority(DMA1_Channel1_IRQn, 0);
|
||||
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
|
||||
DMA_Cmd(DMA1_Channel1, ENABLE);
|
||||
ADC_DMARequestModeConfig(ADC1, ADC_DMAMode_OneShot);
|
||||
|
||||
/*NVIC_InitTypeDef NVIC_InitStructure;
|
||||
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
*/
|
||||
ADC_StartOfConversion(ADC1);
|
||||
}
|
||||
|
||||
void Adc::DeInit()
|
||||
{
|
||||
ADC_Cmd(ADC1, DISABLE);
|
||||
ADC_DeInit(ADC1);
|
||||
}
|
||||
|
||||
void Adc::OnDMAFinish()
|
||||
{
|
||||
this->values_[ADC_CHANNEL_FIRST_MUXED + this->mux_index_] = this->values_[ADC_CHANNEL_MUX];
|
||||
|
||||
this->mux_index_ = (this->mux_index_ + 1) % ADC_CHANNEL_NUM_MUXED;
|
||||
uint8_t address = this->mux_index_;
|
||||
|
||||
// Write the mux address.
|
||||
GPIO_WriteBit(GPIOB, GPIO_Pin_12, static_cast<BitAction>(address & 1));
|
||||
GPIO_WriteBit(GPIOB, GPIO_Pin_13, static_cast<BitAction>(address & 2));
|
||||
GPIO_WriteBit(GPIOB, GPIO_Pin_14, static_cast<BitAction>(address & 4));
|
||||
ADC_StartOfConversion(ADC1);
|
||||
}
|
||||
|
||||
} // namespace rings
|
60
stereo_mix/drivers/adc.h
Normal file
60
stereo_mix/drivers/adc.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include "stmlib/stmlib.h"
|
||||
|
||||
namespace stereo_mix {
|
||||
|
||||
enum AdcChannel {
|
||||
ADC_CHANNEL_MUX,
|
||||
ADC_CHANNEL_CV_PAN_4,
|
||||
ADC_CHANNEL_CV_PAN_3,
|
||||
ADC_CHANNEL_CV_PAN_2,
|
||||
ADC_CHANNEL_CV_PAN_1,
|
||||
ADC_CHANNEL_CV_VOL_4,
|
||||
ADC_CHANNEL_CV_VOL_3,
|
||||
ADC_CHANNEL_CV_VOL_2,
|
||||
ADC_CHANNEL_CV_VOL_1,
|
||||
ADC_CHANNEL_POT_VOL_1,
|
||||
ADC_CHANNEL_POT_VOL_2,
|
||||
ADC_CHANNEL_POT_VOL_3,
|
||||
ADC_CHANNEL_POT_VOL_4,
|
||||
ADC_CHANNEL_POT_PAN_1,
|
||||
ADC_CHANNEL_POT_PAN_2,
|
||||
ADC_CHANNEL_POT_PAN_3,
|
||||
ADC_CHANNEL_POT_PAN_4,
|
||||
ADC_CHANNEL_LAST,
|
||||
|
||||
ADC_CHANNEL_FIRST_DIRECT = ADC_CHANNEL_MUX,
|
||||
ADC_CHANNEL_LAST_DIRECT = ADC_CHANNEL_CV_VOL_1,
|
||||
ADC_CHANNEL_FIRST_MUXED = ADC_CHANNEL_POT_VOL_1,
|
||||
ADC_CHANNEL_LAST_MUXED = ADC_CHANNEL_POT_PAN_4,
|
||||
ADC_CHANNEL_NUM_DIRECT = ADC_CHANNEL_CV_VOL_1 + 1,
|
||||
ADC_CHANNEL_NUM_MUXED = ADC_CHANNEL_LAST - ADC_CHANNEL_FIRST_MUXED,
|
||||
};
|
||||
|
||||
class Adc {
|
||||
public:
|
||||
Adc() {}
|
||||
~Adc() {}
|
||||
|
||||
void Init();
|
||||
void DeInit();
|
||||
void OnDMAFinish();
|
||||
inline const uint16_t* values() { return &values_[0]; }
|
||||
inline int32_t value(int32_t channel) const
|
||||
{
|
||||
return static_cast<int32_t>(values_[channel]);
|
||||
}
|
||||
inline float float_value(int32_t index) const
|
||||
{
|
||||
return static_cast<float>(values_[index]) / 65536.0f;
|
||||
}
|
||||
|
||||
private:
|
||||
uint16_t values_[ADC_CHANNEL_LAST];
|
||||
uint8_t mux_index_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Adc);
|
||||
};
|
||||
|
||||
} // namespace stereo_mix
|
|
@ -1,11 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <stm32f0xx.h>
|
||||
#include "stm32f0xx_gpio.h"
|
||||
#include "stmlib/stmlib.h"
|
||||
#include <stm32f0xx_conf.h>
|
||||
#include <stm32f0xx_rcc.h>
|
||||
#include <stm32f0xx_spi.h>
|
||||
#include <stm32f0xx.h>
|
||||
|
||||
namespace stereo_mix {
|
||||
|
||||
class Dac { // MCP4xx2 dac implementation
|
||||
public:
|
||||
|
@ -101,3 +99,5 @@ class Dac { // MCP4xx2 dac implementation
|
|||
GPIO_TypeDef* ssGpioPort;
|
||||
uint16_t ssGpioPin;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -48,11 +48,11 @@ extern const uint16_t lut_linear_to_exp[];
|
|||
extern const uint16_t lut_left_sin_pan[];
|
||||
extern const uint16_t lut_right_cos_pan[];
|
||||
#define LUT_LINEAR_TO_EXP 0
|
||||
#define LUT_LINEAR_TO_EXP_SIZE 1024
|
||||
#define LUT_LINEAR_TO_EXP_SIZE 4096
|
||||
#define LUT_LEFT_SIN_PAN 1
|
||||
#define LUT_LEFT_SIN_PAN_SIZE 1024
|
||||
#define LUT_LEFT_SIN_PAN_SIZE 4096
|
||||
#define LUT_RIGHT_COS_PAN 2
|
||||
#define LUT_RIGHT_COS_PAN_SIZE 1024
|
||||
#define LUT_RIGHT_COS_PAN_SIZE 4096
|
||||
|
||||
} // namespace stereo_mix
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import numpy as np
|
||||
lookup_tables_u16 = []
|
||||
|
||||
ADC_RESOLUTION = 1024
|
||||
OUTPUT_RESOLUTION = 4096
|
||||
ADC_RESOLUTION = 4096
|
||||
OUTPUT_RESOLUTION = 2 ** 16 - 1
|
||||
|
||||
# linear to exponential conversion
|
||||
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
#include "drivers/adc.h"
|
||||
#include "drivers/dac.h"
|
||||
#include "resources.h"
|
||||
|
||||
using namespace stereo_mix;
|
||||
|
||||
Dac dacs[8];
|
||||
Adc adc;
|
||||
|
||||
// Default interrupt handlers.
|
||||
extern "C" {
|
||||
|
@ -31,13 +38,22 @@ void PendSV_Handler() {}
|
|||
void SysTick_Handler()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
Dac dacs[8];
|
||||
void DMA1_Channel1_IRQHandler(void)
|
||||
{
|
||||
if (DMA_GetITStatus(DMA1_IT_TC1) == SET) /* Test if transfer completed on DMA channel 1 */
|
||||
{
|
||||
adc.OnDMAFinish();
|
||||
DMA_ClearITPendingBit(DMA1_IT_TC1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
SystemInit();
|
||||
|
||||
|
||||
dacs[0].Init(GPIOB, GPIO_Pin_8);
|
||||
dacs[1].Init(GPIOB, GPIO_Pin_9);
|
||||
dacs[2].Init(GPIOB, GPIO_Pin_10);
|
||||
|
@ -47,10 +63,29 @@ int main(void)
|
|||
dacs[6].Init(GPIOA, GPIO_Pin_10);
|
||||
dacs[7].Init(GPIOA, GPIO_Pin_11);
|
||||
|
||||
adc.Init();
|
||||
while (true) {
|
||||
for (uint16_t i = 0; i < 65535; i++) {
|
||||
dacs[0].Write16(0, i);
|
||||
dacs[0].Write16(1, 65535 - i);
|
||||
for(int i = 0; i < 4; i++) {
|
||||
uint32_t value_l;
|
||||
uint32_t value_r;
|
||||
|
||||
uint16_t pan_pot = adc.value(ADC_CHANNEL_POT_PAN_1 + i) >> (16 - 12); // adc is only 12 bit anyways
|
||||
uint16_t vol_pot = adc.value(ADC_CHANNEL_POT_VOL_1 + i) >> (16 - 12);
|
||||
int16_t pan_cv = (adc.value(ADC_CHANNEL_CV_PAN_1 - i) - 32768) >> (16 - 12);
|
||||
uint16_t vol_cv = adc.value(ADC_CHANNEL_CV_VOL_1 - i) >> (16 - 12);
|
||||
int32_t pan = pan_pot + pan_cv;
|
||||
int32_t vol = vol_pot + vol_cv;
|
||||
|
||||
CONSTRAIN(pan, 0, (1 << 12) - 1);
|
||||
CONSTRAIN(vol, 0, (1 << 12) - 1);
|
||||
|
||||
value_l = (lut_left_sin_pan[pan] * lut_linear_to_exp[vol]) >> 16;
|
||||
value_r = (lut_right_cos_pan[pan] * lut_linear_to_exp[vol]) >> 16;
|
||||
|
||||
dacs[i].Write16(0, value_r);
|
||||
dacs[i + 4].Write16(0, value_r);
|
||||
dacs[i].Write16(1, value_l);
|
||||
dacs[i + 4].Write16(1, value_l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue