|
|
  |
pgm_read_xxxx и PROGMEM в winavr20071221, В листинге нет инструкций LPM |
|
|
|
Mar 3 2008, 17:18
|
Участник

Группа: Участник
Сообщений: 25
Регистрация: 12-05-07
Из: Северная Венеция
Пользователь №: 27 684

|
Пишу простейшую програмку. Хочу запихать небольшой массив во флэш, и читать оттуда данные без записи всего массива в ОЗУ.
Мои действия? 1. Присоединяю библиотеку avr/pgmspace.h 2. Обьявляю массив: uint16_t left[] PROGMEM = {60,0x93,45,70}; 3. В программе читаю из массива: REQUIRED_LEFT=pgm_read_word(&left[1]); Переменная, куда читаю, точно такого же типа, что и в массиве. Смотрю в файл main.lst
254:main.c **** REQUIRED_LEFT=pgm_read_word(&left[1]); 905 .LM96: 906 03b0 80E0 /* #NOAPP */ 907 03b2 90E0 mov r18,r26 908 03b4 FC01 subi r18,lo8(-(1)) 909 sts point.1941,r18 911 03b8 5491 .LM97: 912 cpi r18,lo8(4) 913 brlo .L50 915 03ba 5093 0000 .LM98: 916 03be 4093 0000 sts point.1941,__zero_reg__
В файле нет инструкции LPM.
4. Убираем закорючку: REQUIRED_LEFT=pgm_read_word(left[1]);
Тогда это превращается в
254:main.c **** REQUIRED_LEFT=pgm_read_word(left[1]); 905 .LM96: 906 03b0 E3E9 /* #NOAPP */ 907 03b2 F0E0 mov r18,r26 908 subi r18,lo8(-(1)) 909 03b4 8591 sts point.1941,r18 911 .LM97: 912 cpi r18,lo8(4) 913 brlo .L50 915 03bc 8093 0000 .LM98:
Инструкция LPM в коде так и не появилась.
|
|
|
|
|
Mar 3 2008, 18:15
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(Steel_monkey @ Mar 3 2008, 19:18)  3. В программе читаю из массива: REQUIRED_LEFT=pgm_read_word(&left[1]); Мы все надеемся, что REQUIRED_LEFT объявлена как глобальная переменная, или как локальная с квалификатором volatile, или что REQUIRED_LEFT используется в выражении, являющимся параметром какой-либо (не-инлайн) функции, или что REQUIRED_LEFT в дальнейшем используется в выражении, результатом которого является обновление какой-нибудь глобальной или volatile переменной. В противном случае оптимизатор выкидывает это чтение, ибо его результат не нужен и это чтение есть просто ненужная трата времени.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Mar 3 2008, 19:44
|
Участник

Группа: Участник
Сообщений: 25
Регистрация: 12-05-07
Из: Северная Венеция
Пользователь №: 27 684

|
Обьявлена как глобальная volotile static, щас убрал и то, и другое, то есть осталась только глобальной. Тут еще разные чудеса происходили, типа как если добавить произвольный массив PRGMEM, и ничего с ним не делать, то LPM есть, а если убрать, то нет. В конце концов, заработало. Не знаю, где был косяк, но опять смоделировать пропадение LPM не смог. В общем вывод делаю такой, до самого Си надо изучать компилятор и его причуды, причем не меньше, чем сам Си. А за направление в правильное русло спасибо.
Сообщение отредактировал Steel_monkey - Mar 3 2008, 19:45
|
|
|
|
|
Mar 4 2008, 07:40
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(Steel_monkey @ Mar 3 2008, 22:44)  Не знаю, где был косяк, но опять смоделировать пропадение LPM не смог. В общем вывод делаю такой, до самого Си надо изучать компилятор и его причуды, причем не меньше, чем сам Си. 1. Как только компилер увидит константное выражение, он выдаст его результат - нафига ему LPM ? 2. Это не причуды, а кривоватая концепция, не позволяющая автоматизировать обращение к флешу и еепрому. То есть он (компилер) достаточно умный, но соответствия стандартам порождают некоторые казусы. К примеру(из другой области) - если следовать идеологии: Код uint8_t j; for(j=0;j<256;j++){do_something();} Или не мудрствовать лукаво Код char j; for(j=0;j<256;j++){do_something();} то в последнем случае код будет короче
|
|
|
|
|
Mar 4 2008, 09:32
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(_Pasha @ Mar 4 2008, 09:40)  то в последнем случае код будет короче Я думаю, в обоих случаях j будет выкинуто, а цикл заменен на бесконечный. Если бы было написано j < 255, то бесконечный цикл получился бы только если в опциях компилятора задано "char по умолчанию знаковый". В противном случае оба цикла вроде как должны бы получиться одинаковыми. Или я что-то упустил?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Mar 4 2008, 11:07
|
Участник

Группа: Участник
Сообщений: 25
Регистрация: 12-05-07
Из: Северная Венеция
Пользователь №: 27 684

|
Цитата(_Pasha @ Mar 4 2008, 10:40)  1. Как только компилер увидит константное выражение, он выдаст его результат - нафига ему LPM ? Дык в том и проблема, что мне нужна не отдельная константа, которую он может загрузить скажем через ldi и которая хранится априори в памяти программ, а массив констант, который хранится изначально и в ОЗУ и в ПЗУ. И тут уже как я понимаю только LPM. А вообще смотря по англоязычным форумам, PROGMEM вызывает довольно много вопросов по работоспособности.
Сообщение отредактировал Steel_monkey - Mar 4 2008, 11:15
|
|
|
|
|
Mar 4 2008, 12:23
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(Steel_monkey @ Mar 4 2008, 14:07)  Дык в том и проблема, что мне нужна не отдельная константа, которую он может загрузить скажем через ldi и которая хранится априори в памяти программ, а массив констант, который хранится изначально и в ОЗУ и в ПЗУ. И тут уже как я понимаю только LPM. Данные размещеют в памяти пограм как раз для того чтобы чтобы они не занимали место в RAM. Цитата А вообще смотря по англоязычным форумам, PROGMEM вызывает довольно много вопросов по работоспособности. Не по работоспособности а по пониманию. Посути вашенго вопроса. Ассемблерный код который вы привели не похож на код макроса pgm_read_word, возможно сбилось соответствие между С и ассемблерным кодом в файле с лстингом, таеое бывает. Поищите в листинге инструкции LPM/ELPM. Если нет, шлите минимальный неработающий пример. PS: Цитата 1. Присоединяю библиотеку avr/pgmspace.h И давайте разберемся с терминологией: avr/pgmspace.h - это не билиотека а заголовычный файл, и он не присоединяеться а включаеться. Анатолий.
Сообщение отредактировал aesok - Mar 4 2008, 12:30
|
|
|
|
|
Mar 4 2008, 15:01
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(Сергей Борщ @ Mar 4 2008, 12:32)  Я думаю, в обоих случаях j будет выкинуто, а цикл заменен на бесконечный.
Если бы было написано j < 255, то бесконечный цикл получился бы только если в опциях компилятора задано "char по умолчанию знаковый". В противном случае оба цикла вроде как должны бы получиться одинаковыми. Или я что-то упустил? 1. Ошибся я, j<254 2. uint8_t обрабатывается как 16-битовое, отсюда увеличение кода. 3. По поводу Lpm/Elpm, данный факт может сослужить плохую службу только в граничных ситациях, когда надо оценивать объем кода, а тут вдруг массив то есть / то нету. Это плохо. Имхо, единственный выход - избежать константных выражений.
|
|
|
|
|
Mar 4 2008, 15:29
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(_Pasha @ Mar 4 2008, 18:01)  1. Ошибся я, j<254 2. uint8_t обрабатывается как 16-битовое, отсюда увеличение кода. Не верю. AVR-GCC 4.3 main.c Код void do_something(void) __attribute__((noinline)); void do_something(void) { asm(""); }
int main (void) { unsigned char j; for(j=0;j<100;j++){do_something();}
signed char jj; for(jj=0;jj<100;jj++){do_something();}
return 0; } main.lst Код ... d2: 10 e0 ldi r17, 0x00; 0 unsigned char j; for(j=0;j<100;j++){do_something();} d4: 0e 94 67 00 call 0xce; 0xce <do_something> d8: 1f 5f subi r17, 0xFF; 255 da: 14 36 cpi r17, 0x64; 100 dc: d9 f7 brne .-10 ; 0xd4 <main+0x4> de: 10 e0 ldi r17, 0x00; 0
signed char jj; for(jj=0;jj<100;jj++){do_something();} e0: 0e 94 67 00 call 0xce; 0xce <do_something> e4: 1f 5f subi r17, 0xFF; 255 e6: 14 36 cpi r17, 0x64; 100 e8: d9 f7 brne .-10 ; 0xe0 <main+0x10> ... Анатолий.
Сообщение отредактировал aesok - Mar 4 2008, 15:31
|
|
|
|
|
Mar 4 2008, 16:44
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(_Pasha @ Mar 4 2008, 17:01)  1. Ошибся я, j<254 Попытка не защитана  signed char всегда меньше 254 (за исключением платформ, где char имеет размер более 8 битов). Цитата(_Pasha @ Mar 4 2008, 17:01)  2. uint8_t обрабатывается как 16-битовое, отсюда увеличение кода. Вообще-то uint8_t - это синоним unsigned char на платформах, где char 8 -битный и не определен для платформ, где 8-битные данные не поддерживаются. Ну а дальше действуют правила языка - в арифметических операциях unsigned/signed char приводится (минимум) к int, а потом оптимизатор может выкинуть лишние операции.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Mar 4 2008, 19:50
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Сергей Борщ @ Mar 4 2008, 19:44)  Вообще-то uint8_t - это синоним unsigned char на платформах, где char 8 -битный и не определен для платформ, где 8-битные данные не поддерживаются. небольшой OFF: а кто-нить знает как адекватно заставить Gcc воспринимать значения case(...) в switch как восмибитные ?
|
|
|
|
|
Mar 4 2008, 20:37
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(aesok @ Mar 4 2008, 18:29)  Не верю. AVR-GCC 4.3 И правильно делаете Пытался смоделировать ту ситуацию повторно - не получилось. Теперь совсем ничего не понимаю Цитата Попытка не защитана signed char всегда меньше 254 (за исключением платформ, где char имеет размер более 8 битов). В командной строке задавал чтобы unsigned chars было
|
|
|
|
|
Mar 5 2008, 21:17
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(_Pasha @ Mar 4 2008, 22:37)  В командной строке задавал чтобы unsigned chars было А вот к этому привыкать не рекомендую. Я расматриваю такой ключ как "аварийный", когда надо скомпилировать чей-то чужой код, в котором был написан просто char, подразумевая, что он unsigned. Свой код лучше сразу писать с явным указанием. Чем потом глюки ловить, лучше сразу явно указать знаковость. Просто char я использую нечасто и только тогда (но не всегда "тогда"), когда в нём должны храниться именно символы. Когда-то давно я использовал и uchar/schar, и u08/i08, теперь окончательно устаканился на stdint.h, введённом в С99 - uint8_t и компания. Настолько окончательно, что когда недавно поднимал небольшой старый проект для мелких изменений и перевода под avr-gcc - просто взял и прошёся по всему тексту заменой на новые типы  , иначе глаза постоянно спотыкались. Рано или поздно захочется перейти на другйо кристалл/компилятор и можно просто забыть, что давно отлаженные куски писались с рассчётом на беззнаковый char, а у новой платформы он знаковый. Хорошо ещё если компилятор сможет предупреждения выдать (condition always true для j < 255), но есть места, где для него неочевидно, что имел ввиду автор кода (например, p[j]).
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Mar 6 2008, 14:03
|

Начинающий профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 25-10-06
Из: СПб
Пользователь №: 21 648

|
Цитата(_Pasha @ Mar 6 2008, 10:18)  Дык там в аппликухах "uint8_t и компания" никто не пользует. Так уши от gcc растут. поддерживаю стиль, пропагандируемый ReAl. Переносимость улучшается, со временем очень привыкаешь к этим int_t
--------------------
Наука изощряет ум; ученье вострит память. Козьма Прутков
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|