Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: jpeg на at91sam9g20
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
wmakc
Делаю jpeg кодер для сжатия raw картинки с матрицы mt9d131. Картинка сжимается примерно за 3 секунды. Для такого контроллера это нормально?

С помощью встроенного таймера пробовал измерять время на различных этапах сжатия. Около 400 милисекунд уходит на копирование буфера картинки. Как я понял очень много времени уходит на операции в памяти.
Код
for(i=0; i<614400; i++)
{
     data[i] = Buffer[i];
}

Картинка около 600 килобайт. Пробовал напрямую использовать буфер(Buffer), в который ISI интерфейс записывает картинку, но во время сжатия были искажения цветов, тоесть там что-то с обращением.



Еще много времени уходит на квантование:
CODE

void fdct_and_quantization(SBYTE *data,float *fdtbl,SWORD *outdata)
{
int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
int tmp10, tmp11, tmp12, tmp13;
int z1, z2, z3, z4, z5, z11, z13;
int *dataptr;
int datafloat[64];
int temp;
SBYTE ctr;
BYTE i;
for (i=0; i<64; i++)
datafloat[i] = data[i];

dataptr=datafloat;
for (ctr = 7; ctr >= 0; ctr--)
{
tmp0 = dataptr[0] + dataptr[7];
tmp7 = dataptr[0] - dataptr[7];
tmp1 = dataptr[1] + dataptr[6];
tmp6 = dataptr[1] - dataptr[6];
tmp2 = dataptr[2] + dataptr[5];
tmp5 = dataptr[2] - dataptr[5];
tmp3 = dataptr[3] + dataptr[4];
tmp4 = dataptr[3] - dataptr[4];

/* Even part */

tmp10 = tmp0 + tmp3; /* phase 2 */
tmp13 = tmp0 - tmp3;
tmp11 = tmp1 + tmp2;
tmp12 = tmp1 - tmp2;

dataptr[0] = tmp10 + tmp11; /* phase 3 */
dataptr[4] = tmp10 - tmp11;

z1 = (tmp12 + tmp13) * (0.707106781); /* c4 */
dataptr[2] = tmp13 + z1; /* phase 5 */
dataptr[6] = tmp13 - z1;

/* Odd part */

tmp10 = tmp4 + tmp5; /* phase 2 */
tmp11 = tmp5 + tmp6;
tmp12 = tmp6 + tmp7;

/* The rotator is modified from fig 4-8 to avoid extra negations. */
z5 = (tmp10 - tmp12) * (0.382683433); /* c6 */
z2 = ( 0.541196100) * tmp10 + z5; /* c2-c6 */
z4 = ( 1.306562965) * tmp12 + z5; /* c2+c6 */
z3 = tmp11 * ( 0.707106781); /* c4 */

z11 = tmp7 + z3; /* phase 5 */
z13 = tmp7 - z3;

dataptr[5] = z13 + z2; /* phase 6 */
dataptr[3] = z13 - z2;
dataptr[1] = z11 + z4;
dataptr[7] = z11 - z4;

dataptr += 8; /* advance pointer to next row */
}

dataptr = datafloat;
for (ctr = 7; ctr >= 0; ctr--)
{
tmp0 = dataptr[0] + dataptr[56];
tmp7 = dataptr[0] - dataptr[56];
tmp1 = dataptr[8] + dataptr[48];
tmp6 = dataptr[8] - dataptr[48];
tmp2 = dataptr[16] + dataptr[40];
tmp5 = dataptr[16] - dataptr[40];
tmp3 = dataptr[24] + dataptr[32];
tmp4 = dataptr[24] - dataptr[32];

/* Even part */

tmp10 = tmp0 + tmp3; /* phase 2 */
tmp13 = tmp0 - tmp3;
tmp11 = tmp1 + tmp2;
tmp12 = tmp1 - tmp2;

dataptr[0] = tmp10 + tmp11; /* phase 3 */
dataptr[32] = tmp10 - tmp11;

z1 = (tmp12 + tmp13) * ( 0.707106781); /* c4 */
dataptr[16] = tmp13 + z1; /* phase 5 */
dataptr[48] = tmp13 - z1;

/* Odd part */

tmp10 = tmp4 + tmp5; /* phase 2 */
tmp11 = tmp5 + tmp6;
tmp12 = tmp6 + tmp7;

/* The rotator is modified from fig 4-8 to avoid extra negations. */
z5 = (tmp10 - tmp12) * ( 0.382683433); /* c6 */
z2 = ( 0.541196100) * tmp10 + z5; /* c2-c6 */
z4 = ( 1.306562965) * tmp12 + z5; /* c2+c6 */
z3 = tmp11 * ( 0.707106781); /* c4 */

z11 = tmp7 + z3; /* phase 5 */
z13 = tmp7 - z3;

dataptr[40] = z13 + z2; /* phase 6 */
dataptr[24] = z13 - z2;
dataptr[8] = z11 + z4;
dataptr[56] = z11 - z4;

dataptr++; /* advance pointer to next column */
}

for (i = 0; i < 64; i++)
{
/* Apply the quantization and scaling factor */
outdata[i] = datafloat[i] * fdtbl[i];
}
}


После замены у всех переменных типа float на int скорость сжатия возросла в 3 раза.

В общем вопросы по порядку:
1. Как быстро скопировать переменную в памяти( или использовать буфер isi интерфейса без порчи картинки)
2. Ускорить функцию квантования(Хотел бы разместить часть переменных в sram( она же быстрее sdram?))
aaarrr
Цитата(wmakc @ Aug 21 2010, 18:20) *
Картинка сжимается примерно за 3 секунды. Для такого контроллера это нормально?

Нет, это медленно.

Цитата(wmakc @ Aug 21 2010, 18:20) *
1. Как быстро скопировать переменную в памяти( или использовать буфер isi интерфейса без порчи картинки)

Использовать не побайтное копирование, а, например, библиотечную функцию memcpy. Буферы выровнять по границе слова.

Цитата(wmakc @ Aug 21 2010, 18:20) *
2. Ускорить функцию квантования(Хотел бы разместить часть переменных в sram( она же быстрее sdram?))

Судя по скорости копирования, сейчас даже кэш не настроен. Да, в текущих условиях перенос переменных в SRAM принесет заметное ускорение. Но при нормальных настройках этого не потребуется.
AlexandrY
Реальное быстродействие памяти у микроконтроллеров такого типа можете оценить здесь:
http://eewiki.ru/wiki/Example_DRAMSpeed_for_ARMGS10

Для memcpy выравнивание практически не имеет значения, там в начале алгоритм сам подстраивает выравнивание. Разница будет только в пару десятков тактов.
Ваша пересылка должна занять не более 15 мс.
aaarrr
Цитата(AlexandrY @ Aug 21 2010, 21:03) *
Для memcpy выравнивание практически не имеет значения, там в начале алгоритм сам подстраивает выравнивание. Разница будет только в пару десятков тактов.

Еще как имеет. Для одинаково выровненных данных при копировании будут использованы LDM/STM, если же данные выровнены не одинаково, то скоростное копирование отпадает.
AlexandrY
Цитата(aaarrr @ Aug 21 2010, 20:15) *
Еще как имеет. Для одинаково выровненных данных при копировании будут использованы LDM/STM, если же данные выровнены не одинаково, то скоростное копирование отпадает.


Ладно повторю яснее.
Нормальный memcpy в начале выполнения проверяет выровненность адресов. Если адрес невыровненный, то сначала производится пересылка первых невыровненных байт, а потом включается на всю дурь все та же 32-х битная пересылка пачками. Т.е. оверхед из-за невыровненности не превышает пары десятков тактов.
aaarrr
Цитата(AlexandrY @ Aug 22 2010, 00:14) *
Ладно повторю яснее.

И я попробую яснее. Если источник имеет одно выравнивание (скажем, младшие два бита адреса равны 1), а приемник другое (например, 3), то 32-битной пересылки пачками не получится в принципе. Максимум, что можно сделать (и делается в нормальных memcpy) - это 32-битное одинарное чтение, затем перепаковка и 32-битная запись.

Иллюстрация:
Код
Word          0    1    2    3    4
              0123 0123 0123 0123 0123
Source         ABC DEFG HIJK LMNO
Destination      A BCDE FGHI JKLM NO
AlexandrY
Цитата(aaarrr @ Aug 21 2010, 23:27) *
И я попробую яснее. Если источник имеет одно выравнивание (скажем, младшие два бита адреса равны 1), а приемник другое (например, 3), то 32-битной пересылки пачками не получится в принципе. Максимум, что можно сделать (и делается в нормальных memcpy) - это 32-битное одинарное чтение, затем перепаковка и 32-битная запись.

Иллюстрация:
Код
Word          0    1    2    3    4
              0123 0123 0123 0123 0123
Source         ABC DEFG HIJK LMNO
Destination      A BCDE FGHI JKLM NO


Согласен. Что-то замкнуло у меня.
Надо будет проверить влияние этого на производительность.
wmakc
объясните как с помощью memcpy скопировать из char в int
использую memcpy(dataint, datachar, 64);
где и как поставить выравнивание?


Что нужно для настройки кэш?

Задавал вопрос о том как использовать sram. Если я просто переменные в функции объединю в блок
#pragma arm section RW=sram
объявление переменных
#pragma arm section RW
то после когда контроллер с помощью загрузчика копирует мою программу из флешки в sdram, как он поймет, что часть переменных нужно скопировать в sram?
aaarrr
Цитата(wmakc @ Aug 22 2010, 09:16) *
объясните как с помощью memcpy скопировать из char в int
использую memcpy(dataint, datachar, 64);
где и как поставить выравнивание?

Если хотите ускорить выполнение, то выравнивать надо datachar. В Keil'е для этого существует __align().

Цитата(wmakc @ Aug 22 2010, 09:16) *
Что нужно для настройки кэш?

Создать Translation Table, включить MMU, включить кэш. ICache можно включить отдельно от MMU, но это полумера.

Цитата(wmakc @ Aug 22 2010, 09:16) *
Задавал вопрос о том как использовать sram. Если я просто переменные в функции объединю в блок
#pragma arm section RW=sram
объявление переменных
#pragma arm section RW
то после когда контроллер с помощью загрузчика копирует мою программу из флешки в sdram, как он поймет, что часть переменных нужно скопировать в sram?

Чтобы понял, надо еще объяснить линкеру, куда класть объекты секции sram. Например:
CODE

FLASH 0x00000000 0x00020000
{
FLASH 0x00000000 0x00020000
{
start.o (startup, +First)
}
RAM 0x00200000 0x00008000
{
* (sram)
}
SDRAM 0x00300000 0x00800000
{
* (+RO, +RW, +ZI)
}
}

wmakc
Хотелось бы по подробнее узнать как создать Translation Table,включить MMU. Если есть пример на Keil буду очень рад). Когда пытаюсь скопировать данные из char в int с помощью memcpy контроллер виснет. В связи с этим возник вопрос как использовать __align()?



CODE

Load_region 0x20000000 0x2000000 {

Fixed_region 0x20000000 {
*(cstartup +First)
.ANY (+RO +RW +ZI)
}

Relocate_region 0x200000 0x4000 {
*.o (VECTOR, +First)
}

ARM_LIB_HEAP 0x21FFE000 EMPTY 0x1000 {
}

ARM_LIB_STACK 0x22000000 EMPTY -0x1000 {
}
}


Это мой scatter, где в нем описать объявление sram?
aaarrr
Цитата(wmakc @ Aug 22 2010, 11:04) *
Хотелось бы по подробнее узнать как создать Translation Table,включить MMU. Если есть пример на Keil буду очень рад).

Пример можете посмотреть здесь. Только под 926 нужно внести мелкие коррективы.

Цитата(wmakc @ Aug 22 2010, 11:04) *
Когда пытаюсь скопировать данные из char в int с помощью memcpy контроллер виснет. В связи с этим возник вопрос как использовать __align()?

Не должен он виснуть. А если виснет, то в этом никак не виновато выравнивание.

Цитата(wmakc @ Aug 22 2010, 11:04) *
Это мой scatter, где в нем описать объявление sram?

Можно так:
CODE

Load_region 0x20000000 0x2000000 {

Fixed_region 0x20000000 {
*(cstartup +First)
.ANY (+RO +RW +ZI)
}

Relocate_region 0x200000 0x4000 {
*.o (VECTOR, +First)
}

SRAM1 0x300000 0x4000 {
* (sram)
}

ARM_LIB_HEAP 0x21FFE000 EMPTY 0x1000 {
}

ARM_LIB_STACK 0x22000000 EMPTY -0x1000 {
}
}

wmakc
Тогда мне интересно узнать загрузчик at91bootstrap запускает MMU?
aaarrr
Нет, он только включает ICache.
wmakc
Как только добавил сссылку на sram в scatter файл при компилирования появилось предупреждение "No section matches pattern *(sram)"
aaarrr
Значит переменных нет (как вариант, они могли быть выброшены оптимизатором за ненадобностью).
wmakc
CODE


void InitMMU(unsigned int *pTranslationTable)
{
int i;
// Program the TTB
_writeTTB((unsigned int) pTranslationTable);
// Program the domain access register
_writeDomain(0xC0000000);

// Reset table entries
for (i = 0; i < 4096; ++i)
pTranslationTable[i] = 0;
// Program level 1 page table entry

pTranslationTable[0x3] =
(0x3 << 20) | // Physical Address
(1 << 10) | // Access in supervisor mode
(15 << 5) | // Domain
(1 << 4) |
(1 << 3) | // Cachable
0x2; // Set as 1 Mbyte section

/* SDRAM entire mapping */
for(i=0;i<64;i++)
pTranslationTable[0x200+i] =
((0x200+i) << 20) | // Physical Address
(1 << 10) | // Access in supervisor mode
(15 << 5) | // Domain
(1 << 4) |
(1 << 3) | // Cachable
0x2; // Set as 1 Mbyte section

pTranslationTable[0xFFF] =
(0xFFF << 20) | // Physical Address
(1 << 10) | // Access in supervisor mode
(15 << 5) | // Domain
(1 << 4) |
0x2; // Set as 1 Mbyte section

// Enable the MMU
CP15_EnableMMU();
}

int main(void)
{
CP15_Enable_I_Cache();
InitMMU((unsigned int *) 0x310000);



Попробовал запустить MMU. Все операции с памятью теперь не работают. В чем ошибка?
aaarrr
Цитата(wmakc @ Aug 22 2010, 13:01) *
В чем ошибка?

Ну, как минимум таблица расположена мимо памяти - адрес 0x310000 у 9G20 попадает в Reserved. Положите ее в SDRAM.
wmakc
Пробовал в sdram, результата не дало
AlexandrY
Ну вот протестировал. Результат здесь:
http://eewiki.ru/wiki/Example_DRAMSpeed_for_ARMGS10

Как видно для внешней RAM результат не так уж критично отличается.

Но в Keil-е, например, явно заданные массивы никогда не располагаются невыровненными, даже если в стеке объявлены.
Более того, рекомендуется выравнивание включать по границе 8-мь чтобы не было проблем с плавающей точкой.
Поэтому и в голову не приходило тестировать на невыровненных массивах. Да и DMA работать не должно на невыровненных массивах.
wmakc
Как использовать memcpy для копирования из массива char в int? а то когда копировал, получалось что char просто записывается в каждый байт int.
тоесть если в char {0xAB, 0xFA, 0xFF, 0x01}
то один int получится 0xABFAFF01, а
мне нужно чтобы было 0x000000AB, 0x000000FA и т.д. Пробовал объявлять char c __align. Результата не дало
AlexandrY
Цитата(wmakc @ Aug 22 2010, 14:26) *
Как использовать memcpy для копирования из массива char в int? а то когда копировал, получалось что char просто записывается в каждый байт int.
тоесть если в char {0xAB, 0xFA, 0xFF, 0x01}
то один int получится 0xABFAFF01, а
мне нужно чтобы было 0x000000AB, 0x000000FA и т.д. Пробовал объявлять char c __align. Результата не дало


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

Скажу коротко: memcpy для такого переноса данных не подойдет.
wmakc
Да я вроде как новичек, так что если перенесут, то не страшно, главное что ответили на вопрос.
aaarrr
Цитата(wmakc @ Aug 22 2010, 14:34) *
Пробовал в sdram, результата не дало

Как пробовали и что именно получили?

Цитата(wmakc @ Aug 22 2010, 15:26) *
Как использовать memcpy для копирования из массива char в int? а то когда копировал, получалось что char просто записывается в каждый байт int.
тоесть если в char {0xAB, 0xFA, 0xFF, 0x01}
то один int получится 0xABFAFF01, а
мне нужно чтобы было 0x000000AB, 0x000000FA и т.д.

Так это уже не копирование совсем, а перепаковка данных. Ее придется сделать руками.
wmakc
указал в качестве адреса pTranslationTable указать 0x20040000. Также как и до этого программа дальше InitMMU не работала( хотя возможно и нет, нужно проверить под отладчиком).
aaarrr
Перед инициализацией MMU следует запретить и инвалидировать ICache.
etoja
Цитата(wmakc @ Aug 21 2010, 18:20) *
Делаю jpeg кодер для сжатия raw картинки с матрицы mt9d131. Картинка сжимается примерно за 3 секунды. Для такого контроллера это нормально?


Нормально, учитывая, что картинка цветная и её размер 1600х1200.
aaarrr
Цитата(etoja @ Aug 23 2010, 11:39) *
Нормально, учитывая, что картинка цветная и её размер 1600х1200.


Цитата(wmakc @ Aug 21 2010, 18:20) *
Картинка около 600 килобайт.

wmakc
картинка 640 на 480, цветная. Хотелось бы чтобы за секунду смог сжать.

Попробовал проверить инициализацию MMU через отладчик, все вроде проходит нормально. Но дальше уже ничего толком не работает. Не могу объяснить пока что именно, так как с отладчиком не работает TWI, и матрица не запускается, поэтому думаю нужно сделать отдельный проект и уже там вести отладку
aaarrr
Цитата(wmakc @ Aug 23 2010, 20:54) *
...думаю нужно сделать отдельный проект и уже там вести отладку

Вот это правильно. Задвиньте пока JPEG и разберитесь с процессором и его периферией.
andrewlekar
Да и 3 секунды для такой картинки это много. У меня оцифровка, ресайз и сжатие занимала без кэширования порядка секунды. С кэшированием насколько я помню около 0,3 секунды. Ну и простор для оптимизации ещё очень большой. Процессор AT91SAM9260.
etoja
Камера mt9d131 может выдавать картинку сразу в формате JPEG. Так зачем мучаться?
wmakc
Цитата(etoja @ Aug 24 2010, 10:54) *
Камера mt9d131 может выдавать картинку сразу в формате JPEG. Так зачем мучаться?


Будет использоваться еще одна матрица и у нее нет сжатия jpeg, поэтому и нужно было реализовать кодек в контроллере. С возможностью матрицы выводить jpeg тоже нужно будет разобраться


Цитата(andrewlekar @ Aug 24 2010, 08:40) *
Да и 3 секунды для такой картинки это много. У меня оцифровка, ресайз и сжатие занимала без кэширования порядка секунды. С кэшированием насколько я помню около 0,3 секунды. Ну и простор для оптимизации ещё очень большой. Процессор AT91SAM9260.


С кешированием и MMU я вроде как разобрался, теперь сжимает за пол секунды. А оптимизировать нужно функцию дисретного косинусного преобразования и квантования. Пока не знаю как
wmakc
Если есть еще какие - то способы по улучшению быстродействия, или возможности ускорить jpeg, напишите, попробую реализовать.

Сейчас пытаюсь разобраться с матрицей mt9v136. В даташите написано, что на нее нужно подавать частоту 27 МГц, а эта частота считается из PLLA, как бы мне PLLA настроить так чтобы получить кратную 27? Понимаю, что возможно это просто, но до этого такой необходимости не было, поэтому еще не разобрался
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.