Перейти к содержанию
    

WinAVR: Как правильно размещать и работать с таблицами данных во Flash (памяти программ) ?

Вообщем я понял, из за неприспосбленного и непродуманного компилятора WinAVR и кривизны оптимизатора код с заранее настроенным на адрес регистром:

int16_t *p;
p=&(a); 
Cnt1=pgm_read_byte(p++);

- почемуто не работает , увеличение p происходит на 2 байта вместо одного!

Единственный правильный вариант:

volatile uint8_t Cnt1;//фоновый счетчик длительности переключения свдиода
uint16_t p=0;

uint8_t a[] PROGMEM={22,15,233,40,69,39,203,2,1};
......
......
Cnt1=pgm_read_byte(&(a[p++]));

Хотя тоже корявый:

            Cnt1=pgm_read_byte(&(a[p++]));
  aa:    84 91           lpm    r24, Z+
  ac:    80 93 62 00     sts    0x0062, r24
  b0:    31 96           adiw    r30, 0x01; 1

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

почемуто не работает , увеличение p происходит на 2 байта вместо одного!
А с чего бы ему увеличиваться на один, если вы его объявили как указатель на uint16_t. Он честно, как вы и просите, увеличивается на sizeof(uint16_t). Пассаж про зеркалокомпилятор опустим.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А с чего бы ему увеличиваться на один, если вы его объявили как указатель на uint16_t. Он честно, как вы и просите, увеличивается на sizeof(uint16_t). Пассаж про зеркалокомпилятор опустим.

Да, действительно! Я все провожу паралели с Ассемблером и посчитал что тип_данных перед указателем есть размер ячейки памяти которая используется для указания адреса.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кст

ати, это тоже рабочий вариант и ни какой не шедевр! Если правильно задать массив , то работает, но байт информации в массиве пакуется в слово с 00h в ст.байте:

Вы описали массив указателей на int8_t, инициализируя их целыми числами. Компилятор ругнулся по поводу инициализации десяток раз (или сколько у Вас там инициализаторов), а Вы и не заметили...

 

Причём, в первых двух выкладываниях текста программы было всё нормально а в последнем (там где дизассемблерный листинг с кусочками исходного текста) эта ошибка уже внесена. Естественно, при перескоке через байт всё заработало.

 

 

Изменено пользователем Genadi Zawidowski

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы описали массив указателей на int8_t, инициализируя их целыми числами. Компилятор ругнулся по поводу инициализации десяток раз (или сколько у Вас там инициализаторов), а Вы и не заметили...

Теперь понял какую я ерунду написал.

Почему то в строчке p=&a;

volatile uint8_t Cnt1;//фоновый счетчик длительности переключения свдиода
uint8_t *p;
......
uint8_t a[] PROGMEM={22,15,233,40,69,39,203,2,1};
p=&a;
......

компил. выдает предупреждение:

 warning: assignment from incompatible pointer type

?

Изменено пользователем MaxiMuz

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

warning: assignment from incompatible pointer type[/code] ?
p - указатель на uint8_t. Имя массива является указателем на его нулевой член. Оператор & возвращает указательна свой аргумент. Т.е. запись &a имеет тип "указатель на указатель на uint8_t". Вам же надо просто "указатель на uint8_t". Поэтому либо берите адрес нулевого элемента массива p = &a[0], либо берите адрес массива p = a.

 

И еще - ваш массив находится во флеш, значит является константным по условию. Значит ваш указатель нужно делать указателем на константу: uint8_t const * p. И неважно, что компилятор сейчас позволяет объявить указатель на неконстантный объект - во первых, это уже исправлено в последних версиях, а во-вторых - это предохранит вас от ошибочной попытки изменить данные, на которые указывает p простым присваиванием, компилятор выдаст сообщение об ошибке.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Заменил p=&a; на p=&a[0]; действительно предупреждение пропало, спасибо Сергею!

Но возник другой вопрос. Я немного поменял алгоритм основной программы на:

p=&a[0];
........................................
........................................
int main (void)
{
uint8_t temp;
init();
sei ();
while (1)
    {
    if (RF.bOne==0)
        { RF.bOne=1;
            temp=pgm_read_byte(p++);
            if (temp!=0)
                {Cnt1=pgm_read_byte(p++);}
        }
    }    
}

И получил код:

p=&a[0];
  8a:    84 e1           ldi    r24, 0x14   ; 20
  8c:    90 e0           ldi    r25, 0x00   ; 0
  8e:    90 93 61 00     sts    0x0061, r25
  92:    80 93 60 00     sts    0x0060, r24
........................................
........................................
uint8_t temp;
init();
  98:    e8 df           rcall    .-48        ; 0x6a <init>
sei ();
  9a:    78 94           sei
  9c:    20 91 60 00     lds    r18, 0x0060
  a0:    30 91 61 00     lds    r19, 0x0061
  a4:    c9 01           movw    r24, r18
while (1)
    {
    if (RF.bOne==0)
  a6:    10 fd           sbrc    r17, 0
  a8:    fe cf           rjmp    .-4         ; 0xa6 <__stack+0x7>
        { RF.bOne=1;
  aa:    11 60           ori    r17, 0x01   ; 1
}
int main (void)
{
  ac:    ac 01           movw    r20, r24
  ae:    4f 5f           subi    r20, 0xFF   ; 255
  b0:    5f 4f           sbci    r21, 0xFF   ; 255
    {
    if (RF.bOne==0)
        { RF.bOne=1;
            temp=pgm_read_byte(p++);
  b2:    fc 01           movw    r30, r24
  b4:    84 91           lpm    r24, Z+
            if (temp!=0)
  b6:    88 23           and    r24, r24
  b8:    11 f4           brne    .+4         ; 0xbe <__stack+0x1f>
  ba:    ca 01           movw    r24, r20
  bc:    f4 cf           rjmp    .-24        ; 0xa6 <__stack+0x7>
            {
            Cnt1=pgm_read_byte(p++);
  be:    9a 01           movw    r18, r20
  c0:    2f 5f           subi    r18, 0xFF   ; 255
  c2:    3f 4f           sbci    r19, 0xFF   ; 255
  c4:    fa 01           movw    r30, r20
  c6:    84 91           lpm    r24, Z+
  c8:    80 93 62 00     sts    0x0062, r24
  cc:    eb cf           rjmp    .-42        ; 0xa4 <__stack+0x5>

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

:bb-offtopic: И кто будет после этого утверждать, что изучать ассемблер полезно? Вот изучил человек ассемблер, и что? Теперь он вместо написания программы, реализации своего алгоритма, создания своего устройства - занят анализом работы компилятора... :laughing:

MaxiMuz, вы сначала просто программу напишите, а оптимизировать её можно потом. Если возникнет нужда (а она скорее всего и не возникнет). Кроме того, со временем вы набьёте руку в Си, и будете автоматом писать наиболее оптимальным способом.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проблема решилась выносом p++ за "скобки" функции pgm_read_byte:

while (1)
    {
    if (RF.bOne==0)
        { RF.bOne=1;
            temp=pgm_read_byte(p);
            p++;
            if (temp!=0)
            {
            Cnt1=pgm_read_byte(p);
            p++;
            }
        }
    }

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

какая проблема решилась? по-моему, что в скобках, что за скобками - все одно и то же...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

по-моему, что в скобках, что за скобками - все одно и то же...
Однозначно!

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

какая проблема решилась? по-моему, что в скобках, что за скобками - все одно и то же...

Что-то там не так оптимизировалось:

Долго ломал голову зачем по несколько раз копировалась ссылка на массив!

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

какая проблема решилась? по-моему, что в скобках, что за скобками - все одно и то же...

решилась проблема лишних сохранений и тусований ссылочного регистра Z.

при использовании:

pgm_read_byte(p); p++;
вместо
pgm_read_byte(p++);
код сокращается на 18 байт!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...