Перейти к содержанию
    

Eclipse / Linux / GCC / ChibiOs / STM32F401RET6 СRC engine неправильно вычисляет контрольную сумму

  CRC->CR = CRC_CR_RESET;                               // сбросим регистр данных CRC Engine
  for(i = 0; i < FRAME_SIZE - 1; i++)                         // цикл по всем словам данных, кроме последнего
    CRC->DR = TxData[i];                                            // вычисляем CRC
    TxData[i] = CRC->DR;                                            // и заносим в последнее слово данных
  
  spiStartExchange(&SPID2, 12, TxData, RxData);

Контрольная сумма вычисляется неверно (не совпадает с CRC на принимающей стороне, при одинаковых данных на обеих сторонах). Если поставить брекпоинт на любой из первых трех строчек, и прогнать по шагам, CRC вычисляется верно. Если брекпоинт поставить на 4 или 5 строке - CRC неверно. Запрещать прерывания нв время вычисления CRC пробовал - не помогло. CRC Engine используется только в одном Thread.

 

P.S. TxData - uint32_t

Изменено пользователем nanorobot

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если поставить брекпоинт на любой из первых трех строчек, и прогнать по шагам, CRC вычисляется верно. Если брекпоинт поставить на 4 или 5 строке - CRC неверно.
Если непосредственно перед этим кодом включается тактирование модуля CRC, то после него надо вставить __DSB() - тактирование не успевает включиться и CRC->CR = CRC_CR_RESET не отрабатывается.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если непосредственно перед этим кодом включается тактирование модуля CRC, то после него надо вставить __DSB() - тактирование не успевает включиться и CRC->CR = CRC_CR_RESET не отрабатывается.

Нет, тактирование включается модуля CRC значительно раньше. Тем не менее совет проверил - не помогло.

 

 

__DSB() поставил после строки CRC->CR = CRC_CR_RESET - заработало! Спасибо за помощь. Жаль только, чт понимания не прибавилось. Не первый раз поьзуюсь расчетом CRC, в том числе и на STM32F401, но такая проблема первый раз.

Изменено пользователем nanorobot

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что-то мне смутно припоминается, что после CRC->CR = CRC_CR_RESET надо 3 nop-а. (Как раз Сергей это и раскопал, кстати).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что-то мне смутно припоминается, что после CRC->CR = CRC_CR_RESET надо 3 nop-а. (Как раз Сергей это и раскопал, кстати).

Не, в тот раз мне понадобилось __DSB(); между включением тактирования и RESET. А дальше у меня ПДП настраивалось и этого времени, вероятно, хватало.

А вот сегодня напаролся на такое (ARPE = 1):

    Timer->ARR = DELAY1_TICKS;      // cache
    Timer->EGR = TIM_EGR_UG;        // write cache to ARR
    Timer->ARR = DELAY2_TICKS;      // cache

Ожидаю прерывание через DELAY1_TICKS (ну плюс-минус), а получаю через DELAY2_TICKS. И пока методом тыка не сделал вот так, ничего не работало:

    Timer->ARR = DELAY1_TICKS;      // cache
    Timer->EGR = TIM_EGR_UG;        // write cache to ARR
    __DSB();
    Timer->ARR = DELAY2_TICKS;      // cache

Кто-нибудь может это объяснить?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не, в тот раз мне понадобилось __DSB(); между включением тактирования и RESET. А дальше у меня ПДП настраивалось и этого времени, вероятно, хватало.

 

А, нашёл. Это дальше в той же теме было:

Что-то мне подсказывает, что вот это

computation done in 4 AHB clock cycles (HCLK)

надо относить и к тому, когда CRC калькулятор будет готов принять данные не только после записи очередного байта, но и к тому, когда он будет готов после RESET.

 

После этого я вставляю 3 нопа после сброса. Одного DSB может и не хватить.

 

Кто-нибудь может это объяснить?

Наверное то же самое, асинхронность таймера по отношению к CPU. Какой делитель у этого таймера?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Какой делитель у этого таймера?
1:1, на шине тоже 1:1.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

То есть, таймер работает на частоте CPU? Тогда совсем странно.

Или всё же на половинной?

Какой контроллер?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

То есть, таймер работает на частоте CPU? Тогда совсем странно.

Или всё же на половинной?

Какой контроллер?

F100, PPRE1 = 3, PPRE2 = 3, PSC = 0. Что-то мне эта версия кажется сомнительной, потому что в процессе инициализации я всегда пишу все регистры таймера подряд и никаких проблем никогда не было, да и таймер во время этой записи остановлен.

Полный код сейчас выглядит так:

    Timer->CR1 = 0
        | 0 * (TIM_CR1_CKD & -TIM_CR1_CKD)      // Dead-time clock, 0 = /1, 1 = /2, 2 = /4
        | 1 * TIM_CR1_ARPE                      // ARR buffering, 0 = not buffered, 1 = buffered
        | 0 * (TIM_CR1_CMS & -TIM_CR1_CMS)      // 0 = unidirectional, 1 = up/down, OC flags set when counting up
                                                // 2 = up/down, OC flags set when counting down, 3 = up/down, OC flags set when counting up or down
        | 0 * TIM_CR1_DIR                       // 0 = up, 1 = down
        | 0 * TIM_CR1_OPM                       // 1 = stop at update event
        | 1 * TIM_CR1_URS                       // Update request source, 0 = any, 1 = only counter wrap
        | 0 * TIM_CR1_UDIS                      // Update event generation disable
        | 0 * TIM_CR1_CEN                       // Counter enable
      ;

    .......
    
    Timer->ARR = DELAY1;        // cache
    __DSB();
    Timer->EGR = TIM_EGR_UG;    // write cache to ARR
    __DSB();
    Timer->ARR = DELAY2;        // cache
    
    Timer->CR1 = 0
        | 0 * (TIM_CR1_CKD & -TIM_CR1_CKD)      // Dead-time clock, 0 = /1, 1 = /2, 2 = /4
        | 1 * TIM_CR1_ARPE                      // ARR buffering, 0 = not buffered, 1 = buffered
        | 0 * (TIM_CR1_CMS & -TIM_CR1_CMS)      // 0 = unidirectional, 1 = up/down, OC flags set when counting up
                                                // 2 = up/down, OC flags set when counting down, 3 = up/down, OC flags set when counting up or down
        | 0 * TIM_CR1_DIR                       // 0 = up, 1 = down
        | 0 * TIM_CR1_OPM                       // 1 = stop at update event
        | 1 * TIM_CR1_URS                       // Update request source, 0 = any, 1 = only counter wrap
        | 0 * TIM_CR1_UDIS                      // Update event generation disable
        | 1 * TIM_CR1_CEN                       // Counter enable
      ;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...