Точный подсчет тактов контроллера
Точный подсчет тактов контроллера
Здравствуйте, пишу код в Keil uvision и использую отладочную плату STM32F4DISCOVERY и возникла необходимость точного расчета тактов выполнения куска кода. Нашел в интернетах код с помощью которого можно подсчитать количество тактов, но в режиме отладки счетчик выполняет разное количество тактов. Может есть какие либо другие способы подсчета количества тактов?
Код программы:
#include "main.h"
#include "math.h"
uint16_t delay_count=0;
uint16_t data_adc=0;
uint16_t flag=0,i_1,i_2,i_3,i_4;
uint32_t count_tic=0;
uint32_t mod_1=0,m_1,m_2,mo_p;
uint32_t mod_2=0,mod_3=0;
uint32_t N=16,N1=4;
uint32_t sq,X,i=0,sum;
int32_t y1[40][20],y2[40][20];
int32_t a_1,a_2,m;
uint32_t k,s;
void SysTick_Handler(void) //1ms
{
if(delay_count>0){delay_count--;}
}
/*-*/
uint32_t usr_sqrt(uint32_t value)
{
uint32_t d, a;
__asm {
CLZ a, value
RSB a, a, #0x1F
};
d = 1 << ((a >> 1)+1);
a = (d + ( value >> a )) >> 1;
d = (a + value / a)>>1;
a = (d + value / d)>>1;
d = (a + value / a)>>1;
a = (d + value / d)>>1;
return a;
}
/*-*/
uint16_t get_adc_value()
{
ADC_SoftwareStartConv(ADC1);
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
return ADC_GetConversionValue(ADC1);
}
/*-*/
void delay_ms(uint16_t delay_temp)
{
delay_count = delay_temp;
while(delay_count){}
}
/*-*/
int main(void)
{
SystemCoreClockUpdate();
SysTick_Config(SystemCoreClock/1000);
LED_ini();
DAC_ini();
ADC_R_ini();
#define DWT_CYCCNT *(volatile unsigned long *)0xE0001004
#define DWT_CONTROL *(volatile unsigned long *)0xE0001000
#define SCB_DEMCR *(volatile unsigned long *)0xE000EDFC
while(1)
{
if(flag==0){i_1=get_adc_value();flag=1;}
if(flag==1){i_2=get_adc_value();flag=2;}
if(flag==2){i_3=get_adc_value();flag=3;}
if(flag==3){i_4=get_adc_value();flag=0;}
SCB_DEMCR |= 0x01000000;
DWT_CONTROL|= 1; //включение счетчика
DWT_CYCCNT = 0;
i++;
mod_1=i%2;
y1[mod_1][0]=i_1-i_3;
y2[mod_1][0]=i_2-i_4;
mo_p=1;
for(k=1;k<=N1-1;k++)
{
m=mo_p;
m_1=(i)%(m+1);
m_2=(i)%(2*m+1);
mod_2=(m_1+1)%(m+1);
y1[m_2][k]=y1[m_1][k-1]+y1[mod_2][k-1];
y2[m_2][k]=y2[m_1][k-1]+y2[mod_2][k-1];
mo_p=2*mo_p;
}
mod_3=(m_2+1)&(2*m+1);
a_1=y1[m_2][N1-1]+y1[mod_3][N1-1];
a_2=y2[m_2][N1-1]+y2[mod_3][N1-1];
a_1*=a_1;
a_2*=a_2;
sum=a_1+a_2;
sq=usr_sqrt(sum);
X=sq/(2*N);
DAC_SetChannel1Data(DAC_Align_12b_R,X*1.365);
count_tic = DWT_CYCCNT; //результат
}
}
Вот картинки иллюстрирующие разное количество тактов
Код программы:
#include "main.h"
#include "math.h"
uint16_t delay_count=0;
uint16_t data_adc=0;
uint16_t flag=0,i_1,i_2,i_3,i_4;
uint32_t count_tic=0;
uint32_t mod_1=0,m_1,m_2,mo_p;
uint32_t mod_2=0,mod_3=0;
uint32_t N=16,N1=4;
uint32_t sq,X,i=0,sum;
int32_t y1[40][20],y2[40][20];
int32_t a_1,a_2,m;
uint32_t k,s;
void SysTick_Handler(void) //1ms
{
if(delay_count>0){delay_count--;}
}
/*-*/
uint32_t usr_sqrt(uint32_t value)
{
uint32_t d, a;
__asm {
CLZ a, value
RSB a, a, #0x1F
};
d = 1 << ((a >> 1)+1);
a = (d + ( value >> a )) >> 1;
d = (a + value / a)>>1;
a = (d + value / d)>>1;
d = (a + value / a)>>1;
a = (d + value / d)>>1;
return a;
}
/*-*/
uint16_t get_adc_value()
{
ADC_SoftwareStartConv(ADC1);
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
return ADC_GetConversionValue(ADC1);
}
/*-*/
void delay_ms(uint16_t delay_temp)
{
delay_count = delay_temp;
while(delay_count){}
}
/*-*/
int main(void)
{
SystemCoreClockUpdate();
SysTick_Config(SystemCoreClock/1000);
LED_ini();
DAC_ini();
ADC_R_ini();
#define DWT_CYCCNT *(volatile unsigned long *)0xE0001004
#define DWT_CONTROL *(volatile unsigned long *)0xE0001000
#define SCB_DEMCR *(volatile unsigned long *)0xE000EDFC
while(1)
{
if(flag==0){i_1=get_adc_value();flag=1;}
if(flag==1){i_2=get_adc_value();flag=2;}
if(flag==2){i_3=get_adc_value();flag=3;}
if(flag==3){i_4=get_adc_value();flag=0;}
SCB_DEMCR |= 0x01000000;
DWT_CONTROL|= 1; //включение счетчика
DWT_CYCCNT = 0;
i++;
mod_1=i%2;
y1[mod_1][0]=i_1-i_3;
y2[mod_1][0]=i_2-i_4;
mo_p=1;
for(k=1;k<=N1-1;k++)
{
m=mo_p;
m_1=(i)%(m+1);
m_2=(i)%(2*m+1);
mod_2=(m_1+1)%(m+1);
y1[m_2][k]=y1[m_1][k-1]+y1[mod_2][k-1];
y2[m_2][k]=y2[m_1][k-1]+y2[mod_2][k-1];
mo_p=2*mo_p;
}
mod_3=(m_2+1)&(2*m+1);
a_1=y1[m_2][N1-1]+y1[mod_3][N1-1];
a_2=y2[m_2][N1-1]+y2[mod_3][N1-1];
a_1*=a_1;
a_2*=a_2;
sum=a_1+a_2;
sq=usr_sqrt(sum);
X=sq/(2*N);
DAC_SetChannel1Data(DAC_Align_12b_R,X*1.365);
count_tic = DWT_CYCCNT; //результат
}
}
Вот картинки иллюстрирующие разное количество тактов
- Реклама
Re: Точный подсчет тактов контроллера
Вот то что вы получили и есть самый точный расчёт. Даже если он в каждом случае разный.Radist228 писал(а):возникла необходимость точного расчета тактов выполнения куска кода.
Потому что АРМ не является ядром с детерминированным временем выполнения кода. Изначально. Даже в свободном полёте. А в режиме отладки и подавно. Плюс ещё может накладываться куча других факторов типа прерываний запросов ДМА и пр.Нашел в интернетах код с помощью которого можно подсчитать количество тактов, но в режиме отладки счетчик выполняет разное количество тактов.
Есть. На любом таймере например. Но результат будет такой же.Может есть какие либо другие способы подсчета количества тактов?
Re: Точный подсчет тактов контроллера
А можно ли как-нибудь сделать чтобы определенный кусок кода выполнялся определенное количество тактов. к примеру. часть кода выполняется за 100-200 тактов, но надо чтобы он выполнялся, к примеру, за 202 такта. можно ли сделать какое нибудь ожидание, что-то вроде задержки, которая ждала бы оставшееся число тактов до 202?
Re: Точный подсчет тактов контроллера
И еще кое что забыл сказать, разное количество тактов выполняется именно этот кусок, что может быть причиной этому?
for(k=1;k<=N1-1;k++)
{
m=mo_p;
m_1=(i)%(m+1);
m_2=(i)%(2*m+1);
mod_2=(m_1+1)%(m+1);
y1[m_2][k]=y1[m_1][k-1]+y1[mod_2][k-1];
y2[m_2][k]=y2[m_1][k-1]+y2[mod_2][k-1];
mo_p=2*mo_p;
}
for(k=1;k<=N1-1;k++)
{
m=mo_p;
m_1=(i)%(m+1);
m_2=(i)%(2*m+1);
mod_2=(m_1+1)%(m+1);
y1[m_2][k]=y1[m_1][k-1]+y1[mod_2][k-1];
y2[m_2][k]=y2[m_1][k-1]+y2[mod_2][k-1];
mo_p=2*mo_p;
}
Re: Точный подсчет тактов контроллера
Буфер данных буфер кода конвейер команд прерывания SysTick.
Вообще подсчёт тактов плохая примета. Приводит к потере времени и неработоспособному коду.
Вообще подсчёт тактов плохая примета. Приводит к потере времени и неработоспособному коду.
- Реклама
Re: Точный подсчет тактов контроллера
В этой задаче подсчет тактов необходим на этапе отладки. чтобы подстроиться под работу АЦП. время работы АЦП и выполнения кода должны быть одинаковыми, но этого, как я понял, достичь трудно(((
Ведь должны же быть какие нибудь способы решить данную проблему
Ведь должны же быть какие нибудь способы решить данную проблему
Re: Точный подсчет тактов контроллера
способы - не привязываться к тактам вообще.
вам зачем "время работы АЦП и выполнения кода должны быть одинаковыми"?
вам зачем "время работы АЦП и выполнения кода должны быть одинаковыми"?
Re: Точный подсчет тактов контроллера
ну там весь метод на этом построен, подается непрерывный сигнал и мы его обрабатываем. один период мы квантуем ацп, после проводим расчет этого периода и так через период производятся вычисления, сперва ацп, потом расчет. но там еще есть накопление нескольких периодов , поэтому все должно быть точно. если появляются рассинхроны то демодулированный сигнал получается не четкий
Re: Точный подсчет тактов контроллера
и как часто надо опрашивать АЦП?
если я правильно представляю себе описанную задачу, то путь примерно такой: настраиваем АЦП на старт преобразования по событию таймера, в прерывании по окончанию преобразования запускаем расчет. Поскольку интервалы таймера весьма точны, то периоды между преобразованиями будут известны и фиксированы (если вычисления будут успевать пройти между событиями таймера)
если я правильно представляю себе описанную задачу, то путь примерно такой: настраиваем АЦП на старт преобразования по событию таймера, в прерывании по окончанию преобразования запускаем расчет. Поскольку интервалы таймера весьма точны, то периоды между преобразованиями будут известны и фиксированы (если вычисления будут успевать пройти между событиями таймера)
Re: Точный подсчет тактов контроллера
ну, система какая, нужно на одном периоде выполнить 4 отсчета ацп. после чего произвести расчет
Re: Точный подсчет тактов контроллера
ну а сама частота опроса зависит от времени расчета, там вычисления довольно долгие по тактам
Re: Точный подсчет тактов контроллера
период какой?Radist228 писал(а): нужно на одном периоде выполнить 4 отсчета ацп. после чего произвести расчет
так не бываетRadist228 писал(а):частота опроса зависит от времени расчета
Re: Точный подсчет тактов контроллера
Ну смотрите. Суть данного метода в чем заключается.У нас есть синус с определенной частотой , мы берем 4 отсчета на периоде. После чего вычитаем и суммируем их и производим расчет буферных значений. Число тактов работы АЦП должно ровняться числу тактов вычислений. Как будто у нас непрерывные преобразования. Частота самого синуса напрямую зависит от количества тактов вычислений. К примеру, у меня количество тактов на вычисления где-то 1000, а число тактов на работу АЦП тоже примерно 1000. Частота несущей около 168 кГц.
Re: Точный подсчет тактов контроллера
на периоде синуса?Radist228 писал(а):У нас есть синус с определенной частотой , мы берем 4 отсчета на периоде.
Radist228 писал(а):Частота самого синуса напрямую зависит от количества тактов вычислений.
если по-другому: вам нужны четыре последовательных отсчета АЦП, с фиксированными временными промежутками между ними. По этим отсчетам вы производите расчет и пихаете результат в ЦАП. Так?
если да, то, собственно, в описанной схеме с таймерами вообще не вижу проблемы. Если у вас допустимо отставание по времени ЦАП-а от отсчетов АЦП на два периода (==время восьми отсчетов), а не один с четвертью (==четырех плюс вычисления), то все еще вкуснее - обсчет предыдущей пачки можно делать в то время, пока формируется новая пачка целиком, а не ее четверть.
Re: Точный подсчет тактов контроллера
Попробую еще раз обьяснить. А то и я начинаю путаться. В общем есть синус из вне, он подается на АЦП. Сам АЦП делает 4 отсчета(к примеру 500 тактов). После чего эти отсчеты отправляются считаться в коде. После чего надо рассчитанное значение подать на ЦАП. И все это надо сделать ровно за 500 тактов. Чтобы АЦП начал преобразование синуса в той же фазе как и в прошлый раз. Но проблема у меня возникла с тем, что блок расчетов делал разное количество тактов, в результате чего на выходе ЦАП сигнал был не четкий и были отклонения от нужного значения. Я как думал сделать, если я знаю число тактов на преобразование АЦП, то могу сделать так. Взять таймер, настроить его на прерывание каждые 2*(число тактов преобразования АЦП) и при том условии что число тактов на расчетную часть и вывод через ЦАП будет меньше числа тактов работы АЦП.
Re: Точный подсчет тактов контроллера
вот самая проблема - "все нужно сделать за 500 тактов". Забудьте пока о том, что в природе существуют такты. За какое время должна выполняться выдача значения в ЦАП от начала первого преобразования АЦП? Какая задержка допустима?
проблема в том, что ваша задача - что вы конкретно хотите сделать на выходе из (какого?) входящего сигнала - совершенно непонятна.
например, как вижу сейчас:
объявляем 8 переменных для отсчетов - 4 текущих, 4 рабочих
объявляем счетчик отсчетов
объявляем флаг готовности к расчету
объявляем переменную под результат расчета
АЦП настраиваем на запуск от события таймера
в прерывании по окончании преобразования АЦП пишем в "текущую" переменную согласно счетчика, инкрементируем счетчик. Если счетчик досчитал до четвертого преобразования (т.е. текущее завершенное - четвертое), то пишем отсчеты из текущих в рабочие, сбрасываем счетчик, поднимаем флаг готовности к расчету
в основном цикле:
ждем флага готовности. Как он появился:
производим расчет
пишем результат в переменную
сбрасываем флаг готовности
** пишем результат в ЦАП
или, если нам нужны точные промежутки между выдачей в ЦАП:
заводим таймер на нужный период
в основном цикле не делаем **
в прерывании по данному таймеру пишем в ЦАП значение переменной результата
проблема в том, что ваша задача - что вы конкретно хотите сделать на выходе из (какого?) входящего сигнала - совершенно непонятна.
например, как вижу сейчас:
объявляем 8 переменных для отсчетов - 4 текущих, 4 рабочих
объявляем счетчик отсчетов
объявляем флаг готовности к расчету
объявляем переменную под результат расчета
АЦП настраиваем на запуск от события таймера
в прерывании по окончании преобразования АЦП пишем в "текущую" переменную согласно счетчика, инкрементируем счетчик. Если счетчик досчитал до четвертого преобразования (т.е. текущее завершенное - четвертое), то пишем отсчеты из текущих в рабочие, сбрасываем счетчик, поднимаем флаг готовности к расчету
в основном цикле:
ждем флага готовности. Как он появился:
производим расчет
пишем результат в переменную
сбрасываем флаг готовности
** пишем результат в ЦАП
или, если нам нужны точные промежутки между выдачей в ЦАП:
заводим таймер на нужный период
в основном цикле не делаем **
в прерывании по данному таймеру пишем в ЦАП значение переменной результата
Re: Точный подсчет тактов контроллера
Ну, я примерно понял систему. Спасибо за подсказку))
- moLCHec
- Мявтор!
- Сообщения: 825
- Зарегистрирован: Вс дек 18, 2005 20:04:42
- Откуда: Свердловская обл.
- Контактная информация:
Re: Точный подсчет тактов контроллера
А чего таймеры использовать то никак ?!
В СТМ с ними чудеса творить можно даже каскадом при желании запустить.
Да и ДМА никто не отменял, настроил запуск АЦП по таймеру, настроил ДМА на 8 преобразований и по прерыванию ДМА в середине и в конце выполняешь расчет и пр.
В СТМ с ними чудеса творить можно даже каскадом при желании запустить.
Да и ДМА никто не отменял, настроил запуск АЦП по таймеру, настроил ДМА на 8 преобразований и по прерыванию ДМА в середине и в конце выполняешь расчет и пр.
Настоящий кот всегда либо голоден,
либо невыспался ...
либо невыспался ...


