ReSpeaker DSP V02
Dependencies: mbed MbedJSONValue
main.cpp
- Committer:
- Arkadi
- Date:
- 2019-06-20
- Revision:
- 14:8a4699aa69b5
- Parent:
- 13:c0a13a99905e
File content as of revision 14:8a4699aa69b5:
////////////////////////////////////////
// Tau_ReSpeaker_DSP V02 //
// Arkadiraf@gmail.com - 08/06/2019 //
////////////////////////////////////////
/*
Json Format: json:{"name":"dsp","mode":"off"}\r\n
*/
/*
Board : Nucleo STM32F446RE
Power Source : DC-DC 5V Regulator E5V Jumper
*/
/*
Pinout:
PC - Serial 2
PA_2 (Tx) --> STLINK
PA_3 (Rx) --> STLINK
Switch - Serial 3
PC_10 (Tx) --> SW_Rx
PC_11 (Rx) --> SW_Tx
Digital output
PA_5 --> led (DigitalOut)
PA_10 --> DSP_Trigger
Digital Input
PC_13 --> BTN (Blue)
PA_6 --> Toggle Pin (Loop Freq D12)
Analog Input
PA_0 --> SIG_IN_DSP (A0)
Analog Output
PA_4 --> SIG_OUT_DSP (A2)
*/
///////////////
// Libraries //
///////////////
#include "mbed.h"
#include "MbedJSONValue.h"
#include "chirp.h"
///////////////
// #defines //
///////////////
//#define TOGGLE_IO_MODE // loop frequency indicator
// UART debug modes:
//#define DEBUG_MOD1 // json packet recognise
//#define DEBUG_MOD2 // json parse
//#define DEBUG_MOD3 // dsp handler
//#define DEBUG_MOD10 // responsivity msges to gui
// PI variable
#define PI_DOUBLE (3.141592653589793238462)
#define PI_FLOAT (3.14159f)
// json commad
#define MSG_BUFFER_SIZE 1024
#define HEADER_SIZE 5
#define FOOTER_SIZE 2
// Frequency counter
#define TICKS2TOGGLE 1000000
/////////////
// Objects //
/////////////
// json
MbedJSONValue guiCmd;
// uart
Serial pc(USBTX, USBRX);
// uart switch_dsp
Serial switch_dsp(PC_10, PC_11);
// digital
DigitalIn user_button(PC_13);
DigitalOut dsp_trigger(PA_10);// D2
DigitalOut led(PA_5); // D13
DigitalOut mytoggle(PA_6); // D12
// analog / define to init at mbed initialization. work directly with registers
AnalogOut dsp_output(PA_4);
AnalogIn dsp_input(PA_0);
// ADC/DAC declarations
ADC_HandleTypeDef hadc1;
DAC_HandleTypeDef hdac1;
///////////////
// variables //
///////////////
// Frequency counter
uint32_t toggleCounter = 0;
// toogle pin state
bool toggleCounterState = 0;
// toogle pin state
bool toggelState=0;
// json buffer
char json[MSG_BUFFER_SIZE];
// packet variables
struct packetMSG_struct {
// recieve message variables
uint8_t header[HEADER_SIZE];
uint8_t footer[FOOTER_SIZE];
uint8_t syncIndex; // sync index for header / footer
uint8_t syncFlag; // 0 - waiting for header, 1 - waiting for footer, 2 - verify footer, 3 - finish footer send to parser, flash buffer
// buffer
uint16_t bufferIndex; // buffer index
uint8_t buffer[MSG_BUFFER_SIZE];
} ;
packetMSG_struct packetMSG;
// Dac Register for direct method of setting DAC value`s
__IO uint32_t Dac_Reg = 0;
// create function pointer
typedef void(*functionPtr)(void);
functionPtr FilterFunction;
// alternative functuin selection (faster mcu process)
volatile uint8_t operationMode = 1;
// 0 - off
// 1 - passthrough - no filter
// 2 - highpass - High Pass filter
// 3 - hpf_trig - High Pass filter + Trigger mode
// 4 - gains_trig - highpass filter + trigger mode + Gains vector
///////////////
// Functions //
///////////////
// init functions header //hadc1 needs to be defined preiod #incude
#include "adc_init.h" // initialize adc/dac directly for continious sample
#include "filters.h"
// nop operation
inline void NOP()
{
__ASM volatile ("nop"); // one tick operation, Use to adjust frequency by slowing down the proccess
}
// Serial Event function
void rxCallback(void);
// initialize packet struct
void initPacket(void);
// Packet Parser
void parsePacket(void);
// DSP Packet Handler
void dspPacket(void);
// DSP Param Packet Handler
void dspParamPacket(void);
// DSP Filter Packet Handler
void dspFilterPacket(void);
// DSP Play Packet Handler
void dspPlayPacket(void);
// initialize DSP
void initDSP(void);
////////////////////////
// Main Code Setup : //
////////////////////////
int main()
{
// init packet:
initPacket();
// initialize DSP
initDSP();
pc.baud(57600);
switch_dsp.baud(57600);
// pc is used for debbuging, in application mode the commands are from the switch_dsp.
// attach serial event interrupt
pc.attach(&rxCallback, Serial::RxIrq);
// attach serial event interrupt
switch_dsp.attach(&rxCallback, Serial::RxIrq);
#ifdef DEBUG_MOD1
pc.printf("ReSpeaker Test \r\n");
#endif
///////////////////////
// Main Code Loop : //
///////////////////////
while(1) {
// run selected filter
if (operationMode == 0) {
offMode();
} else if (operationMode == 1) {
passthrough();
} else if (operationMode == 2) {
highpass();
} else if (operationMode == 3) {
highpassTrig();
} else if (operationMode == 4) {
GainsTrig();
}
// more elegant but much slower option:
//FilterFunction();
#ifdef TOGGLE_IO_MODE
// toggle pin, Loop frequency indicator
toggelState=!toggelState;
mytoggle.write(toggelState);
#endif
// Frequency counter
toggleCounter++;
if (toggleCounter == TICKS2TOGGLE) {
toggleCounter=0;
toggleCounterState = !toggleCounterState;
dsp_trigger.write(toggleCounterState);
}
} // end loop
} // end main
///////////////
// Functions //
///////////////
// initialize DSP
void initDSP(void)
{
// init dac
ADC1_Init();
DAC1_Init();
HAL_ADC_Start(&hadc1);
HAL_DAC_Start(&hdac1, DAC_CHANNEL_1);
// define Dac Register for direct method of setting DAC value`s
Dac_Reg = (uint32_t) (hdac1.Instance);
Dac_Reg += __HAL_DHR12R1_ALIGNEMENT(DAC_ALIGN_12B_R);
// intialize filter function pointer
FilterFunction = offMode;//highpass_filter;
operationMode = 0 ;
}
// Serial Event function
void rxCallback(void)
{
while ((pc.readable()) || (switch_dsp.readable())) {
// read icoming
uint8_t in_byte=0;
//led = !led;
if (pc.readable()) {
in_byte = pc.getc();
} else if (switch_dsp.readable()) {
in_byte = switch_dsp.getc();
}
#ifdef DEBUG_MOD1
pc.putc(in_byte);
#endif
// detect start message , end message
switch (packetMSG.syncFlag) {
// waiting for header
case 0: {
if (packetMSG.header[packetMSG.syncIndex] == in_byte) {
packetMSG.syncIndex++;
if (packetMSG.syncIndex == HEADER_SIZE) { // finish header SYNC
packetMSG.syncFlag = 1; // start collecting data, wait for footer
packetMSG.bufferIndex = 0;
packetMSG.syncIndex=0;
}
} else { // reinit sync
packetMSG.syncIndex=0;
}
//pc.printf("case 0 , %d \r\n",packetMSG.syncIndex);
break;
}
// waiting for footer
case 1: {
// add byte to buffer
packetMSG.buffer[packetMSG.bufferIndex] = in_byte;
packetMSG.bufferIndex++;
if (packetMSG.bufferIndex >= MSG_BUFFER_SIZE) { // buffer overflow
// reset buffer
packetMSG.bufferIndex = 0;
packetMSG.syncIndex = 0;
packetMSG.syncFlag = 0;
} else if (packetMSG.footer[packetMSG.syncIndex] == in_byte) { // footer char recieved
packetMSG.syncIndex++;
packetMSG.syncFlag=2; // move to verify footer
}
//pc.printf("case 2 , %d \r\n",packetMSG.syncIndex);
break;
}
// verify footer
case 2: {
// add byte to buffer
packetMSG.buffer[packetMSG.bufferIndex] = in_byte;
packetMSG.bufferIndex++;
if (packetMSG.bufferIndex >= MSG_BUFFER_SIZE) { // buffer overflow
// reset buffer
packetMSG.bufferIndex = 0;
packetMSG.syncIndex = 0;
packetMSG.syncFlag = 0;
} else if (packetMSG.footer[packetMSG.syncIndex] == in_byte) { // footer char recieved
packetMSG.syncIndex++;
if (packetMSG.syncIndex == FOOTER_SIZE) { // finish footer SYNC
packetMSG.syncFlag = 3;
// copy packet to json buffer
memcpy (&json, &packetMSG.buffer, packetMSG.bufferIndex);
json[packetMSG.bufferIndex]=NULL; // end with NULL to indicate end of string
// copy packet to json buffer with sprintf
//sprintf(json, "%.*s", packetMSG.bufferIndex, packetMSG.buffer );
// send msg to parse.
parsePacket();
// reset buffer
packetMSG.bufferIndex = 0;
packetMSG.syncIndex = 0;
packetMSG.syncFlag = 0;
}
} else { // footer broke restart wait for footer
packetMSG.syncFlag=1;
// verify that it didnt broke on first footer char
if (packetMSG.footer[0] == in_byte) {
packetMSG.syncIndex=1;
} else {
packetMSG.syncIndex=0;
}
}
break;
}
default: {
pc.printf("Sonmething went wrong \r\n");
break;
}
} // end switch
}// end uart readable
} // end rxCallback
// initialize packet struct
void initPacket(void)
{
// init variables to default:
packetMSG.header[0] = 'j';
packetMSG.header[1] = 's';
packetMSG.header[2] = 'o';
packetMSG.header[3] = 'n';
packetMSG.header[4] = ':';
packetMSG.footer[0]= 13; // /r
packetMSG.footer[1]= 10; // /n
packetMSG.syncIndex=0; // sync index for header / footer
packetMSG.syncFlag=0; // 0 - waiting for header, 1 - waiting for footer, 2 - verify footer, 3 - finish footer send to parser, flash buffer
packetMSG.bufferIndex=0; // buffer index
}// end init Packet struct
// Packet Parser
void parsePacket(void)
{
string targetName;
#ifdef DEBUG_MOD2
// write buffer to screen
//pc.printf("%d, %.*s", packetMSG.bufferIndex ,packetMSG.bufferIndex, packetMSG.buffer );
pc.printf("%s", json);
#endif
// GUI message format Switch: {"name":"switch","mic":0, "spk": [0,1,0,0,0]}
parse(guiCmd, json);
// get target:
targetName = guiCmd["name"].get<string>(); // switch / dsp
#ifdef DEBUG_MOD2
// send parsed values
pc.printf("targetName: %s \r\n", targetName.c_str());
#endif
// select handler based on target mcu
if (targetName == "dsp") {
dspPacket();
} else if (targetName == "dspParam") {
dspParamPacket();
} else if (targetName == "dspFilter") {
dspFilterPacket();
} else if (targetName == "dspPlay") {
dspPlayPacket();
} else {
#ifdef DEBUG_MOD2
// unrecognised target
pc.printf("unrecognised target: %s \r\n", targetName.c_str());
#endif
}
// led blink
led = !led;
}// end parse
// DSP Packet Handler
void dspPacket(void)
{
string modeType;
// get operation mode
modeType = guiCmd["mode"].get<string>();
#ifdef DEBUG_MOD10
// send parsed values
pc.printf("mode: %s\r\n", modeType.c_str());
//switch_dsp.printf("mode: %s\r\n", modeType.c_str());
#endif
// selected operation mode
if ( modeType == "off" ) {
FilterFunction = offMode;
operationMode = 0 ;
} else if( modeType == "passthrough" ) {
FilterFunction = passthrough;
operationMode = 1 ;
} else if( modeType == "highpass" ) {
FilterFunction = highpass;
operationMode = 2 ;
} else if( modeType == "hpf_trig" ) {
FilterFunction = highpassTrig;
operationMode = 3 ;
} else if( modeType == "gain_trig" ) {
FilterFunction = GainsTrig;
operationMode = 4 ;
} else {
switch_dsp.printf("undefined mode %s \r\n", modeType.c_str());
FilterFunction = offMode;
operationMode = 0 ;
}
// succesfull parse
switch_dsp.printf("{\"Ack\":\"dsp\",\"mode\":\"%s\"}\r\n",modeType.c_str());
}// end dspPacket
// DSP Param Packet Handler
void dspParamPacket(void)
{
// get values.
signalGain = ((float)guiCmd["gain"].get<int>())/1000; // issue in parsing doubles when the number is round
trigTresh = ((float)guiCmd["trigTresh"].get<int>()) / 100.0f;
trigDelaySet = (uint32_t)guiCmd["trigPass"].get<int>();
trigPause = (uint32_t)guiCmd["trigPause"].get<int>();
trigDelay = trigDelaySet;
#ifdef DEBUG_MOD10
// send parsed values
pc.printf("SignalGain: %.3f , trigTresh: %.3f , trigDelaySet %d , trigPause: %d\r\n", signalGain , trigTresh , trigDelaySet , trigPause);
#endif
// succesfull parse
switch_dsp.printf("{\"Ack\":\"dspParam\",\"SignalGain\":%.3f,\"trigTresh\":%.3f,\"trigDelaySet\":%d,\"trigPause\":%d}\r\n", signalGain , trigTresh , trigDelaySet , trigPause);
} // end dspParamPacket
// DSP Filter Packet Handler
void dspFilterPacket(void)
{
// get values.
FilterSections = (guiCmd["Sections"].get<int>());
Gscale = ((float)(guiCmd["Gscale"].get<int>()))/10000.0f; // issue in parsing doubles
// get SOSMat
for (int jj=0 ; jj < FilterSections ; jj++) {
for (int ii=0 ; ii < 6 ; ii++) {
SOSMat[jj][ii] = ((float)guiCmd["SOSMat"][ii+jj*6].get<int>())/10000.0f;
}
}
#ifdef DEBUG_MOD10
// send parsed values
pc.printf("FilterSections: %d , Gscale: %.3f\r\n", FilterSections , Gscale);
pc.printf("SOSMat \r\n");
for (int jj=0 ; jj < FilterSections ; jj++) {
pc.printf("%.3f , %.3f , %.3f , %.3f , %.3f , %.3f \r\n",SOSMat[jj][0] ,SOSMat[jj][1],SOSMat[jj][2],SOSMat[jj][3] ,SOSMat[jj][4] ,SOSMat[jj][5]);
}
#endif
// succesfull parse
switch_dsp.printf("{\"Ack\":\"dspFilter\",\"FilterSections\":%d,\"Gscale\":%.3f}\r\n", FilterSections , Gscale);
} // end dspFilterPacket
// DSP Play Packet Handler
void dspPlayPacket(void)
{
// get values.
float playGain = ((float)guiCmd["gain"].get<int>())/1000; // issue in parsing doubles when the number is round
uint32_t playFile = (uint32_t)guiCmd["file"].get<int>(); // file to play
// succesfull parse
switch_dsp.printf("{\"Ack\":\"dspPlay\",\"file\":%d,\"gain\":%.3f}\r\n", playFile, playGain);
//////////////////////////////////////////////////////////////////
// Temp mode - need to update file selection , gain settings //
//////////////////////////////////////////////////////////////////
__disable_irq(); // Disable Interrupts
// generate chirp out
for (int ii=0; ii<NUM_SAMPLES; ii++) {
// toogle io for loop frequency
toggelState=!toggelState;
mytoggle.write(toggelState);
// generate delay for 1MHz Sample rate
for (int jj=0; jj<31; jj++) {
NOP();
}
// micro nops :)
NOP();
NOP();
NOP();
NOP();
NOP();
NOP();
NOP();
// Output value using DAC
// HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, ADCValueOut);
*(__IO uint32_t *) Dac_Reg = chirpData[ii];
}
// Output value using DAC
// HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, ADCValueOut);
*(__IO uint32_t *) Dac_Reg = (uint16_t)(4095/2);
__enable_irq(); // Enable Interrupts
// Option to reset play mode after file has been played
//operationMode = 0;
} // end dspPlayPacket