Опытного эмбеддера не проведёшь! CH32V203, эта сука потребовала
барьера между сбросом модуля CRC подачей данных: CH32V203, тактовая ядра и HCLK ~77МГц (не предельная, в общем). Вот тут:
uint32_t CRC32calcBlock (uint32_t *Data, unsigned Length) { //Calculate CRC-32 value for a block of uint32_t words
CRC->CTLR = CRC_CTLR_RESET; //Reset CRC data register before computing new block check value
asm volatile ("NOP"); //A pause to let the CRC unint actually reset
for (unsigned WordIdx = 0; WordIdx < Length; WordIdx++) {
CRC->DATAR = Data[WordIdx];
}
return (CRC->DATAR);
}
Пришлось вставить NOP после установки CRC_CTLR_RESET.
В общем, дело было так: стадия проекта близка к финалу (я надеюсь). Вижу, что памяти хватает, а вот скорости никогда много не бывает. Поменял оптимизацию с Os на O3 (LTO всегда включено).
Так вот, у меня перестали проходить проверку только что записанные во флеш данные. Вычисление при записи - одно, вычисление при проверке по тем же данным - другое. Это два блока данных, последнее слово - CRC. Так вот, в первом случае в CRC писалось значение 3088948752, а при проверке во втором, CRC по первым четырём словам, было другое!

Пришлось смотреть ассемблер. Искать разницу. А разница была:
В первом случае, данные из 4 слов, подавались циклом и после CRC_CTLR_RESET, была команда выборки данных по индексу. И между сбросом и записью первого слова в CRC DATAR, проходила минимум одна команда. Работало.
Во втором случае, с неверным результатом, оптимизатор засунул весь пакет данных в регистры и развернул цикл. Так, что сразу за подачей CRC_CTLR_RESET, сразу следовала подача данных в CRC->DATAR. И это ломало работу модуля.
Когда была оптимизация по размеру, Os, в обоих случаях использовался один и тот же код, без разворачивания цикла. А с оптимизацией - один цикл не развернулся, а другой - развернулся.
Что примечательно: в инструкции к CRC, указано, что писать в DATAR можно непрерывно - задержка на время вычисления в 4 такта HCLK обеспечивается автоматически. А вот про RESET такого не было сказано. И модуль CRC не успевал установить своё исходное значение 0xFFFFFFFF до записи новых данных в DATAR.
С одним NOP-ом в качестве барьера, заработало.
UPD: всё же, загрузка слов была не из регистров, а с косвенной адресацией, но уже по готовым смещениям, сразу же с первой инструкции после сброса CRC.