Обсуждаем контроллеры компании Atmel.
Ответить

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

Ср май 31, 2017 07:08:41

Ivanoff-iv писал(а):тем более прерывание использовать не сложно
я бы приблизительный таймер на 3 часа делал вообще без прерываний и задержек - на WDT. тупо по сбросу ячейку памяти инкрементировал бы и все - строго линейный алгоритм, без прерываний :) а между сбросами наглухо усыплял бы МК.

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

Ср май 31, 2017 09:05:05

Что-то я в двух соснах разобраться не могу
Подскажите, сколько циклов в данном коде?
Код:
 
    ldi  r18, 2
    ldi  r19, 142
L1:
    dec  r19
    brne L1
    dec  r18
    brne L1
    nop

Вроде ж 2*142+1=285, на деле получается около 840. AVR Delay Loop Calculator говорит что будет 1200.

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

Ср май 31, 2017 09:28:31

Coldheart писал(а):Подскажите, сколько циклов в данном коде?
Вы забыли, что после первого обнуления r19 в нем будет 0 и его маленький цикл уже не 142 раза прокрутится, а 256.

т.е. количество прогонов всего кода у вас будет равно 142 + 256, а не 142 + 142. а количество тактов надо считать соответственно - тут я не подскажу, ибо точно не помню, сколько тактов каждая команда занимает.

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

Чт июн 01, 2017 12:16:44

Даже если этот код загнать в студию, то можно пронаблюдать за количеством тактов на каждую команду.
Декремент выполняется за один такт, также, как и присваивание.
А вот команды ветвления (переходов) выполняются за один такт, если НЕ ВЫПОЛНЯЕТСЯ условие, и за два такта если ВЫПОЛНЯЕТСЯ условие, т.к. надо адрес (метку) перехода еще грузануть.

Итого. (расчет примерный).
2 такта на то, чтобы присвоить два значения переменным (регистрам Р18 и Р19).
1 такт на декремент 142
2 такта НА КАЖДЫЙ РАЗ на переход, т.к. условие у вас ВЫПОЛНЯЕТСЯ (флаг нулевого результата Z не равен нулю)
И все это по кругу 142 раза. Т.е. 2+(3*142) = 428
Потом, как вам и сказал Роман, счет начинается уже не с 142, а с 256, т.к. новое значение никто не грузил в Р19.
1 такт на декремент Р18 (он стал равен 1)
2 такта на переход на метку Л1.
И по новой
1 такт на декремент 256
2 такта на переход
Итого 1+2+(3*256) = 771
428+771 = 1199.

Ах, да, там же еще декремент Р18 до нуля и выход из цикла. Вот и еще пара тактов.

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

Вт июн 13, 2017 00:23:42

Доброго времени суток!
Пишу на Бейсике, но в Ассемблер "метнулся" из-за того, что программа уже на 96-98% забита (Atmega8). Причесываю, перечесываю и ужимаю ее не один день. Думал, часто повторяющуюся арифметику выполнить в ASM-блоке. Нашел в книге Ревича перемножение многобайтных чисел, чуть изменил под себя, прогнал в симуляторе Баскома... работает! НО! Как и большинство учебников и сайтов, ВЕЗДЕ практикуется ввод в регистры РОН готовых значений. А если в программе это/и значение/я меняются? У меня уже извилины выпрямились в одну линию от гор информации, литературы и попыток "направить" в регистр переменную :-(. Подскажите, пожалуйста, кто понимает, по паре моментов:
1) Баском (2.0.7.5) упорно ругается 222-ой ошибкой на строку:
!LDI R16 , Y
Заносить готовые HEX-данные в регистр, с последующей обработкой и результатом - без проблем! А переменную (даже с объявлением через .def) не дает. Что не так? КАК отправлять переменную в регистр?
2) Конечный результат разнесен в 3-х регистрах. С директивой STS могу вынести за ASM-блок все три байта, объединить, "превратить" в число... Но, может быть, в Ассемблере имеется что-то короче для получения конечного (числового) результата из нескольких регистров? А иначе теряется смысл в этих танцах - результирующий код намного превышает код заменяемый.

P.S. Баском позволяет поместить переменную в фигурные скобки (правда, так и не нашел описания этим скобкам):
!LDI R16 , {Y}
Но все равно, в конечном итоге, в целевом регистре будет 0 :-( и, следовательно, результат будет искажен.

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

Вт июн 13, 2017 07:45:04

1) Баском (2.0.7.5) упорно ругается 222-ой ошибкой на строку:
!LDI R16 , Y
Заносить готовые HEX-данные в регистр, с последующей обработкой и результатом - без проблем! А переменную (даже с объявлением через .def) не дает. Что не так? КАК отправлять переменную в регистр?

X,Y,Z - существующие регистровые пары (R26-R31 или XH,XL,YH,YL,ZH,ZL), поэтому в качестве второго аргумента LDI их использовать некорректно. Попробуйте использовать другое, более осмысленное имя для переменной (ну или константы, раз LDI используется).
2) Конечный результат разнесен в 3-х регистрах. С директивой STS могу вынести за ASM-блок все три байта, объединить, "превратить" в число... Но, может быть, в Ассемблере имеется что-то короче для получения конечного (числового) результата из нескольких регистров? А иначе теряется смысл в этих танцах - результирующий код намного превышает код заменяемый.

Тут не понятно что конкретно нужно получить и как данные расположены. Например, имея 3 байта подряд можно выгадать 1 слово в программной памяти, используя ST X+,rn с предварительной загрузкой регистровой пары XH:XL начальным адресом (STS занимает 2 слова, а ST одно, но нужно потратить еще пару на LDI). Для оптимизации такого места нужно видеть весь код.

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

Вт июн 13, 2017 13:29:17

X,Y,Z - существующие регистровые пары (R26-R31 или XH,XL,YH,YL,ZH,ZL),...
...более осмысленное имя для переменной (ну или константы...

А где Вы видите в моем примере использование старших регистров R26-R31?
Осмысленные имена... Так и поступаю. Здесь "Y" вписал лишь для краткости.
А константы... В процессе работы программы значение переменной, которую пытаюсь отправить в регистры, постоянно меняется.
Тут не понятно что конкретно нужно получить и как данные расположены. Например, имея 3 байта подряд можно выгадать 1 слово в программной памяти, используя ST X+,rn с предварительной загрузкой регистровой пары XH:XL начальным адресом (STS занимает 2 слова, а ST одно, но нужно потратить еще пару на LDI). Для оптимизации такого места нужно видеть весь код.

В Ассемблере у меня не то что первые шаги, а поползновения :-) Так что с понятием "память" и использованием директив мне еще потеть и пыхтеть.
Вот рабочий код, с ручной подстановкой данных (а-ля константа):
СпойлерDim tmp1 As Byte
Dim tmp2 As Byte
'data = 16 [$0010] 1-ый множитель
'koef = 2489 [$09B9] 2-ой множитель
'temp = 39824 [$9B90] -> ожидаемый результат
!.def dataL = R4 ; $10 - младший разряд
!.def dataH = R5 ; $00 - старший разряд
!.def koefL = R2 ; $B9 - младший разряд
!.def koefH = R3 ; $09 - старший разряд
!.def tmp1 = R16 ; $90 - младший разряд
!.def tmp2 = R17 ; $9B - старший разряд
!ldi R24 , $10
!mov R4 , R24
!ldi R24 , $00
!mov R5 , R24
!ldi R24 , $b9
!mov R2 , R24
!ldi R24 , $09
!mov R3 , R24
!clr tmp2 ; очищаем старший разряд R18
!mul dataL , koefL ; умножаем младшие разряды => R4 * R2 => $09 * $13 = $AB => копируем в R0,R1
!mov tmp1 , R0 ; копируем R0 в мл. разр. результата R16 => $AB => R16
!mov tmp2 , R1 ; копируем R1 в ср. разр. результата R17 => $00 => R17
!mul dataH , koefL ; умножаем старший на младший => R5 * R2 => $01 * $13 = $13 => копируем в R0,R1
!add tmp2 , R0 ; складываем R17 и R0 => $00 + $13 = $13 => R17
!mul dataL , koefH ; умножаем младший на старший => R4 * R3 => $09 * $01 = $09 => копируем в R0,R1
!add tmp2 , R0 ; складываем R17 и R0 => $13 + $09 = 1C => R17
!mul dataH , koefH ; умножаем старший на старший => R5 * R3 => $01 * $01 = $01 => копируем в R0,R1
!sts {tmp1} , tmp1
!sts {tmp2} , tmp2

Dim tmp4 As String * 6
Dim tmp5 As Word
tmp4 = Hex(tmp2)
tmp4 = tmp4 + Hex(tmp1) ' $9B90
tmp5 = HexVal(tmp4) ' 39824

Результат разнесен по регистрам R16,R17. Их то я и вытаскиваю директивой STS и форматирую последними тремя строками. Это извлечение можно выполнить менее емким кодом?

По поводу переменной... Перед ASM-блоком разбил число поразрядно и пытался впихнуть в регистры (оба разряда тут присвоены одной переменной - это лишь для попытки "пропихивания")
Код:
Dim Y As String * 2   
X = 2489     
Y = Hex(High(X))                   ' -> 09     
Y = Hex(Low(X))                    ' -> b9

Проблемка в том, что куда-то не туда увели меня танцы - 16-ричные результаты смог получить лишь для переменной String :-(. В чем ошибка? Но полный тупик даже не в этом. В регистры пытался отправлять переменную ВСЕХ типов - и Ворд, и Лонг, и Байт,... Один ответ у Баскома - 222-ая ошибка.

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

Вт июн 13, 2017 13:42:58

Проблема больше в том, что все "высокоуровневые" компиляторы сами решают чего куда поместить...
А вставка на ассемблере предусматривает прямое вмешательство в логику распределения ресурсов...
Обязательно надо учитывать правила предварительного освобождения/резервирования тех ресурсов в "высокоуровневом", которые будут использованы вставкой на ассемблере. А там... у каждого компилятора свои правила... не всегда в явном виде указаны...
:roll:

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

Вт июн 13, 2017 15:19:57

Не работал с баском, но гугль говорит что 222 это некорректный символ в команде, значит у вас что-то не то с "грамматикой". Код вы сначала не привели, откуда мне знать что "Y" был как пример? Привычный asm-компилятор АВР-студии за "LDI R16,Y" вполне закономерно послал бы вас с формулировкой "неправильное число". Привели бы конкретный пример на какую строчку ругается, может знатоки баскома наставят на путь истинный.
Насколько я понял надо ассемблером умножить data (word) на koef (word) и результат получить в temp (должен быть dword, двух байт тут маловато).
Может тут че поможет...

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

Вт июн 13, 2017 16:06:09

Не работал с баском, но гугль говорит что 222 это некорректный символ в команде...

Спасибо, конечно! :-) Об ошибке я и сказал в первом сообщении. Подобная страница имеется и в скупой справке Баскома. Она изначально ничем не помогла. Там в регистр загружают или адрес переменной, или уже готовые значения. Но нет ничего (либо "не врубился") о загрузке самой переменной.
Привели бы конкретный пример на какую строчку ругается,...

Вообще-то :shock: , в самом начале и привел:
LDI R16 , Y
На нее и ругается. Полное ругательство:
Illegal character [expected (, got '' [Y]] , in File....
Если верно понимаю, он ожидал открывающую скобку, а получил... ничего.
Насколько я понял надо ассемблером умножить data (word) на koef (word) и результат получить в temp (должен быть dword, двух байт тут маловато).

Поняли верно, но обратив внимание на разрядность множителей, согласитесь, что и Ворда хватает. Те, размерности, что использовал в коде - это почти потолок их значений, которые могут быть в программе. А конечный результат в 65535 (дес) или FFFF (hex) - в программе невозможен.
И код (в моей проблеме) тот же самый. За исключением, что вместо готовых 16-ричных значений прописываю переменную. Какого бы типа ни была переменная (Word, Byte. String,...) - ругань одна и та же. Вот и возвращаюсь к вопросу: как в регистр загрузить переменную?

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

Вт июн 13, 2017 19:42:41

Так на
LDI R16 , Y
и ассемблер матюкнётся -
LDI R16,k где k 0-255 (константа), но никак не зарезервированное имя регистровой пары Yh:Yl (R29:R28)
(LD R16,Y к примеру - загрузка R16 из ячейки памяти по адресу указанному в Yh:Yl (R29:R28)).
В принципе всегда рекомендуется избегать применения "зарезервированных имен" не по назначению!
8)

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

Ср июн 14, 2017 07:37:54

Вообще-то :shock: , в самом начале и привел:
LDI R16 , Y
На нее и ругается. Полное ругательство:
Illegal character [expected (, got '' [Y]] , in File....
Если верно понимаю, он ожидал открывающую скобку, а получил... ничего.

Ну так мы с ВОВ51 уже сказали что Y в LDI нельзя вторым аргументом писать, это имя регистра, а должна быть константа.
Одной командой LDI в регистр переменную из RAM загрузить нельзя. Либо напрямую через LDS, либо через LD с индексными регистрами (X,Y,Z), по ссылке что я привел выше как раз пример. И за один раз одной ассемблерной командой больше чем байт не загрузить, для word надо два регистра и две команды загрузки, типа:
Код:
Dim A As word
LOADADR a, X
!Ld R16, X+ 
!Ld R17, X+

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

Ср июн 14, 2017 09:01:21

Ладно...
Повторюсь для новеньких КОТЯТ
шпора AVR.pdf
(60.25 KiB) Скачиваний: 203

:beer:

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

Вс июн 25, 2017 16:38:50

Народ, кто разбирался с аппнотой AVR204: BCD Arithmetics - преобразование bin 2 bcd - не могу понять, каким образом оно работает - прибавляется к байту 0x03 - смотрится бит 3 и прибавляется к байту 0x30 и смотрится бит 7. Кто может, объясните.

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

Ср июл 05, 2017 12:40:50

Доброго времени суток!
В одной из программ (Atmega8) имеется прерывание Таймера0:
Код:
Prertim:                        ' прерывание таймера Timer0
  Stop Timer0                   ' останавливаем Таймер0
    $asm
      <какие-то действия>
    $end asm
  timer0 = Timer0pre            ' начальная точка старта таймера
  Start Timer0                  ' запускаем Таймер0
Return
Эти <какие-то действия> уже на АСМ-е, и работают. Осталось останов и запуск таймера написать - тут уже заблудился. Литература только запутала, а поиск (в теме "Ассемблер для AVR") привел на 82 страницу, где mypkot останавливал таймер загрузкой нулей в регистр управления TCCR0. У TCCR0 используются только три младших разряда, и используются только как выбор источника и предделитель. Хотел бы убедиться, что верно понял...
В моем случае (предделитель 1024) нижеследующая запись будет верна и работоспособна?
Код:
Prertim:                            ' прерывание таймера Timer0
    $asm
      LDI R16 , 0b00000000
      OUT TCCR0 , R16               ' останавливаем Таймер0
      <какие-то действия>
      LDS R16 , {Timer0pre}
      OUT TCNT0 , R16               ' вернем начальную точку старта таймера
      LDI R16 , 0B00000101
      OUT TCCR0 , R16               ' запускаем Таймер0
    $end asm
Return
Разумеется, сохранение и возвращение SREG, PUSH-и и POP-ы имеются (убрал для краткости).

P.S. В железе не проверял - нет пока доступа к нему. Баском жалуется 377-ой ошибкой (Unexpected non numeric characters) на строку с присвоением двоичного числа, но молчит на 16-ричное.
Код:
      LDI R16 , 0b00000101     ' 377-ая ошибка
      LDI R16 , $5             ' молчание
Что упускаю?

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

Ср июл 05, 2017 17:54:52

Все верно, чтобы запустить таймер, надо указать источник тактирования.
Lavad писал(а):Литература только запутала
На ДШ старайтесь налегать.
На счет синтаксиса записи двоичного числа в Баскоме, то лучше сюда обратитесь.
----
Товарищ "Гугл" сказал мне, что синтаксис двоичных чисел имеет вот такой формат &b01010101, врет поди собака ;).

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

Ср июл 05, 2017 19:52:45

На ДШ старайтесь налегать.
Вот это и называю литературой (вкупе с книгами, журналами). А международный собачий я не знаю, от него меня коробит, да и поздновато для изучения.
Товарищ "Гугл" сказал мне, что синтаксис двоичных чисел имеет вот такой формат &b01010101, врет поди собака ;).
Только что проверил... Нет, не врет, данный вариант записи Баском проглотил молча.
Спасибо за ответ, но, увы, не заработало :-( Закоментировал свои 3 строки, вместо них вставил эти 6...
Код:
Prertim:                            ' прерывание таймера Timer0
    $asm
      LDI R16 , $00
      OUT TCCR0 , R16               ' останавливаем Таймер0
      <какие-то действия>
      LDI R16 , $3d
      OUT TCNT0 , R16               ' вернем начальную точку старта таймера
      LDI R16 , $5
      OUT TCCR0 , R16               ' запускаем Таймер0
    $end asm
Return
Где ловить таракана?

P.S. Методом исключений добрался до 2-х последних АСМ строк (на запуск таймера). Если вместо них вернуть прежнее
Код:
Start Timer0
, то все работает. Почему?

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

Чт июл 06, 2017 07:33:24

"Все работает" или "не работает" слишком абстрактно. Что именно у Вас не работает?
Я Баском не знаю. Но могу предложить сравнить во что компилируется Start Timer0 и не забывать про главный инструмент отладки - пошаговое выполнение.

Добавлено after 20 minutes 44 seconds:
Тот же гугл говорит, что синтаксис шестнадцатеричных чисел имеет префикс &h. Вы смотрели что у Вас по факту пишется в регистры с префиксом $ ?

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

Чт июл 06, 2017 08:22:45

преобразование bin 2 bcd

Когда-то изголялся...
Вложения
Пример BCD преобразования.rar
(8.3 KiB) Скачиваний: 205

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

Чт июл 06, 2017 15:54:51

...Что именно у Вас не работает?
:shock: Прерывание не работает. В прерывании, помимо прочего, проводится подсчет временнЫх интервалов (секунда, 2 сек., 5,...). Во внешних подпрограммах эти интервалы (переменные), помимо прочих операций, зажигают/тушат св/диоды. Вот по ним и сужу. Не мигают? Значит в прерывании не отмеряются временнЫе промежутки! Плюс, в самом начале программы проводится проверка состояния устройства. И если оно отличается от необходимой, то устройство останавливается и ждет вмешательства пользователя. Эта проверка также повязана с прерыванием. И, следовательно, устройство (программа) останавливается, даже не начав работу.
Другими словами (так понимаю) - АСМ-код внутри этих 3-х злополучных строк вылизан, и работает, как часы.
...главный инструмент отладки - пошаговое выполнение.
Вы абсолютно правы! Из-за слабого знания Бейсика (и тем более Ассемблера) так и делаю. Пока переписывал прерывание на АСМ, чуть ли не после каждой новой команды прогонял в симуляторе. Но тут еще незнание всех возможностей симулятора, нехватка времени, да и подзабываю быстро :(
...могу предложить сравнить во что компилируется Start Timer0...
Поделитесь, пожалуйста. Может, что-то новое узнаю.
...что у Вас по факту пишется в регистры с префиксом $ ?
Это уже многократно пройденный этап. Работаю только в Баском. В его симуляторе содержимое регистров можно смотреть в 3-х видах: 10-тичное, 16-ричное и двоичное значения. В любом виде отображаются и обрабатываются корректные значения (если ввожу через $). Вопрос по поводу нерабочей команды "LDI R16 , 0b00000101" был лишь для познания. Вы сами же и дали верный ответ - "LDI R16 , $b00000101" :)
16-ричные данные ввожу через $, без h. Если число меньше 16, то и без $.
Ответить