Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: xmega64a3u CRC-32
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
ffs2001
Господа, помогите советом:

хочу считать CRC-32 на указанном МК. Аппаратный модуль имеется.
Код использовал родной атмелевский отсюда и упрощённый вариант:

Код
CRC_CTRL |= CRC_CRC32_bm;
CRC.CTRL |= CRC_SOURCE_IO_gc;
        
for (n = 0; n < 32; n++){            
    
    CRC.DATAIN = test[n]; // send data
}
        
CRC.STATUS |= CRC_BUSY_bm; // finish
while (CRC_STATUS & CRC_BUSY_bm == CRC_BUSY_bm);

itoa(CRC.CHECKSUM3,str);
puts_usf0(str);
//и так далее


Сам модуль работает, но выдаёт неверные данные.
Проверял вот этим калькулятором.
Полиномы совпадают, в даташите есть описание. В эррате ничего.
Тестовый массив: uint8_t[32] = {0xFF}

ЧЯДНТ?
Xenia
Цитата(ffs2001 @ Dec 3 2014, 23:04) *
[code]CRC_CTRL |= CRC_CRC32_bm;
CRC.CTRL |= CRC_SOURCE_IO_gc;
Сам модуль работает, но выдаёт неверные данные.


Возможно, вы забыли сделать обнуление перед накоплением.

CRC_CTRL = CRC_CRC32_bm | CRC_SOURCE_IO_gc;
CRC_CTRL |= CRC_RESET_RESET0_gc; // Reset CRC with CHECKSUM to all zeros

P.S. И вот еще:
надо вызывать функцию
ltoa(CRC.CHECKSUM3,str);
вместо
itoa(CRC.CHECKSUM3,str);
Т.к. int у XMega 16-битный.
CRC32 тогда long, а не int.
ffs2001
Цитата(Xenia @ Dec 3 2014, 23:34) *
Возможно, вы забыли сделать обнуление перед накоплением.

CRC_CTRL = CRC_CRC32_bm | CRC_SOURCE_IO_gc;
CRC_CTRL |= CRC_RESET_RESET0_gc; // Reset CRC with CHECKSUM to all zeros


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

_Артём_
Цитата(ffs2001 @ Dec 4 2014, 14:55) *
Да, в атмелевском драйвере это есть.

Драйвер неправильный (или может его исправили?).

Попробуйте такой код, он вроде работал:
Код
uint32_t Crc32(uint8_t * data, uint16_t data_size, bool init_zero, uint32_t xor_value)
{

    CRC.CTRL=0
        | init_zero ? (CRC_RESET_RESET0_gc) : (CRC_RESET_RESET1_gc)
        | 1<<CRC_CRC32_bp
        | CRC_SOURCE_IO_gc
    ;
    CRC.CTRL=0
        | CRC_RESET_NO_gc
        | 1<<CRC_CRC32_bp
        | CRC_SOURCE_IO_gc
    ;
    CRC.STATUS=1<<CRC_BUSY_bp;    
    uint8_t byte_counter=0;
    for (uint8_t i=0; i<data_size; i++)
        CRC.DATAIN=*data++;

    uint32_t crc=*(volatile uint32_t *)&CRC.CHECKSUM0;
    crc^=xor_value;
    return crc;
}


typedef dma_channel<'0'> Dma0;
uint32_t CrcDma(uint8_t * data, bool init_zeros, uint16_t length)
{
    CRC.CTRL=0
        | init_zeros ? CRC_RESET_RESET1_gc : CRC_RESET_RESET0_gc
        | 1<<CRC_CRC32_bp
        | CRC_SOURCE_DMAC0_gc
    ;
    CRC.CTRL=0
        | CRC_RESET_NO_gc
        | 1<<CRC_CRC32_bp
        | CRC_SOURCE_DMAC0_gc
    ;
    Dma0::ResetChannel();
    Dma0::SetSrcAddress((uint16_t)data);
    Dma0::SetDestAddress((uint16_t)data);
    Dma0::SetAddressControl(DMA_CH_SRCRELOAD_NONE_gc, DMA_CH_SRCDIR_INC_gc, DMA_CH_DESTRELOAD_NONE_gc, DMA_CH_DESTDIR_INC_gc);
    Dma0::SetTransferSize(length);
    Dma0::SetTriggerSource(DMA_CH_TRIGSRC_OFF_gc);
    Dma0::StartRamToRamTransfer(DMA_CH_BURSTLEN_8BYTE_gc);

    while (Dma0::TransferComplete()==false);

    uint32_t crc = *(uint32_t *)&CRC.CHECKSUM0;

    return crc;
}

В драйвере не было вроде такой строки (функция Crc32):
Код
CRC.STATUS=1<<CRC_BUSY_bp;

С ДМА как ни странно работало без проблем.
ffs2001
Так, проблема, похоже, не в контроллере.
В этом калькуляторе получается то же значение, что выдаёт мой контроллер. Проблема в том, что в него я скопировал полином из этого калькулятора, где получается другое значение (с этим полиномом). Это, как говорится, какое-то фуфло; но бедная иксмега не при чём.
Когда разберусь с полиномами, отпишу, в чём соль.

Цитата(_Артём_ @ Dec 4 2014, 15:18) *
Драйвер неправильный (или может его исправили?).


Мда, печально.
Расскажите подробнее, если не затруднит.


Цитата(_Артём_ @ Dec 4 2014, 15:18) *
В драйвере не было вроде такой строки (функция Crc32):
Код
CRC.STATUS=1<<CRC_BUSY_bp;

С ДМА как ни странно работало без проблем.


Да, уже обрабатывал этот момент; это единственная ошибка в драйвере?
_Артём_
Цитата(ffs2001 @ Dec 4 2014, 15:32) *
Мда, печально.
Расскажите подробнее, если не затруднит.

Рассказывать-то и нечего: есть стандартная функция расчёта CRC
Код
/*
  Name  : CRC-32
  Poly  : 0x04C11DB7    x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11
                       + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
  Init  : 0xFFFFFFFF
  Revert: true
  XorOut: 0xFFFFFFFF
  Check : 0xCBF43926 ("123456789")
  MaxLen: 268 435 455 байт (2 147 483 647 бит) - обнаружение
   одинарных, двойных, пакетных и всех нечетных ошибок
*/
uint_least32_t Crc32Soft(uint8_t *buf, size_t len, uint32_t init_value)
{
    uint_least32_t crc_table[256];
    uint_least32_t crc; int i, j;

    for (i = 0; i < 256; i++)
    {
        crc = i;
        for (j = 0; j < 8; j++)
            crc = crc & 1 ? (crc >> 1) ^ 0xEDB88320UL : crc >> 1;

        crc_table[i] = crc;
    };

    crc = init_value;

    while (len--)
        crc = crc_table[(crc ^ *buf++) & 0xFF] ^ (crc >> 8);

    return crc ^ 0xFFFFFFFFUL;
}

Результат CRC32 который выдаёт модуль xmega не совпадает с ним для CRC32.


Цитата(ffs2001 @ Dec 4 2014, 15:32) *
это единственная ошибка в драйвере?

Я драйвер подробно не рассматривал, смотрел пример который шёл вместе со AtmelStudio. И в примере результат неправильный получается.

Цитата(ffs2001 @ Dec 4 2014, 15:32) *
драйвере?

Да в общем-то тут и драйвер-то не нужен - там весь модуль 3 регистра. Самому проще написать.
ffs2001
Цитата(_Артём_ @ Dec 4 2014, 15:43) *
Рассказывать-то и нечего: есть стандартная функция расчёта CRC


Благодарю!


В общем, CRC-модуль, похоже, рабочий. Теперь (немного в сторону от темы) ситуация получилась такая:

модуль xmega и вот этот калькулятор выдают одинаковое значение;

библиотека CRC-32 для VS (PC) и вот этот калькулятор тоже выдают одинаковое значение, но другое!

Полином везде один и тот же. Видимо, под конец они как-то хитро XOR-ятся или ещё что...
Тестовое значение (hex) 940C.

Буду очень рад, если кто-нибудь объяснит, как так происходит.

_Артём_
Цитата(ffs2001 @ Dec 4 2014, 16:53) *
Полином везде один и тот же.

Возможно они инициализируют crc перед началом подсчёта нулями, а вы единицами. Или наоборот.
Попробуйте посчитать CRC по функции из сообщения 6.
Код
    uint8_t Test10[10]={1,2,3,4,5,6,7,8,9,10};
    volatile uint32_t soft_crc[2];
    soft_crc[0]=Crc32Soft(Test, sizeof(Test), 0xFFFFFFFFUL);
    soft_crc[1]=Crc32Soft(Test, sizeof(Test), 0);

ffs2001
Результаты работы приведённого кода идентичны результатам библиотеки для PC (собственно, и код идентичен).

Крайне смущает совпадение результатов из xmega'вского генератора с другим калькулятором.
Хочу использовать hardware генератор, т.к. нужно считать CRC app-table из бутлодера.

Буду копать дальше.
_Артём_
Цитата(ffs2001 @ Dec 4 2014, 18:24) *
Хочу использовать hardware генератор, т.к. нужно считать CRC app-table из бутлодера.

Тогда лучше использовать подсчёт CRC через команду NVM-контроллера Flash range CRC - оно само подсчитает.
ffs2001
Цитата(_Артём_ @ Dec 4 2014, 18:35) *
Тогда лучше использовать подсчёт CRC через команду NVM-контроллера Flash range CRC - оно само подсчитает.


Так будет использоваться тот же самый хардварный генератор. А он выдаёт не то.

Совпадение калькулятора и генератора, похоже, было случайным. Совпадают только значения, генерируемые из массива [32] = {0xFF}

Делаю вывод, что хардварный генератор нерабочий.
Странно, что этого нет в эррате.

При возможности проверю на другом контроллере, отпишусь.

Ещё интересный нюанс относительно приведённого в сообщении 6 кода:

Код
crc = crc & 1 ? (crc >> 1) ^ 0xEDB88320UL : crc >> 1;


Visual studio ругнулась тут на невозможность привести int к bool, и я ничтоже сумняшеся привёл код к виду

Код
for (j = 0; j < 8; j++)
                {
                    if ((crc & 1) == 1)
                    {
                        crc = (crc >> 1) ^ 0xedb88320u;
                    }
                    else
                    {
                        crc = (crc >>
                };

                crc_table[i] = crc;


тем более что так это реализовано в библиотеке, которую я использовал для PC.


Компилятор для Атмеги (работаю в CVAVR) на эту строку не ругнулся.
Но если не привести код к тому же виду, результат получается РАЗНЫЙ.
_Артём_
Цитата(ffs2001 @ Dec 4 2014, 19:58) *
Так будет использоваться тот же самый хардварный генератор. А он выдаёт не то.

То он выдаёт.

Цитата(ffs2001 @ Dec 4 2014, 19:58) *
Совпадение калькулятора и генератора, похоже, было случайным. Совпадают только значения, генерируемые из массива [32] = {0xFF}

Ну да,случайность...
У меня при входных данных из комментария к функции
Цитата
/*
Name : CRC-32
Poly : 0x04C11DB7 x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11
+ x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
Init : 0xFFFFFFFF
Revert: true
XorOut: 0xFFFFFFFF
Check : 0xCBF43926 ("123456789")
MaxLen: 268 435 455 байт (2 147 483 647 бит) - обнаружение
одинарных, двойных, пакетных и всех нечетных ошибок
*/

результат получался всеми тремя способами одинаковый - 0xCBF43926. Случайно...
Проверял в симуляторе - плату лень искать. На PC не проверял - не нашёл реализацию.

Цитата(ffs2001 @ Dec 4 2014, 19:58) *
Делаю вывод, что хардварный генератор нерабочий.
Странно, что этого нет в эррате.

Описан он в мануале как-то криво. Но работает.

Цитата(ffs2001 @ Dec 4 2014, 19:58) *
При возможности проверю на другом контроллере, отпишусь.

У меня проверялось в atxmega256A3U

Цитата(ffs2001 @ Dec 4 2014, 19:58) *
Компилятор для Атмеги (работаю в CVAVR) на эту строку не ругнулся.
Но если не привести код к тому же виду, результат получается РАЗНЫЙ.

Вот проект для GCC:
Нажмите для просмотра прикрепленного файла
ffs2001
Проверил на двух 64ых, результаты разные для hard и soft в обоих случаях. Правильное значение выдаёт soft.
Очень странно.
_Артём_
Цитата(ffs2001 @ Dec 5 2014, 12:46) *
результаты разные для hard и soft в обоих случаях.
Очень странно.

Проверил на xmega256A3U - hard, soft и dma дают одинаковый результат.

Цитата(ffs2001 @ Dec 5 2014, 12:46) *
Проверил на двух 64ых

На двух? Тенденция , однако...Выложите проект, а вдруг и правда в 64х ошибка.
ffs2001
Проект для CVAVR 3.1 .
Скомпилированные ROM и HEX в Debug.
_Артём_
Цитата(ffs2001 @ Dec 8 2014, 13:12) *
Проект для CVAVR 3.1 .
Скомпилированные ROM и HEX в Debug.

Код такой же как у меня за исключением того что в STATUS.BUSY 1 пишется после вычисления, но это может и не важно.

Попробуйте написать проще (вдруг это CV глючит):
Код
uint32_t Crc32(uint8_t * data, uint16_t data_size)
{

    CRC.CTRL=0
        | CRC_RESET_RESET1_gc
        | 1<<CRC_CRC32_bp
        | CRC_SOURCE_IO_gc
;
    CRC.CTRL=0
        | CRC_RESET_NO_gc
        | 1<<CRC_CRC32_bp
        | CRC_SOURCE_IO_gc
;
    CRC.STATUS=1<<CRC_BUSY_bp;

    for (uint16_t i=0; i<data_size; i++)
        CRC.DATAIN=*data++;
    uint32_t crc=*(volatile uint32_t *)&CRC.CHECKSUM0;
    crc^=0xFFFFFFFFUL;
    return crc;
}


P.S. Загрузил ваш проект в xm256 - получилось что у вас блок CRC инициализирует CRC не единицами, а нулями.
То есть CV почему-то не понимает такое выражение:
Код

    CRC.CTRL=0
        | init_zero ? (CRC_RESET_RESET0_gc) : (CRC_RESET_RESET1_gc)
        | 1<<CRC_CRC32_bp
        | CRC_SOURCE_IO_gc
;

Вместо 0xE1 в CRC.CTRL пишется 0x80.
Duhas
1<<CRC_CRC32_bp должно быть эквивалентно CRC_CRC32_bm, так на всякий.
_Артём_
Цитата(Duhas @ Dec 8 2014, 18:28) *
1<<CRC_CRC32_bp должно быть эквивалентно CRC_CRC32_bm, так на всякий.

Так и есть - они эквивалентны.
ffs2001
Цитата(_Артём_ @ Dec 8 2014, 16:06) *
P.S. Загрузил ваш проект в xm256 - получилось что у вас блок CRC инициализирует CRC не единицами, а нулями.
То есть CV почему-то не понимает такое выражение:
Код

    CRC.CTRL=0
        | init_zero ? (CRC_RESET_RESET0_gc) : (CRC_RESET_RESET1_gc)
        | 1<<CRC_CRC32_bp
        | CRC_SOURCE_IO_gc
;

Вместо 0xE1 в CRC.CTRL пишется 0x80.



Действительно, замена этого куска на такой код:

Код
    
CRC.CTRL=0;
if (init_zero) {
        
        CRC.CTRL |= CRC_RESET_RESET0_gc;
} else {
        CRC.CTRL |= CRC_RESET_RESET1_gc;
}
    
CRC.CTRL |= 1<<CRC_CRC32_bp;
СRC.CTRL |= CRC_SOURCE_IO_gc;


привела к правильному результату вычислений.

Артём, спасибо!

P.S. Честно говоря, раньше практически не встречал кода, сформированного таким, как в вашей библиотеке, образом. Удивился, когда CVAVR его переварил даже без warning'ов. Видимо, не зря CVAVR ругают.
Genadi Zawidowski
Как я помню, в языке "C" у тернарной операции (?:) приоритет ниже всех. Ниже только у запятой. Скобок надо добавить в
Код
CRC.CTRL=0
        | init_zero ? (CRC_RESET_RESET0_gc) : (CRC_RESET_RESET1_gc)
        | 1<<CRC_CRC32_bp
        | CRC_SOURCE_IO_gc


вот так
Код
CRC.CTRL=0
        | (init_zero ? CRC_RESET_RESET0_gc : CRC_RESET_RESET1_gc)
        | 1<<CRC_CRC32_bp
        | CRC_SOURCE_IO_gc
_Артём_
Цитата(Genadi Zawidowski @ Dec 9 2014, 00:51) *
Как я помню, в языке "C" у тернарной операции (?sm.gif приоритет ниже всех. Ниже только у запятой. Скобок надо добавить в

Может быть, скобки никогда не помешают. Но как же тогда результат получается правильным (пробовал на IAR и GCC)?
ffs2001
Артём,

кстати, а каким эмулятором контроллера пользуетесь?
_Артём_
Цитата(ffs2001 @ Dec 9 2014, 22:54) *
кстати, а каким эмулятором контроллера пользуетесь?

Сейчас пользуюсь или AVR Dragon (худший из всех аппаратных отладчиков) или просто симулятором AtmelStudio (CRC или AES/DES считает правильно, но очень медленно). Раньше пользовался JTAG ICE - JTAG ICE 2 (самый лучший из всех) - JTAG ICE 3.
У Atmel-а сейчас какие-то новые отладчики появились (дешёвые совсем), но ими не пользовался - про них ничего сказать не могу.
Genadi Zawidowski
Ваш вариант
Код
CRC.CTRL=0
        | init_zero ? (CRC_RESET_RESET0_gc) : (CRC_RESET_RESET1_gc)
        | 1<<CRC_CRC32_bp
        | CRC_SOURCE_IO_gc


Вычисляется вот так:
Код
CRC.CTRL=(0 | init_zero) ? (CRC_RESET_RESET0_gc) : ((CRC_RESET_RESET1_gc) | 1<<CRC_CRC32_bp | CRC_SOURCE_IO_gc)


Если не init_zero, то правильно.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.