Jump to content

    

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

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

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

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

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

Edited by HHIMERA

Share this post


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

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

Share this post


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

Share this post


Link to post
Share on other sites

Докладываю.

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

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, что гарантирует, что началась пересылка последнего байта, и приемопередатчик занят.

Share this post


Link to post
Share on other sites

И еще.

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

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

Share this post


Link to post
Share on other sites

Как правильно написать функцию отправки 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);
}

Share this post


Link to post
Share on other sites

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

Странно, что обсуждают только 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 циклов

Share this post


Link to post
Share on other sites

Уважаемые коллеги, прочел материалы по данной теме 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 ();

 

Share this post


Link to post
Share on other sites
В 12.10.2018 в 11:23, Vladimir_T сказал:

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

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

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

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

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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this