Перейти к содержанию
    

stm32f407 SPI обнаружил косяк

1. Прочесть DR.

2. Записать в DR байт для передачи.

3. Ждать RXNE (будь-то тупо или путем реакции на прерывание).

4. Перейти к п.1., если еще есть данные для передачи.

И еще один момент если я осуществляю обмен таким образом, то часть байтов затирается. Например: я отсылаю следующие данные: 0x9F; 0; 0x9F; 0x9F; 0x9F; 0x9F. На осциллограмме первый байт правильный, второй тоже правильный остальные не правильные. Вместо 0x9F (0b10011111) судя по всему 1F (0b11111).post-41333-1355909123_thumb.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

И еще один момент если я осуществляю обмен таким образом, то часть байтов затирается.

Скорее всего косяк у вас в коде. Потому что описанный алгоритм - рабочий.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Похоже у меня подобная проблема на 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 );

62aae2d21572c8db3467e7de37cbc1d8.jpeg

 

 

 

Ситуация номер 2. Делитель на 2

75afd6abf4264e491f9e8ac2dc98d288.jpeg

 

 

 

И ситуация номер 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 );

9714d8c3339b45326b0153cf2800e129.jpeg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Похоже у меня подобная проблема на STM32F103VE. После отсылки байта, не происходит задержи при проверки флага.

У вас другая проблема. Вы отключаете CS сразу после записи байта в 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++];            //Передаем следующий байт
  }
}

Изменено пользователем sidy

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У вас другая проблема. Вы отключаете CS сразу после записи байта в DR, не дожидаясь, пока он уйдёт в линию.

Если вы прочитаете эту ветку сначала, то найдёте пару рекомендаций, как это сделать.

Ок, спасибо. Я правильно понимаю, что момент когда отпускать CS нужно смотреть по флагу BSY?

Изменено пользователем cyb

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Привожу кусок кода:

Хорошо, давайте разбираться по порядку. Где у вас п.1 ("Прочесть DR.") ?

 

Ок, спасибо. Я правильно понимаю, что момент когда отпускать CS нужно смотреть по флагу BSY?

Да, он именно для этого и предназначен.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хорошо, давайте разбираться по порядку. Где у вас п.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++];            //Передаем следующий байт
  }
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А чему равно Rx_Data?

Как настроен SPI, какие прерывания разрешены?

Почему вы проверяете if(Rx_Data>=6) вне ветки if(SPI3->SR&SPI_SR_RXNE)?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А чему равно 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Посмотрел я сейчас осциллограммы и кажется (если я правильно понял, что в SPI нет пауз между байтами) передаю я, то что записываю в буфер передачи (см осциллограмму).

post-41333-1355985299_thumb.jpg

 

Теперь у меня возник вопрос по поводу поднимания CS. Из следующей осциллограммы видно, что при передаче одного байта CS поднимается раньше чем заканчиваются SCK.

post-41333-1355985507_thumb.jpg

 

Как я понял для поднятия CS нужно ждать когда снимется флаг BSY. Но в прерывании не есть хорошо ждать while(!(SPI3->SR&SPI_SR_BSY)).

Изменено пользователем sidy

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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). Потому что случаются прерывания совсем без установленных флагов.

 

Как я понял для поднятия CS нужно ждать когда снимется флаг BSY. Но в прерывании не есть хорошо ждать while(!(SPI3->SR&SPI_SR_BSY)).

Там после RXNE ждать максимум пол-бита. Так что ничего страшного.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как я понял для поднятия CS нужно ждать когда снимется флаг BSY. Но в прерывании не есть хорошо ждать while(!(SPI3->SR&SPI_SR_BSY)).

По идеи ОСРВ должно перехватывать и выполнять параллельно задачи, поэтому зависонов как бы не будет. Только не все ОСРВ, у FreeRTOS например может возникнуть затык, там есть специальная функция для передачи управления другим задачам taskYIELD()

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо за разъяснения. Задам еще вопрос здесь по поводу data-flash at45db поскольку уже упоминалась в данной теме. Пытаюсь считать с нее device id и manufacture id для этого подаю код команды 0х9F и дополнительно 5 фиктивных байтов (см осциллограммы). На выходе SO получаю не понятную картину. Что это может быть (сигналы WP=1, RESET=1, Vcc=3.3 В)? Или может просто попалась неисправная микросхема.

post-41333-1356091694_thumb.jpg

post-41333-1356091701_thumb.jpg

post-41333-1356091706_thumb.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...