Выделение байтов из слова. функции/директивы компилятора/препроцессора

Ранее писал на ассемблере в avr studio 4.
Но потребовалось добавить возможность чтения данных с SD-карты
Решил не заморачиваться, ибо посчитал что реализовывать работу с SPI, обмен данными с SD-картой и с файловой системой на ассемблере - это извращение, и проще воспользоваться готовой библиотекой. Поэтому решил перевести все в среду ардуино. Но код для работы с остальными устройствами, в частности с Олед-дисплеем решил оставить на ассемблере, ибо существующие библиотеки и ужасно тормозные и не обладают требуемыми возможностями и весьма громоздки, так как содержат в себе кучу ненужных мне вещей.
Но сразу напоролся на такую штуку:
Вот кусок кода на ассемблере из авр студио:

...
            ldi ZL,  low(InitSD1316 << 1)
            ldi ZH, high(InitSD1316 << 1)
...
InitSD1316:
    .db  0x0ae, 0x0d5 /* display off, sleep mode */
...

Но если я его переношу в ардуино (файл с расширением .S) компилятор ругается:
sketch\oled.S: Assembler messages:
sketch\oled.S:28: Error: garbage at end of line
sketch\oled.S:29: Error: garbage at end of line
exit status 1
Ошибка компиляции для платы Arduino Uno.

Подскажите, как правильно такое написать.
В авр студио у компилятора имелись функции low() и high() для выделения байтов из слова. Как быть с этим в среде ардуино?

Код надо приводить полностью. Вот как по Вашему куску понять на какие именно строки ругается?

Теперь по сути. Дело тут не в avr-студии и IDE, а в том как у Вас сконфигурирован тулчейн.

Судя по директиве .db, в студии Вы используете AVRASM. А в IDE используется GNU Assembler. Это совершенно разные ассемблеры. Например, в GNU Assembler нет никакого .db.

Так что Вам надо или перенастраивать тулчейн, или переписывать код на GNU ассемблер.

Ну мне собственно нужно переписать на GNU
c .db я там разобрался.
У меня вопрос по тому как переписать вот это:

            ldi ZL,  low(InitSD1316 << 1)
            ldi ZH, high(InitSD1316 << 1)

с AVRASM на GNU, если InitSD1316 - это метка, где в програмной памяти у меня находятся некоторые данные и мне нужно их считать побайтно.

Только что нашел инете про функции lo8(), hi8(), pm()
Я так понимаю что мне нужно написать:

            ldi ZL,  lo8(InitSD1316)
            ldi ZH, hi8(InitSD1316)

и сдвиг влево тут уже не нужен. Правильно? Или я что-то не так понял?

Это Вам виднее, никто же, кроме Вас, не знает что именно Вы хотите сделать.

Ну вообще-то я это у Вас и пытаюсь спросить, в надежде внести ясность для себя в данную ситуацию.

А что касается сдвига, то понятно что он умножает на 2, т.е. в моем случае преобразует адрес слова, скажем так: из 16-битного представления программной памяти ячейки в адрес байта, если память представить как массив 8-битных ячеек.

В AVRASM сдвиг нужно было делать. А вот в GNU не знаю, но подозреваю что не нужно.

Ну данный кусок - это инициализация OLED-дисплея

...
.global OledInitialize

OledInitialize:
            push R16
            push zl
            push zh
            ldi R16,0
            sts TWSR,R16  
            ldi r16,FreqTWBR
            sts TWBR,r16
            call i2c_start
            ldi r16, I2C_SLAW
            call i2c_send     
            ldi ZL, lo8(InitSD1316)  /* нужно тут делать сдвиг или нет ? */ 
            ldi ZH, hi8(InitSD1316) /*                                                                 */
            ldi R17,33
nextcom:    ldi r16,I2C_CMD_MODE
            call i2c_send
            lpm R16,Z+
            call i2c_send
            dec r17
            brne nextcom
            call i2c_stop
            pop  zh
            pop  zl
            pop  r16
            ret

InitSD1316:
    .byte  0x0ae, 0x0d5 /* display off, sleep mode */
    .byte  0x080, 0x0a8 /* clock divide ratio (0x00=1) and oscillator frequency (0x8) */
    .byte  0x01f, 0x0d3 /**** Feb 23, 2013: 128x32 OLED: 0x01f,  128x32 OLED 0x03f */
    .byte  0x000, 0x040 /*  *//* start line */
    .byte  0x08d, 0x014 /* [2] charge pump setting (p62): 0x014 enable, 0x010 disable */ 
    .byte  0x020, 0x002 /* com pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5), Feb 23, 2013: 128x32 OLED: 0x002,  128x32 OLED 0x012 */
    .byte  0x0a1, 0x0c0 
    .byte  0x081, 0x0cf /* [2] set contrast control */
    .byte  0x0d9, 0x0f1 /* [2] pre-charge period 0x022/f1*/
    .byte  0x0db, 0x040 /* vcomh deselect level */
    .byte  0x02e, 0x0a4 /* 2012-05-27: Deactivate scroll ; output ram to display */
    .byte  0x0a6,0x020
    .byte 0x000, 0x40
    .byte  0x0da, 0x012 /* com pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5) */
    .byte 0x81,0x7f
    .byte 0xD6, 0,0x0af,0x0AF

Данные это. Надо умножать на 2 или сдвигать влево на один бит, так ссылка в словах, а адрес в байтах

Хорошо. скажем по другому. память 16-разрядная. Адрес адресует слова. Но при работе с программной памятью как с данными, можно обращаться к отдельным байтам в слове. Т.е. адрес в регистре должен быть сдвинут влево, а в 0 бите должен быть номер байта в слове.

Я не знаю адрес ячейки. Потому что он определяется компилятором.

спасибо за ответ.
Считайте, что я тут ничего не писал

Все. верно. В AVRASM сдвиг нужен был, я его делал и все работало как нужно.
Т.е. если данные то нужен сдвиг влево, а если например адрес например для косвенного перехода то сдвиг не нужен.
Но в среде ардуино операции сдвига влево нет. Вернее компилятор на него ругается если он не в с-шном коде а в ассемблерном.

И у меня есть подозрение, что в GNU в случае с данными сдвиг не нужен, а в случае с переходами нужен сдвиг вправо (иначе зачем тогда существует функция pm() )

Но это пока предположение, и хотелось бы 100% быть уверенным да или нет.
Сегодня нет возможности, но завтра попробую проверить это на железе.

А еще лучше подскажите где взять дизасемблер, чтобы убедиться что компилятор компилирует так как это мне нужно.
Или можно ли в ардуино получить подробный листинг компиляции.

МК какой ?

<где стоит ардуино>\hardware\tools\avr\avr\bin\objdump.exe

1 лайк

Украли ???

В GNU Assembler

Есть. И вправо - тоже.

Скорее всего надо будет еще подстроить код под правила передачи параметров в функции !

1 лайк

Я вот никогда такого не делал, но что-то думается, что перенастроить тулчейн на AVRASM было бы проще, коль уж код на нём.

Ну так как кода мы не видели … может он не хочет передавать из C/C++ ничего в свои функции на ASM… - пусть у него голова болит …

Честно говоря, так ли это, - не знаю, я всегда пользуюсь только своими библиотеками (кстати - возможно. Должна же быть причина, пор которой я пользуюсь только своими!), но неужели Вы думаете, что “тормознутость” связана с языком, на котором они написаны?

Есть и еще одна (очень существенная) причина не писать на Ассемблере. По крайней мере, для Ардуино.
Ардуино - это платформа, которая включает AVR, SAM3, STM32, ESPxxx и кучу других вариантов, ОБЩЕГО ассемблера для которых попросту не существует.
Стало быть, писать для Ардуино на Ассемблере - невозможно.

Одно из следствий: тема об Ассемблере на форуме Ардуино - оффтопик.
И, кстати, почему слова “Ассемблер” не фигурирует в названии темы?

ТС вставьте ассемблер для SSD1306 прямо в C/C++

Вот еще быстрее код
https://arduino.ru/forum/programmirovanie/programmnyi-i2c-1-mgts-dlya-16-mgts-ustroistv-dlya-avr?page=1#comment-572687

Есть код и для аппаратного I2C (он медленнее !), но он сейчас не под рукой …

Передавать параметры конечно придется, но думаю там проблем не должно возникнуть. Да и не настолько много у меня будет параметров что их нельзя будет передать исключительно через регистры.

Не полностью, конечно, но частично да. Ибо ни один компилятор не в состоянии настолько оптимизировать генерируемый код, насколько это может сделать человек, напрямую пишущий инструкции для процессора.