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

Участник

Группа: Участник
Сообщений: 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
|
|
|
|
|
Nov 23 2014, 20:23
|

Участник

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

|
Код инициализации: CODE // инициализация SPI // APB1 CLK = 168/4 = 42 MHz // APB2 CLK = 168/2 = 84 MHz // включаем тактирование модуля SPI if ( (SPI_HI_CLK == RCC_APB1Periph_SPI2) || (SPI_HI_CLK == RCC_APB1Periph_SPI3) ) { RCC_APB1PeriphClockCmd(SPI_HI_CLK, ENABLE); } else { RCC_APB2PeriphClockCmd(SPI_HI_CLK, ENABLE); } SPI_StructInit(&SPI_InitStructure); SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; // SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_CRCPolynomial = 16; SPI_Init(SPI_HI_SPI, &SPI_InitStructure); SPI_CalculateCRC(SPI_HI_SPI, ENABLE); //Enable CRC SPI_SSOutputCmd(SPI_HI_SPI, DISABLE); // Disable the selected SPI SS output SPI_NSSInternalSoftwareConfig(SPI_HI_SPI, SPI_NSSInternalSoft_Set); // Set NSS pin internally by software SPI_I2S_ITConfig(SPI_HI_SPI, SPI_I2S_IT_TXE, DISABLE); // interrupts SPI_I2S_ITConfig(SPI_HI_SPI, SPI_I2S_IT_RXNE, DISABLE); SPI_I2S_ITConfig(SPI_HI_SPI, SPI_I2S_IT_ERR, DISABLE); SPI_I2S_DMACmd(SPI_HI_SPI, SPI_I2S_DMAReq_Tx, ENABLE); // Enables DMA TX request SPI_I2S_DMACmd(SPI_HI_SPI, SPI_I2S_DMAReq_Rx, ENABLE); // Enables DMA RX request // включаем прерывание блока NVIC для SPI NVIC_InitStructure.NVIC_IRQChannel = SPI_HI_IRQChannel; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = SPI_HI_IRQChannel_Prio; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); NVIC_ClearPendingIRQ(SPI_HI_IRQChannel); // настраиваем DMA // включение тактовой частоты для блока DMA RCC_AHB1PeriphClockCmd(SPI_HI_DMA_CLK, ENABLE); // Disable DMA channel SPI DMA_Cmd(SPI_HI_TX_DMA_Stream, DISABLE); DMA_Cmd(SPI_HI_RX_DMA_Stream, DISABLE); // DMA channel SPI HI TX configuration DMA_DeInit(SPI_HI_TX_DMA_Stream); DMA_InitStructure.DMA_Channel = SPI_HI_TX_DMA_Channel; DMA_InitStructure.DMA_PeripheralBaseAddr = SPI_HI_DR_Address; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)SPI_HI_TXbuf; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_BufferSize = MAX(SPI_HI_BUFFERS[0].RXBUF_SIZE, SPI_HI_BUFFERS[0].TXBUF_SIZE); DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(SPI_HI_TX_DMA_Stream, &DMA_InitStructure); // включаем прерывание блока NVIC для DMA TX NVIC_InitStructure.NVIC_IRQChannel = SPI_HI_TX_DMA_IRQChannel; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = SPI_HI_TX_DMA_IRQChannel_Prio; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); NVIC_ClearPendingIRQ(SPI_HI_TX_DMA_IRQChannel); 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_ITConfig(SPI_HI_TX_DMA_Stream, DMA_IT_TC, ENABLE); DMA_ITConfig(SPI_HI_TX_DMA_Stream, DMA_IT_HT, DISABLE); DMA_ITConfig(SPI_HI_TX_DMA_Stream, DMA_IT_TE, ENABLE); DMA_ITConfig(SPI_HI_TX_DMA_Stream, DMA_IT_DME, ENABLE); DMA_ITConfig(SPI_HI_TX_DMA_Stream, DMA_IT_FE, ENABLE); // DMA channel SPI LO RX configuration DMA_DeInit(SPI_HI_RX_DMA_Stream); DMA_InitStructure.DMA_Channel = SPI_HI_RX_DMA_Channel; DMA_InitStructure.DMA_PeripheralBaseAddr = SPI_HI_DR_Address; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)SPI_HI_RXbuf; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = MAX(SPI_HI_BUFFERS[0].RXBUF_SIZE, SPI_HI_BUFFERS[0].TXBUF_SIZE); DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(SPI_HI_RX_DMA_Stream, &DMA_InitStructure); // включаем прерывание блока NVIC для DMA RX NVIC_InitStructure.NVIC_IRQChannel = SPI_HI_RX_DMA_IRQChannel; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = SPI_HI_RX_DMA_IRQChannel_Prio; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); NVIC_ClearPendingIRQ(SPI_HI_RX_DMA_IRQChannel); 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_ITConfig(SPI_HI_RX_DMA_Stream, DMA_IT_TC, ENABLE); DMA_ITConfig(SPI_HI_RX_DMA_Stream, DMA_IT_HT, DISABLE); DMA_ITConfig(SPI_HI_RX_DMA_Stream, DMA_IT_TE, ENABLE); DMA_ITConfig(SPI_HI_RX_DMA_Stream, DMA_IT_DME, ENABLE); DMA_ITConfig(SPI_HI_RX_DMA_Stream, DMA_IT_FE, ENABLE);
--------------------
Александр, UT4UBL
|
|
|
|
|
Nov 24 2014, 07:12
|

Участник

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

|
Цитата(SasaVitebsk @ Nov 24 2014, 09:36)  Я уже где-то писал. Экспериментировал с stm32f407. CRC, реально применить не получилось. Механизм включения выключения не работает. (Там автоматически CRC инитится) и ещё куча всего. Я уже сейчас слабо помню. В мануале об этом и многом другом упоминается. Никаким внятным способом заставить работать не получилось. Результаты были непредсказуемы. Для каких целей они его разработали и как работает - непонятно. Я хотел применить для работы с флэш памятью. Типа просчитывать при записи блока. Спасибо за ответ. Теперь немного проясняется. Искал по нету и по этому форуму, но не нашёл подобной проблемы. На форуме ST вроде решили проблему, но у них другой МК был. сегодня еще поэксперементирую.
--------------------
Александр, UT4UBL
|
|
|
|
|
Nov 25 2014, 14:38
|

Участник

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

|
Цитата(SasaVitebsk @ Nov 25 2014, 16:11)  Вы в основном о трудностях применения в конкретной вашей задаче. А я говорю что модуль подсчёта работает нестабильно. Но работает, и даже по даташиту. Перепробовал все возможности и даже на разных контроллерах - ничего не помогает. Только немного меняет частоту ошибок если работать с другой областью памяти, но это не панацея. Буду делать программный подсчёт.
--------------------
Александр, UT4UBL
|
|
|
|
|
Nov 26 2014, 08:21
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(AlexUT4 @ Nov 25 2014, 17:38)  Вы в основном о трудностях применения в конкретной вашей задаче.... И да и нет. SPI это только интерфейс. Абсолютно выхолощенный. Соответственно работа с ним требует протокола. Проще говоря, ну и посчитали вы CRC, её же куда-то вставить нужно. То есть транспортного уровня недостаточно, требуются пакеты, команды и так далее .. Таким образом, работа с датафлэш, это абсолютно типовая задача. Применительно к пакетам требуется инициализировать CRC, и включать выключать подсчёт. Очевидно, что у st с этим возникли трудности, и причины этого скорее всего в синхронизации. Скорее всего подсчёт CRC идёт при передаче (так проще), а передача относительно асинхронна. Поэтому, на мой взгляд, они либо должны были указать для какой конкретно цели (устройства) они разрабатывали данную фичу, либо должны были показать примеры работы с тем либо иным устройством, ну или хотя бы абстрактный пример привести. Ну чтобы я или Вы сразу бы определили подходит данный узел под вашу задачу или нет, а не тратили кучу времени на исследования в области ...
|
|
|
|
|
Nov 26 2014, 14:46
|

Участник

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

|
Цитата(SasaVitebsk @ Nov 26 2014, 11:21)  И да и нет. SPI это только интерфейс. Абсолютно выхолощенный. Соответственно работа с ним требует протокола. Проще говоря, ну и посчитали вы CRC, её же куда-то вставить нужно. То есть транспортного уровня недостаточно, требуются пакеты, команды и так далее .. Таким образом, работа с датафлэш, это абсолютно типовая задача. Применительно к пакетам требуется инициализировать CRC, и включать выключать подсчёт. Очевидно, что у st с этим возникли трудности, и причины этого скорее всего в синхронизации. Скорее всего подсчёт CRC идёт при передаче (так проще), а передача относительно асинхронна. Поэтому, на мой взгляд, они либо должны были указать для какой конкретно цели (устройства) они разрабатывали данную фичу, либо должны были показать примеры работы с тем либо иным устройством, ну или хотя бы абстрактный пример привести. Ну чтобы я или Вы сразу бы определили подходит данный узел под вашу задачу или нет, а не тратили кучу времени на исследования в области ... Они разработали очень нужную фичу этот аппаратный CRC. В основном он применяется для связи двух МК или другой "умной" периферии с относительно простым, пользовательским протоколом верхнего уровня (как у меня, например) где подсчёт CRC делается на весь пакет. Для всяких микросхем памяти, где CRC используется не на канальном уровне этот модуль применять бессмысленно. Примеров я видел множество, но не ST-шных. Мне кажется, что они знают, что начудили с этим модулем, и очень скромно его описывают и обходят в примерах. Ну и ещё раз повторюсь: модуль чётко работает по даташиту, НО глючит (не стабилен) только на передачу. Сейчас заделал программный подсчёт CRC - полёт нормальный)))
--------------------
Александр, UT4UBL
|
|
|
|
|
Nov 26 2014, 16:43
|

Участник

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

|
Цитата(Golikov A. @ Nov 26 2014, 19:00)  Как он может в одну сторону глючить а в другую нет? Это вопросы к ST. Там два независимых аппаратных блока расчёта CRC: одни на приём, другой на передачу. Цитата(Golikov A. @ Nov 26 2014, 19:00)  Как проверялось что на прием не ошибается? Так может для передачи сначала делать типа псевдоприем с ДМА, получать цифру суммы а потом все выдавливать наружу с правильным кодом? Использую счётчики исключений/событий. За всё время наблюдений (неделю целую убил на это) на приём всегда было ОК. Посмотрите как он работает что на приём что на передачу. Я ему даю пакет и запускаю, а дальше он сам аппаратно всё делает без моего участия: DMA даёт блоку SPI байт/слово, SPI, в свою очередь передаёт его из микросхемы и попутно "на лету" побитно рассчитывает контрольную сумму и в конце передачи САМ передаёт эту контрольную сумму. На выходе я реально наблюдаю на осциллографе статический пакет и "дёргающуюся" контрольную сумму. Предполагаю глюки самого проца. Пока нет времени писать с STшный сапот.
--------------------
Александр, UT4UBL
|
|
|
|
|
Nov 26 2014, 18:59
|

Участник

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

|
Цитата(Golikov A. @ Nov 26 2014, 20:03)  а на приеме он может ОК говорить и на не неправильные - не сошедшиеся суммы, может он так ошибается, так что то что не было ерроров не факт что оно работает  я заводил счётчик и на такое событие - не замечал расхождений на приём.
--------------------
Александр, UT4UBL
|
|
|
|
|
Nov 27 2014, 05:59
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

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