Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Распаковка zip на стороне ATmega
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
StanislavF
Здравствуйте,

Прошиваю два Spartan3 с помощью AVR Atmega2561, последовательно, один за другим. Использую WinAVR 2010****. Прошивки для обеих ПЛИС компоную с прошивкой для ATmega. НО прошивки для ПЛИС со временем стали довольно большими и не влезают в 256 Кб для ATmega. Битовое сжатие не помогает.

Придёться сжимать и распаковывать их потом с помощью самого ATmega при программировании ПЛИС. Существуюит ли алгоритмы распаковки zip для ATmega или какие-то другие решения этой проблемы? То, что я находил в сети работет с файлами, а в ATmega файлов по сути никаких и нет.

Буду благодарен за любую предоставленную помощь.
MrYuran
Ещё 10 лет назад статьи видел, про сжатие прошивок конфигураций для ПЛИС.
И необязательно zip, ввиду специфики заливаемого массива можно применять простейшие методы (например, кодировать повторяющиеся серии нулей или единиц).
Тогда это было связано с дороговизной флеши.
А теперь?
Что мешает поставить сбоку флешку и лить из неё?

Кстати, файл - это всего лишь массив данных.
ReAl
Да, 10+ лет назад это интенивно обсуждалось в PVT.HARDW.MAX2PLUS.
Не знаю, как у xilinx, у альтеры прошивки в HEX выглядят как «много нулей, проскакивают ненули». Весьма неплохо жмутся простейшими алгоритамми типа модифицированного packbits (повторяться массово может только 0, поэтому его не нужно сохранять). Для распаковки: «если старший бит байта 0, то скопировать столько байт со входа на выход, иначе выдать на выход столько нулей, сколько записано в младших семи битах»

Или с битовой картой - берём со входа байт, идём по его битам. Если 0 — выдаём на выход нулевой байт, если 1 — копируем на выход байт со входа (© Ivan Mak).

Жмут они похуже ZIP-а, но распаковщик занимает настолько меньше места, что для меги256 может оказаться по сумме выгоднее zip.

Cyclone альтеровские уже в себе имеют распаковщик какого-то RLE и Quartus при соответствующей галке генерирует сжатый поток, у спартана3 такого нет?
Впрочем, кажется, какой-то из алгоритмов для первого циклона жал лучше, чем штатный квартусовский. Зато тот можно в конфиг eeprom записать и циклон сам поймёт.
rezident
У нас в похожей ситуации используется сжатие RLE, которое тут уже упоминалось. Альтернативным решением м.б использование другого (более простого/дешевого) МК и SPI Flash.
StanislavF
Спасибо за ответы.

Цитата(MrYuran @ Nov 3 2010, 17:30) *
Что мешает поставить сбоку флешку и лить из неё?

То, что аппаратура уже какая есть.

Цитата(ReAl @ Nov 3 2010, 18:16) *
Cyclone альтеровские уже в себе имеют распаковщик какого-то RLE и Quartus при соответствующей галке генерирует сжатый поток, у спартана3 такого нет?

В Spartran 3 есть сжатие битового потока, есть сжатие z для многоблочных PROM Xilinx. У меня стоит больше задача распаковать это на стороне ATmega. Буду благодарен на ссылки с алгоритмами. На счёт первого бита в байте не совсем понял -- что если он на чамом деел уже такой есть (не искуственно созданный).

Цитата(rezident @ Nov 4 2010, 00:23) *
У нас в похожей ситуации используется сжатие RLE, которое тут уже упоминалось. Альтернативным решением м.б использование другого (более простого/дешевого) МК и SPI Flash.

Другие МК уже не поставить. RLE попробую посмотреть.

Если вспомните полезные ссылки и прочее для кода на C, буду благодарен. Спасибо.
ReAl
О первом бите — ну так мы его так сгенерировали. Пример:
Вход на упаковку
FA AC 11 00 00 00 00 00 00 00 04 18 21 E7 00 00 00 00 00 00 00 00 00 00 22 00 44 55 00 00 00 00 00 00 00 01

Выход упаковщика
03 FA AC 11 87 04 04 18 21 E7 8A 04 22 00 44 55 87 01 01
Оиночный 00, выдленный курсивом, не было смысла пускать как ноль. До двух нулей смысла нет.

Распаковщик
03 FA AC 11 — копируем три байта со входа на выход
87 — пишем на выход семь нулей
04 04 18 21 E7 — копируем четыре байта со входа на выход
8A — пишем на выход десять нулей
04 22 00 44 55 — копируем четыре байта со входа на выход
87 — пишем на выход семь нулей
01 01 — копируем один байт со входа на выход
StanislavF
Использую PackBits. На машине упаковка и распаковка работают нормально. При программировании AVR, тестовый у ПЛИС светодиод не мигает, т.е. ПЛИС программируется неправильно.

В чём может быть дело?

Процедура программирования ПЛИС несжатой прошивкой.
Код
void FPGA_sendfile(uint_farptr_t buf, uint32_t buf_len)
{
  unsigned char i;
  uint32_t l;
  uint8_t c;

  for (l = 0; l < buf_len; l ++) // buf_len-1
   {
    c = pgm_read_byte_far(buf + l);
    for (i = 0;i < 8;i ++)
     {
        if ((c & 0x80)>0) SET_XSP_DIN;
        else CLEAR_XSP_DIN;
        CLEAR_XSP_CLK;
        c<<=1;
        SET_XSP_CLK;
     }
    }  
  SET_XSP_DIN;
}


Процедура программирования ПЛИС сжатой прошивкой.
Код
void FPGA_sendpackedfile(uint_farptr_t buf, uint32_t buf_len)
{
  unsigned char i;
  uint32_t L;
//  uint8_t c;

  int32_t countChar;                      /* run/copy count */
  uint8_t c;                       /* current character */

  L =  - 1;
  while(L <= buf_len - 1) // - 2?
    {
      L += 1;
      countChar = (int32_t) pgm_read_byte_far(buf + L);

      if (countChar < 0)
    {
      /* we have a run write out  2 - countChar copies */
      countChar = (MIN_RUN - 1) - countChar;

      L += 1;

      while (countChar > 0)
        {
          c = pgm_read_byte_far(buf + L);
          for (i = 0;i < 8;i ++)
        {
          if ((c & 0x80)>0) SET_XSP_DIN;
          else CLEAR_XSP_DIN;
          CLEAR_XSP_CLK;
          c <<= 1;
          SET_XSP_CLK;
        }
          countChar--;
        }
    }
      else
    {
      /* we have a block of countChar + 1 symbols to copy */
      for (countChar++; countChar > 0; countChar--)
        {
          L += 1;
          c = pgm_read_byte_far(buf + L);

          for (i = 0; i < 8; i ++)
        {
          if ((c & 0x80)>0) SET_XSP_DIN;
          else CLEAR_XSP_DIN;
          CLEAR_XSP_CLK;
          c <<= 1;
          SET_XSP_CLK;
        }
        }
    }
    }
  SET_XSP_DIN;
}


Не пойму, где тут мог намудрить. Я прикрепил проект для тестирования упаковки/распаковки на инструментальной системе и проект для программирования целевой. Буду благодарен за советы и помощь.

SasaVitebsk
Можно делать и прямую распаковку. Там тоже ничего сложного нет, но вам понадобится довольно много озу, для формирования словаря. Иногда делают с предустановленным фиксированным словарём, тогда эффективность несколько ниже, но приведенные последовательности исключительно хорошо будет сжимать/разжимать. Прямой метод LZH даст эффективность ~ 80-90% от ZIP сжатия.
XVR
Код
  int32_t countChar;
Зачем 32 бита? У вас максимальный счетчик - 128
Код
     countChar = (int32_t) pgm_read_byte_far(buf + L);
      if (countChar < 0)
Если pgm_read_byte_far возвращает беззнаковый char то работать не будет
Код
    countChar = (MIN_RUN - 1) - countChar;
Это вообще не понял - там счетчик в чистом виде: countChar &= 0x7F;
Код
     while (countChar > 0)
        {
          c = pgm_read_byte_far(buf + L);
А вот это ошибка - мы 0 должны выводить, а не содержимое следующего байта флеша:
Код
     while (countChar > 0)
        {
          c = 0;

ViKo
Я делал сжатие несколько иначе - последовательность нулевых байтов заменялась одним нулевым байтом и следующим байтом, задающим количество нулевых байтов.
StanislavF
Цитата(XVR @ Nov 24 2010, 18:37) *
Код
  int32_t countChar;
Зачем 32 бита? У вас максимальный счетчик - 128

На самом деле 129. Можно обойтись и 16-тью.
Цитата(XVR @ Nov 24 2010, 18:37) *
Код
     countChar = (int32_t) pgm_read_byte_far(buf + L);
      if (countChar < 0)

Если pgm_read_byte_far возвращает беззнаковый char то работать не будет

Как тогда быть? Что использовать вместо pgm_read_byte_far?
Цитата(XVR @ Nov 24 2010, 18:37) *
Код
    countChar = (MIN_RUN - 1) - countChar;

Это вообще не понял - там счетчик в чистом виде: countChar &= 0x7F;


Цитата(XVR @ Nov 24 2010, 18:37) *
Код
     while (countChar > 0)
        {
          c = pgm_read_byte_far(buf + L);

А вот это ошибка - мы 0 должны выводить, а не содержимое следующего байта флеша:

Код
     while (countChar > 0)
        {
          c = 0;

Я брал код отсюда (PackBits Variant): http://michael.dipperstein.com/rle/index.html
На инструментальной системе всё работает, поэтому на сам алгоритм я не особо грешу, а вот на реалтзацию для avr...
Надеюсь на вашу дальнейшую помощь.
XVR
Цитата
Как тогда быть? Что использовать вместо pgm_read_byte_far?
Его и использовать. Приведение типа неправильное, должно быть countChar = (unsigned char) pgm_read_byte_far(buf + L);
Цитата
Я брал код отсюда (PackBits Variant)
Пардон, я думал, что вы реализовали алгоритм от ReAl (он сюда подходит гораздо лучше)
demiurg_spb
Цитата(XVR @ Jan 12 2011, 17:45) *
Приведение типа неправильное, должно быть countChar = (unsigned char) pgm_read_byte_far(buf + L);

pgm_read_byte и так по умолчанию uint8_t возвращает.
ReAl
Цитата(XVR @ Jan 12 2011, 16:45) *
Пардон, я думал, что вы реализовали алгоритм от ReAl (он сюда подходит гораздо лучше)

Я на ACEX1K30..1K50 когда-то давно сверял, c битовой картой © Ivan Mak вроде бы чуть лучше работал.
А я просто по быстрячку Macintosh PackBits модифицировал под случай, когда массово повторяться может только 0, поэтому его нет смысла и писать в выходной поток.

Цитата(StanislavF @ Jan 12 2011, 11:26) *
Как тогда быть? Что использовать вместо pgm_read_byte_far?
У Вас в массиве во флеше записаны знаковые байты. Значит, нужно возврат pgm_read_byte_far приводить к знаковому байту.
Код
   int8_t counter;
   counter = (int8_t)pgm_read_byte_far( ptr );


Я пользовался не знаковым числом, а флагом в старшем бите беззнакового 8-битного числа.
ViKo
Цитата(ReAl @ Jan 12 2011, 22:36) *
Я на ACEX1K30..1K50 когда-то давно сверял, c битовой картой © Ivan Mak вроде бы чуть лучше работал.

Не могли бы вы показать, во что превратится код из примера в сообщении №6, закодированный © Ivan Mak, а то из вашего описания я не понял, как он работает.
ReAl
Вход на упаковку. Минусами разбито на группы по восемь байт, как это нужно для байтов масок (в байтах масок каждому входному байту упаковщика (выходному байту распаковщика) соответствет один бит.
FA AC 11 00 00 00 00 00 - 00 00 04 18 21 E7 00 00 - 00 00 00 00 00 00 00 00 - 22 00 44 55 00 00 00 00 - 00 00 00 01

Выход упаковщика. Байты масок показаны в двичном коде с префиксом 0b
0b11100000 0xFA 0xAC 0x11 0b00111100 0x04 0x18 0x21 0xE7 0b00000000 0b10110000 0x22 0x44 0x55 0b00010000 0x01
При своей потрясающей простоте метод очень хорошо жмёт прошивки. Кажется, лучше, чем встроенный в квартус пожиматель / встроенный в циклоны разжиматель.

Там выше ужалось в 19 байт, тут в 16.
Перед массивом для разжимателя нужно указывать общую длину, так как алгоритм округляет число байтов вверх до кратного восьми.
ViKo
Цитата(ReAl @ Jan 14 2011, 00:01) *
При своей потрясающей простоте метод очень хорошо жмёт прошивки.
Перед массивом для разжимателя нужно указывать общую длину, так как алгоритм округляет число байтов вверх до кратного восьми.

Спасибо. Да, просто и со вкусом. И, как мне на первый взгляд кажется, отсутствуют "недопустимые" коды, т.е., нет избыточности. Конечно, если потерять хотя бы один байт, весь остаток кода будет испорчен. Но в ПЛИС даже часть правильного кода не нужна.
Надо взять на вооружение. Рояльти платить не требуется? sm.gif
И еще, по-моему, ничего страшного не произойдет, если послать в ПЛИС чуть больше кода. Лишние биты проигнорируются.
ReAl
Цитата(ViKo @ Jan 14 2011, 12:55) *
Рояльти платить не требуется? sm.gif
Это не ко мне, я сам на тех же правах :-) А его можно поискать в окрестностях "спринтер"-ов или как там те ZX-клоны с ACEX-ом называются. По крайней мере, в те времена от чем-от таким занимался, форт-сопроцессор делал куда-то туда.

Цитата(ViKo @ Jan 14 2011, 12:55) *
И еще, по-моему, ничего страшного не произойдет, если послать в ПЛИС чуть больше кода. Лишние биты проигнорируются.
С FLEX8000/ACEX1K, кажется, я так и делал. Для FLEX8K вообще надо было послать несколько "лишних" байтов, точнее, обеспечить пару десятков тактов "для старта". Позже, вроде бы, софт сразу в прошивку несколько FF в конце стал добавлять.
По идее, после получения прошивки микросхема всё остальное просто должна игнорировать. Но в каждом конкретном случае надо бы смотреть.
SysRq
Цитата(StanislavF @ Nov 23 2010, 20:24) *
Код
void FPGA_sendpackedfile(uint_farptr_t buf, uint32_t buf_len)
//...
uint32_t L;
//...
  L =  - 1;
  while(L <= buf_len - 1)
//...
Ни разу не выполнится же ж. Сделайте signed.
Leka
Битстрим (альтеровский *.rpd) по медленному радиоканалу передается, и распаковывается мелким софт-процессором без лишней памяти. Поэтому задача - сжать получше (с распаковщиком попроще). Ориентир на степень сжатия - как zip. Может кто оценки привести, как рассмотренные в этой ветке, и какие-либо другие алгоритмы, сжимают битстрим по сравнению с zip, для разной степени заполненности кристалла?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.