|
WinAVR: Как правильно размещать и работать с таблицами данных во Flash (памяти программ) ?, Не читает данные из Flash-памяти! |
|
|
|
Dec 7 2011, 17:58
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Доброго времяни суток! Видимо опять столкнулся с кривизной WinAVR Пример: нужно читать данные из памяти программ, и задействовать из в программе. Чтобы небыло лишних вопросов привожу весь текст программы: Код #include <avr/io.h> #include <avr/interrupt.h> // задает макросы sei() , cli() #include <inttypes.h> #include <avr/pgmspace.h>
uint8_t Cnt1;// фоновый счетчик длительности переключения свдиода volatile int16_t *p;// указатель
volatile register struct { uint8_t bOne : 1; uint8_t bTwo : 1; uint8_t bThree : 1; uint8_t bFour : 1; } RF asm ("r17");
#define sbi(p,b) (p |= (1<<b)) //Установить бит
#define DIRB 0b00010001 #define PUPB 0b00000111 #define Led PB0 /* линия светодиода ("1" - вкл. ч/з резистор на общ.) */
//;---------------------------------------------------------------------------------------------------------------------------------------- //Определение констант:
#define Vl_DBKCnt 101 #define Vl_FLCnt 5
const uint8_t a[] PROGMEM={22,15,233,40,69,39,203,2,1};
//===================================================================== ISR( TIM0_COMPA_vect) { if (!(--Cnt1)) { RF.bOne=0; sbi (PINB,Led);// ________ Переключение свдиода ! } }
//_______________ПОДПРОГРАММЫ_________________ void init (void) { PORTB=PUPB; //иницализация порта B DDRB=DIRB; // задание направления для порта B TIMSK0=(1<<OCIE0A); /* установка разр. прер-ия по совпадению т/сч.0 с регистром OCR0A */ OCR0A=234; //загрузка регистра совпадения OCR0A коэф. деления TCCR0A= (1<<WGM01); //установка режима СТС - обнуление Т/С0 при совпадении с регистром OCR0A TCCR0B=(1<<CS02)|(1<<CS00); // <---- конфигурация и запуск сч-ка в реж. СТС с предделителем ckl/1024 RF.bOne=0; Cnt1=100; //задание начальных значений для счетчиков
p=&a; // Установка указателя на начало таблицы a }
//============================================================================= int main (void) { //_________________________ ИНИЦИАЛИЗАЦИЯ _____________________________ uint16_t temp;
init(); sei ();// Разрешение общего прерывания while (1) { if (RF.bOne==0) { RF.bOne=1; temp=*p; Cnt1=(uint8_t)temp; ++p; } } } После использования команды PROGMEM в задании таблицы из программы удалилась секция где массив копировался в ОЗУ, что собственно и требовалось. Но обращение к таблице не поменялось. Вопрос вызывает только место: Код temp=*p; a6: 81 91 ld r24, Z+ a8: 91 91 ld r25, Z+ Cnt1=(uint8_t)temp; aa: 80 93 62 00 sts 0x0062, r24 Читает неизвестно откуда , только не из программы! Как прочитать данные из программы?
|
|
|
|
|
Dec 7 2011, 18:37
|

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

|
QUOTE (MaxiMuz @ Dec 7 2011, 19:58)  Видимо опять столкнулся с кривизной WinAVR  Видимо опять поленились прочитать документацию. QUOTE (MaxiMuz @ Dec 7 2011, 19:58)  CODE temp=*p; Читает неизвестно откуда , только не из программы! Читает известно откуда - из ОЗУ, как вы и попросили. Посмотрите в папке doc от вашего WinAVR папочку с документацией на avr-libc. В том же файле, в котором описано использованное вами магическое слово PROGMEM, описано и как работать с данными, размещенными во флеш при помощи этого слова.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Dec 8 2011, 11:36
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(Genadi Zawidowski @ Dec 8 2011, 11:21)  Может, поможет: Код void uc1601s_put_str_P(const char * str) { char c;
uc1601s_put_char_begin(); while((c = pgm_read_byte(str ++)) != '\0') uc1601s_put_char(c); uc1601s_put_char_end(); } Ничего не понимаю !!! Уже пробывал и с pgm_read_byte и с _LPM результата никакого ! Цитата(Палыч @ Dec 7 2011, 21:49)  Коль поменяли размещение массива а, то нужно изменить и указатель р таким образом, чтобы он указывал не на ОЗУ, а на flash (PROGMEM добавьте). Куда конкретно добавлять PROGMEM ? Цитата(Сергей Борщ @ Dec 8 2011, 09:57)  Не поможет. В WinAVR (avr-gcc) пока нет поддержки адресных пространств. чето я к такому же выводу прихожу, хотя в дока Data in Program Space четко описано как читать с Flash ! Вы вывод сделали на собственном опыте или по чужому ?
|
|
|
|
|
Dec 8 2011, 13:03
|

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

|
QUOTE (MaxiMuz @ Dec 8 2011, 13:36)  Ничего не понимаю !!! Уже пробывал и с pgm_read_byte и с _LPM результата никакого ! Показывайте исходник и листинг с pgm_read_byte(). QUOTE (MaxiMuz @ Dec 8 2011, 13:36)  чето я к такому же выводу прихожу, хотя в дока Data in Program Space четко описано как читать с Flash ! И оно таки работает именно так, как описано в доке. QUOTE (MaxiMuz @ Dec 8 2011, 13:36)  Вы вывод сделали на собственном опыте или по чужому ? По своему, естетсвенно.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Dec 9 2011, 12:06
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Код #include <avr/io.h> #include <avr/interrupt.h> #include <inttypes.h> #include <avr/pgmspace.h>
//===================================================================== uint8_t Cnt1;// фоновый счетчик длительности переключения свдиода uint16_t *p;
volatile register struct { uint8_t bOne : 1; uint8_t bTwo : 1; uint8_t bThree : 1; uint8_t bFour : 1; } RF asm ("r17");
#define sbi(p,b) (p |= (1<<b)) //Установить бит
#define DIRB 0b00010001 #define PUPB 0b00000111
//;------------------------------------------------------------------------------- //Определение контактов #define Control1 PB4 /* линия управления VT (1 - откр; 0 - закр ) */ #define Led PB0 /* линия светодиода ("1" - вкл. ч/з резистор на общ.) */
uint8_t a[] PROGMEM={22,15,233,40,69,39,203,2,1};
//===================================================================== ISR( TIM0_COMPA_vect) { if (!(--Cnt1)) { RF.bOne=0; sbi (PINB,Led);// ________ Переключение свдиода ! } }
//_______________ПОДПРОГРАММЫ_________________ void init (void) { PORTB=PUPB; //иницализация порта B DDRB=DIRB; // задание направления для порта B TIMSK0=(1<<OCIE0A); /* установка разр. прер-ия по совпадению т/сч.0 с регистром OCR0A */ OCR0A=234; //загрузка регистра совпадения OCR0A коэф. деления TCCR0A= (1<<WGM01); //установка режима СТС - обнуление Т/С0 при совпадении с регистром OCR0A TCCR0B=(1<<CS02)|(1<<CS00); // <---- конфигурация и запуск сч-ка в реж. СТС с предделителем ckl/1024 RF.bOne=0; RF.bTwo=0; Cnt1=100; //задание начальных значений для счетчиков p=&(a); }
//============================================================================= //============================================================================= int main (void) { init(); sei ();
while (1) { if (RF.bOne==0) { RF.bOne=1; //Cnt1=pgm_read_byte(&(a[p])); // варианте 2 //Cnt1=__LPM(*p); // варианте 3 Cnt1=pgm_read_byte(p); ++p; } } } вот текст программы. были опробованы различные варианты и комбинации , результатов это не принесло !
Сообщение отредактировал MaxiMuz - Dec 9 2011, 12:12
|
|
|
|
|
Dec 9 2011, 13:51
|

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

|
QUOTE (MaxiMuz @ Dec 9 2011, 14:06)  вот текст программы. Здесь все, что касается PROGMEM правильно. А вот uint8_t Cnt1; должен быть volatile. В вашем же случае компилятор имеет право строку Cnt1=pgm_read_byte(p); выкинуть совсем. И последний вопрос - файл компилируется как C или как C++? QUOTE QUOTE Следуя вашему FAQ "Как варить яйцо в микроволновке" я стал его варить, но оно взорвалось и сильно испачкало мне аппарат!
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Dec 9 2011, 20:29
|

Профессионал
    
Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634

|
А это было вообще "шедевр" Код //Cnt1=pgm_read_byte(&(a[p])); // варианте 2 Вы хоть немного читайте диагностику компилятора. А то на asm ("r17"); Вас хватило, а на адресную арифметику нет... В приведённом тексте ++p будет через пропускать каждый второй элемент массива a.
Сообщение отредактировал Genadi Zawidowski - Dec 9 2011, 20:34
|
|
|
|
|
Dec 12 2011, 07:09
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(Сергей Борщ @ Dec 9 2011, 16:51)  И последний вопрос - файл компилируется как C или как C++? Я не знаю как определить как компилируется файл! Есть скопированный makefile, меняю в нем тип МК, имяфайла, оптимизацию , и все. Про яйцо и микроволновку смешно  )) Вы хотите сказать что там где не нужно использовать volatile он был использован и наоборот?
|
|
|
|
|
Dec 12 2011, 07:56
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(MaxiMuz @ Dec 12 2011, 10:09)  Я не знаю как определить как компилируется файл! Есть скопированный makefile, меняю в нем тип МК, имяфайла, оптимизацию , и все. Приведите строки вызова компилятора. Цитата Вы хотите сказать что там где не нужно использовать volatile он был использован и наоборот?  Об этом всё в том же FAQ на avr-libc написано.
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Dec 12 2011, 08:20
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(Genadi Zawidowski @ Dec 9 2011, 23:29)  А это было вообще "шедевр" Код //Cnt1=pgm_read_byte(&(a[p])); // варианте 2 Кстати, это тоже рабочий вариант и ни какой не шедевр! Если правильно задать массив , то работает, но байт информации в массиве пакуется в слово с 00h в ст.байте: Код uint8_t *a[] PROGMEM={22,15,233,40,69,39,203,2,1}; 00000014 <a>: 14: 16 00 0f 00 e9 00 28 00 45 00 27 00 cb 00 02 00 ......(.E.'..... 24: 01 00 uint16_t p; p=0; ...... ...... int main (void) { init(); 9c: ea df rcall .-44 ; 0x72 <init> sei (); 9e: 78 94 sei a0: e0 91 60 00 lds r30, 0x0060 a4: f0 91 61 00 lds r31, 0x0061 a8: ee 0f add r30, r30 aa: ff 1f adc r31, r31 ac: ec 5e subi r30, 0xEC; 236 ae: ff 4f sbci r31, 0xFF; 255 if (RF.bOne==0) b0: 10 fd sbrc r17, 0 b2: fe cf rjmp .-4 ; 0xb0 <__stack+0x11> { RF.bOne=1; b4: 11 60 ori r17, 0x01; 1 Cnt1=pgm_read_byte(&(a[p++])); b6: 84 91 lpm r24, Z+ b8: 80 93 62 00 sts 0x0062, r24 bc: 32 96 adiw r30, 0x02; 2 be: f8 cf rjmp .-16 ; 0xb0 <__stack+0x11> Здесь я обнаружил неточную трансляцию команд, в месте : Код b6: 84 91 lpm r24, Z+ на самом деле заменяется командой lpm r24,Z !!! Что меня в начале смутило , так как инкремент судя по листингу происходит 3 раза. Цитата(demiurg_spb @ Dec 12 2011, 10:56)  Приведите строки вызова компилятора. Код > "make.exe" all
-------- begin -------- avr-gcc (WinAVR 20100110) 4.3.3 Copyright (C) 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Size before: AVR Memory Usage ---------------- Device: attiny13a
Program: 196 bytes (19.1% Full) (.text + .data + .bootloader)
Data: 3 bytes (4.7% Full) (.data + .bss + .noinit)
Compiling C: table_Fsh.c avr-gcc -c -mmcu=attiny13a -I. -gdwarf-2 -DF_CPU=8000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=./table_Fsh.lst -std=gnu99 -MMD -MP -MF .dep/table_Fsh.o.d table_Fsh.c -o table_Fsh.o table_Fsh.c:56: warning: initialization makes pointer from integer without a cast table_Fsh.c:56: warning: initialization makes pointer from integer without a cast table_Fsh.c:56: warning: initialization makes pointer from integer without a cast table_Fsh.c:56: warning: initialization makes pointer from integer without a cast table_Fsh.c:56: warning: initialization makes pointer from integer without a cast table_Fsh.c:56: warning: initialization makes pointer from integer without a cast table_Fsh.c:56: warning: initialization makes pointer from integer without a cast table_Fsh.c:56: warning: initialization makes pointer from integer without a cast table_Fsh.c:56: warning: initialization makes pointer from integer without a cast
Linking: table_Fsh.elf avr-gcc -mmcu=attiny13a -I. -gdwarf-2 -DF_CPU=8000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=table_Fsh.o -std=gnu99 -MMD -MP -MF .dep/table_Fsh.elf.d table_Fsh.o --output table_Fsh.elf -Wl,-Map=table_Fsh.map,--cref,-gc-sections -lm
Creating load file for Flash: table_Fsh.hex avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature table_Fsh.elf table_Fsh.hex
Creating load file for EEPROM: table_Fsh.eep avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \ --change-section-lma .eeprom=0 --no-change-warnings -O ihex table_Fsh.elf table_Fsh.eep || exit 0
Creating Extended Listing: table_Fsh.lss avr-objdump -h -S -z table_Fsh.elf > table_Fsh.lss
Creating Symbol Table: table_Fsh.sym avr-nm -n table_Fsh.elf > table_Fsh.sym
Size after: AVR Memory Usage ---------------- Device: attiny13a
Program: 196 bytes (19.1% Full) (.text + .data + .bootloader)
Data: 3 bytes (4.7% Full) (.data + .bss + .noinit)
-------- end --------
> Process Exit Code: 0 > Time Taken: 00:04
Сообщение отредактировал MaxiMuz - Dec 12 2011, 08:15
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|