|
|
  |
stm32f407 SPI обнаружил косяк |
|
|
|
Dec 19 2012, 09:25
|
Местный
  
Группа: Участник
Сообщений: 280
Регистрация: 2-11-08
Пользователь №: 41 333

|
Цитата(KnightIgor @ Nov 17 2012, 02:37)  1. Прочесть DR. 2. Записать в DR байт для передачи. 3. Ждать RXNE (будь-то тупо или путем реакции на прерывание). 4. Перейти к п.1., если еще есть данные для передачи. И еще один момент если я осуществляю обмен таким образом, то часть байтов затирается. Например: я отсылаю следующие данные: 0x9F; 0; 0x9F; 0x9F; 0x9F; 0x9F. На осциллограмме первый байт правильный, второй тоже правильный остальные не правильные. Вместо 0x9F (0b10011111) судя по всему 1F (0b11111).
|
|
|
|
|
Dec 19 2012, 13:58
|

Участник

Группа: Участник
Сообщений: 39
Регистрация: 29-08-11
Из: Киев
Пользователь №: 66 910

|
Похоже у меня подобная проблема на STM32F103VE. После отсылки байта, не происходит задержи при проверки флага. В общем ситуация номер 1, всё на картинке. Код:Код GPIO_ResetBits( SD_CS_GPIO_PORT, SD_CS_PIN ); while( SPI_I2S_GetFlagStatus( SD_SPI, SPI_I2S_FLAG_TXE ) == RESET ) /*!< Wait until the transmit buffer is empty */ ; SPI_I2S_SendData( SD_SPI, 0xAA ); /*!< Send the byte */
GPIO_SetBits( SD_CS_GPIO_PORT, SD_CS_PIN ); Ситуация номер 2. Делитель на 2 И ситуация номер 3. Тут вставленна задержкаКод GPIO_ResetBits( SD_CS_GPIO_PORT, SD_CS_PIN ); while( SPI_I2S_GetFlagStatus( SD_SPI, SPI_I2S_FLAG_TXE ) == RESET ) /*!< Wait until the transmit buffer is empty */ ; SPI_I2S_SendData( SD_SPI, 0xAA ); /*!< Send the byte */
__delay_cycles( 45 );
GPIO_SetBits( SD_CS_GPIO_PORT, SD_CS_PIN );
|
|
|
|
|
Dec 19 2012, 15:35
|
Местный
  
Группа: Участник
Сообщений: 280
Регистрация: 2-11-08
Пользователь №: 41 333

|
Цитата(AHTOXA @ Dec 19 2012, 13:36)  Скорее всего косяк у вас в коде. Потому что описанный алгоритм - рабочий. Привожу кусок кода: первоночально записываю первый байт в передатчик: Код SPI3->DR=TransmitBuffer[0]; Tx_Data=1; затем обработчик прерываний: Код void SPI3_IRQHandler (void){ if(Rx_Data>=6) { //Если все передали CS_SET1; return; } if(SPI3->SR&SPI_SR_RXNE){ ReceiveBuffer[Rx_Data++]=SPI3->DR; //Очищаем RXNE чтением DR SPI3->DR=TransmitBuffer[Tx_Data++]; //Передаем следующий байт } }
Сообщение отредактировал sidy - Dec 19 2012, 15:35
|
|
|
|
|
Dec 19 2012, 17:02
|

Участник

Группа: Участник
Сообщений: 39
Регистрация: 29-08-11
Из: Киев
Пользователь №: 66 910

|
Цитата(AHTOXA @ Dec 19 2012, 16:22)  У вас другая проблема. Вы отключаете CS сразу после записи байта в DR, не дожидаясь, пока он уйдёт в линию. Если вы прочитаете эту ветку сначала, то найдёте пару рекомендаций, как это сделать. Ок, спасибо. Я правильно понимаю, что момент когда отпускать CS нужно смотреть по флагу BSY?
Сообщение отредактировал cyb - Dec 19 2012, 17:03
|
|
|
|
|
Dec 19 2012, 17:36
|

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

|
Цитата(sidy @ Dec 19 2012, 21:35)  Привожу кусок кода: Хорошо, давайте разбираться по порядку. Где у вас п.1 ("Прочесть DR.") ? Цитата(cyb @ Dec 19 2012, 23:02)  Ок, спасибо. Я правильно понимаю, что момент когда отпускать CS нужно смотреть по флагу BSY? Да, он именно для этого и предназначен.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Dec 20 2012, 04:08
|
Местный
  
Группа: Участник
Сообщений: 280
Регистрация: 2-11-08
Пользователь №: 41 333

|
Цитата(AHTOXA @ Dec 19 2012, 21:36)  Хорошо, давайте разбираться по порядку. Где у вас п.1 ("Прочесть DR.") ? Добавил чтение DR, но это ничего не изменило: Код Recycler=SPI3->DR; SPI3->DR=TransmitBuffer[0]; Tx_Data=1; Обработчик: Код void SPI3_IRQHandler (void){ if(Rx_Data>=6) { //Если все передали CS_SET1; return; } if(SPI3->SR&SPI_SR_RXNE){ ReceiveBuffer[Rx_Data++]=SPI3->DR; //Очищаем RXNE чтением DR SPI3->DR=TransmitBuffer[Tx_Data++]; //Передаем следующий байт } }
|
|
|
|
|
Dec 20 2012, 04:51
|
Местный
  
Группа: Участник
Сообщений: 280
Регистрация: 2-11-08
Пользователь №: 41 333

|
Цитата(AHTOXA @ Dec 20 2012, 08:28)  А чему равно Rx_Data? Как настроен SPI, какие прерывания разрешены? Почему вы проверяете if(Rx_Data>=6) вне ветки if(SPI3->SR&SPI_SR_RXNE)? Первоначально Rx_Data=0; Привожу конфигурацию SPI3, прерывания разрешены только по приему. Код //******************************************************************************** ********* //*Конфигурация SPI3 //******************************************************************************** ********* RCC->APB1ENR|=RCC_APB1ENR_SPI3EN; //Тактирование SPI3 SPI3->CR1|=SPI_CR1_BR_2 |SPI_CR1_BR_1 |SPI_CR1_BR_0 //Скорость Fpclk/256 84 МГц/256=328,125 кГц |SPI_CR1_LSBFIRST //LSB передается вперед |SPI_CR1_SSM //NSS управляется програмно |SPI_CR1_SSI; //NSS=1 SPI3->CR2|=SPI_CR2_SSOE; //NSS в качестве выхода /*CPOL=0 (clock polarity) CK to 0 when idle; CPHA=0 (clock phase) the first clock transition is the first data capture edge DFF=0 (data frame format) 8-bit data format*/ SPI3->CR2|=SPI_CR2_RXNEIE; //Прерывания по окончанию приема и передачи SPI3->CR1|=SPI_CR1_MSTR; //SPI3 режим мастера NVIC_SetPriority(SPI3_IRQn, 3); //Прерывание SPI3 третье по приоритету NVIC_EnableIRQ(SPI3_IRQn); //Разрешаем прерывания SPI3 SPI3->CR1|=SPI_CR1_SPE; //Разрешаем работу SPI3 CS_SET0; //CS=0 Recycler=SPI3->DR; //Прочесть DR SPI3->DR=MASTER_Buffer_Tx[0]; //Первый байт в буфер передачи Tx_Data=1; }
void SPI3_IRQHandler (void){ if(SPI3->SR&SPI_SR_RXNE){ SLAVE_Buffer_Rx[Rx_Data++]=SPI3->DR; //Очищаем RXNE чтением DR if(Rx_Data==6){ CS_SET1; return; } SPI3->DR=MASTER_Buffer_Tx[Tx_Data++]; //Следующий байт в буфер передачи } }
Сообщение отредактировал sidy - Dec 20 2012, 04:52
|
|
|
|
|
Dec 20 2012, 06:41
|
Местный
  
Группа: Участник
Сообщений: 280
Регистрация: 2-11-08
Пользователь №: 41 333

|
Посмотрел я сейчас осциллограммы и кажется (если я правильно понял, что в SPI нет пауз между байтами) передаю я, то что записываю в буфер передачи (см осциллограмму).
Теперь у меня возник вопрос по поводу поднимания CS. Из следующей осциллограммы видно, что при передаче одного байта CS поднимается раньше чем заканчиваются SCK.
Как я понял для поднятия CS нужно ждать когда снимется флаг BSY. Но в прерывании не есть хорошо ждать while(!(SPI3->SR&SPI_SR_BSY)).
Сообщение отредактировал sidy - Dec 20 2012, 06:41
|
|
|
|
|
Dec 20 2012, 07:16
|

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

|
Цитата(sidy @ Dec 20 2012, 10:51)  Код void SPI3_IRQHandler (void){ if(SPI3->SR&SPI_SR_RXNE){ SLAVE_Buffer_Rx[Rx_Data++]=SPI3->DR; //Очищаем RXNE чтением DR if(Rx_Data==6){ CS_SET1; return; } SPI3->DR=MASTER_Buffer_Tx[Tx_Data++]; //Следующий байт в буфер передачи } } Всё же лучше запись в DR тоже засунуть в блок if(SPI3->SR&SPI_SR_RXNE). Потому что случаются прерывания совсем без установленных флагов. Цитата(sidy @ Dec 20 2012, 12:41)  Как я понял для поднятия CS нужно ждать когда снимется флаг BSY. Но в прерывании не есть хорошо ждать while(!(SPI3->SR&SPI_SR_BSY)). Там после RXNE ждать максимум пол-бита. Так что ничего страшного.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Dec 20 2012, 09:22
|

Участник

Группа: Участник
Сообщений: 39
Регистрация: 29-08-11
Из: Киев
Пользователь №: 66 910

|
Цитата Как я понял для поднятия CS нужно ждать когда снимется флаг BSY. Но в прерывании не есть хорошо ждать while(!(SPI3->SR&SPI_SR_BSY)). По идеи ОСРВ должно перехватывать и выполнять параллельно задачи, поэтому зависонов как бы не будет. Только не все ОСРВ, у FreeRTOS например может возникнуть затык, там есть специальная функция для передачи управления другим задачам taskYIELD()
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|