~If I have time I'll play around with it and see if I can get a reasonably flat-band response down to 20 Hz, then do a pull request if I think I have it worked out.~ [EDIT] Too interesting to drop it off my mind and it was driving me nuts not to do it. Done 😃 [/EDIT]
The datasheet gives the transfer function so I don't see any reason I can't set the cut-off at 8 Hz or something 🙂
[EDIT]In fact this filter could be used for anything realizable by the 1rst order IIR general form with 1-pole and 1-zero[/EDIT]
FYI here is what I work out for the coefficients:
#This was run in Gnu Octave
a=e^(-2*pi*ts*8);
d0=32768;
d0 = 32768;
n0 = a*d0;
d1=n0;
n1=-n0;
hz=(n0 + n1*z1)./(d0 - d1*z1);
semilogx(f,20*log10(abs(hz))) #This produces the expected 1-pole HPF plot
d0 = 32768 #given by the datasheet, already in hardware
d1 = 32731
n0 = 32731
n1 = -32731
The general feel for how it behaves in the audio band:
octave:163> f(9)
ans = 19.845
octave:164> abs(hz(9))
ans = 0.92695
octave:165> 20*log10(abs(hz(9)))
ans = -0.65891
So it's down 0.65 dB at 20 Hz,
octave:169> f(45)
ans = 99.225
octave:170> 20*log10(abs(hz(45)))
ans = -0.033090
And nearly nil at 100 Hz
This brings up a final interesting note on line inputs on Bela. The DC blocking capacitor is 0.1uF, which forms a 20 Hz cut-off at 80k, but an 80 Hz cut-off at 20k.
Per datasheet advice input impedance is 20k at 0dB PGA setting and 80k at -12 dB PGA setting. This means the input DC blocking capacitor is too small a value to cover the full range of audio input levels unless I have missed something.
The input cap should be at least 0.47uF to cover all cases. 1uF would be better since an 8 Hz cut-off has less than 1 dB roll-off at 20 Hz.
Fortunately for me PGA setting of -12 dB and the 0.1uF is perfectly acceptable for guitar and bass use, but I can see some issues with some synthesizer applications where the incoming signal may be hitting some sub-bass notes in the 20 to 40 Hz range.
[EDIT] Confirmed and added hardware issue at github. See plots in post below for actual Bela frequency response graphs [/EDIT]
Just some note-taking here.
I think this will do it, so now I just need to try it and see if it works as expected.
//
// Enable DC offset removal in CODEC hardware (High-Pass filter)
// Datasheet reference: TLV320AIC3104, SLAS510F - FEB 2007, Rev DEC 2016
// CODEC 1-pole Filter. Datasheet calls it HPF but it can be any 1-pole filter
// realizable by the following the transfer function:
// n0 + n1 * z^-1
// H(z) = ------------------ (10.3.3.2.1 - pg 26)
// d0 - d1 * z^-1
// d0 = 32768 //defined by hardware
// For the high-pass filter case (bilinear transform method),
// d1 = n0 = -n1
// d1 = d0*e^(-2*pi*fc/fs) = 32768*e^(-2*pi*8/44100) = 32730.7, round up
// d1 = 32731 = 0x7FDB
// n0 = 32731 = 0x7FDB
// n1 = -32731 = 0x8025 //2s complement
//
int I2c_Codec::configureDCRemovalIIR(){
//Explicit Switch to config register page 0:
if(writeRegister(0x00, 0x00)) //Page 1/Register 0: Page Select Register
return 1;
//
// Config Page 0 commands
//
if(writeRegister(0x0C, 0x50)) // Digital filter register: enable HPF on L&R Channels
return 1;
if(writeRegister(0x6B, 0xC0)) // HPF coeff select register: Use programmable coeffs
return 1;
//Switch to config register page 1:
if(writeRegister(0x00, 0x01)) //Page 1/Register 0: Page Select Register
return 1;
//
// Config Page 0 commands
//
//Left Channel HPF Coeffiecient Registers
//N0:
if(writeRegister(0x41, 0x7F)) // Page 1/Register 65: Left-Channel ADC High-Pass Filter N0 Coefficient MSB Register
return 1;
if(writeRegister(0x42, 0xDB)) //Page 1/Register 66: Left-Channel ADC High-Pass Filter N0 Coefficient LSB Register
return 1;
//N1:
if(writeRegister(0x43, 0x80)) //Page 1/Register 67: Left-Channel ADC High-Pass Filter N1 Coefficient MSB Register
return 1;
if(writeRegister(0x44, 0x25)) //Page 1/Register 68: Left-Channel ADC High-Pass Filter N1 Coefficient LSB Register
return 1;
//D1:
if(writeRegister(0x45, 0x7F)) //Page 1/Register 69: Left-Channel ADC High-Pass Filter D1 Coefficient MSB Register
return 1;
if(writeRegister(0x46, 0xDB)) //Page 1/Register 70: Left-Channel ADC High-Pass Filter D1 Coefficient LSB Register
return 1;
//Right Channel HPF Coeffiecient Registers
//N0:
if(writeRegister(0x47, 0x7F)) //Page 1/Register 71: Right-Channel ADC High-Pass Filter N0 Coefficient MSB Register
return 1;
if(writeRegister(0x48, 0xDB)) //Page 1/Register 72: Right-Channel ADC High-Pass Filter N0 Coefficient LSB Register
return 1;
//N1:
if(writeRegister(0x49, 0x80)) //Page 1/Register 73: Right-Channel ADC High-Pass Filter N1 Coefficient MSB Register
return 1;
if(writeRegister(0x4A, 0x25)) //Page 1/Register 74: Right-Channel ADC High-Pass Filter N1 Coefficient LSB Register
return 1;
//D1:
if(writeRegister(0x4B, 0x7F)) //Page 1/Register 75: Right-Channel ADC High-Pass Filter D1 Coefficient MSB Register
return 1;
if(writeRegister(0x4C, 0xDB)) //Page 1/Register 76: Right-Channel ADC High-Pass Filter D1 Coefficient LSB Register
return 1;
//Explicitly restore to config Page 0
if(writeRegister(0x00, 0x00)) //Page 1/Register 0: Page Select Register
return 1;
return 0;
}