# Demo program for FIR filter module
# Author: Peter Hinch
# 12th Feb 2015
# Outputs a swept frequency sine wave on Dac1
# Timer interrupt reads the analog input, filters it, and outputs the result on Dac 2.
# Requires a link between X5 and X7

import math
import pyb
import array
from fir import fir
import micropython
micropython.alloc_emergency_exception_buf(100)

# Define hardware
dac1 = pyb.DAC(1)
dac2 = pyb.DAC(2)
adc  = pyb.ADC("X7")
tim = pyb.Timer(4, freq=2000) # Sampling freq 10KHz is about the limit 14KHz without constraint

# Data for FIR filter Pass (@2Ksps) 0-40Hz Stop 80Hz->
coeffs = array.array('i', (72, 47, 61, 75, 90, 105, 119, 132, 142, 149, 152, 149,
  140, 125, 102, 71, 33, -12, -65, -123, -187, -254, -322, -389, -453, -511, -561,
  -599, -622, -628, -615, -579, -519, -435, -324, -187, -23, 165, 375, 607, 855,
  1118, 1389, 1666, 1941, 2212, 2472, 2715, 2938, 3135, 3303, 3437, 3535, 3594,
  3614, 3594, 3535, 3437, 3303, 3135, 2938, 2715, 2472, 2212, 1941, 1666, 1389,
  1118, 855, 607, 375, 165, -23, -187, -324, -435, -519, -579, -615, -628, -622,
  -599, -561, -511, -453, -389, -322, -254, -187, -123, -65, -12, 33, 71, 102, 125,
  140,  149, 152, 149, 142, 132, 119, 105, 90, 75, 61, 47, 72))
ncoeffs = len(coeffs)
data = array.array('i', [0]*(ncoeffs +3)) # Scratchpad must be three larger than coeffs
data[0] = ncoeffs
data[1] = 16

# Data input, filter and output
# The constraint is a convenience to ensure that any inadvertent overflow shows as
# clipping on the 'scope. If you get the scaling right you can eliminate it...
def cb(timer):
    val = fir(data, coeffs, adc.read()) // 16 # Filter amd scale
    dac2.write(max(0, min(255, val))) # Constrain, shift (no DC from bandpass) and output

tim.callback(cb)

# Sweep generator
def sine_sweep(start, end, mult):     # Emit sinewave on DAC1
    buf = bytearray(100)
    for i in range(len(buf)):
        buf[i] = 128 + int(110 * math.sin(2 * math.pi * i / len(buf)))

    freq = start
    while True:
        dac1.write_timed(buf, int(freq) * len(buf), mode=pyb.DAC.CIRCULAR)
        print(freq, "Hz")
        pyb.delay(2500)
        freq *= mult
        if freq > end:
            freq = start

sine_sweep(10, 400, 1.33)