Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как сделать времевую задержку в AVR без таймера
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Student2
Хочу сделать переменную задержку без използование таймера с резолюцию 1 или 2 цикла.

То что сделал выглядить так:

CODE
#pragma inline=forced
#pragma optimize=s 9 /* this switches the maximum speed optimization for this function only */
void delay(uint8_t delatTime) /* delay routine */
/*------------------------------------------------------ */
{
if(delatTime> TIME_0) /* we do delay on base on the dwell time */
{ /* no branch - 2 clock cycles to this point */
if(delatTime> TIME_1)
{ /* no branch - 4 clock cycles to this point */
if(delatTime> TIME_2)
{ /* no branch - 6 clock cycles to this point */
if(delatTime> TIME_3)
{ /* no branch - 8 clock cycles to this point */
if(delatTime> TIME_4)
{ /* no branch - 10 clock cycles to this point */
if(delatTime> TIME_5)
{ /* no branch - 12 clock cycles to this point */
if(delatTime> TIME_6)
{ /* no branch - 14 clock cycles to this point */
if(delatTime> TIME_7)
{ /* no branch - 16 clock cycles to this point */
if(delatTime> TIME_8)
{ /* no branch - 18 clock cycles to this point */
if(delatTime> TIME_9)
{ /* no branch - 20 clock cycles to this point */
if(delatTime> TIME_10)
{ /* no branch - 22 clock cycles to this point */
__delay_cycles(2);
}
}
}
}
}
}
}
}
}
}
}
}


Я думаю что задержка с резолюции из одного цикла можно сделать с lookup table но не могу понять как ее построить в IAR.

Буду благодарен если поделитесь как Вы делаете задержки без използование таймера.
izerg
Цитата(Student2 @ Aug 9 2009, 13:42) *
Я думаю что задержка с резолюции из одного цикла можно сделать с lookup table но не могу понять как ее построить в IAR.



__delay_cycles(unsigned long int);
Makes the compiler generate code that takes the given amount of cycles to perform, that is it inserts a time delay that lasts the specified number of cycles.

Note: The specified value must be a constant integer expression and not an expression that is evaluated at runtime.

Цитата из справочника IAR.
Чем не устраивает delay_cycles?
Student2
Цитата(izerg @ Aug 9 2009, 15:45) *
__delay_cycles(unsigned long int);
Цитата из справочника IAR.
Чем не устраивает delay_cycles?


Меня устраивает если задержка работатет на переменная (var). К сожалению если поставить переменная в __delay_cycles() и компилатор начинает глючить:
Код
Fatal Error[Ta030]: Argument to __delay_cycles must be a constant expression.
Student2
Я увидел что IAR for TI имеет ключевое слово __even_in_range которое может использоваться в сочетание с switch() для создание очень эффективные lookup JUMP таблицы.

Вопрос - как можно создать такую JUMP lookup таблицу в IAR AVR?
izerg
Приведите пример кода, в котором хотите использовать такую задержку.
MrYuran
Код
void Pause(unsigned int volatile mks)
{
    while(mks--);
}

Правда, такую конструкцию оптимизатор может "оптимизировать" в ноль, поэтому лучше вставить инлайн-ассемблер и написать именно то, что нужно, в т.ч. с точностью до тактов
Если память не изменяет, в инструкции к ИАРу именно так и советуется поступать. И даже пример есть.
Goodefine
Можно как то так:
Код
#define TICK 2
...
void delay_variable(uint8 tick)
{
     for(uint8 i=tick;i;i--) __delay_cycles(TICK);
}
...
delay_variable(x);
Палыч
Цитата(Student2 @ Aug 10 2009, 11:06) *
Вопрос - как можно создать такую JUMP lookup таблицу в IAR AVR?
Этот вопрос, наверное, перекликается с Вашим вопросом http://electronix.ru/forum/index.php?showtopic=66032

Вы хотите с помощью этой таблицы формировать задержки? Если -так, то, наверное, необходимо написать на ассемблере, что-то типа этого:
Код
my_delay:
        ldi   r30, low (Label/2)
        ldi   r31, high (Label/2)
        add   r30, r16
        adc   r31, r17
        ijmp
Label:
        nop
        nop
........................
        nop
        nop
        ret
Student2
Цитата(Палыч @ Aug 10 2009, 14:05) *
Этот вопрос, наверное, перекликается с Вашим вопросом http://electronix.ru/forum/index.php?showtopic=66032


Спасибо за идею. Вопрос об "Как сделать времевую задержку в AVR без таймера" конечно имеет много общего с новый пост, но акцент сейчас к табличное описание lookup таблицу. В общем таблицу можно использовать для множество других приложений и конечно одно из них - задержка).

Что будеть если директно увеличить PC как делает __even_in_range ? Увидел что в AVR документации нет описание где находиться PC (program copunter) регистер.
Student2
Цитата(izerg @ Aug 10 2009, 13:03) *
Приведите пример кода, в котором хотите использовать такую задержку.


Хочу установить pinState в 1 для 1, 2.... 7 cycles и потом возвратить в высокоимпедансное состояние

goto($ + delay); /* pseudocode, normally will yield error */
pinState = 1; /* force the pin to 1 */
pinState = 1; /* force the pin to 1 */
pinState = 1; /* force the pin to 1 */
pinState = 1; /* force the pin to 1 */
pinState = 1; /* force the pin to 1 */
pinState = 1; /* force the pin to 1 */
pinState = 1; /* force the pin to 1 */
pinStateTRIS = 0; /* float the pin */



Цитата(Goodefine @ Aug 10 2009, 13:17) *
Код
#define TICK 2
...
void delay_variable(uint8 tick)
{
     for(uint8 i=tick;i;i--) __delay_cycles(TICK);
}
...
delay_variable(x);


Резолюция кода есть 2 или больше системных циклов. То что надо - резолюция из одного системного цикла. Описание кода в начале темы есть резолюция из 2 цикла.
MrYuran
Цитата(Student2 @ Aug 10 2009, 15:29) *
Хочу установить pinState в 1 для 1, 2.... 7 cycles и потом возвратить в высокоимпедансное состояние

сформировать таблицу из 7 NOP-ов и прыгать на нужный, учитывая задержку подготовительных операций
Для уверенности всё писать на инлайн-ассемблере
всё - это внутренности Pause()
Rst7
Ну если уж очень хочется извратиться, то можно так
CODE
#define ONE_NOP(NAME,NEXT_NAME)\
static void delay_##NEXT_NAME(char cool.gif;\
static void delay_##NAME(char cool.gif\
{\
__no_operation();\
delay_##NEXT_NAME(cool.gif;\
}\

ONE_NOP(4,3)
ONE_NOP(3,2)
ONE_NOP(2,1)
ONE_NOP(1,0)

#pragma optimize=no_inline
static void delay_0(char cool.gif
{
PORTB=b;
}

void delay_x(char b, char c)
{
char __flash *p=(char __flash *)delay_4;
p+=c;
((void(*)(char))p)(cool.gif;
}


с вот таким результатом
CODE
\ In segment CODE, align 2, keep-with-next
11 ONE_NOP(4,3)
\ delay_4:
\ 00000000 0000 NOP
\ 00000002 0000 NOP
\ 00000004 0000 NOP
\ 00000006 0000 NOP
\ 00000008 REQUIRE delay_0
\ 00000008 ; // Fall through to label delay_0
12 ONE_NOP(3,2)
13 ONE_NOP(2,1)
14 ONE_NOP(1,0)
15
16 #pragma optimize=no_inline

\ In segment CODE, align 2, keep-with-next
17 static void delay_0(char cool.gif
\ delay_0:
18 {
19 PORTB=b;
\ 00000000 B905 OUT 0x05, R16
20 }
\ 00000002 9508 RET
\ 00000004 REQUIRE _A_PORTB
21

\ In segment CODE, align 2, keep-with-next
22 void delay_x(char b, char c)
\ delay_x:
23 {
24 char __flash *p=(char __flash *)delay_4;
25 p+=c;
26 ((void(*)(char))p)(cool.gif;
\ 00000000 .... LDI R30, LOW(delay_4/2)
\ 00000002 .... LDI R31, (delay_4/2) >> 8
\ 00000004 E030 LDI R19, 0
\ 00000006 0FE1 ADD R30, R17
\ 00000008 1FF3 ADC R31, R19
\ 0000000A 9409 IJMP
27 }
Student2
Цитата(MrYuran @ Aug 10 2009, 14:41) *
сформировать таблицу из 7 NOP-ов и прыгать на нужный, учитывая задержку подготовительных операций
Для уверенности всё писать на инлайн-ассемблере
всё - это внутренности Pause()


Мне хотелось как нибудь не трогать ассемблеря (для лучшей поддержки кода) - ассемблер = "черт в коде". Тоже ассемблер и С вместе часто создают глубокие ошибки.
Student2
Спасибо Rst7 - код выглядит хорошо и буду пользоваться. Есть только одна проблема - начальное опоздание (время) для подготовки регистров. Если нужная задержка 2 цикла а начальное опоздание 6-8 циклов то будет добавочные 4-6 циклов. Но идея воистину хорошая!

Я думаю что это и есть путь к _even_in_range для AVR!
Rst7
Цитата
Мне хотелось как нибудь не трогать ассемблеря


Ну так зайдите в другую тему (которую Вы создали про even_range) и прочитайте мой ответ smile.gif
Rst7
Можно чуть убрать оверхед, используя такой бубен:
Код
#define ONE_NOP(NAME,NEXT_NAME)\
static void delay_##NEXT_NAME(char b);\
static void delay_##NAME(char b) @ "SEG_0100" \
{\
  __no_operation();\
  delay_##NEXT_NAME(b);\
}\

ONE_NOP(4,3)
ONE_NOP(3,2)
ONE_NOP(2,1)
ONE_NOP(1,0)

#pragma optimize=no_inline
static void delay_0(char b) @ "SEG_0100"
{
  PORTB=b;
}

void delay_x(char b, char c)
{
  char __flash *p=(char __flash *)(((unsigned int)delay_4&0xFF00)|c);
  ((void(*)(char))p)(b);
}


При этом создать сегмент SEG_0100 в конфигурации линкера с круглого адреса (кратного 0x100). Результат:
Код
   \                                 In  segment CODE, align 2, keep-with-next
     22          void delay_x(char b, char c)
   \                     delay_x:
     23          {
     24            char __flash *p=(char __flash *)(((unsigned int)delay_4&0xFF00)|c);
     25            ((void(*)(char))p)(b);
   \   00000000   ....               LDI     R31, (delay_4/2) >> 8
   \   00000002   2FE1               MOV     R30, R17
   \   00000004   9409               IJMP
     26          }
Student2
Цитата
name='Rst7'


Воистину это еще лучше! Мне надо больше времени чтобы понять в глубине кода, но идея с flash pointer очень хитрая и все на С коде. Получаете мои поздравления!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.