реклама на сайте
подробности

 
 
9 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> К знатокам, Локальные переменные.
SasaVitebsk
сообщение Sep 6 2007, 00:58
Сообщение #1


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Пишу достаточно простую прогу. Пытаюсь оптимизировать.

Столкнулся с одной бедой. Попробую описать.

Построено на прерываниях. Между прерываниями разные промежутки. Есть короткие, есть длинные. Как назло именно короткое прерывание сильно загружено. Дабы разгрузить его я пытаюсь часть вычислений вынести в предыдущее не загруженное прерывание. Уже полностью перешёл на указатели, но всё равно шляпа получается.

Проблема в том, что я не могу ввести локальные переменные на два прерывания. Таким образом я ввожу статик. Но тогда во втором прерывании компилятор пытается сохранить значения. А мне это не надо ни капельки. Чтобы этого избежать я ввёл локальные переменные и во втором прерывании выполнил присваивание локальным статик. Код получился значительно компактнее, но всё равно выполняется никому не нужное присваивание. А это 6 указателей!

Теперь сам вопрос.
Могу ли я указать компилятору что можно разрушать переменные в данном прерывании. То есть что не надо их хранить. Или как это сделать. Надо типа переобъявить статические переменные локальными. Не знаю как выразится. Надеюсь поняли.
Go to the top of the page
 
+Quote Post
dxp
сообщение Sep 6 2007, 04:33
Сообщение #2


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Все равно как-то туманно. Вы бы псевдокод привели, коротенько, только самое необходимое с пояснениями по тексту, а так гадать, что у вас получается, и что хотите, сложновато.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
alexander55
сообщение Sep 6 2007, 04:53
Сообщение #3


Бывалый
*****

Группа: Свой
Сообщений: 1 584
Регистрация: 7-08-07
Пользователь №: 29 615



Цитата(SasaVitebsk @ Sep 6 2007, 04:58) *
Пишу достаточно простую прогу. Пытаюсь оптимизировать.

Столкнулся с одной бедой. Попробую описать.

Построено на прерываниях. Между прерываниями разные промежутки. Есть короткие, есть длинные. Как назло именно короткое прерывание сильно загружено. Дабы разгрузить его я пытаюсь часть вычислений вынести в предыдущее не загруженное прерывание. Уже полностью перешёл на указатели, но всё равно шляпа получается.

Проблема в том, что я не могу ввести локальные переменные на два прерывания. Таким образом я ввожу статик. Но тогда во втором прерывании компилятор пытается сохранить значения. А мне это не надо ни капельки. Чтобы этого избежать я ввёл локальные переменные и во втором прерывании выполнил присваивание локальным статик. Код получился значительно компактнее, но всё равно выполняется никому не нужное присваивание. А это 6 указателей!

Теперь сам вопрос.
Могу ли я указать компилятору что можно разрушать переменные в данном прерывании. То есть что не надо их хранить. Или как это сделать. Надо типа переобъявить статические переменные локальными. Не знаю как выразится. Надеюсь поняли.

Как-то все не очеь ясно, но и из того, что я понял, могу предложить ввести какой-то класс со всеми данными и в нем функции, работы с этими данными. В прерываниях и где-нужно их вызывать и не париться больше со статиками глобальными, локальными и еще чем-то. За Вас все сделает компилятор.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 6 2007, 05:02
Сообщение #4


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Да, действительно мутновато. Если я правильно понял, то вы можете завести глобальные переменные, в одном прерывании в них сохранять, а во втором заведите локальные переменные, копируйте в них глобальные и работайте с локальными копиями. Если оба прерывания в одном файле - объявите эти глобальные как static, тогда они не будут видны в других файлах. И еще одна мысль - если переменных не много, не знаю как в новых, а в старых версиях можно было залочить несколько регистров и разместить эти переменные в залоченных регистрах.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
MALLOY2
сообщение Sep 6 2007, 05:49
Сообщение #5


Знающий
****

Группа: Validating
Сообщений: 838
Регистрация: 31-01-05
Пользователь №: 2 317



Можно еще все нужные переменные загнать в 1 структуру, создать глобальный указатель на структру, в прерываниии глобальный указатель копировать в локальный с ним и работать.
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Sep 6 2007, 07:51
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823



Цитата(SasaVitebsk @ Sep 6 2007, 03:58) *
Построено на прерываниях. Между прерываниями разные промежутки. Есть короткие, есть длинные. Как назло именно короткое прерывание сильно загружено. Дабы разгрузить его я пытаюсь часть вычислений вынести в предыдущее не загруженное прерывание. Уже полностью перешёл на указатели, но всё равно шляпа получается.

Я тоже не особенно понял суть проблемы, а свои подобные решаю так...
Я тоже разбиваю некоторую обработку внутри прерываний на более мелкие части, чтобы сократить время прерывания, но не понимаю, как это связано с классом переменных.
Все переменные являются статическими (точнее, определены снаружи), после выполнения части обработки происходит выход из прерывания, а при последующем входе осуществляется другая часть расчета. Выбор - по interrupt_counter. Убогость системы прерываний AVR удручает, но что делать? Чтобы сократить перебор в switch, можно сделать массив функций и выбирать по индексу, но оптимизатор сам это может сделать.

Вот мой пример обработки клавиатуры :
Код
        switch (interrupt_counter)     // to reduce time of function
    {
    case    0:    interrupt_counter=1;        //refresh statuses
            kbd_status3=kbd_status2;
            kbd_status2=kbd_status1;
            kbd_status1=kbd_status0;
            kbd_status0=Kbd;
            interrupt_counter=interrupt_counter;
            break;

    case    1:   interrupt_counter=2;        //check pressed key every tic
            pressed_keys=kbd_status0&kbd_status1&kbd_status2;
            if (pressed_keys&(~kbd_status3))
            if (bSound==SoundAlwaysOn) Beep(5,1);
            found_events|=pressed_keys&(~kbd_status3);        // found edge
            if ((pressed_keys==kUp+kDn)&&  // now this two keys
                ((~kbd_status3)&(kUp+kDn)))//and before it wasn't so
                {found_events|=kUpDn;    // set new bit
                found_events&=~(kUp+kDn);    break; } //reset usual bits
            if ((pressed_keys==kUp+kSt)&&  // now this two keys
                ((~kbd_status3)&(kUp+kSt)))//and before it wasn't so
                {found_events|=kUpSt;    // set new bit
                found_events&=~(kUp+kSt);    break; }//reset usual bits                
            if ((pressed_keys==kDn+kSt)&&  // now this two keys
                ((~kbd_status3)&(kDn+kSt)))//and before it wasn't so
                {found_events|=kDnSt;    // set new bit
                found_events&=~(kDn+kSt); break; }    //reset usual bits                    
        break;            
                
    case    2:    interrupt_counter=3;        //check if key the same as before
            if ((pressed_keys&kUp)||(pressed_keys&kDn))    //key for repeat
            {    if (pressed_keys==old_pressed_keys) // same key?
                {    if (pressed_counter)         // yes, time over?
                    {pressed_counter--;}      //No
                    else     {    pressed_counter=NextDelay;        //Yes
                            found_events=pressed_keys; }        //reset
                    }
                else                                            // other key
                    {pressed_counter=StartDelay;    
                    }
            };
            old_pressed_keys=pressed_keys;
            break;
    case    3:    interrupt_counter++;
              break;
    default: interrupt_counter=0;
  }


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
alexander55
сообщение Sep 6 2007, 09:20
Сообщение #7


Бывалый
*****

Группа: Свой
Сообщений: 1 584
Регистрация: 7-08-07
Пользователь №: 29 615



Цитата(Dog Pawlowa @ Sep 6 2007, 11:51) *
Я тоже разбиваю некоторую обработку внутри прерываний на более мелкие части, чтобы сократить время прерывания, но не понимаю, как это связано с классом переменных.

Попробую объяснить. Используем C++.
Объявление класса
class TCalc {
int x,y,z; // промежуточные переменные
public:
TCalc(void) {x=y=z=0;}; // начальная инициализация
void F!(void); // первая функция заносит результат в x
void F2(void); // вторая функция заносит результат в y
void F3(void); // третья функция заносит результат в z
int Read_Z(void) {return z;};
};
Реализация,допустим для F3
void TCalc::F3(void) {z=x+y*y;};

В main.cpp есть строчка TCalc Calc;
В других, где нужно extern TCalc Calc;
В прерывании 1 Calc.F1();
В прерывании 2 Calc.F2();
В прерывании 3 Calc.F3();
Где нужен результат ....=Calc.Read_Z();
Обратите внимание никаких статиков, инициализаций в main, volatile и т.д.
Для любителей указателей можно сделать и на них, но рекомендую прочитать соответствующий пост для понимамания, где они нужны, а где вредны.
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Sep 6 2007, 11:27
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Лучше всех понял проблему Сергей Борщ. Я так и сделал. Но всё равно есть лишние операции. Хотелось бы от них избавится. Приведу код с пояснениями.
Код
__no_init    uint8_t        static    *uFaz1,*uFaz2,*uFaz3,
                                *uFaz4,*uFaz5,*uFaz6;    // Вспомогательный. Указатель на текущую фазу двигателя

Это объявление по сути в этих переменных нет необходимости. Чисто чтобы одну операцию разбить на два прерывания.
Код
// Обработка Шима тех каналов (двигателей) которые отрабатывают угол 45
// вывод уровня 0.707 уровень 2
#pragma    vector=TIMER1_COMPB_vect
__interrupt    static void    pvPWWLvl2(void)
{
// Вывод предварительно расчитанных значений портов
PORTE = bOportE[2];
PORTA = bOportA[2];
PORTC = bOportC[2];
// Предварительный расчёт фаз двигателей. Требуется для фазы C
uint8_t    bFaz;
bFaz = (wStateReal[0] & (MAXFAZ-1))>>2;                // Выделить фазу одного двигателя порта
uFaz1 = &bfPortSh1[0][0]+bFaz;
bFaz = (wStateReal[1] & (MAXFAZ-1))>>2;                // Выделить фазу одного двигателя порта
uFaz2 = &bfPortSh2[0][0]+bFaz;
bFaz = (wStateReal[2] & (MAXFAZ-1))>>2;                // Выделить фазу одного двигателя порта
uFaz3 = &bfPortSh3[0][0]+bFaz;
bFaz = (wStateReal[3] & (MAXFAZ-1))>>2;                // Выделить фазу одного двигателя порта
uFaz4 = &bfPortSh4[0][0]+bFaz;
bFaz = (wStateReal[4] & (MAXFAZ-1))>>2;                // Выделить фазу одного двигателя порта
uFaz5 = &bfPortSh5[0][0]+bFaz;
bFaz = (wStateReal[5] & (MAXFAZ-1))>>2;                // Выделить фазу одного двигателя порта
uFaz6 = &bfPortSh6[0][0]+bFaz;
}

Это первое прерывание с места где "Предварительный ..." идёт подготовка инфы для следующего прерывания

Код
// Обработка Шима тех каналов (двигателей) которые отрабатывают угол 67.5. Расчёт предустановленных значений портов.
// вывод уровня 0.9239 уровень 3
#pragma    vector=TIMER1_COMPC_vect
__interrupt    static void    pvPWWLvl3(void)
{
// Вывод предварительно расчитанных значений портов
PORTE = bOportE[3];
PORTA = bOportA[3];
PORTC = bOportC[3];
// Расчёт предустановленных значений портов.
uint8_t    i, *faz1,*faz2,*faz3,*faz4,*faz5,*faz6;
faz1=uFaz1;
faz2=uFaz2;
faz3=uFaz3;
faz4=uFaz4;
faz5=uFaz5;
faz6=uFaz6;
for(i=0;i<MAXLVLPWW;i++)
{
   bOportE[i] = *faz1++ | *faz2++;                    // сформировать значение порта
   bOportA[i] = *faz3++ | *faz4++;                    // сформировать значение порта
   bOportC[i] = *faz5++ | *faz6++;                    // сформировать значение порта
};
}


Здесь вы видите локальные переменные которые введены чтобы избавится от сохранения uFaz. Но суть в том, что сохранять то мне не надо. В следующем цикле эти значения будут высчитаны заново. Введение локальных переменных Дало самый оптимальный код, но может всё таки кто-нибудь из опыта подскажет другое решение. Важно быстродействие последнего прерывания
Go to the top of the page
 
+Quote Post
scifi
сообщение Sep 6 2007, 13:05
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(SasaVitebsk @ Sep 6 2007, 15:27) *
Введение локальных переменных Дало самый оптимальный код, но может всё таки кто-нибудь из опыта подскажет другое решение. Важно быстродействие последнего прерывания

Быстрее всего можно сделать при помощи ассемблера. Но тогда огласите, какой процессор. Например, если это ARM, то можно в обработчике прерывания, которое подготавливает данные, подготовленные данные сохранить в регистрах процессора R8_fiq, ..., R14_fiq. В быстром прерывании перейти в режим FIQ и использовать эти регистры.
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Sep 6 2007, 19:45
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(scifi @ Sep 6 2007, 16:05) *
Быстрее всего можно сделать при помощи ассемблера. Но тогда огласите, какой процессор. Например, если это ARM, то можно в обработчике прерывания, которое подготавливает данные, подготовленные данные сохранить в регистрах процессора R8_fiq, ..., R14_fiq. В быстром прерывании перейти в режим FIQ и использовать эти регистры.

Нет процессор at90can128. Применять ASM не хочу. У меня в первый день все двигатели заработали. Ошибки только инициализации и расчётных констант были. Ну и одна ошибка выхода за пределы массива. Что-то я не припомню чтобы на АСМе у меня в первый день что-то заработало. Хочу средствами Си. Нет значит нет. Немного снижу частоту ШИМа.

Спасибо за участие
Go to the top of the page
 
+Quote Post
vmp
сообщение Sep 7 2007, 13:42
Сообщение #11


Местный
***

Группа: Свой
Сообщений: 426
Регистрация: 20-01-05
Из: Зеленоград
Пользователь №: 2 070



Похоже, здесь основная проблема - это ограничения Си. Для передачи между функциями (в частном случае прерываниями) приходится использовать статические переменные. Каждая их модификация на AVR - это загрузка в регистр, модификация, сохранение в память. Локальные же переменные могут храниться в регистрах и доступ к ним заметно быстрее.
Что бы я сделал с данным конкретным кодом.
1. Объединил бы глобальные переменные в структуру. Доступ к элементам структуры - более быстрый.
2. Перешел бы от указателей (слова) к байтовым индексам. По идее они должны работать быстрее, но надо смотреть, что сгенерит компилятор.
3. Попробовал бы развернуть цикл.
Go to the top of the page
 
+Quote Post
dxp
сообщение Sep 8 2007, 10:12
Сообщение #12


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(vmp @ Sep 7 2007, 20:42) *
Похоже, здесь основная проблема - это ограничения Си. Для передачи между функциями (в частном случае прерываниями) приходится использовать статические переменные. Каждая их модификация на AVR - это загрузка в регистр, модификация, сохранение в память. Локальные же переменные могут храниться в регистрах и доступ к ним заметно быстрее.

Действительно, в стандартном С такая проблема есть. Но конкретно в EWAVR есть возможность выделить регистр(ы) для своих целей, и компилятор их использовать не будет. Делается это, насколько помню, с помощью расширенного ключевого слова __regvar.

Цитата(vmp @ Sep 7 2007, 20:42) *
2. Перешел бы от указателей (слова) к байтовым индексам. По идее они должны работать быстрее, но надо смотреть, что сгенерит компилятор.

Там (в EWAVR) можно разместить объект в секции TINY, которая размещается в младшем сегменте - в 8-разрядном адресном пространстве, при обращении к объектам, размещенным в этом адресном пространстве, обращение осуществляется на основе, понятно, 8-битных адресов. Все это тоже, ессно, расширение, объект объявляется с помощью расширенного ключевого слова __tiny.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
Rst7
сообщение Sep 8 2007, 10:49
Сообщение #13


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Цитата(SasaVitebsk @ Sep 6 2007, 14:27) *
Код
// Обработка Шима тех каналов (двигателей) которые отрабатывают угол 67.5. Расчёт предустановленных значений портов.
// вывод уровня 0.9239 уровень 3
#pragma    vector=TIMER1_COMPC_vect
__interrupt    static void    pvPWWLvl3(void)
{
// Вывод предварительно расчитанных значений портов
PORTE = bOportE[3];
PORTA = bOportA[3];
PORTC = bOportC[3];
// Расчёт предустановленных значений портов.
uint8_t    i, *faz1,*faz2,*faz3,*faz4,*faz5,*faz6;
faz1=uFaz1;
faz2=uFaz2;
faz3=uFaz3;
faz4=uFaz4;
faz5=uFaz5;
faz6=uFaz6;
for(i=0;i<MAXLVLPWW;i++)
{
   bOportE[i] = *faz1++ | *faz2++;                    // сформировать значение порта
   bOportA[i] = *faz3++ | *faz4++;                    // сформировать значение порта
   bOportC[i] = *faz5++ | *faz6++;                    // сформировать значение порта
};
}


Здесь вы видите локальные переменные которые введены чтобы избавится от сохранения uFaz. Но суть в том, что сохранять то мне не надо. В следующем цикле эти значения будут высчитаны заново. Введение локальных переменных Дало самый оптимальный код, но может всё таки кто-нибудь из опыта подскажет другое решение. Важно быстродействие последнего прерывания


Тут вообще много кода генерит иар. Так как проц у вас с немалым флешем, я думаю можно особо память программ не экономить. Посему предлагаю такой вариант:

Код
//Заменяем массивы на просто переменные
char bOportE0;
char bOportE1;
char bOportE2;
char bOportE3;
char bOportA0;
char bOportA1;
char bOportA2;
char bOportA3;
char bOportC0;
char bOportC1;
char bOportC2;
char bOportC3;
#pragma    vector=TIMER1_COMPC_vect
__interrupt    static void    pvPWWLvl3(void)
{
  PORTE = bOportE3;
  PORTA = bOportA3;
  PORTC = bOportC3;
  uint8_t *faz1,*faz2;
  
  faz1=uFaz1;
  faz2=uFaz2;
  bOportE0=*faz1++|*faz2++;
  bOportE1=*faz1++|*faz2++;
  bOportE2=*faz1++|*faz2++;
  bOportE3=*faz1++|*faz2++;

  faz1=uFaz3;
  faz2=uFaz4;
  bOportA0=*faz1++|*faz2++;
  bOportA1=*faz1++|*faz2++;
  bOportA2=*faz1++|*faz2++;
  bOportA3=*faz1++|*faz2++;
  
  faz1=uFaz5;
  faz2=uFaz6;
  bOportC0=*faz1++|*faz2++;
  bOportC1=*faz1++|*faz2++;
  bOportC2=*faz1++|*faz2++;
  bOportC3=*faz1++|*faz2++;

}


и отключаем для этого модуля кластеризацию переменных. Это освободит один индексный регистр и здорово сократит код. А вообще, наверное надо копать не от финальных процедур, а чуть выше, возможно, пересмотрев алгоритм генерации данных, можно будет сильно улучшить производительность... Если есть возможность, расскажите, какие данные вам надо лить в порты, попробуем придумать что-то оригинальное...


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 8 2007, 11:39
Сообщение #14


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(dxp @ Sep 8 2007, 13:12) *
Там (в EWAVR) можно разместить объект в секции TINY, которая размещается в младшем сегменте - в 8-разрядном адресном пространстве,
Увы, у этого процессора младшие 256 байт заняты регистрами периферии. Объем tiny памяти у него равен нулю, как и у меги48/88/168. В аналогичной ситуации программа, использующая tiny-память не переносится с меги8 на мегу88.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
mdmitry
сообщение Sep 8 2007, 22:28
Сообщение #15


Начинающий профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 25-10-06
Из: СПб
Пользователь №: 21 648



Возможно, поможет сократить время выполнения генерация кода прерывания не автоматическая (компилятором), а руками, т.е. использовать инструкцию аналогичную GCC NAKED, кажется, _raw для IAR.


--------------------
Наука изощряет ум; ученье вострит память. Козьма Прутков
Go to the top of the page
 
+Quote Post

9 страниц V   1 2 3 > » 
Reply to this topicStart new topic
3 чел. читают эту тему (гостей: 3, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 21:33
Рейтинг@Mail.ru


Страница сгенерированна за 0.01492 секунд с 7
ELECTRONIX ©2004-2016