FMAC Cascade for SOS
Hi Together,
I am currently trying to use the FMAC hardware accelerator. Normal usage already works. Now for numerical stability I want to implement the filter as second order sections (sos). According to RM0481:
Cascaded filters must either be combined into a single stage, or implemented as
separate filters. In the latter case, multiple sets of filter coefficients can be pre-loaded
into the memory, one set per stage, and only the X2_BASE address changed to select
which set is used.
To do this I currently:
Concatenate all the stage coeffs into one vector:
static int16_t const b_Coeffs_0[b_Coeff_len_0] = { 55, 111, 55 };
static int16_t const a_Coeffs_0[a_Coeff_len_0] = { -3745, -258 };
static int16_t const b_Coeffs_1[b_Coeff_len_1] = { 16384, 32767, 16384 };
...static int16_t all_coeffs[sos_Coeff_Count] = {
b_Coeffs_0[0], b_Coeffs_0[1], b_Coeffs_0[2],
a_Coeffs_0[0],
...On setup input the vector as b coefficients:
filter_Config.Clip = FMAC_CLIP_ENABLED;
filter_Config.Filter = FMAC_FUNC_IIR_DIRECT_FORM_1;
filter_Config.pCoeffA = NULL;
filter_Config.CoeffASize = 0;
filter_Config.pCoeffB = all_coeffs;
filter_Config.CoeffBSize = sos_Coeff_Count;
filter_Config.CoeffBaseAddress = 0UL;
filter_Config.CoeffBufferSize = sos_Coeff_Count; //X2 in reference manual
filter_Config.OutputBaseAddress = b_Coeff_len_0 + sos_Coeff_Count + input_headroom;
filter_Config.OutputBufferSize = a_Coeff_len_0 + output_headroom; //Y in reference manual
filter_Config.OutputAccess = FMAC_BUFFER_ACCESS_DMA;
filter_Config.InputBaseAddress = sos_Coeff_Count + 1;
filter_Config.InputBufferSize = b_Coeff_len_0 + input_headroom; //X1 in reference manual
filter_Config.InputAccess = FMAC_BUFFER_ACCESS_DMA;
filter_Config.P = b_Coeff_len_0;
filter_Config.Q = a_Coeff_len_0;
filter_Config.R = fmac_Gain;And then calculate my entire 15k data vector on one stage. After that I increment the X2 base vector:
MODIFY_REG(hfmac.Instance->X2BUFCFG,
FMAC_X2BUFCFG_X2_BASE,
((uint32_t)(filter_Config.CoeffBaseAddress + coeff_per_stage * stage) << FMAC_X2BUFCFG_X2_BASE_Pos)
& FMAC_X2BUFCFG_X2_BASE);
I copy data from one iteration to the next this way:
memcpy(fData.x_q15, fData.y_q15, fData.yLen * sizeof(int16_t));
fData.xLen = fData.yLen;
fmacAppendData(fData.x_q15, &fData.xLen, fData.y_q15, &fData.yLen, &fMetadata.fCalcFinished);Where:
HAL_StatusTypeDef fmacAppendData(int16_t *dataIn, uint16_t *inLen, int16_t *dataOut, uint16_t *outLen, volatile bool *pCalcFinished) {
calcFinished = pCalcFinished;
HAL_StatusTypeDef status = HAL_FMAC_AppendFilterData(&hfmac, dataIn, inLen);
if (status != HAL_OK) {
return status;
}
if (isInitialData) {
isInitialData = false;
} else {
// For explanation on why output length is halved, see function fmacStart(...)
uint16_t halfLen = (*outLen) / 2;
status = HAL_FMAC_ConfigFilterOutputBuffer(&hfmac, dataOut, &halfLen);
if (status != HAL_OK) {
return status;
}
}
return HAL_OK;
}The append function and everything around it is already tested and works for non-cascaded filters. Only when i try to cascade it wont work. (The output looks like gibberish)
Unfortunately I cant find any application note or something more except this sentence in the reference manual regarding how to cascade filters this way.
Thanks in advance for any useful hints.
