Аппаратный CRC32 на весь объём флешки

ejsanyo

Active member
В составе нашего контроллера имеется весьма неплохой блок для аппаратного подсчёта CRC32, причём позволяющий очень гибко настроить параметры под любой из популярных алгоритмов. Однако в текущей версии HAL-овской функции длина обрабатываемой последовательности ограничена размером аппаратного буфера CRC-блока. А можно ли её увеличить? В частности, посчитать CRC на всю длину кода прошивки, ну или хотя бы грубо - на всю ёмкость флешки? Попробуем слегка исправить HAL-овскую функцию и сделать это:
C:
CRC_HandleTypeDef hcrc;

__HAL_PCC_CRC32_CLK_ENABLE();
    hcrc.Instance = CRC;
    hcrc.Poly = 0x04C11DB7; //параметры для разновидности CRC32b
    hcrc.Init = 0xFFFFFFFF;
    hcrc.InputReverse = CRC_REFIN_TRUE;
    hcrc.OutputReverse = CRC_REFOUT_TRUE;
    hcrc.OutputInversion = CRC_OUTPUTINVERSION_ON;
    HAL_CRC_Init(&hcrc);
    .
    .
    .
    .
//считает CRC по всей ёмкости флешки
//закомментить в HAL_CRC_WriteData() строку HAL_CRC_SetInit(hcrc);
uint32_t CalcCRC(void)
{
    //в каких пределах считать CRC32
    #define crc_start 0x80000000
    #define crc_capacity 1048576

    uint8_t* crc_pointer;
    uint32_t crc_result;
    uint32_t i;

    HAL_CRC_SetInit(&hcrc);
    crc_pointer = (uint8_t *)crc_start;
    for (i = 0; i < (crc_capacity - CRC_MAX_BYTES); i += CRC_MAX_BYTES)
    {
        HAL_CRC_WriteData(&hcrc, crc_pointer, CRC_MAX_BYTES);
        HAL_CRC_WaitBusy(&hcrc);
        crc_pointer += CRC_MAX_BYTES;
    }
    HAL_CRC_WriteData(&hcrc, crc_pointer, (crc_capacity - i));
    HAL_CRC_WaitBusy(&hcrc);
    return HAL_CRC_ReadCRC(&hcrc);
}
Да, в оригинале HAL_CRC_WriteData() каждый раз переписывает начальное значение в блоке CRC, но нам это не нужно, поэтому убираем.
И такой ещё вопрос: а возможно ли каким-либо образом получить информацию о реальной ёмкости запаянной флешки, когда код прошивки выполняется непосредственно с неё? Чтобы не вбивать константу каждый раз. Я вот попробовал давать команды 0x90 и 0x9F через HAL_SPIFI_SendCommand(), но контроллер на этом месте сразу подвисает. Похоже, "отстреливаю себе ногу".
 

mscs

Member
Получить информацию о реальной ёмкости запаянной ИМС Flash-памяти возможно. В моей программе это делается с помощью команды 0x9F. HAL не использую, работаю с регистрами:
Код:
        lui        a5, 0x70            # a5 = 70000h (SPIFI controller base address)
        lui        a1, 0x9F200
        c.addi     a1, 3
        c.sw       a1, 4(a5)           # SPIFI_CMD = 9F200003h (Read JEDEC ID)

        c.li       a4, 25              # Timeout counter initialization
                                       # Waiting for SPIFI readyness subroutine
2:      c.lw       a3, 0x1C(a5)        # a3 = SPIFI_STA
        andi       a3, a3, 0x20        # If command execution has been completed,
        c.bnez     a3, 3f              # jump to label 3

        c.addi     a4, -1              # If timeout is expired, jump to label Fault
        c.beqz     a4, Fault

        c.j        2b                  # Otherwise, jump to label 2

3:      c.sw       a3, 0x1C(a5)        # SPIFI_STA = 20h (clear interrupt request)

        lbu        a0, 0x14(a5)        # a0 = SPIFI_DATA (the first byte of ID)
        lbu        a1, 0x14(a5)        # a1 = SPIFI_DATA (the second byte of ID)
        lbu        a2, 0x14(a5)        # a2 = SPIFI_DATA (the third byte of ID)
 
Последнее редактирование:

ejsanyo

Active member
Суровый ассемблерный код... :censored: Но, так понимаю, выполняется он у вас НЕ с флешки? Потому и выполняется нормально.
 

mscs

Member
Да, все верно. Согдасно документации МК, контроллер SPIFI может работать в двух режимах: режим работы с периферией и режим работы с памятью (в котором выбираются команды). Для чтения ID необходимо перейти в режим работы с периферией, что подразумевает прекращение выборки команд.
 
Последнее редактирование:

mscs

Member
Также и при выполнении процедуры записи Flash-памяти кода выборка команд невозможна. Поэтому код подпрограммы записи копируется в ОЗУ. Так делается в STM-ках, в Миландр-ах, и так же должно делаться в К1948ВК018.
 
Также и при выполнении процедуры записи Flash-памяти кода выборка команд невозможна. Поэтому код подпрограммы записи копируется в ОЗУ. Так делается в STM-ках, в Миландр-ах, и так же должно делаться в К1948ВК018.
Хм, про STM о таком не слышал (что нужно что-то в ОЗУ копировать). Можно стирать страницы и записывать во флэш кодом, выполняющимся из флэша. Эмуляция EEPROM так и работает. Если не пытаться стереть страницу, на которой находится исполняемый код, то всё прекрасно работает.

During a write operation to the Flash memory, any attempt to read the Flash memory will
stall the bus. The read operation will proceed correctly once the write operation has
completed.

То есть исполнение кода из флэша просто останавливается на время записи.
Вот с К1948ВК018 такое скорее всего не прокатит.
 
Однако в текущей версии HAL-овской функции длина обрабатываемой последовательности ограничена размером аппаратного буфера CRC-блока. А можно ли её увеличить? В частности, посчитать CRC на всю длину кода прошивки, ну или хотя бы грубо - на всю ёмкость флешки? Попробуем слегка исправить HAL-овскую функцию и сделать это
А не пробовали не делать WaitBusy после записи очередного слова в IFIFO блока CRC? В доке написано, что "При полном заполнении буфера активизируется сигнал HREADY_o, останавливающий транзакцию по шине AHB.". В теории ждать надо только после записи последнего слова, а до этого шина всё сделает сама. Попробую проверить.
 
Да, так работает. Можно ждать только в самом хвосте. Причем вместо странного (в HAL)
Код:
    /* Ожидание 1 такта для установления флага BUSY в 1 после записи в регистр данных слова */
    for (uint8_t i = 0; i < 100; i++);
можно использовать (в стиле HAL)
Код:
 hcrc->Instance->CTRL;
 
Дополню, что после установки начального значения в CRC->DATA32 нельзя сразу же снимать флаг CRC_CTRL_WAS_M, нужна задержка (о которой есть упоминание в описании бита CRC->CTRL.Busy), нужна задержка, формируемая хотя бы чтением регистра CRC->CTRL. Хотя, если снимать флаг не просто установкой значения регистра
Код:
  CRC->CTRL = a_tot
            | a_totr
            | a_fx
            ;
а как обычно делается через чтение-модификацию-запись
Код:
CRC->CTRL &= ~CRC_CTRL_WAS_M
то чтение и обеспечит ту самую задержку.
 
Сверху