Andy_F, я, глядя на Ваш код, переделал свой.
Частота Tx - 6000 Гц.
Частота вызова фильтра 60 Гц.
длина DMA может меняться В процессе настройки кода.
При увеличении длины буфера уменьшается число вызовов DMA1_Channel1_IRQHandle.
Таким образом, уменьшается частота переключения контекста при запуске прерывания.
Раньше я множил входной сигнал на sin/cos на каждом периоде Tx и накапливал только квадратуры.
Разницы не заменил.
Вообще, надо бы попробовать сравнить результаты в примерно одинаковых условиях.
Код:
// SMPS_PER_TX - Num. samples per Tx period (16) for now
// SMPS_PER_TX_HLF - Half of SMPS_PER_TX
// SMPS_PER_TX_QUOT - Quote of SMPS_PER_TX
// NUM_TX_PER_DMA - Num. Tx periods per one ADC_DMA (1) for now may be {1,2,4,5,... 100}
void DMA1_Channel1_IRQHandler(void)
{
uint32_t IT;
uint32_t i, idx_bgn;
if (DMA_GetITStatus(ADC_DMA_HT) != RESET)
{
IT = ADC_DMA_HT;
idx_bgn = 0;
}
else if (DMA_GetITStatus(ADC_DMA_TC) != RESET)
{
IT = ADC_DMA_TC;
idx_bgn = SMPS_PER_TX * NUM_TX_PER_DMA;
}
if(++tx_count < tx_per_sd)
{
#if NUM_TX_PER_DMA != 1
uint32_t j;
for(j=0; j<NUM_TX_PER_DMA; ++j)
#endif
{
for(i=0; i<SMPS_PER_TX; ++i)
{
#if NUM_TX_PER_DMA != 1
adc[i] += (int32_t)input[idx_bgn+j*SMPS_PER_TX+i];
#else
adc[i] += (int32_t)input[idx_bgn+i];
#endif
}
}
}
// DMA_ClearITPendingBit(IT);
DMA1->IFCR = IT;
}
void TIM9_IRQHandler (void)
{
// Circular buffers for filters
static int32_t sin_filter_taps[13] = {0};
static int32_t cos_filter_taps[13] = {0};
static uint32_t sin_idx = 0;
static uint32_t cos_idx = 0;
if((TIM9->DIER & TIM_IT_CC1) && (TIM9->SR & TIM_IT_CC1))
{
int i;
counted_tx = tx_count;
tx_count = 0;
if(tx_per_sd && counted_tx != tx_per_sd)
mderror = TX_PER_SD_ERROR;
memcpy(&adc[0], &adc1[0], sizeof(int32_t)*SMPS_PER_TX);
// Sic! Начинаю с 1. Пропускаю точки, которые равны 0 или 1. Таблицы sin/cos я переделал. См. ниже.
// Перемножение c sin/cos происходит там же, где вызывается фильтр
for (i=1; i<SMPS_PER_TX_QUOT; ++i)
{
quad_sin = sum_int32(mul_int64_sh(
adc1[i]
+ adc1[SMPS_PER_TX_HLF-i]
- adc1[SMPS_PER_TX_HLF+i]
- adc1[SMPS_PER_TX-i], SINTAB[i], 1<<22, 23),
quad_sin);
quad_cos = sum_int32(mul_int64_sh(
adc1[i]
- adc1[SMPS_PER_TX_HLF-i]
- adc1[SMPS_PER_TX_HLF+i]
+ adc1[SMPS_PER_TX-i], SINTAB[i], 1<<22, 23),
quad_cos);
}
quad_sin = sum_int32(
adc1[SMPS_PER_TX_QUOT] -
adc1[SMPS_PER_TX_3QUOT],
quad_sin);
quad_cos = sum_int32(
adc1[0] -
adc1[SMPS_PER_TX_HLF],
quad_cos);
if(counted_tx == tx_per_sd)
{
// Low pass filter after SD
quad_sin_filtered = fir(quad_sin,
&sin_idx, &sin_filter_taps[0],
&FIRLP_Bessel_19_60_10, 0);
quad_cos_filtered = fir(quad_cos,
&cos_idx, &cos_filter_taps[0],
&FIRLP_Bessel_19_60_10, 0);
/************************ STATISTIC ************************/
// ...
/***********************************************************/
++sd_count;
}
quad_sin = quad_cos = 0;
// TIM_ClearITPendingBit(TIM9, TIM_IT_CC1);
TIM9->SR = (uint16_t)~TIM_IT_CC1;
}
}
__INLINE int32_t sum_int32(const int32_t a, const int32_t b)
{
#if defined(_DEBUG) || defined(DEBUG)
/* a + b would overflow */ /* a + b would underflow */
if(((a > 0) && (b > INT_MAX - a)) || ((a < 0) && (b < INT_MIN - a)))
{
while(bzerror);
}
#endif
return (a + b);
}
__INLINE int64_t mul_int64(const int64_t a,
const int64_t b)
{
return (a * b);
}
__INLINE int32_t mul_int64_sh(const int64_t a,
const int64_t b,
const int64_t roundv,
const uint32_t sh)
{
#if defined(_DEBUG) || defined(DEBUG)
int64_t tmp = (a * b) >> sh;
if(tmp > INT_MAX || tmp < INT_MIN)
{
while(bzerror);
}
return (int32_t)tmp;
#else
return (int32_t)((a * b + roundv) >> sh);
#endif
}
const int64_t sin16bit24[] = {
0,
3210181,
5931641,
7750062,
8388607,
7750062,
5931641,
3210181,
-0,
-3210181,
-5931641,
-7750062,
-8388607,
-7750062,
-5931641,
-3210181
};
const int64_t cos16bit24[] = {
8388607,
7750062,
5931641,
3210181,
-0,
-3210181,
-5931641,
-7750062,
-8388607,
-7750062,
-5931641,
-3210181,
0,
3210181,
5931641,
7750062
};