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

Обсуждаем контроллеры компании Atmel.
Ответить
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 31
Зарегистрирован: Вс окт 18, 2020 19:01:52
Откуда: Харьковская область

Сообщение a1000 »

В процессе дальнейшего копания возникла ещё одна проблемка. Попробовал сделать кольцевой сдвиг символа влево. Задумка такова - в оперативке по метке Kod зарезервировано 8 байт. Там лежит построчно закодированный символ. Temp5 - счётчик и указатель на номер строки при передаче. Они совпадают. Извлекаем в Temp6 первый байт, отправляем в max7219, выполняем кольцевой сдвиг и возвращаем в оперативку с пост-инкрементом и снова по кругу. Получился такой код
Спойлер

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

LDI 	Temp5, 0x01   
Proga: 
	
	LDI	XL,low(Kod)     //запись адреса метки ОЗУ
	LDI 	XH,High(Kod)
	m05:
	LD  	Temp6, X	//получение данных
	RCALL SPI_transfer      //подпрограмма отправки данных (Temp5 и Temp6)
	CLC
	rol     Temp6           //сдвиг байта влево
	BRCC m03
	ORI     Temp6,0b00000001 
	m03:
	ST      X+,Temp6         //сохранение нового сзачения с пост-инкрементом
	INC     Temp5            //инкрементируем счётчик
	CPI     Temp5,0x09       //проверяем прошло-ли 8 циклов
	BRNE    m05              //если нет на метку m05
	                         //если да:
	RCALL delay_01           //задержка
	LDI 	Temp5, 0x01      //обновляем счётчик
	
	rjmp Proga 

Символ выводится но не сдвигается. Где я напартачил?
Это Спарта! В смысле, ассемблер. Все ручками.
Реклама
Друг Кота
Аватара пользователя
Сообщения: 15816
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Для матричного экрана более рационально менять содержимое буфера видеопамяти, а затем делать пакетный вывод в СБИС индикатора.
8)
Реклама
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 31
Зарегистрирован: Вс окт 18, 2020 19:01:52
Откуда: Харьковская область

Сообщение a1000 »

А можно немного по подробнее.
Это Спарта! В смысле, ассемблер. Все ручками.
Вымогатель припоя
Сообщения: 615
Зарегистрирован: Вс дек 28, 2014 21:54:05

Сообщение dgrett »

BOB хотел сказать, что ваши 8 байт являются видеопамятью. Каждые Х мС времени подпрограмма вывода выводит всё содержимое этой видеопамяти в ваш модуль 8Х8. А вы, когда ВАМ надо эту видеопамять модифицируете.
Я всё-всё узнAю и стану профессором.
Реклама
Эиком - электронные компоненты и радиодетали
Друг Кота
Аватара пользователя
Сообщения: 15816
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Легче заново набросок сделать, чем в чужом, фрагментами представленном коде, разбираться.
Тем более, что в данном случае надо еще и к даташиту на MAX7219 плотненько возвернуться. Да со структурой привязки пикселей уточнить (теоретически там 8 колонок по 8 вертикальных точек в колонке - блок данных "на боку" - в наличии такой матрицы на данный момент нету за ненадобностью - могу лишь "теоретизировать").
Да и МК для меня не "базовый" - хотя в примитиве с программным SPI что на тиньку2313, что на мегу8 лаподрыг особо отличаться не должен...
Разве что без привязки к МК то уже библиотечка получается...
8)
Реклама
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 31
Зарегистрирован: Вс окт 18, 2020 19:01:52
Откуда: Харьковская область

Сообщение a1000 »

Не уверен, что
BOB51 писал(а): более рационально менять содержимое буфера видеопамяти, а затем делать пакетный вывод
8)
Тогда надо будет вытащить байт из оперативки, модифицировать, вернуть обратно, а потом ещё раз вытаскивать для отправки. Как по мне - вытащил, отправил, модифицировал, вернул более оптимально. По поводу
BOB51 писал(а):в данном случае надо еще и к даташиту на MAX7219 плотненько возвернуться. Да со структурой привязки пикселей уточнить
это всё не нужно. По работе с MAX7219 вопросов нет. Вывод реализован без вопросов. Вопрос в модификации. Почему после первого прохода я получаю из оперативки немодифицированные данные?
Это Спарта! В смысле, ассемблер. Все ручками.
Реклама
Друг Кота
Аватара пользователя
Сообщения: 15816
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Вообще-то данные из ячейки видеобуфера вытаскиваются однократно на каждое обращение к СБИС контроллера.
Тем более, что у АВРок косвенное чтение памяти имеется.
А вот отсылка блока из двух байт при каждом обращении к СБИС (адрес и данные) выполняется.
Полный цикл - пересылка блока 8*2=16 байт по SPI заметно длиннее всех имеющихся обращений к ОЗУ.
8)
Касательно обработки содержимого видеобуфера - это уже на усмотрение автора.
В зависимости от задачи можно обработку и в регистровом файле делать.
:wink:
Допустим блок видеобуфера в ОЗУ имеет вот такое размещение:
Изображение
а вот относительно дисплея... шаблон развернется "боком":
Изображение
Это как первая подсказка к алгоритму обработки.
И еще одно замечание -
Если для циклических процессов (бегущие точки или полоски, разнообразные сдвиги) еще можно применить программные решения, то для версий мультипликации гораздо выгоднее применять ряд из "кадров", размещенных или в ПЗУ или во внешней ЕЕПРОМ.
8)
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 31
Зарегистрирован: Вс окт 18, 2020 19:01:52
Откуда: Харьковская область

Сообщение a1000 »

BOB51 писал(а):Тем более, что у АВРок косвенное чтение памяти имеется.
Знаю, я его и использовал. Спасибо за советы, разобрался сам. Ошибка была не в коде, он рабочий. Допустил детскую ошибку при прошивке.
Это Спарта! В смысле, ассемблер. Все ручками.
Друг Кота
Аватара пользователя
Сообщения: 15816
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Прекрасно!
А теперь попробуйте используя только один байт буферного регистра вывести на индикацию вот такую трассу (или картинку при достаточной скорости смены информации):
Изображение
стрелочки показывают последовательность обхода светящейся точкой поля матрицы.
(направление обхода может быть и обратным).
8)
Подсказка - смотреть специфику адресации MAX7219.
:wink:
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 31
Зарегистрирован: Вс окт 18, 2020 19:01:52
Откуда: Харьковская область

Сообщение a1000 »

Не совсем понятно
BOB51 писал(а):один байт буферного регистра
Что имеется ввиду?
А вообще, для комфортной работы понядобится два РОН. Если совсем изаратиться и одного может хватить. Больше ведь никаких требований к алгоритму не вадвинуто. Самое тупое решение - через LDI кидаем в РОН нужное значение и засылаем его в SPDR.
Это Спарта! В смысле, ассемблер. Все ручками.
Друг Кота
Аватара пользователя
Сообщения: 15816
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

В данном случае имеется ввиду чисто программный синтез картинки - без "заготовки в ПЗУ".
Продвижка точки только алгоритмом программы при использовании одного байта временного хранения данных, а не матрицы 8*8.
ессно и счетчики и подпрограмма вывода будут присутствовать - но то и для обычного алгоритма применяется.
8)
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 31
Зарегистрирован: Вс окт 18, 2020 19:01:52
Откуда: Харьковская область

Сообщение a1000 »

И чего там военного? Начинаем с правого верхнего угла. Кидаем в РОН, пусть будет R16, 0b00000001. В счётчик тоже ложим единицу.
Прогоняем отправку 0b00000001 восемь раз. Счётчик одновременно служит номером строки.
Когда достигли 8 - цикл со сдвигом R16 влево, декриментом счётчика и отправкой данных.
Когда достигли 1 - цикл аналогичный первому, без изменения R16.
Когда достигли 8 - цикл со сдвигом R16 вправо, декриментом счётчика и отправкой данных.
Мы вернулись в правый верхний угол.
Перед отправкой данных вызываем подпрограмму очистки дисплея.
Это Спарта! В смысле, ассемблер. Все ручками.
Друг Кота
Аватара пользователя
Сообщения: 15816
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Вот и возврат к вопросу правильно выбранных координат.
Поскольку возможно получить две трактовки привязки строк и колонок - надо перед публикацией оговаривать что принимаем за строку, а что за колонку.
8)
Колонка - вертикальный ряд (аналогия позиции знакоместа и соответственно адресу ОЗУ MAX7219), а строка - горизонталь (аналогия позициям сегментов в знакоместе).
Почему так удобнее - смотрим вариант "беглой строчки" - перемещение вертикальной колонки, привязанной к адресу ячейки ОЗУ MAX7219 гораздо удобнее выполняется в буфере видеопамяти.
При том, что можно как угодно привязку делать. Это уже подбор более оптимального варианта на вкусы разработчика.
:wink:
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 31
Зарегистрирован: Вс окт 18, 2020 19:01:52
Откуда: Харьковская область

Сообщение a1000 »

Если у вас одиночный модуль, тогда да, его можно вертеть как угодно. А если линейка из четырёх модулей, тут уже всё зафиксировано. А если трудно запомнить, что адрес это столбец, а отправляемый байт строка - не надо и начинать писать программы.
Это Спарта! В смысле, ассемблер. Все ручками.
Друг Кота
Аватара пользователя
Сообщения: 15816
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Как раз для нескольких модулей более выгодно "классическое" распределение точек (принятое в MAX7219) - по вертикали "сегментные", а по горизонтали "позиционные".
Строкой принято называть развертку по горизонтали.
Или развертку пакета из энного числа байт позиционного ("сегментного") кода в результате которого на дисплее отображается строка символов.
Хотя... терминология без схемы - штука весьма вредная (общепринятой обязательной не существует).
Посему и требуется вместе с прожкой выкладывать точную привязку и собственную, принятую для конкретной программы систему обозначений.
Иначе алгоритмы обработки у каждого из занимающихся одним и тем же вопросом будут кардинально отличаться (и в то же время быть справедливы для каждой из конкретных схем).
8)
А вот чего там на самом деле, когда матрицы в едином блоке на общей платке смонтированы - это надо конкретную платку смотреть и проверять.
8)
Родился
Сообщения: 17
Зарегистрирован: Сб фев 25, 2017 07:26:17

Сообщение onwire »

Понимаю что не в тему но в лом искать подходящую, что-то они все закрытые.
Видно АВР совсем не в моде нынче..
Надо стало быстрое деление константы 32767 на переменную 16 бит.
Придумал вот такую делилку.
Она проста, понятна, легко может быть приспособлена под любую разрядность
Для сравнения, делилка 16\16 из АВР аппноты тратит 260 тактов


DivU_TempHL_BT: ; TempH:L делимое (потом здесь будет удвоенный остаток)-
ldi Cnt, 1 ; -Buff:Temp делитель, R1:R0 округленный результат
mov One, Cnt
clr R1 clr R0
mov R2, One ; начальное значение маски для записи единиц в результат-
clr R3 clr Zero ; -она же будет счетчиком в цикле деления
cpi Temp, 128
cpc Buff, Zero
brsh shl
cpi Temp, 32 ; чтоб не повиснуть при делении на 0 :
cpc Buff, Zero
brsh swdv
ldi Temp, 32
swdv:
mov Buff, Temp ; для ускорения работы, если делитель <128-
clr Temp ; -можно сдвинуть делитель влево сразу на 8 бит
mov R3, One ; -и маску тоже
clr R2
shl:
sbrc Buff, 6
rjmp dv
lsl Temp rol Buff ; сделать делитель близким к делимому
lsl R2 rol R3 ; при этом приготовить маску
rjmp shl
dv:
cp Temp_L, Temp ; в цикле, сравнить делимое и делитель
cpc Temp_H, Buff
brlo shr
sub Temp_L, Temp ; если можно то вычесть
sbc Temp_H, Buff
or R1, R3 ; и маской внести единицу в результат
or R0, R2
shr:
lsr R3 ror R2 ; в любом случае, сдвинуть 1 в маске вправо
brcs edv ; (пока она совсем не обнулится, тогда выйти из цикла)
lsr Buff ror Temp ; и сдвинуть вправо делитель
rjmp dv
edv:
lsl Temp_L rol Temp_H ; удвоить остаток
cp Temp, Temp_L ; сравнить его с делителем
cpc Buff, Temp_H
adc R0, Zero ; округлить
adc R1, Zero
ret ; 185 тактов макс. время, мин. время 31 тактов
Встал на лапы
Аватара пользователя
Сообщения: 104
Зарегистрирован: Пн ноя 04, 2019 09:58:29
Откуда: г. Нижний Тагил Свердл. обл.

Сообщение Эйлер Леонард »

Добрый день. Решил всё-таки освоить ассемблер для AVR. И как следовало ожидать - грабли полезли отовсюду. Простые инструкции проходят. Но даже присвоить литеральный псевдоним регистру - нет. Да многе чего. Компилятор просто пишет "не знаю что это такое" и падает. Вот сделал сложение двух 32-разрядных чисел, получилось. Инкремент 8-разрядных тоже работает. Я создаю файл с расширением S, а в файле на C/C++ функцию со спецификаторами доступа, либо напрямую с помощью ассемблерных вставок. В протеусе скомпоновал "испытательный стенд" из двух 7-сегментных индикаторов на ТМ1637 и контроллера ATtiny84.
На github.com(ссылка) есть библиотека которую мне хотелось бы местами использовать. Как говорится в релизе
"ТРЕБОВАНИЯ И ЗАВИСИМОСТИ:"
"Данная реализация написана на языке ассемблера "AVRASM2". Соответственно, она предназначена для разработки программных прошивок (firmware) на языке ассемблер, для микроконтроллеров Atmel AVR (8-bit)."
ссылка на библиотеку
Но, что-то идет не так.
main.cpp
Спойлер

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

/* -std=c++11 
   -std=gnu++11
   Atmel Studio 7
   ATtiny84
*/
#define F_CPU 1000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include "TM1637.h"

using namespace IO;
// два иникатора (красный и синий )
typedef TM1637<Pa1/*DIO_pin*/,Pa0/*CLK_pin*/> tm1637_0;
typedef TM1637<Pa3/*DIO_pin*/,Pa2/*CLK_pin*/> tm1637_1;


extern "C" {
extern uint32_t add32(uint32_t arg1, uint32_t arg2);[color=#808000]// сложение двух uint32_t чисел[/color]
//extern uint32_t inc32(uint8_t c);// инкремент до uint32_t числа
}

volatile uint32_t Counter0;
register uint8_t Counter1 asm("r2");//


ISR(INT0_vect){	
	//Counter0++;
	//asm volatile("inc %[VAL]" : [VAL]"=r" (Counter0) : "[VAL]" (Counter0));
	//asm volatile("inc %0" : "=r" (Counter0) : "0" (Counter0));
	//asm volatile("inc %0" : "+r"(Counter0) );

	asm volatile("inc r2");
	tm1637_0::output(Counter1);// синий
	//tm1637_1::output(Counter0);// красный
}

int main(void){
	
	PORTB |=  (1<<PB2); //Устанавливаем pull-up режим ножки PB2
	DDRB &= ~(1<<PB2); //Настраиваем ножку PB2 в режим входа
		 // Инициализация внешнего прерывания для вывода PB2
	GIMSK |= (1<<INT0);
	MCUCR |= (1<<ISC01)|(1<<ISC00); // Нарастающий фронт INT0 генерирует прерывание.
	sei(); // Разрешить все прерывания

tm1637_0::init();
tm1637_1::init();

uint32_t n = add32(222222,333333);
tm1637_1::output(n);
	
    while (1) {		
//if( Counter1 == 10 ){ tm1637_1::output(654321); }		
    }
}
add32.S
Этот работает. Вставляется так:
extern "C" {
extern uint32_t add32(uint32_t arg1, uint32_t arg2);// сложение двух uint32_t чисел
}
Спойлер

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

	.global add32
	.func   add32
add32:
  add    r20, r16  ; Add low bytes // Добавить младшие байты
  adc    r21, r17  ; Add higher bytes with carry // Добавить старшие байты с переносом
  adc    r22, r18   
  adc    r23, r19
  adc    r24, r20   
  adc    r25, r21

	ret
	.endfunc
В файле...
uint32_t n = add32(222222,333333);
tm1637_1::output(n);// = 555555
НО шаг вправо, шаг влево - сплошные грабли. То - не то, это - не это. Извините за глупый вопрос - куда копать?
Вложения
Test-1.gif
Тренеровочно-испытательный стенд в протеусе
(120.15 КБ) 261 скачивание
Друг Кота
Аватара пользователя
Сообщения: 20135
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

Сообщение Gudd-Head »

Эммм... А зачем в СИ-шный код вставлять сложение двух регистров на АСМе?
Может, глобально задача совсем другая?
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Друг Кота
Аватара пользователя
Сообщения: 15816
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Есть два разных варианта:
"чистый ассемблер" - avrasm2
и
ассемблерные вставки в рамках Си
подход соответственно будет также различным.
Если с "чистым вариантом" особо проблем нету, то с ассемблерными вставками только СИшники помочь могут...
:roll:
Встал на лапы
Аватара пользователя
Сообщения: 104
Зарегистрирован: Пн ноя 04, 2019 09:58:29
Откуда: г. Нижний Тагил Свердл. обл.

Сообщение Эйлер Леонард »

Gudd-Head, Задача - научиться. А там, как звезды покажут. В жизни всякое может пригодиться. Самообразование понимаете.
Ответить

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