// Basic FIR filter using timer interrupts for precise sampling time
// -----------------------------------------
// This implements a low-pass filter with cutoff frequency fc=150Hz @ fs=1kHz
// The impulse response is at coeffs.h.
//
// (c) 2024 Jorge Iván Marín ([email protected])
#include <SPI.h>
#define ADC_IN 36
#define DAC_OUT 25
#define CS_DAC 5
// Driver for DAC TLC5616
// ----------------------
class TLC5616 {
int CS_pin;
public:
TLC5616(int _CS_pin) {
CS_pin = _CS_pin;
}
void begin(void) {
SPI.begin();
pinMode(CS_pin, OUTPUT);
digitalWrite(CS_pin, HIGH);
}
void write(uint16_t value) {
value = (value & 0x3ff) << 2;
digitalWrite(CS_pin, LOW);
SPI.beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE0));
SPI.transfer16(value);
SPI.endTransaction();
digitalWrite(CS_pin, HIGH);
}
};
// Digital Filtering
// ------------------------------------------------
#include "coeffs.h"
int16_t x[Nh];
int16_t filter(int16_t x_ADC) {
int k;
int32_t y;
x[0] = x_ADC;
//Compute convolution
y = 0;
for(k=0; k<Nh; k++) {
y += (int32_t)h[k]*(int32_t)x[k];
}
//Delay elements in the array x
for(k=Nh-1; k>0; k--) {
x[k] = x[k-1];
}
return y >> 14;
}
float filter_sym(float x_ADC) {
int k;
float y;
x[0] = x_ADC;
//Compute convolution
y = 0;
for(k=0; k<((Nh-1)/2); k++) {
y += h[k]*(x[k]+x[Nh-1-k]);
}
//Calculo cuando Nh es impar
y = y + (h[(Nh-1)/2]*x[(Nh-1)/2]);
//Delay elements in the array x
for(k=Nh-1; k>0; k--) {
x[k] = x[k-1];
}
return y;
}
int xins = 0;
float filter_buf(float x_ADC) {
float y;
int k, k_h, k_x, N1, N2;
//Inserta la muestra leída en la posición xins
x[xins] = x_ADC;
//Determina las longitudes de los dos ciclos for
N2 = xins;
N1 = Nh - xins;
//Calcula la convolución
k_h = 0;
k_x = xins;
y = 0;
for(k=0; k<N1; k++) {
y += h[k_h++] * x[k_x++];
}
k_x = 0;
for(k=0; k<N2; k++) {
y += h[k_h++] * x[k_x++];
}
//Decrementa el puntero de inserción xins
xins--;
//Si se sale del arreglo lo inicializa a la última posición del arreglo x
if (xins < 0) { xins = Nh-1; }
return y;
}
// Entry point
// ----------------
TLC5616 dac(CS_DAC);
hw_timer_t* timer = NULL; //Hardware timer
void ARDUINO_ISR_ATTR isrTimer() {
//ADC read (Note: ADC is 12-bit resolution)
int x = analogRead(ADC_IN) - 2048;
//Perform filtering
int y = filter_buf(x);
//Control output saturation
// if (y>4095) y=4095;
//if (y<0) y=0;
//DAC Write (Note: DAC is 10-bit resolution, so we need to scale down)
dac.write ((y >> 2) + 512);
//For internal DAC replaces the above line by
// dacWrite(DAC1, y>>4);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
//DAC Initialization
dac.begin();
// For internal DAC initialization replaces the above line by
// (Note: Not supported in Wowki):
// analogReadResolution(12);
// pinMode(DAC_OUT, OUTPUT);
//Timer configuration to set the sampling frequency at 1kHz
timer = timerBegin(1000000); // Set timer frequency to 1Mhz
timerAttachInterrupt(timer, &isrTimer); // Attach ISR to timer
// Set alarm to call isrTimer function every Ts (value in microseconds).
// Repeat the alarm (third parameter) with unlimited count = 0 (fourth parameter).
timerAlarm(timer, 2000, true, 0);
}
void loop() {
int x_in;
unsigned long time_start, time_end;
int yt;
time_start = micros(); // Tiempo antes de aplicar el filtro
yt = filter(x_in); // Aplicación del filtro
time_end = micros(); // Tiempo después
Serial.println(time_end - time_start); // Tiempo en microsegundos
// Retornamos la salida filtrada
}