Поскольку мигающим светодиодом интерфейс пользователя построить сложно, решил подключить к STM32F407 простенький SPI дисплей из Китая. Интерфейс дисплея PCD8544, подключение по SPI, на aliexpress и ebay обычно ищется по строке LCD nokia 5110, питание дисплея как раз от 2.7 до 3,3 вольт.
По информации полученной из даташита частота SPI дисплея не должна превышать 4 Мгц, однако все имеющиеся у меня экземпляры надежно работали при такте SPI в 21 Мгц…
STM32F4: GNU AS: Мигаем светодиодом (Оживление) (Часть 2)
STM32F4: GNU AS: Мигаем светодиодом (Версия для STM32F4 Discovery, Оптимизация) (Часть 3)
STM32F4: GNU AS: Настраиваем среду компиляции (Часть 4)
STM32F4: GNU AS: Настройка тактирования микроконтроллера (Часть 5)
STM32F4: GNU AS: Прерывания, Системный таймер (SysTick) (Часть 6)
Описание проекта, исходные тексты программы, настроенный файл автоматической компиляции и сборки проекта под «катом»:
В проект из шестой части публикации добавил работу с счетчиком тактов микроконтроллера DWT (честно взято с www.stm32asm.ru и переформатировано в модуль под раздельную компиляцию). Теперь в каталоге периферии микроконтроллера три модуля:
В корень проекта добавил папку devices — в нее планирую размещать модули подключаемых к микроконтроллеру устройств:
Из устройств самым необходимым сейчас являются
Файл lcd_func.asm это модуль графических функций которые не зависят от «железа», в настоящий момент содержит в себе следующие функции:
@ ***************************************************************************
@ * МОДУЛЬ ДОПОЛНИТЕЛЬНЫХ ФУНКЦИЙ МОДУЛЯ LCD *
@ ***************************************************************************
@ * Процедуры: *
@ * LCD_PUTSTR: Вывод строки по координатам: *
@ * R0:Y, R1:X, R2:COLOR R4:ADR_TEXT *
@ * Текст должен заканчиваться нулевым символом *
@ * Управляющий код: 0x01, .short Y, .short X, .word col *
@ * *
@ * LCD_PUTHEX: Вывод шестнадцатеричного числа: *
@ * R0:Y, R1:X, R2:COLOR R4:HEXVal, R5:DigitCol *
@ * *
@ * LCD_PUTDEC: Вывод десятичного числа: *
@ * R0:Y, R1:X, R2:COLOR R4:DECVal, R5:DigitCol *
@ * *
@ * LCD_LINE: Вывод линии: *
@ * R0:Y1, R1:X1, R2:COLOR R3:Y2, R4:X2 *
@ * *
@ * LCD_RECT: Вывод прямоугольника: *
@ * R0:Y1, R1:X1, R2:COLOR R3:Y2, R4:X2 *
@ * *
@ * ПРИМЕЧАНИЕ ! *
@ * - Все процедуры не портят регистры! *
@ * *
@ * - допустимые координаты и шаг печати native процедурами определяются *
@ * в файле lcd_param.inc который должен лежать рядом с файлом модуля *
@ * *
@ * - Драйвер дисплея должен содержать функции определенные как .global: *
@ * LCD_CHAR: (R0:Y, R1:X, R2:Color, R3:Char) - native вывод символа *
@ * LCD_PIXEL: (R0:Y, R1:X, R2:Color) - native вывод пиксела *
@ * *
@ ***************************************************************************
Поскольку модуль планируется использовать для различных типов дисплеев, то процедуры старался сразу написать в расчете на разнообразное применение, например, под кодирование цвета отвел 32 бита (регистр R2) — для монохромного дисплея конечно многовато (достаточно было одного бита), но вот для цветных дисплеев с 16-ти битной палитрой в самый раз.
Для рисования линий применил алгоритм Брезенхейма — могу сказать, что ассемблер ARM в этом себя показал просто великолепно! Возможность условного исполнения команд присваивания и арифметических действий сделала код рисования линии не намного большим процедуры вывода символа.
Вывод десятичного числа написан с использованием блока деления на 10 при помощи арифметики и сдвигов — тоже получилось очень компактно.
Файл настроек для модуля lcd_func.asm под драйвер дисплея pcd8544 выглядит пока так:
@GNU AS
@ ***************************************************************************
@ * Файл настроек для модуля дополнительных функций LCD (lcd_func.asm) *
@ ***************************************************************************
@ * Файл настроек сообщает параметры драйвера дисплея для функци- *
@ * онирования библиотек дополнительных функций LCD, это такие параметры, *
@ * как: разрешение экрана по горизонтали и вертикали в графическом режиме, *
@ * наличие native процедуры печати символов, и возможность их печати с *
@ * точностью до пиксела, шаг вывода текста по X и Y для внешней процедуры *
@ * печати строк, и т.д. *
@ * *
@ * файл настроек необходимо положить в папку с модулем lcd_func.asm кото- *
@ * рый их загрузит и будет использовать в своих функциях *
@ ***************************************************************************
@
@ Устройство: LCD SPI PCD8544
@
@ графические параметры дисплея
.equ LCD_PARAM_pixel_present, 1 @ в драйвере есть процедура вывода точек LCD_PIXEL
.equ LCD_PARAM_size_px, 84 @ количество точек на экране по горизонтали
.equ LCD_PARAM_size_py, 48 @ количество точек на экране по вертикали
@ текстовые параметры дисплея
.equ LCD_PARAM_char_present, 1 @ в драйвере есть процедура печати букв LCD_CHAR
.equ LCD_PARAM_char_stepx, 7 @ - шаг текста по оси Х
.equ LCD_PARAM_char_stepy, 8 @ - шаг текста по оси Y
еще не все параметры использую, отложил это до того момента как запущу еще какой нить дисплей (скорее всего это будет цветной SPI дисплей с aliexpress) — вот тогда и буду вводить дополнительные блоки условной компиляции в зависимости от типа дисплея.
В папке PCD8544 размещен драйвер дисплея, это 3 файла:
- font6x8.inc — шрифт 6х8, немного страшненький, но зато рисовал сам, маленьких букв нет (не получаются они у меня), состоит из знаков, цифр, заглавных букв латинского и русского алфавита. За счет отсутствия маленьких букв — существует в виде двух блоков символов LCD_LAT_CHARS (64 символа) и LDC_RUS_CHARS (31 символ), всего 570 байт
- lcd_param.inc файл настроек для lcd_func.asm, при использовании драйвера этот файл должен быть скопирован в одну с ним папку (что я и сделал — смотрите содержимое папки LCD приведенное выше)
- lcd_pcd8544.asm драйвер дисплея. Содержит в себе процедуру инициализации дисплея (LCD_INIT), процедуру очистки буфера (LCD_CLEAR), процедуру обновления экрана содержимым буфера (LCD_REFRESH), процедура рисования пиксела (LCD_PIXEL), процедура вывода символа (LCD_CHAR). В последней процедуре решил немного по «выпендриваться» и сделал вывод символов с точностью до пиксела (причем не через попиксельный вывод каждой точки)
Еще раз повторю: никаких дополнительных функций (вывод числа, вывод строки, вывод линии) в драйвер намеренно не вмещал — это функции от железа не зависящие.
Как всегда самое сложное — это написать демонстрацию возможностей получившихся модулей… Но это я наконец-то сделал:
У меня получилось 3 слайда:
— первый, (он же в начале статьи) — вывод текста с точностью до пиксела, вывод рамки
— второй — вывод шестнадцатеричного числа (до 32ух бит, число цифр задается в программе), вывод десятичного числа (32 бита, число цифр задается в программе)
— третий — рисование линий и точек, внизу слайда приведено количество тактов микроконтроллера затраченное на такое рисование (вместе с очисткой буфера), подсчет тактов производился при помощи модуля DWT:
Да, и еще, чур на дисплей не пинять, он у меня какой-то контуженый. Был другой, но отказался заводиться не только от программы написанной на ассемблере, но и от программы написанной на си с частотой SPI в 2 Мгц (за что сразу был выброшен в мусорку дабы не портил нервы).
Снял небольшое видео работы программы:
Музыка в фоне от телевизора, звуком я пока не занимался.
Ссылка на архив проекта.
P.S. Кстати, никто не занимается написанием текстовых редакторов? Очень хочется среду разработки с подсветкой кода, контекстным меню, и прочими рюшками… Пока делаю это в FAR, но хочется чего то более удобного. Мои контакты прежние: gorbukov @ тот_кто_знает_ всё. ru
Комментарии (7)
VitGo
29.01.2016 14:09По поводу BIC / BFI — посмотрю, просто сам ассемблер только изучаю, и ресурсов в которых бы понятно объяснялась логика команд в сети от совсем мало до совсем нет (хотелось бы видеть примеры вида: на входе / на выходе, а везде только названия из которых не всегда понятно что они собой представляют) — на счет того что написано по Си-шному — в точку! со своего старого исходника на Си и делал! :-)
Теперь когда у меня появился вывод на LCD — у меня как раз запланировано изучение команд, я наметил себе следующую часть публикации именно по командам, чтобы полностью разобрать какая и как работает…
На счет сохранения регистров — ну по процедурам _INIT согласен, на счет других же — абсолютно не согласен! процедуры тогда и только тогда хороши — когда не нужно думать о том что будет после них… в том же драйвере дисплея есть подпрограммы проверки флагов, управления линиями управления дисплея — вот они регистры не сохраняют, и это уже моя забота была за этим следить… а все что отдается на .global — должно гарантировано не портить регистры (ну по крайней мере где это логично)
А какие из существующих подходят для ассемблера (я не про подсветку кода говорю это как раз низкоприоритетное желание)?
у меня вот получился следующий список желания (я еще не сортировал по очередности и нужности):
1) Подсветка кода ассемблера
2) Авто дополнение вводимого кода (PUSH -> POP, IT — IT Block, и т.д.)
3) Контроль глобальных и локальных меток
4) Подсказка по инструкциям ассемблера
5) Контроль параметров подпрограмм
6) Поддержка программ как модулей с возможностью их добавления и удаления
7) Контроль в редакторе опций условного исполнения
8) Перенаправление сообщений консоли на себя, компиляция и компановка при помощи GNU AS
9) Файлменеджер проекта с крупными значками
10) Закладки в файл менеджере (переход в нужную папку одним кликом)
11) Переход на метку программы в редакторе
12) Автоматическое формирование списка констант модуля и дописывание в начало
13) Система помощи по регистрам настройки микроконтроллера
14) Мастеркода (автосоставитель кода) — например для настройки GPIO, SPI, DCMI и т.д.
15) Эмуляция исполнения кода
16) Настраиваемые окна среды (все! а не только окно редактора)
17) Отладка (пока не понимаю как, но как задача висит)beeruser
29.01.2016 19:25>> на счет других же — абсолютно не согласен! процедуры тогда и только тогда хороши — когда не нужно думать о том что будет после них
Ну как хотите. Используйте стандартный ABI хотя бы. По крайней мере можно будет работать с другими языками.
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.subset.swdev.abi/index.html
>> у меня вот получился следующий список желания
Ну этого вы до скончания веков будете ждать =)
VitGo
29.01.2016 19:50на счет стандартного ABI — спасибо за подсказку, посмотрел, подумаю…
просто на асме я давно программирую (это на ARM недавно стал смотреть по серьездному), и у меня всегда низшие регистры являются расходными…
а вот сколько их будет — я себя не ограничиваю…
на счет списка желаний — если бы нашелся программист на Delpi (я как то очень давно писал на нем немного) и если бы мне хотябы каркас дали — то я бы дописывал потихоньку…
самому конечно разбираться не очень хочется с нуля, потому что тут что то одно — либо в асме разбираешься и максимально погружаешься либо во что то еще…
в принципе список за исключением некоторых пунктов не такой уж и сложный, по крайней мере у меня в голове задача структурируется, и я потихоньку функциональность напишу… но вот что касается интерфейса программы — то тут я точно не смогу :-((( (ну по меньшей мере пока не начну погружаться по серьездному)
beeruser
>> Все процедуры не портят регистры!
Какой в этом смысл?
Прелесть асма как раз в том, что не нужно соблюдать стандартный ABI.
Весь код не смотрел, но глянул LCD_PIXEL
Скажу что у вас там не асм, а скорее C сконвертированный в асм.
Более того, если бы это был чистый C, функция скорее всего просто была бы заинлайнена в вызывающий код и работала бы в 2 раза быстрее.
Вот это вообще неудачный код
MOV R3, 1
AND R0, R0, 0x07
LSL R3, R3, R0
CMP R2, 0x01
ITEE EQ
ORREQ R4, R4, R3
RSBNE R3, R3, 0xFF
ANDNE R4, R4, R3
RSB AND (&~) заменяются одной командой BIC.
Вся эта последовательность не более чем вставка битового поля, выполняемая инструкцией BFI
Можно сдвинуть R2 и потом
AND R4, R3
OR R4, R2
У M4 есть инструкции типа MLA, ROR, BFC, ORN, которых также нет в C
Можно, например написать так (не проверено):
r0 y
r1 x
r2 0/1
lcd_pixel:
push {r0,r1,r3,r4}
lsr r3, r0, #3
mov r4, #48
mla r3, r4, r3, r1
movw r1, #(48/8*84)
cmp r3, r1
blt 1f
ldr r1, =lcd_buff
add r3,r1
ldrb r1, [r3]
ror r1, r1, r0
rsb r0, r0, #0
bfi r1, r2, #0, #1
ror r1, r1, r0
strb r1, [r3]
1: pop {r0, r1,r3,r4}
bx lr
-5 инструкций
-1 бранч
-3 сохранённых в стеке регистра
Я под thumb2 праада не писал и не проверял, так что скорее всего не скомпиляется =)
Но тем не менее, посыл должен быть ясен — раз вы занялись асм-ом, используете возможности, которые предоставляет процессор.
Также не нужно сохранять то, что не меняется.
Даже если использовать сишный ABI, push/pop можно вообще убрать, а вместо r4 использовать r12
>> кстати, никто не занимается написанием текстовых редакторов? очень хочется среду разработки с…
А чем все существующие не подходят, интересно?
beeruser
Опс. Думал про BIC, а написал AND
BIC R4, R3
ORR R4, R2
=)
VitGo
Такую проверку координат не хочу:
это не проверка координат а скорее проверка выхода за границы буфера экрана… да и при попытке задать допустимый параметр Y но не допустимый по X — потом замучаешься отлаживаться
а вот циклический сдвиг — это красивое решение!!!
постараюсь попробовать сегодня вечером!
VitGo
в общем реализовал ваш алгоритм со сдвигом
правда с небольшими уточнениями
прирост скорости 80%!!! (38225 тактов на рисование третьего слайда)