|
|
  |
Eclipse / Linux / GCC / ChibiOs / STM32F401RET6 СRC engine неправильно вычисляет контрольную сумму |
|
|
|
Apr 8 2018, 09:18
|
Местный
  
Группа: Участник
Сообщений: 244
Регистрация: 29-02-08
Пользователь №: 35 503

|
Код 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 - Apr 8 2018, 09:33
|
|
|
|
|
Apr 8 2018, 10:41
|
Местный
  
Группа: Участник
Сообщений: 244
Регистрация: 29-02-08
Пользователь №: 35 503

|
Цитата(Сергей Борщ @ Apr 8 2018, 15:08)  Если непосредственно перед этим кодом включается тактирование модуля CRC, то после него надо вставить __DSB() - тактирование не успевает включиться и CRC->CR = CRC_CR_RESET не отрабатывается. Нет, тактирование включается модуля CRC значительно раньше. Тем не менее совет проверил - не помогло. __DSB() поставил после строки CRC->CR = CRC_CR_RESET - заработало! Спасибо за помощь. Жаль только, чт понимания не прибавилось. Не первый раз поьзуюсь расчетом CRC, в том числе и на STM32F401, но такая проблема первый раз.
Сообщение отредактировал nanorobot - Apr 8 2018, 10:42
|
|
|
|
|
Apr 9 2018, 16:09
|

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

|
QUOTE (AHTOXA @ Apr 8 2018, 18:08)  Что-то мне смутно припоминается, что после CRC->CR = CRC_CR_RESET надо 3 nop-а. (Как раз Сергей это и раскопал, кстати). Не, в тот раз мне понадобилось __DSB(); между включением тактирования и RESET. А дальше у меня ПДП настраивалось и этого времени, вероятно, хватало. А вот сегодня напаролся на такое (ARPE = 1): CODE Timer->ARR = DELAY1_TICKS; // cache Timer->EGR = TIM_EGR_UG; // write cache to ARR Timer->ARR = DELAY2_TICKS; // cache Ожидаю прерывание через DELAY1_TICKS (ну плюс-минус), а получаю через DELAY2_TICKS. И пока методом тыка не сделал вот так, ничего не работало: CODE Timer->ARR = DELAY1_TICKS; // cache Timer->EGR = TIM_EGR_UG; // write cache to ARR __DSB(); Timer->ARR = DELAY2_TICKS; // cache Кто-нибудь может это объяснить?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 9 2018, 20:45
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Сергей Борщ @ Apr 9 2018, 21:09)  Не, в тот раз мне понадобилось __DSB(); между включением тактирования и RESET. А дальше у меня ПДП настраивалось и этого времени, вероятно, хватало. А, нашёл. Это дальше в той же теме было: Цитата(Genadi Zawidowski @ Jan 23 2014, 23:42)  Что-то мне подсказывает, что вот это Цитата computation done in 4 AHB clock cycles (HCLK) надо относить и к тому, когда CRC калькулятор будет готов принять данные не только после записи очередного байта, но и к тому, когда он будет готов после RESET. После этого я вставляю 3 нопа после сброса. Одного DSB может и не хватить. Цитата(Сергей Борщ @ Apr 9 2018, 21:09)  Кто-нибудь может это объяснить? Наверное то же самое, асинхронность таймера по отношению к CPU. Какой делитель у этого таймера?
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Apr 10 2018, 07:36
|

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

|
QUOTE (AHTOXA @ Apr 9 2018, 23:09)  То есть, таймер работает на частоте CPU? Тогда совсем странно. Или всё же на половинной? Какой контроллер? F100, PPRE1 = 3, PPRE2 = 3, PSC = 0. Что-то мне эта версия кажется сомнительной, потому что в процессе инициализации я всегда пишу все регистры таймера подряд и никаких проблем никогда не было, да и таймер во время этой записи остановлен. Полный код сейчас выглядит так: CODE 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 ;
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|