Jump to content

    

uni

Участник
  • Content Count

    68
  • Joined

  • Last visited

Community Reputation

0 Обычный

About uni

  • Rank
    Участник
  • Birthday 06/30/1980

Старые поля

  • Facebook
    Array
  • Vkontakte
    Array

Контакты

  • Сайт
    Array
  • ICQ
    Array

Информация

  • Город
    Array

Recent Profile Visitors

981 profile views
  1. Функция Сrc16Optim(): 36 команд или 72 байта.
  2. Это очень просто прикинуть для avr8. Судя по картинке с кодом для этого метода там используется около 45 инструкций. Это 90 байт для этой архитектуры, что значительно меньше размера таблицы и обслуживающего его кода. Этот метод вполне может называться оптимальным для avr8. В avr почти все инструкции (опкоды) двухбайтовые, кроме некоторых исключений.
  3. Попробовал ещё раз. Видимо что-то не так сделал в первый и был не внимателен. Теперь всё сошлось, код прилагаю. Итак, полином 0xA001, CRC16/MODBUS, результат для строки "123456789" равен 0#4B37. Для ATmega16 @ 16 МГц имеем: Table - 12.9 мкс (таблица 512 байт) Optim - 17.3 мкс (без таблицы) Simple - 20.0 мкс (без таблицы) Cycle - 52.4 мкс (без таблицы) Т.е. алгоритм из библиотеки avrlibc действительно быстрее и самый близкий по времени к табличному методу расчёта. crc16-modbus.pdf
  4. Для полинома 0x1021 теперь уже 4 варианта: https://godbolt.org/z/ja9Lwq Для проверки используется строка "123456789", которая имеет crc = 0x29B1. Для avr8 чуда не произошло, но алгоритм GetCrc16Optim() оказался быстрее моего самого первого варианта и быстрее двойного цикла: Table - 13.9 мкс (таблица 512 байт) Optim - 22.9 мкс (без таблицы) Simple - 24.6 мкс (без таблицы) Cycle - 51.3 мкс (без таблицы)
  5. Надо добавить, что алгоритм не только полиномом отличаются между собой, но и порядком работы с битами. В результате чего могут применятся те же, но инвертированные полиномы (0xA001 <-> 0x8005. 0x1021 <-> 0x8408). Код на асме для avr в avrlibc не содержит переходов, насколько я вижу, поэтому это не двойной цикл. Теоретически он должен быть быстрее обсуждаемой в теме реализации, но не ясно почему он на стандартной строке показал другой результат.
  6. К сожалению, результат не совпал с табличным вариантом и с предыдущим моим двойным циклом с полиномом 0xA001. В любом случае этот алгоритм гораздо медленнее приведённого мной варианта, т.к. также использует двойной цикл, судя по эквивалентным с-кодам, приведённым в документации. Сам асм-код не разбирал. Optimized CRC-16 calculation. Polynomial: x^16 + x^15 + x^2 + 1 (0xa001)<br> Initial value: 0xffff This CRC is normally used in disk-drive controllers. The following is the equivalent functionality written in C. \code uint16_t crc16_update(uint16_t crc, uint8_t a) { int i; crc ^= a; for (i = 0; i < 8; ++i) { if (crc & 1) crc = (crc >> 1) ^ 0xA001; else crc = (crc >> 1); } return crc; }
  7. Вот последний вариант: https://godbolt.org/z/9txEB2
  8. Интересная сопутствующая тема: ARM, 32bit - CRC32
  9. Покажите пример псевдокода или кода на каком-нибудь c-подобном языке. Чем больше примеров, тем лучше.
  10. Вы не знакомы с архитектурой avr, как я вижу, иначе не предлагали бы засунуть таблицу в ОЗУ. Это мелкий камень и ОЗУ там на вес золота. Я специально привёл пример для ATmega16, т.к. это "отъест" 50% от общего объёма. Лично я занялся этой темой с avr, т.к. хочу сделать на базе arduino простую плату для демонстрации возможностей среды SimInTech в плане генерации кода. Там есть пример для Миландра, но в здравом уме никто в этом разбираться не будет. Порог вхождения гораздо больше. SimInTech - это что-то вроде нашего Simulink'а. Если я сделаю то, что хочу, то смогу "рисовать" алгоритмы и загружать их в целевую систему мимо стадии программирования. Это вот то к чему всё идёт. Программист - он для этих целей вообще лишний. Нарисовал схему автоматизации, залил в железку, отлаживаешь на уровне сигналов и понятия не имеешь об архитектуре железа. Проект в этом случае получается портируемым под другую железку без переписывания схемы и документации. Нужно сделать только так называемую "адаптацию", где и нужны программисты. Arduino для этих целей вообще замечательная простая штука. Я бы хотел только, чтобы не только Mega2560 вариант работал, но и меньшие собратья, а для этого нужно экономно сделать "адаптацию". Там применяется расчёт crc16 табличным способом, а меня это не устроило. Вот и появилась эта тема. Если хотите предложить arm'ы для этих целей :) - флаг в руки, адаптируйте по аналогии с Миландром. Я не говорю, что они не подойдут, просто этого уже на коленке не сделать, как я балуюсь.
  11. Некоторым людям нужно ехать, а не шашечки. Я же приводил пример из темы про DDS. Ну не нУжно ему arm'ов. В столе лежала ATmega8535 и девайс завёлся с полпинка от другой прошивки. Пусть пользуется на здоровье. Чем мог, тем помог. Я бы ещё туда вставил, как говорил, обновление таблицы сигналов через modbus-rtu, тем более, что это, похоже, можно сделать прямо из терминала скриптом. Если бы также arm лежал, то помог бы там другой товарищ.
  12. Вот, проверил (ATmega16 @ 16 МГц, полином 0xA001 (modbus)): Данные: "123456789" Ключ: -O1 GetCrc16Table() - 13.3 мкс GetCrc16Simple() - 20.0 мкс GetCrc16Cycle() - 57.5 мкс Данные: массив, размером 256 байт Ключ: -O1 GetCrc16Table() - 0.35 мсек GetCrc16Simple() - 0.53 мсек GetCrc16Cycle() - 1.6 мсек crc16test.pdf Я работаю и с двух-ядерными (ARM+DSP) процами, что не мешает мне баловаться avr.
  13. В первой pdf выдаёт три одинаковых, во второй что-то сам сомневаюсь уже. Пытаюсь немного улучшить результат для последнего.
  14. Вот теперь больше на правду похоже. Переписал немного: Ключ: -Os GetCrc16Table() - 14.6 мкс (кушает 512 байт флеша) GetCrc16Simple() - 24.3 мкс <- наш случай GetCrc16Cycle() - 67.2 мкс Ключ: -O1 GetCrc16Table() - 13.9 мкс (кушает 512 байт флеша) GetCrc16Simple() - 23.3 мкс <- наш случай GetCrc16Cycle() - 57.5 мкс crc16test.pdf Ассемблерный код функции. Не знаю можно ли тут что-то придумать. GetCrc16Simple: 30e: 2f ef ldi r18, 0xFF ; 255 310: 3f ef ldi r19, 0xFF ; 255 312: fc 01 movw r30, r24 314: 68 0f add r22, r24 316: 79 1f adc r23, r25 318: e6 17 cp r30, r22 31a: f7 07 cpc r31, r23 31c: 51 f1 breq .+84 ; 0x372 <_Z14GetCrc16SimplePhj+0x64> 31e: 91 91 ld r25, Z+ 320: 92 27 eor r25, r18 322: 23 2f mov r18, r19 324: 39 2f mov r19, r25 326: 90 ff sbrs r25, 0 328: 04 c0 rjmp .+8 ; 0x332 <_Z14GetCrc16SimplePhj+0x24> 32a: 80 e4 ldi r24, 0x40 ; 64 32c: 28 27 eor r18, r24 32e: 82 e0 ldi r24, 0x02 ; 2 330: 38 27 eor r19, r24 332: 31 ff sbrs r19, 1 334: 03 c0 rjmp .+6 ; 0x33c <_Z14GetCrc16SimplePhj+0x2e> 336: 20 58 subi r18, 0x80 ; 128 338: 84 e0 ldi r24, 0x04 ; 4 33a: 38 27 eor r19, r24 33c: 32 ff sbrs r19, 2 33e: 02 c0 rjmp .+4 ; 0x344 <_Z14GetCrc16SimplePhj+0x36> 340: 89 e0 ldi r24, 0x09 ; 9 342: 38 27 eor r19, r24 344: 33 ff sbrs r19, 3 346: 02 c0 rjmp .+4 ; 0x34c <_Z14GetCrc16SimplePhj+0x3e> 348: 82 e1 ldi r24, 0x12 ; 18 34a: 38 27 eor r19, r24 34c: 34 ff sbrs r19, 4 34e: 02 c0 rjmp .+4 ; 0x354 <_Z14GetCrc16SimplePhj+0x46> 350: 84 e2 ldi r24, 0x24 ; 36 352: 38 27 eor r19, r24 354: 35 ff sbrs r19, 5 356: 02 c0 rjmp .+4 ; 0x35c <_Z14GetCrc16SimplePhj+0x4e> 358: 88 e4 ldi r24, 0x48 ; 72 35a: 38 27 eor r19, r24 35c: 36 ff sbrs r19, 6 35e: 02 c0 rjmp .+4 ; 0x364 <_Z14GetCrc16SimplePhj+0x56> 360: 80 e9 ldi r24, 0x90 ; 144 362: 38 27 eor r19, r24 364: 33 23 and r19, r19 366: c4 f6 brge .-80 ; 0x318 <_Z14GetCrc16SimplePhj+0xa> 368: 81 e0 ldi r24, 0x01 ; 1 36a: 28 27 eor r18, r24 36c: 80 e2 ldi r24, 0x20 ; 32 36e: 38 27 eor r19, r24 370: d3 cf rjmp .-90 ; 0x318 <_Z14GetCrc16SimplePhj+0xa> 372: c9 01 movw r24, r18 374: 08 95 ret
  15. Для полинома 0xA001 результат странный в тех же условиях: ATmega16 @ 16МГц. Тестовую программу прикрепил (pdf). Время расчёта строки "123456789": GetCrc16Cycle() - 67.2 мкс GetCrc16Table() - 97.1 мкс GetCrc16Simple() - 24.3 мкс <- наш случай Может быть что-то не так понял. Собирал с ключом -Os. crc16test.pdf P.S. В общем, там от ключа оптимизации и вида табличного алгоритма быстродействие зависит. Нужно найти самую оптимальную комбинацию. В тактах считать пока лень, т.к. нужно минимум по коду и быстродействию сначала найти.