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

    

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

С другой стороны, имеющийся у меня негативный опыт неопровержимо доказывает, что с таким подходом могут быть проблемы.

Несомненно...

Приведённый код избыточен и работоспособен для низких скоростей...

На полной скорости (половинной) трансфер станет "дырявым" при 8 bit, где поведение BSY уже отличается... придётся всё пересматривать и т.д. ...

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

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


Ссылка на сообщение
Поделиться на другие сайты
С другой стороны, имеющийся у меня негативный опыт неопровержимо доказывает, что с таким подходом могут быть проблемы.

Надо, все-таки, добавить ремарку. Может ваш негативный опыт обусловлен кривизной даташита? Помните про количество тактов 15 или 16?

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


Ссылка на сообщение
Поделиться на другие сайты
Может ваш негативный опыт обусловлен кривизной даташита? Помните про количество тактов 15 или 16?
Вряд ли. Во-первых, я всё время передавал 16 бит. И во-вторых, как только я стал удерживать чипселект до окончания клоков, проблема ушла.

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


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

Докладываю.

Посылаю в длинный последовательный регистр (или в ЦАП) последовательность из нескольких байтов. Читать ничего не читаю (не нужно, нечего). Так вот в таком случае определять завершение передачи способом

while (!(SPI3->SR & SPI_SR_RXNE));    // ждать конец передачи - так нельзя!

не годится! Потому что флаг RXNE установится после первой же пересылки байта. И не сбросится, пока не прочитаешь регистр данных DR.

Так как мне не нужно было читать из SPI, то конец передачи обнаруживался "досрочно", при первой же проверке SR & SPI_SR_RXNE.

В этом случае правильное решение - проверять BSY.

while (!(SPI3->SR & SPI_SR_TXE));    // ждать освобождение буфера передатчика
while (SPI3->SR & SPI_SR_BSY);    // ждать освобождение приемопередатчика

Поскольку пересылка байтов может быть прервана в середине, то BSY тоже может иметь "разрыв". Спасает ожидание освобождения буфера передатчика перед проверкой BSY, что гарантирует, что началась пересылка последнего байта, и приемопередатчик занят.

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


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

И еще.

Для переключения полярности синхроимпульсов при работе то на ЦАП, то на регистр, нужно запрещать SPI. Мелочь, об этом и в datasheet написано, но сразу я так не сделал.

  SPI3->CR1 &= ~SPI_CR1_SPE;        // запретить SPI
  SPI3->CR1 |= SPI_CR1_CPOL;        // данные стабильные на срезе \_
  SPI3->CR1 |= SPI_CR1_SPE;        // разрешить SPI

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


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

Как правильно написать функцию отправки 16 бит по SPI ? Нужно в общем так: линию Fsync в ноль, затем отправка 16 бит, и после поднять линию Fsync вверх.

void SPI1_WriteWorld(int Data)
{
    // FSYNC в 0
    GPIO_WriteBit(GPIOA,GPIO_Pin_4,Bit_RESET);
    // Отправка данных (16 бит)
  SPI_I2S_SendData(SPI1, Data);
  // Жду пока буфер TX будет пустой
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET)
    // FSYNC в 1
  GPIO_WriteBit(GPIOA,GPIO_Pin_4,Bit_SET);
}

так или

{
    // FSYNC в 0
    GPIO_WriteBit(GPIOA,GPIO_Pin_4,Bit_RESET);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    SPI_I2S_SendData(SPI1, Data);
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);  
    GPIO_WriteBit(GPIOA,GPIO_Pin_4,Bit_SET);
}

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


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

Подниму тут тему.

Странно, что обсуждают только STM32 SPI MASTER.

Хотя, судя по моим мучениям, проблемы с SPI SLAVE тоже имеется.

 

Работаю с STM32F0. Частота SPI максимальная (PCLK/2, PCLK = HCLK)

Нарвался на 1 косяк описанный в ERRATA (BUSY=1 навсегда) и еще штуки 4 не описанных никак:

 

1. При CPOL=1 CPHA=1 SPI просто не рабочий - SO на последнем бите меняет свое состояние в момент, когда происходит фиксакция состояния

post-10882-1529651955_thumb.png

 

2. При CPOL=1 CPHA=0 все нормально, но вот MASTER непонятно когда фиксирует бит, очень похоже, что все равно на последнем фронте (как при CPHA=1)? так как последний бит может прийти неверным!

post-10882-1529652403_thumb.png

 

3. При работе в BIDIMODE=1 при переходе с приема на передачу (у MASTER) должно пройти некоторое время, большее чем длительность 2-х байтов!.

Иначе при переключении в BIDIOE = 0 передача первого содержимого в FIFO теряется. Т.е. передача начинается, но первая запись (2 байта, если писали в 16 разрядный DR) на выходе неверная! Ну, или как минимум первый бит

  static char txbuf[] = "0123456789ABCDEFG";

post-10882-1529653661_thumb.png

      DEBUG_PIN_HIGH();
      SPILINK->CR1 = SPI_MASTER_START_TX_CR1;
      SPILINK->DR = 0xAAAA;

post-10882-1529654766_thumb.png

 

4. Вообще, первые биты при переходе с приема на передачу могут закосячится ВСЕГДА! Даже если подождать ООчень долго.

Тут, как видно, закосячились аж ДВА бита:

post-10882-1529654766_thumb.png post-10882-1529656573_thumb.png

 

5. SPE для SLAVE похоже по боку. При наличии SS даже при сброшенном SPE он все равно начинает прием данных! :wacko:

 

6. Что за "художества" возникают e MASTER на ноге CLK сразу после SPE=1?

При CPOL=1 CPHA=0 post-10882-1529658891_thumb.png

При CPOL=0 CPHA=0 post-10882-1529659014_thumb.png

последний бит крупным планом post-10882-1529659126_thumb.png

 

Обсчем, не очень понимаю, как с таким работать.... По мне так он в STM нерабочий наравне с I2C

 

PS. Задержка на вход в прерывание у F0 очень своеобразная... Такое ощущение, что где-то стоит делитель на 4: реакция на изменение значение COMPARE у таймера только каждые 4 значение (тактирование от PCLK = HCLK).

На примере:

Могу попасть либо сюда post-10882-1529664293_thumb.png, либо сюда post-10882-1529664584_thumb.png

но никак не попасть между ними!

Длительность входа я не измерял. но от прерывание таймера явно раза в 3-4 превышает заявленные 16 циклов

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


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

Уважаемые коллеги, прочел материалы по данной теме SPI в STM32F4xx, но прежде все "неточности" работы SPI обнаружил у себя на MCU STM32F410. Мастером является STM32F405 , а ведомым STM32F410. На обоих процессорам обмен производится через прерывания. У мастера обмен: прием/передача без ошибок. А ведомый ведет себя так:

принимает без ошибок, а вот передает - с ошибками! Но главное, что пока идет прием одного байта, он умудряется несколько раз вызвать прерывание по опустошению буфера TX. Код обработчика простой, инициализация также. Может будут какие-либо мысли - поделитесь со мной, пожалуйста.

Идея обмена проста. В фоновом режиме получаем последовательность и в также заполняем буфер передатчика: опустел буфер, взвелся флаг TXE в SPI->SR, вырабатывается прерывание и в буфер передатчика заносим очередное значение.  Но когда начинается обмен, то флаг TXE появляется чаще RXNE, хотя они должны следовать один после другого.  Потому тестовые счетчики Cnt1 и Cnt2.    

  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //Config SPI Protocol
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;				 //
  SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;            // High
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;           // 
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;     //
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;  // 16  
  SPI_Init(SPI1, &SPI_InitStructure);
  SPI_Cmd(SPI1, ENABLE);
  SPI_CalculateCRC(SPI1, DISABLE);
  SPI_SSOutputCmd(SPI1, DISABLE);
    
  Cnt_Tx = Cnt_Rx =0; 
  SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE);
  SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_TXE, ENABLE);

/*****************************************************************************
 SPI1_IRQHandler (); 
******************************************************************************/
TControl *pCtrl = &Control;

u32 Cnt1 =0, Cnt2=0, Cnt3=0;

__irq void SPI1_IRQHandler(void)
{
 if (SPI_I2S_GetITStatus(SPI1, SPI_IT_TXE))
  { 		
		 SPI1->DR = *pOut_Buff++;
	 if (++Cnt_Tx == Cnt_Pack)
		{ 
			Cnt_Tx = 0;
			Cnt1 ++;								// For Test
			pOut_Buff = (u8*)&SPI_USonic_Out;		// Init pointer
	  }
  }	
		
 if (SPI_I2S_GetITStatus(SPI1, SPI_IT_RXNE))
  { 		 
		 *pIn_Buff++ = SPI1->DR;
   if (++Cnt_Rx == Cnt_Pack) 
    { 
      Cnt_Rx = 0;
	  Cnt2++;									// For Test
      pCtrl-> Link_SPI = True;  				// Link is Ready
	  pIn_Buff = (u8*)&SPI_USonic_In;			// Init pointer
    } 
   }			
} // SPI1_IRQHandler ();

 

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


Ссылка на сообщение
Поделиться на другие сайты
В 12.10.2018 в 11:23, Vladimir_T сказал:

Но главное, что пока идет прием одного байта, он умудряется несколько раз вызвать прерывание по опустошению буфера TX

Такое поведение я бы понял при наличии буферов FIFO на кристалле (в частности, для STM32F745 / F3xx / F030 такое поведение нормально. Данные загружаются в регистр данных, но попадают в FIFO буфер, в очередь передачи (размер - 32 бита), и фактически буфер передачи в этот момент становится пуст.

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

Если есть логический анализатор - можете попробовать выводить отладку на пины. Сверьтесь с графиком 248 (параграф 25.3.9) по передачи данных со стороны ведомого контроллера. Естественно, внутренние сигналы придётся выводить во вне во время прерываний. И помните, что последние будут отставать от фактического события.

Но можно сильно увеличить делитель частоты для SPI, чтобы минимизировать отставание.

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


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

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
Авторизация