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

 
 
> STM32 сбои работы аппаратного CRC в SPI, непонятная работа аппаратного вычислителя CRC в модуле SPI
AlexUT4
сообщение Nov 23 2014, 14:15
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 15
Регистрация: 2-05-11
Пользователь №: 64 731



Столкнулся с непонятками в работе аппаратного вычислителя CRC в модуле SPI у STM32F417.

Надо связать один мастер с многими слейвами через SPI (full duplex) с контрольной суммой. И всё это под управлением DMA. Написал мастер. В первом приближении работает сам на себе (loop back заделал). Но при проверках/отладках выяснилось, что, изредка, аппаратный вычислитель CRC на одной и той же последовательности битов НА ПЕРЕДАЧУ выдаёт РАЗНОЕ значение контрольной суммы. Это случается примерно 100 раз на 30000 верных значений. Частота появления ошибки не стабильна. Причём, неверные значения почти не повторяются. На приём всегда всё верно вычисляет. Флаг CRCERR срабатывает адекватно. На осциллографе наблюдается это чётко - на пине MOSI вижу статическую свою посылку (для теста взял 3 слова) за которой "подёргиваясь" идёт аппаратный CRC.
На сайте STMа народ тоже поднимал тему проблем работы аппаратного CRC в SPI - (ссылка). Что-то там решили, но их методы мне не помогли. Я пробовал все рекомендации из этого форума, но ни какова результата не дало (вообще ни каких изменений в частоте появления ошибки или в работе).
Пробовал менять степень полинома - не влияет. Влияет только само значение передаваемых слов: если все 0, то всё ОК; если все 1, то тоже все ОК; а если какие то другие рандумные значения, то начинаются сбои.

Сам алгоритм:

В задачи под работу SPI (использую FreeRFOT) в бесконечном цикле:
задержка
копирую что буду передавать в буфер SPI на передачу
выбираю нужный CS
инициализирую DMA
запускаю SPI
жду семафора
выключаю CS, DMA и SPI
смотрю и проверяю контрольные суммы
если все ОК - копирую принятые данные из приёмного буфера SPI в целевую переменную
CODE
static void vSPI_HI_Task( void *pvParameters )
{
channelsel = 0;

for(;; )
{
// делаем задержку перед запускоом следующего обмена
Delay1ms( SPI_HI_CHANNEL_SW_Delay );

// формируем пакет на передачу
memcpy((char *)&SPI_HI_TXbuf, SPI_HI_BUFFERS[channelsel].TXBUF, SPI_HI_BUFFERS[channelsel].TXBUF_SIZE);
SPI_HI_cur_ID = SPI_HI_TXbuf[0]; // запоминаем ID текущего модуля

// включаем нужный #EN
SPI_HI_EN( channelsel, RESET );

// перезапускаем DMA
SPI_HI_ReStart( MAX(SPI_HI_BUFFERS[channelsel].RXBUF_SIZE, SPI_HI_BUFFERS[channelsel].TXBUF_SIZE) );

// запустился цикл обмена по SPI HI

// Ждём семафора для разблокировки события - конец обмена по SPI HI
xSemaphoreTake( xSPI_HI_Semaphore, portMAX_DELAY );

// Обмен по SPI HI проведён

// выключаем нужный #EN
SPI_HI_EN( channelsel, SET );

// останавливаем DMA
DMA_Cmd(SPI_HI_TX_DMA_Stream, DISABLE);
while (DMA_GetCmdStatus(SPI_HI_TX_DMA_Stream)) {}
DMA_Cmd(SPI_HI_RX_DMA_Stream, DISABLE);
while (DMA_GetCmdStatus(SPI_HI_RX_DMA_Stream)) {}

//проверяем контрольную сумму
tx_crc[channelsel] = SPI_HI_SPI->TXCRCR;
rx_crc[channelsel] = SPI_HI_SPI->RXCRCR;
crc_b[channelsel] = crc_p;
if (SPI_I2S_GetFlagStatus(SPI_HI_SPI, SPI_FLAG_CRCERR))
{
// ошибка контрольной суммы
crc_e[channelsel] = crc_p;
SPI_HI_evtcnt.CRC_ERR[channelsel]++;
}
else
{
// контрольная сумма верна
// проверка что пришёл буфер от своего модуля
if ( SPI_HI_RXbuf[0] == SPI_HI_cur_ID )
{
// разбираем принятый буфер
memcpy(SPI_HI_BUFFERS[channelsel].RXBUF, (char *)&SPI_HI_RXbuf, SPI_HI_BUFFERS[channelsel].RXBUF_SIZE);
SPI_HI_evtcnt.EXCH_COMP[channelsel]++;
}
else
{
//пакет с неверным ID
SPI_HI_evtcnt.ID_ERR[channelsel]++;
SPI_HI_evtcnt.UNIT_STAT &= (uint32_t)~(((uint32_t)0x00000001) << channelsel);
}
}

// Disable SPI
SPI_I2S_ClearFlag(SPI_HI_SPI, SPI_FLAG_CRCERR); //Clears the SPI CRC Error
SPI_Cmd( SPI_HI_SPI, DISABLE );

// переходим на следующий канал
// channelsel++;
// if (channelsel >= SPI_HI_ChannelNumInWork) {channelsel = 0;}

}

}


В обработчике прерывания DMA конец приёма разрешаю прерывание SPI RXNE
CODE
//Global interupt for DMA SPI RX
void DMA_SPI_HI_RX_IRQHandler( void )
{
//NVIC_ClearPendingIRQ(SPI_HI_RX_DMA_IRQChannel); //сбрасываем запрос прерываниея NVIC

//Transfer complete
if (DMA_GetITStatus(SPI_HI_RX_DMA_Stream, DMA_IT_TCIF_SPIHI_RX))
{
DMA_ClearITPendingBit(SPI_HI_RX_DMA_Stream, DMA_IT_TCIF_SPIHI_RX);
SPI_HI_evtcnt.DMA_RX_TC++;
// конец пересылки основных данных
// разрешаем прерывание RXNE на приём последней посылки с контрольной суммой
SPI_I2S_ITConfig(SPI_HI_SPI, SPI_I2S_IT_RXNE, ENABLE);
}

//Transfer error
if (DMA_GetITStatus(SPI_HI_RX_DMA_Stream, DMA_IT_TEIF_SPIHI_RX))
{
DMA_ClearITPendingBit(SPI_HI_RX_DMA_Stream, DMA_IT_TEIF_SPIHI_RX);
SPI_HI_evtcnt.DMA_RX_TE++;
}

//Direct mode error
if (DMA_GetITStatus(SPI_HI_RX_DMA_Stream, DMA_IT_DMEIF_SPIHI_RX))
{
DMA_ClearITPendingBit(SPI_HI_RX_DMA_Stream, DMA_IT_DMEIF_SPIHI_RX);
SPI_HI_evtcnt.DMA_RX_DME++;
}

//FIFO overrun/underrun
if (DMA_GetITStatus(SPI_HI_RX_DMA_Stream, DMA_IT_FEIF_SPIHI_RX))
{
DMA_ClearITPendingBit(SPI_HI_RX_DMA_Stream, DMA_IT_FEIF_SPIHI_RX);
SPI_HI_evtcnt.DMA_RX_FE++;
}

}



В обработчике прерывания SPI RXNE делаю чтение приёмного регистра SPI, выключаю прерывание SPI RXNE, разблокирую семафор.
CODE
// Глобальный обработчик прерывания SPI
void SPI_HI_IRQHandler( void )
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
//NVIC_ClearPendingIRQ(SPI_HI_IRQChannel); //сбрасываем запрос прерывания NVIC

//RXNE
if (SPI_I2S_GetITStatus(SPI_HI_SPI, SPI_I2S_IT_RXNE))
{
// пришла последня посылка с контрольной суммой
SPI_I2S_ITConfig(SPI_HI_SPI, SPI_I2S_IT_RXNE, DISABLE); // отключаем это прерывание
crc_p = SPI_HI_SPI->DR; // пустое чтение для сброса флага прерывания
SPI_HI_evtcnt.RX_CRC++;

// разблокируем задачу vSPI_HI_Task через семафор
xSemaphoreGiveFromISR( xSPI_HI_Semaphore, &xHigherPriorityTaskWoken );
if( xHigherPriorityTaskWoken == pdTRUE )
{
taskYIELD();
}
}
}



CODE
// перезапуск SPI HI с заданием нужной длинны буфера buff
static void SPI_HI_ReStart( uint16_t buff )
{
buff = buff >> 1; // делим на 2 так как передаваемые данные 16-ти битные
DMA_SetCurrDataCounter(SPI_HI_TX_DMA_Stream, buff);
DMA_SetCurrDataCounter(SPI_HI_RX_DMA_Stream, buff);

DMA_ClearITPendingBit(SPI_HI_TX_DMA_Stream, DMA_IT_TCIF_SPIHI_TX);
DMA_ClearITPendingBit(SPI_HI_TX_DMA_Stream, DMA_IT_HTIF_SPIHI_TX);
DMA_ClearITPendingBit(SPI_HI_TX_DMA_Stream, DMA_IT_TEIF_SPIHI_TX);
DMA_ClearITPendingBit(SPI_HI_TX_DMA_Stream, DMA_IT_DMEIF_SPIHI_TX);
DMA_ClearITPendingBit(SPI_HI_TX_DMA_Stream, DMA_IT_FEIF_SPIHI_TX);

DMA_ClearITPendingBit(SPI_HI_RX_DMA_Stream, DMA_IT_TCIF_SPIHI_RX);
DMA_ClearITPendingBit(SPI_HI_RX_DMA_Stream, DMA_IT_HTIF_SPIHI_RX);
DMA_ClearITPendingBit(SPI_HI_RX_DMA_Stream, DMA_IT_TEIF_SPIHI_RX);
DMA_ClearITPendingBit(SPI_HI_RX_DMA_Stream, DMA_IT_DMEIF_SPIHI_RX);
DMA_ClearITPendingBit(SPI_HI_RX_DMA_Stream, DMA_IT_FEIF_SPIHI_RX);

DMA_Cmd(SPI_HI_TX_DMA_Stream, ENABLE);
while (!DMA_GetCmdStatus(SPI_HI_TX_DMA_Stream)) {}

DMA_Cmd(SPI_HI_RX_DMA_Stream, ENABLE);
while (!DMA_GetCmdStatus(SPI_HI_RX_DMA_Stream)) {}

SPI_CalculateCRC(SPI_HI_SPI, DISABLE); // Disable CRC
SPI_CalculateCRC(SPI_HI_SPI, ENABLE); // Enable CRC - clear CRC regs
SPI_I2S_ClearFlag(SPI_HI_SPI, SPI_FLAG_CRCERR); //Clears the SPI CRC Error
SPI_Cmd(SPI_HI_SPI, ENABLE); // Enable SPI
}


В чём может быть глюк?

Сообщение отредактировал IgorKossak - Nov 23 2014, 19:53
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!


--------------------
Александр, UT4UBL
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
SasaVitebsk
сообщение Nov 27 2014, 05:59
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



В общем-то что такое CRC? Это сдвиг и исключающее ИЛИ. В данном случае, когда идёт битовый поток, то подсчёт битов и исключающее ИЛИ. То есть схемотехнически это с десяток вентилей, не больше. Причём статических. Как-то не вяжется, что они могут сбоить. Не верю.
Там нахомучено что-то именно с инициализацией и запретом - это точно.
Может какие-то вопросы по DMA? Сейчас гляну.
PS: Почитал. Они в этой части существенно изменили мануал. Появилась последовательность инициализации и действий. Когда я писал - этого не было. Там написано, что в DMA режиме не требуется NEXT передавать, а я думал в ручную, после завершения DMA транзакции. Тогда непонятно. Здесь даже и ошибиться сложно. По сути инициализируешь SPI формируешь буфер и в DMA указываешь адрес и размер. Всё должно в автомате работать.

Может скорость слишком большая? Там не выше 42МГц, на сколько я помню.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Nov 27 2014, 10:47
Сообщение #3


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

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



Общее соображение: когда в STM-ке что-то работает нестабильно, надо добавить барьерчиков.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- AlexUT4   STM32 сбои работы аппаратного CRC в SPI   Nov 23 2014, 14:15
- - AlexUT4   Код инициализации: CODE // инициализация SPI //...   Nov 23 2014, 20:23
- - SasaVitebsk   Я уже где-то писал. Экспериментировал с stm32f407....   Nov 24 2014, 06:36
- - AlexUT4   Цитата(SasaVitebsk @ Nov 24 2014, 09:36) ...   Nov 24 2014, 07:12
- - SasaVitebsk   Плохо искали ... )) http://electronix.ru/forum/ind...   Nov 25 2014, 13:11
|- - AlexUT4   Цитата(SasaVitebsk @ Nov 25 2014, 16:11) ...   Nov 25 2014, 14:38
|- - SasaVitebsk   Цитата(AlexUT4 @ Nov 25 2014, 17:38) Вы в...   Nov 26 2014, 08:21
|- - AlexUT4   Цитата(SasaVitebsk @ Nov 26 2014, 11:21) ...   Nov 26 2014, 14:46
- - ViKo   Ничего не понял ни здесь, ни в указанной выше ветк...   Nov 25 2014, 13:22
- - Golikov A.   Как он может в одну сторону глючить а в другую нет...   Nov 26 2014, 16:00
|- - AlexUT4   Цитата(Golikov A. @ Nov 26 2014, 19:00) К...   Nov 26 2014, 16:43
- - Golikov A.   а на приеме он может ОК говорить и на не неправиль...   Nov 26 2014, 17:03
|- - AlexUT4   Цитата(Golikov A. @ Nov 26 2014, 20:03) а...   Nov 26 2014, 18:59
- - SasaVitebsk   Цитата(AHTOXA @ Nov 27 2014, 13:47) Общее...   Nov 28 2014, 06:10


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

 


RSS Текстовая версия Сейчас: 21st July 2025 - 15:00
Рейтинг@Mail.ru


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