Ассемблер (ASM) для AVR в вопросах и ответах

Обсуждаем контроллеры компании Atmel.
Аватара пользователя
Engineer_Keen
Друг Кота
Сообщения: 3868
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение Engineer_Keen »

Gudd-Head писал(а):Т.к. адресуются слова, то 2^23-1 = 8М слов, т.е. 16Мбайт.

Адресуются слова, так что 2^22=4Мслов (почему ^23?), а то что это 8Мбайт, не важно, у нас же PC в словах считает :wink:
Хорошо еще что речь не о MCS51, а то там есть AJMP, SJMP, LJMP и хитрый JMP с использованием аккумулятора и указателя, но зато путаницы со словами/байтами нет :)
Мikа писал(а):Пытаюсь вникнуть в написанное вами :D

Давайте давайте, вникайте скорее, вас еще IJMP\ICALL ждут :)))
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение shads »

Подскажите, какой самый эффектный способ декремента 16-ти разрядного счетчика (2 регистра в нижней половине) и при достижении 0xffff загрузки в него нового значение....

Сначала думал что есть команда перехода при переполнении, т.е. при переходе 0 -> 255, но наверное она работает только при переполнении в сторону 255 -> 0... т.к. у меня не получилось это с декрементом....

На данный момент лучше ничего не придумал чем это, но думаю можно эффективнее.....

Код: Выделить всё

   ldi      temp,0xff
   dec      DivL
   cp      DivL,temp
   brne   exit
   dec      DivH
   cp      DivH,temp
   brne   exit

   ldi      temp,lo8(DIV_CONST)
   mov      DivL,temp
   ldi      temp,hi8(DIV_CONST)
   mov      DivH,temp

exit:
Аватара пользователя
ibiza11
Поставщик валерьянки для Кота
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение ibiza11 »

ну как минимум можно убрать загрузку в temp числа 0хFF, используя вместо cp команду cpi :)

Добавлено: Вот как вариант

Код: Выделить всё

   ldi   temp,$1
   sub   DivL,temp
   brcc  exit         ;Branch if Carry is Cleared
   sub   DivH,temp
   brcc  exit
   ldi   temp,low(DIV_CONST)
   mov   DivL,temp
   ldi   temp,high(DIV_CONST)
   mov   DivH,temp
exit:
Последний раз редактировалось ibiza11 Пн май 20, 2013 15:48:19, всего редактировалось 1 раз.
Ставим плюсы: )
akl
Друг Кота
Сообщения: 4444
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение akl »

Может как-то так

Код: Выделить всё

.def DivH =R25
.def DivL =R24

RESET:
   SBIW   DivL,1
   BRCS   T1
   RJMP   RESET
T1:
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение shads »

ibiza11 писал(а):ну как минимум можно убрать загрузку в temp числа 0хFF, используя вместо cp команду cpi :)
Немогу, т.к. регистры в нижней половине.... они же не переваривают cpi.....

ibiza11 писал(а):Вот как вариант

Код: Выделить всё

   ldi   temp,$1
   sub   DivL,temp
   brcc  exit         ;Branch if Carry is Cleared
   sub   DivH,temp
   brcc  exit
   ldi   temp,low(DIV_CONST)
   mov   DivL,temp
   ldi   temp,high(DIV_CONST)
   mov   DivH,temp
exit:
Во..... это уже пинок в нужном направлении.....
а я то думаю почему компилятор всегда иногда заменяет декремент на вычитание.....

akl писал(а):Может как-то так

Код: Выделить всё

.def DivH =R25
.def DivL =R24

RESET:
   SBIW   DivL,1
   BRCS   T1
   RJMP   RESET
T1:
Не могу занимать старшие регистры... нужно морочится с младшими.....
Alexeyslav
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич
Контактная информация:

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение Alexeyslav »

А зачем их занимать? Есть PUSH/POP и не бойся что изменения регистра выйдут за рамки данного алгоритма. Защита забирает по 4 такта на регистр...
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение shads »

Alexeyslav писал(а):А зачем их занимать? Есть PUSH/POP и не бойся что изменения регистра выйдут за рамки данного алгоритма. Защита забирает по 4 такта на регистр...
Все дело в том, что это продолжение эпопеи про совмещение Си и Асма в одном проекте... viewtopic.php?f=20&t=37190&start=3020
У меня вся прога на Си.... а на асме только маленький кусочек - скоростное прерывание с частотой вызова 250 000 Гц.
У меня на отработку прерывания дано только 38 тактов. Ито это чтобы успеть выйти до начала следующего прерывания. А еще надо чтобы осталось время и на фоновую работу.....

Несколько нижних регистров у меня определены как переменные и в Си и в асме, только с ними я и работаю в прерывании.
Я даже отказался от того чтобы пуш\попить временный регистр и SREG, сохраняю их все в тех же нижних регистрах, так в 2 раза быстрее получается чем пуш\поп. Так что пуш\попить верхние регистры и потом еще перегружать туда\оттуда нижние регистры - несбыточная мечта.....



Вот весь кусок на асме. (кстати я кажется придумал самый короткий способ инкремента и инициализации 16-ти битного счетчика - см. DivL, DivH.)
Спойлер

Код: Выделить всё

//----------
#include <avr/io.h>

#define T_SLOT   32                  /*количество тиков 16 разрядного таймера на один слот RFID сигнала*/
#define DIV_CONST   1250            /*константа для инициализации счетчика деления с 125000Гц до 100 Гц*/

#define   DivL     r2                  /*счетчик делителя частоты с 125000Гц до 100Гц - младший байт*/
#define   DivH   r3                  /*счетчик делителя частоты с 125000Гц до 100Гц - старший байт*/
#define   Timer    r4                  /*программный таймер\счетчик*/
#define   Flags   r5                  /*байт флагов*/
   #define    INT_100      (1<<0)      /*флаг прерывания частоты 100Гц*/
   #define      Div2      (1<<1)      /*флаг деления частоты прерывания с 250000Гц до 125000Гц*/
#define   PushSreg r6                  /*регистр хранения регистра SREG*/
#define PushTemp r7                  /*регистр хранения регистра TEMP*/
#define   temp     r16                  /*временный регистр*/



//----------
.global TIM0_COMPA_vect

TIM0_COMPA_vect:
   //тут частота прохода 250 000 Гц
   mov      PushTemp,temp            //сохраняем регистры
   in      PushSreg,_SFR_IO_ADDR (SREG)

   ldi      temp,Div2               //делим частоту прохода с 250000Гц до 125000Гц
   eor      Flags,temp
   and      temp,Flags
   breq   exit

   //тут частота прохода 125 000 Гц
   inc      Timer                  //обработка счета программного таймера/счетчика (останавливается на 0xff)
   brne   TmrEnd
   dec      Timer
TmrEnd:

   ldi      temp,T_SLOT+(T_SLOT/2)      //проверка, необходимо ли включить внешнее прерывание
   cp      Timer,temp
   brne   NoEqual
   ldi      temp,1<<_SFR_IO_ADDR (INT0)   //включаем внешнее прерывание
   out      _SFR_IO_ADDR (GIMSK),temp
NoEqual:

   inc      DivL                  //обработка счетчика делителя частоты cо 125000Гц до 100Гц
   brne   exit
   inc      DivH
   brne   exit

   //тут частота прохода 100 Гц
   ldi      temp,lo8(0-DIV_CONST)      
   mov      DivL,temp
   ldi      temp,hi8(0-DIV_CONST)
   mov      DivH,temp
   ldi      temp,INT_100
   or      Flags,temp               //с частотой 100Гц устанавливать флаг медленного прерывания
exit:
                           //выход из прерывания
   out      _SFR_IO_ADDR (SREG),PushSreg
   mov      temp,PushTemp
   reti
.end


//----------




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

Хочу tiny13 уговорить работать как декодер карт RFID. В схеме должен быть генератор 125 000 Гц для питания катушки связи. Так вот меня заклинило на том, чтобы эту частоту выдавала тинька. А проблема в том, что у тиньки только один железный таймер. Т.е. если им генерить частоту 125 000 Гц, то соответственно остальные прерывания будут плясать от этой частоты.

Т.е. у нас есть частота контроллера 9600000Гц, настраиваем изменение вывода по совпадению. Чтобы получить частоту 125000Гц, надо 9600000 / 125000, получается 76. Но это будет длина периода. Чтобы получить промежуток в полупериод, надо гонять таймер не до 76 а до 38.....
При этом прерывания которые мы можем получить от этого таймера будут с частотой 9600000 / 38 = 250000 (примерно).
Вот вам и циферка.... от которой пляшем.....
В этом сумасшедшем прерывании обрабатываем таймер программный, для измерений сигнала RFID, и генерим флаг для низкоскоростного прерывания 100Гц.
Вот в принципе и вся задачка...
Alexeyslav
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич
Контактная информация:

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение Alexeyslav »

Контроллер уже на максимальной частоте в 20Мгц работает? 38 тактов, это с учетом времени на вход в прерывание, выход и +1 такт на очередную инструкцию? На самом деле у тебя времени завались - каждое второе прерывание отрабатывает лишь 10 тактов, у него можно "украсть" еще десяток отложив его обработку, если не уложишься в первом. И еще возникает вопрос, а столь необходимо работать с такой частотой если тебе нужно только каждое второе прерывание? Почему бы не настроить таймер на 125Кгц изначально?
Отсев каждого второго можно сократить если инвертировать бит в глобальном регистре и переходить на выход в зависимости от этого бита, в качестве инверсии взять простой инкремент и проверять 0-й бит SBIC/SBIS. Если уж пляска пошла на такты в прерывании, выделение отдельного регистра под ускорение может быть оправданным.
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение shads »

Alexeyslav писал(а):Контроллер уже на максимальной частоте в 20Мгц работает?
Не, на 9600000. Если бы на 20000000 то было бы легче, но неохота пихать кварц.....

Alexeyslav писал(а):38 тактов, это с учетом времени на вход в прерывание, выход и +1 такт на очередную инструкцию? На самом деле у тебя времени завались - каждое второе прерывание отрабатывает лишь 10 тактов, у него можно "украсть" еще десяток отложив его обработку, если не уложишься в первом.
Да, каждое второе прерывание, получается совсем короткое, но это хорошо, т.к. фоновая задача тоже не должна тормозить... пусть для фона резерв будет.
И кстати я тоже думал, что отложенное прерывание должно сработать, если первое не успело закончится к началу второго, ан нет.... если первое не успело до возникновения второго, то почему то оно не срабатывает по окончании первого..... и один такт прерывания пропускается.....
С чем интересно это может быть связано?

Alexeyslav писал(а):И еще возникает вопрос, а столь необходимо работать с такой частотой если тебе нужно только каждое второе прерывание? Почему бы не настроить таймер на 125Кгц изначально?
Мне изначально нужна частота на ножке 125000Гц, а уж потом из того что имеем, получаю остальное, а при генерации такой частоты, у меня получается прерывание 250000Гц..... по другому я чет не дотукал пока, вроде и так и сяк рылся, вроде только так.....

Alexeyslav писал(а):Отсев каждого второго можно сократить если инвертировать бит в глобальном регистре и переходить на выход в зависимости от этого бита, в качестве инверсии взять простой инкремент и проверять 0-й бит SBIC/SBIS. Если уж пляска пошла на такты в прерывании, выделение отдельного регистра под ускорение может быть оправданным.
Я в принципе так и делаю, флаг Div2. Или ты чтото другое имееш ввиду?
А нет уже места где резервировать доп регистр, все уже исчерпал, Си позволяет резервировать вроде только r2-r7. Они как раз уже забиты.....
Аватара пользователя
ibiza11
Поставщик валерьянки для Кота
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение ibiza11 »

можно уменьшить частоту прерываний в 2 раза, если использовать для генерации частоты 125кГц один из аппаратных режимов таймера типа Clear On Compare или PWM. Для этого есть две ноги у контроллера (OC0A и OC0B).
Ставим плюсы: )
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение shads »

ibiza11 писал(а):можно уменьшить частоту прерываний в 2 раза, если использовать для генерации частоты 125кГц один из аппаратных режимов таймера типа Clear On Compare или PWM. Для этого есть две ноги у контроллера (OC0A и OC0B).

Ага, я именно аппаратную реализацию и использую, но у меня по другому не получается, частота на OC0A равна 125кГц, но при этом прерывания происходят с частотой 250кГц.....
Вот как у меня настроен таймер:

Код: Выделить всё

    //генерация частоты 125000 Hz на выводе OC0A с помощью таймера Т0 (tiny13)
    TIMSK0 = (1<<OCIE0A)|(0<<OCIE0B)|(0<<TOIE0);        //разрешить соответствующие прерывания
    TCNT0 = 0;                                            //СЧЕТНЫЙ РЕГИСТР
    OCR0A = 38;                                            //РЕГИСТР СРАВНЕНИЯ
    OCR0B = 0;                                            //РЕГИСТР СРАВНЕНИЯ
    TCCR0A =                                            //РЕГИСТР УПРАВЛЕНИЯ
        (0<<COM0A1)|(1<<COM0A0)|                        //состояние выводов OC0A при совпадении            
        (0<<COM0B1)|(0<<COM0B0)|                        //состояние выводов OC0B при совпадении    
        (1<<WGM01)|(0<<WGM00);                            //режим CTC - сброс при совпадении
    TCCR0B =                                            //РЕГИСТР УПРАВЛЕНИЯ
        (0<<WGM02)|
        (0<<FOC0A)|(0<<FOC0B)|                            //разрешить принудит изменение состоян выв OC0A и OC0B             
        (0<<CS02)|(0<<CS01)|(1<<CS00);                    //источник тактового сигнала (0001 - прямое тактирование)
 


Мож подскажите, как при такой частоте на ножке, уменьшить частоту прерываний.....
Аватара пользователя
ibiza11
Поставщик валерьянки для Кота
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение ibiza11 »

Щас подскажу. Даташит почитаю... если никто не напишет, дополню сообщение.

Добавлено: Вот код инициализации таймера на работу в режиме Fast PWM, таймер считает от 0 до значения TOP. В этом режиме TOP задается регистром OCR0A, а регистром OCR0B задается точка сравнения. Таким образом сигнал 125кГц будет присутствовать на выводе OC0B. (по-другому здесь нельзя). Прерывание переполнения будет вызываться каждые 76 тактов при достижении счетчиком значения TOP.

Код: Выделить всё

#define F_CPU        (9600000UL)
#define f_RFID       (125000UL)
#define T0_PWM_TOP   (F_CPU/f_RFID)

TCCR0A  = 0;
TCCR0A |= (1<<COM0B1)|(1<<COM0B0)  /* Set OC0B on Compare Match, clear OC0B at TOP */
         |(1<<WGM01)|(1<<WGM00);   /* Set Fast PWM mode */
      
TCCR0B  = 0;
TCCR0B |= (1<<WGM02);              /* Set TOP = OCR0A */

OCR0A   = T0_PWM_TOP;              /* Set TOP value */
OCR0B   = T0_PWM_TOP/2;            /* Set compare value */

TIMSK0  = 0;
TIMSK0 |= (1<<TOIE0);              /* overflow interrupt enable (generates on TOP) */

TCCR0B |= (1<<CS00);               /* start the timer */
Ставим плюсы: )
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение shads »

Ай пасип те мил человек!!!!!
Я когда увидел результат, аж запрыгал как маленький....
Поставлю тебе плюсы везде где только можно :))

Я прям, ваще слов нет... код в прерывании короче стал (убрал делитель на 2), освободилось 2 нижних регистра (вернулся к стандартным пуш\попам), теперь все спокойно в развалочку помещается, красота.....

А я кстати думал что прерывание на TIM0_OVF_vect возможно только при переходе ч-з 255 на 0..... а оказывается и не только ч-з 255..... наверное поэтому я не нашел решения, потому что крутился тлько вокруг TIM0_COMPA и TIM0_COMPB.....

Вот что теперь имеем:
Желтый - сигнал 125КГц
Голубой - маркер времени выполнения прерывания
Красный - метка прохождения самого длинного пути прерывания
Основное прерывание занимает менее 30% от ширины прерывания,
а самый длинный путь - менее 50% (установка флага медленных прерываний, с частотой 100Гц)

Изображение
Вложения
oscil.jpg
(65.56 КБ) 905 скачиваний
Аватара пользователя
ibiza11
Поставщик валерьянки для Кота
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение ibiza11 »

"Подумаешь..я еще и вышивать могу.. и на машинке тоже." (c)
Изображение
Рад, что помог!)))
Ставим плюсы: )
Alexeyslav
Друг Кота
Сообщения: 4550
Зарегистрирован: Чт май 05, 2011 21:26:34
Откуда: Украина, Славутич
Контактная информация:

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение Alexeyslav »

Ну вот, уже все ответили. Как и предполагал...
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение shads »

Да.... с таймерами мне еще надо подтянутся.....
Я смотрю там куча всяких режимов, так что с ходу голыми руками не взять...
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение Kavka »

Если есть желающие размять мозги, то вот задачка.
Дано:
МК ATtiny13.
Регистры var1 и var2 (любые).
Начальные значения var1=0, var2=0x80
Можно использовать дополнительные регистры и ОЗУ. В том числе заранее инициализированные.
Задача: минимизировать время выполнения следующих действий.
сдвинуть вправо var2
если var2 == 0 то {
var1 = var1 + 1
если var1 > 3 то var1 = 0
var2 = 0x80
}

Попытка на ночь глядя чего-то придумать дала 5 тактов (5 команд).
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Аватара пользователя
Engineer_Keen
Друг Кота
Сообщения: 3868
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение Engineer_Keen »

По-моему меньше 5 команд не получится, хотя вариантов несколько, самый логичный естественно:

Код: Выделить всё

LSR VAR2
BRCC END
INC VAR1
ANDI VAR1,0x03
LDI VAR2,0x80
END:

3 цикла при VAR2<>0 и 5 при VAR2=0
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение Kavka »

Есть такой вариант. :)
У меня ещё вот такое получилось.

Код: Выделить всё

; zero - регистр с нулевым значением

bst    var2, 0
lsr    var2
bld    var2, 7
adc    var1, zero
andi   var1, 0x03
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Аватара пользователя
Engineer_Keen
Друг Кота
Сообщения: 3868
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Сообщение Engineer_Keen »

Такой вариант тоже думал, но задача была минимизировать время, а этот вариант всегда выполняется по максимуму - 5 тактов. Или важна как раз стабильность по времени?
Ответить

Вернуться в «AVR»