реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Eclipse / Linux / GCC / ChibiOs / STM32F401RET6 СRC engine неправильно вычисляет контрольную сумму
nanorobot
сообщение Apr 8 2018, 09:18
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Apr 8 2018, 10:08
Сообщение #2


Гуру
******

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



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


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
nanorobot
сообщение Apr 8 2018, 10:41
Сообщение #3


Местный
***

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 8 2018, 16:08
Сообщение #4


фанат дивана
******

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



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


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Apr 9 2018, 16:09
Сообщение #5


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 9 2018, 20:45
Сообщение #6


фанат дивана
******

Группа: Свой
Сообщений: 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. Какой делитель у этого таймера?


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Apr 9 2018, 20:58
Сообщение #7


Гуру
******

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



QUOTE (AHTOXA @ Apr 9 2018, 22:45) *
Какой делитель у этого таймера?
1:1, на шине тоже 1:1.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 9 2018, 21:09
Сообщение #8


фанат дивана
******

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



То есть, таймер работает на частоте CPU? Тогда совсем странно.
Или всё же на половинной?
Какой контроллер?


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Apr 10 2018, 07:36
Сообщение #9


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 16:56
Рейтинг@Mail.ru


Страница сгенерированна за 0.01458 секунд с 7
ELECTRONIX ©2004-2016