|
CRC в IAR, не совпадает с программным расчетом |
|
|
|
Jun 18 2013, 10:20
|
Участник

Группа: Участник
Сообщений: 56
Регистрация: 18-11-07
Из: Москва
Пользователь №: 32 424

|
Здравствуйте! Использую IAR для AVR версии 6.3.3.1990 МК xmega32D4. Для написания бутлоадера необходимо подсчитывать CRC прошивки. Хочу это сделать средствами линкера. Прописываю в настройках:
Рассчитываю программно в соответствии с документацией на линкер IAR CODE unsigned long ChecksumStart = 0x0000; unsigned long ChecksumEnd = 0x8FFD; ... unsigned short slow_crc16(unsigned short sum, unsigned char *p,unsigned int len) { while (len--) { int i; unsigned char byte = *(p++); for (i = 0; i < 8; ++i) { unsigned long osum = sum; sum <<= 1; if (byte & 0x80) sum |= 1; if (osum & 0x8000) sum ^= 0x1021; byte <<= 1; } } return sum; } ... unsigned short calc = 0; // Run the checksum algorithm calc = slow_crc16(0, (unsigned char *) ChecksumStart,(ChecksumEnd - ChecksumStart+1)); // Rotate out the answer unsigned char zeros[2] = {0, 0}; calc = slow_crc16(calc, zeros, 2); ...
Результат как программного расчета, так и линкером отправляю в com порт. Они не совпадают. И программный расчет не постоянен: при передергивании питания значение меняется. P.S. Видела подобные проблемы и их обсуждения на форуме, но не поняла, есть ли решение
Сообщение отредактировал Мария Е - Jun 18 2013, 11:16
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
|
|
|
|
|
Feb 1 2014, 08:14
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Привет всем! Столкнулся с похожей проблемой. IAR 6.12.1, МК ATxmega64A3U. Линкер CRC генерит и ложит в конец прошивки, вроде все собирается верно. Вот выдержка из MAP-файла: Код SEGMENT SPACE START ADDRESS END ADDRESS SIZE TYPE ALIGN ======= ===== ============= =========== ==== ==== ===== INTVEC CODE 00000000 - 000001FB 1FC com 1 ?FILL1 CODE 000001FC - 000001FF 4 rel 0 NEAR_F CODE 00000200 - 00000218 19 rel 0 NEAR_F CODE 00000219 - 00000675 45D rel 0 SWITCH CODE 00000676 - 000007DF 16A rel 1 CODE CODE 000007E0 - 0000558B 4DAC rel 1 <FAR_F> 1 CODE 0000558C - 00005F12 987 rel 0 INITTAB CODE 00005F13 - 00005F20 E rel 0 NEAR_ID CODE 00005F21 - 00006122 202 rel 0 ?FILL2 CODE 00006123 - 0000FFFD 9EDB rel 0 CHECKSUM CODE 0000FFFE - 0000FFFF 2 rel 0 ABSOLUTE DATA 00000020 rel 0 DATA 00000034 DATA 000001C0 DATA 00001000 - 000011A0 1A1 DATA 000011C0 - 00001360 1A1 DATA 00001380 - 00001381 2 NEAR_I DATA 00002000 - 00002201 202 rel 0 NEAR_Z DATA 00002202 - 00002B81 980 rel 1 RSTACK DATA 00002B82 - 00002BC1 40 dse 0 CSTACK DATA 00002BC2 - 00002DC1 200 dse 0 Symbol Checksum Memory Start End Initial value ------ -------- ------ ----- --- ------------- __checksum 0x3286 CODE 00000000 - 0000FFFD 0x0000 (#0x0000) Алгоритм брал и из примеров в документации на линкер, и из атмеловских аппноутов и свой, давно используемый код - результат один - подсчитанная программой CRC не совпадает с той, что посчитал линкер... Написал приложение по Win, которая считает CRC файла прошивки - подсчитанная приложением CRC сходится!!! Подозреваю, что проблема в моем коде, но вроде все просто и очевидно. В общем бревна в глазу не вижу... Привожу код функции: CODE crc = 0; while (len--) { unsigned char i; unsigned char byte = *data++; for (i = 0; i < 8; ++i) { unsigned long osum = crc; crc <<= 1; if(byte & 0x80) crc |= 1; if (osum & 0x8000) crc ^= 0x1021; byte <<= 1; } } return crc;
И листинг: CODE 237 crc = 0; \ 00000006 E080 LDI R24, 0 \ 00000008 E090 LDI R25, 0 \ 0000000A 2F04 MOV R16, R20 \ 0000000C 2B05 OR R16, R21 \ 0000000E 2B06 OR R16, R22 \ 00000010 2B07 OR R16, R23 \ 00000012 F0E1 BREQ ??BOARD_CRC16_MakeF_0 \ 00000014 018A MOVW R17:R16, R21:R20 \ 00000016 019B MOVW R19:R18, R23:R22 238 239 while (len--) 240 { 241 unsigned char i; 242 unsigned char byte = *data++; \ ??BOARD_CRC16_MakeF_1: \ 00000018 9175 LPM R23, Z+ 243 244 for (i = 0; i < 8; ++i) \ 0000001A E068 LDI R22, 8 \ 0000001C 5001 SUBI R16, 1 \ 0000001E 4010 SBCI R17, 0 \ 00000020 4020 SBCI R18, 0 \ 00000022 4030 SBCI R19, 0 \ 00000024 E241 LDI R20, 33 \ 00000026 E150 LDI R21, 16 245 { 246 unsigned long osum = crc; \ ??BOARD_CRC16_MakeF_2: \ 00000028 2E19 MOV R1, R25 247 crc <<= 1; \ 0000002A 0F88 LSL R24 \ 0000002C 1F99 ROL R25 248 if(byte & 0x80) \ 0000002E FB77 BST R23, 7 \ 00000030 F40E BRTC ??BOARD_CRC16_MakeF_3 249 crc |= 1; \ 00000032 6081 ORI R24, 0x01 250 if (osum & 0x8000) \ ??BOARD_CRC16_MakeF_3: \ 00000034 FE17 SBRS R1, 7 \ 00000036 C002 RJMP ??BOARD_CRC16_MakeF_4 251 crc ^= 0x1021; \ 00000038 2784 EOR R24, R20 \ 0000003A 2795 EOR R25, R21 252 byte <<= 1; \ ??BOARD_CRC16_MakeF_4: \ 0000003C 0F77 LSL R23 253 } \ 0000003E 956A DEC R22 \ 00000040 F799 BRNE ??BOARD_CRC16_MakeF_2 254 } \ 00000042 2F40 MOV R20, R16 \ 00000044 2B41 OR R20, R17 \ 00000046 2B42 OR R20, R18 \ 00000048 2B43 OR R20, R19 \ 0000004A F731 BRNE ??BOARD_CRC16_MakeF_1 255 return crc; \ ??BOARD_CRC16_MakeF_0: \ 0000004C 018C MOVW R17:R16, R25:R24 \ 0000004E 2D80 MOV R24, R0 \ 00000050 2D93 MOV R25, R3 \ 00000052 9508 RET
--------------------
|
|
|
|
|
Feb 1 2014, 08:38
|

Профессионал
    
Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409

|
Код Алгоритм брал и из примеров в документации на линкер, и из атмеловских аппноутов и свой, давно используемый код - результат один - подсчитанная программой CRC не совпадает с той, что посчитал линкер... Написал приложение по Win, которая считает CRC файла прошивки - подсчитанная приложением CRC сходится!!! Подозреваю, что проблема в моем коде, но вроде все просто и очевидно. В общем бревна в глазу не вижу... Я вот таким кодом пользовался. В конце результат инвертировал чтобы совпадало с тем, что вычисляет линкер. CODE /* Name : CRC-16 Poly : 0x1021 1000000100001 x^12 + x^5 + 1 Init : 0x0000 */ #define POLY 0x1021 //полином для вычисления crc16 памяти программ
//функция вычисления CRC-16 памяти программ AVR прямым методом //перед возвратом результат инвертируется unsigned int crc16_slow(unsigned int *pData, unsigned int size) { unsigned int crc16_result = 0; //создаём результат вычисления, начальное значение = 0 while(size--) { crc16_result ^= *pData++; for (unsigned char j = 0; j < 16; j++) { crc16_result = crc16_result & 0x8000 ? (crc16_result << 1) ^ POLY : crc16_result << 1; } } return ~crc16_result; //возвращаем инверсное значение }
|
|
|
|
|
Feb 1 2014, 08:54
|

Профессионал
    
Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409

|
Цитата(prottoss @ Feb 1 2014, 12:43)  Да дело то вроде не в алгоритме, т.к. тот же код на РС подсчитывает CRC верно! В линкере корректно расположен сегмент для CRC16? Код -Z(CODE)CHECKSUM=(_..X_CRC_FLASH_END-1)-_..X_CRC_FLASH_END //тут располагается сегмент crc16 - 2 последних байта памяти -J2,crc16,1//=(CODE)1E004-1E00b //а это ключ линкера для вычисления crc16 по области (CODE)0-(_..X_CRC_FLASH_END-2) Не хочу вводить в заблуждение т.к. проект старый и я уже не помню подробностей, но вроде как результат вычисления crc по приведённому ранее коду совпадал с тем, что вычисляет линкер. Я использовал заполнение неиспользованной памяти 0xff.
|
|
|
|
|
Feb 1 2014, 09:06
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Уважаемый mempfis_ Вы похоже не весь мой первый пост прочитали или не поняли меня. CRC располагается в конце файла прошивки по двум последним адресам - 0xFFFE - 0xFFFF. Я показывал кусок MAP-файла: Код CHECKSUM CODE 0000FFFE - 0000FFFF 2 rel 0 Сама CRC считается для области 0-FFFD включительно: Код Symbol Checksum Memory Start End Initial value ------ -------- ------ ----- --- ------------- __checksum 0xab3a CODE 00000000 - 0000FFFD 0x0000 (#0x0000) Программа, написанная мной для Windows, открывает файл прошивки считает CRC от 0 до FFFD и сравнивает с тем, что лежит по адресам FFFE - FFFF. Все сходится. Тем же алгоритмом считаю CRC в программе - не сходится!
--------------------
|
|
|
|
|
Feb 1 2014, 09:17
|

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

|
Цитата(prottoss @ Feb 1 2014, 11:06)  Программа, написанная мной для Windows, открывает файл прошивки считает CRC от 0 до FFFD Там есть две интересные области: Код ?FILL1 CODE 000001FC - 000001FF 4 rel 0 ?FILL2 CODE 00006123 - 0000FFFD 9EDB rel 0 Линкер при расчете думает, что они заполнены нулями. В прошивке этих областей нет и они остаются заполненными 0xFFFF. Вероятно ваша программа тоже знает, что в этих областях единицы. Отсюда и несовпадение. В свое время из-за этого отказался от расчета CRC линкером и считаю ее отдельной утилиткой.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Feb 1 2014, 10:26
|

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

|
Цитата(prottoss @ Feb 1 2014, 11:25)  Еще раз говорю - для проверки CRC написал программу на Borland Builder - она считает CRC прошивки - все совпадает! Читайте внимательно - предполагаю, что ваш файл прошивки описывает не всю область 0 - 0xFFFF. В нем есть "дыры", в частности отсутствует информация о содержимом адресов 6123-FFFD. Содержимое этих дыр в кристалле - стертая флеш, т.е. "все единицы". Линкер об этом не знает и считает, что содержимое пустых областей - нули. Поэтому результат вашего расчета не совпадает с результатом линкера. Я так думаю. Добавлено: все вышесказанное имеет смысл если формат файла прошивки - Intel HEX
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|