Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: stm32f407 SPI обнаружил косяк
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2
SasaVitebsk
При инициализации с делителем на 64 (с другими не проверял). SPI3 (с другими не проверял). stm407 на 168МГц (с другими не проверял).
После записи в регистр DR необходимо выждать задержку до проверки флага BSY в регистре SR. Иначе байт может потерятся (затерется следующим).
То есть флаг занятости выскакивает с задержкой. Причём задержка приличная, успеваю выйти и войти в процедуру.
После установки задержки всё устаканилось.
VslavX
Цитата(SasaVitebsk @ Nov 16 2012, 12:45) *
После записи в регистр DR необходимо выждать задержку до проверки флага BSY в регистре SR.

Имхо, не BSY нужно проверять, а TXE. А SPI на STM32 кажется и правда слегка шизанутый, обмен стартует с задержкой после записи в DR если в текущий момент еще ничего не передавалось. Есть у меня подозрение что это схема аппаратного руления CS не до конца отключена и паузы вставляет.
skripach
Попробуйте проверять TXE, а не BSY. BSY это наверно когда непосредственно обмен начался.
SasaVitebsk
Я конечно понимаю, но
Цитата
Bit 7 BSY: Busy flag
0: SPI (or I2S)not busy
1: SPI (or I2S)is busy in communication or Tx buffer is not empty
This flag is set and cleared by hardware.

И по моему у них в stdlib именно BSY используется ...
Flexz
наверное не просто так в RM написано
Цитата
Note: Do not use the BSY flag to handle each data transmission or reception. It is better to use the
TXE and RXNE flags instead.
HHIMERA
Цитата(SasaVitebsk @ Nov 16 2012, 13:45) *
При инициализации с делителем на 64 (с другими не проверял). SPI3 (с другими не проверял). stm407 на 168МГц (с другими не проверял).

Это есть во всех STM32... и ни какой это не косяк...
"Читать даташит до, а не после!"(С)
Цитата
Note: 1 During discontinuous communications, there is a 2 APB clock period delay between the

write operation to SPI_DR and the BSY bit setting.

Цитата
После записи в регистр DR необходимо выждать задержку до проверки флага BSY в регистре SR. Иначе байт может потерятся (затерется следующим).
То есть флаг занятости выскакивает с задержкой. Причём задержка приличная, успеваю выйти и войти в процедуру.
После установки задержки всё устаканилось.

Если STM32F4 сидит на 168MHz, a APB SPI3 42MHz... сам и посчитай...
Всё правильно... никаких косяков и нет...

SasaVitebsk
Цитата(HHIMERA @ Nov 16 2012, 22:34) *
никаких косяков и нет...

C учётом последствий - это просто косяк описанный в даташите.
Там, кстати 2 APB. APB1 (SPI3) и APB2. APB1 по-моему у меня /2.
===
Спорить не буду - сложно посчитать будет. Да и не это главное... Написал, чтобы народ обратил внимание. Я не исключаю, что в другой периферии не может оказаться аналогичных проблем. Думаю из-за значительной скорости процессора.
Я не спорю, это можно описать как "особенности работы с узлами МК" ...
Так, у меня уже проявились "особенности" при работе с I2C и SPI. Так это только начало. Этот SPI работает с АЦП, а SPI1 будет с датафлэшем работать... Если там ещё особенности вылезут - опишу ... ))
KnightIgor
Цитата(Flexz @ Nov 16 2012, 17:14) *
наверное не просто так в RM написано

Поддерживаю. Для полнодуплексного (даже если только передача нужна) SPI завершение передачи нужно проверять по... RXNE (и забыть о TXE или BSY, т.к. STM32F не поддерживает аппаратное формирование SS в режиме мастера!). Тогда будет абсолютная уверенность, что байт ушел, а следующий его не затрет по пути: ведь пока байт выдвигается по MOSI, входящий байт вдвигается по MISO тем же тактовым сигналом. Это означает, что флаг RXNE все равно возникнет, пусть позже TXE, зато наверняка после последнего такта. Нужно помнить чистить RXNE путем чтения DR перед записью туда:

1. Прочесть DR.
2. Записать в DR байт для передачи.
3. Ждать RXNE (будь-то тупо или путем реакции на прерывание).
4. Перейти к п.1., если еще есть данные для передачи.
VslavX
Цитата(KnightIgor @ Nov 17 2012, 00:37) *
Поддерживаю. Для полнодуплексного (даже если только передача нужна) SPI завершение передачи нужно проверять по... RXNE (и забыть о TXE или BSY, т.к. STM32F не поддерживает аппаратное формирование SS в режиме мастера!). Тогда будет абсолютная уверенность, что байт ушел, а следующий его не затрет по пути: ведь пока байт выдвигается по MOSI, входящий байт вдвигается по MISO тем же тактовым сигналом. Это означает, что флаг RXNE все равно возникнет, пусть позже TXE, зато наверняка после последнего такта. Нужно помнить чистить RXNE путем чтения DR перед записью туда:

Делал я так. Побочный эффект - обмен не непрерывный, между байтами пропуски получаются. При тактовой 15МГц, еле на 1МБайт/сек выходило. Пришлось сделать такой вариант:
CODE

IO_CALL_TYPE
DWORD
IO_CALL_OPTION
io_at45_read(void)
{
PSTM_SPI pspi = _AT_SPI_;
//
// В целях сохранения быстродействия не производим проверку
// синхроресурса в функциях самого нижнего уровня
//
// IO_ASSERT( at45_mutex.holder == tn_curr_run_task, "AT45 synch failure");
//
for(;;)
{
DWORD stat;
//
// Значительно более быстрый вариант - ждать TXE и немедленно
// запускать новый цикл на SPI если буфер передатчика готов
// Иначе контроллер делает паузы между символами. Чтобы не
// потерять принимаемый символ при вытеснении потока, запуск
// осуществляем при запрещенных прерываниях
//
stat = pspi->sSPI_SR;
if (stat & bSPI_TXE)
{
DWORD lock, ret;

lock = hal_lock_interrupt();
pspi->sSPI_DR = 0xFF;

for(;;)
{
//
// Ждем завершения предыдущего цикла
// и забираем принятые данные по готовности
//
if (stat & bSPI_RXNE)
{
ret = pspi->sSPI_DR;
break;
}
stat = pspi->sSPI_SR;
}
hal_unlock_interrupt(lock);
return ret & 0xFF;
}
}
}

Скорость выросла раза в 1.5, DMA не пробовал - не очень подходт для задачи.
HHIMERA
Цитата(KnightIgor @ Nov 17 2012, 02:37) *
Поддерживаю.

Да всё там просто...
Всё скрупулёзно и последовательно расписано в даташите...
Нужно просто воспринять TXE, RXNE и BSY так, как их задумал производитель... и обратить их во благо своё...
Вся эта чехарда с флагами, ИМХО, мнимая и надуманная...
SasaVitebsk
Цитата(HHIMERA @ Nov 17 2012, 03:23) *
Да всё там просто...

Ok. Не поленюсь и в понедельник проверю. Есть осциллограф - он чётко покажет. Какие вопросы.
AHTOXA
Цитата(KnightIgor @ Nov 17 2012, 04:37) *
Это означает, что флаг RXNE все равно возникнет, пусть позже TXE, зато наверняка после последнего такта.

Кстати, не факт, что после. В зависимости от режима SPI, RXNE может возникать на середине последнего такта (если данные на приёме защёлкиваются по переднему фронту). Вот тут-то наверное и может пригодиться BSY. (Хотя я лично просто делаю несколько nop-ов перед отпусканием CS)
SasaVitebsk
Цитата(AHTOXA @ Nov 19 2012, 18:47) *
Вот тут-то наверное и может пригодиться BSY.

Подтверждаю. CS по BSY работает корректно. И вообще. Минимальная библиотека получается. Единственное, что требуется задержка перед проверкой флага. Я на этом остановился. Меня это устраивает полностью. Правда пока я работаю с достаточно медленным АЦП. AD7192. Чуть позже, и по другому SPI буду работать с AT45DB... Пока не решил для себя как. Наверное, сначала, чтобы полностью проверить функционал прибора запущу его тем же драйвером. Потом, уже буду думать. Может ПДП буду испоьзовать и CRC аппаратный ... не знаю.
sidy
Цитата(KnightIgor @ Nov 17 2012, 02:37) *
1. Прочесть DR.
2. Записать в DR байт для передачи.
3. Ждать RXNE (будь-то тупо или путем реакции на прерывание).
4. Перейти к п.1., если еще есть данные для передачи.

Не получается: 1. Прочесть DR - после этого флаг RXNE не устанавливается (У меня разрешены прерывания по RXNE). Если сперва что-то записать в DR, то тогда RXNE устанавливается и происходит прерывание.

Еще вопрос как я понимаю при работе с SPI необходимо Мастером всегда толкать данные? Например data-flash at45db имеет команду для чтения manufacture id и device id длиной 1 байт=0x9FH, а ответ 6 байт, т.е. после подачи первого байта я должен еще подать 5 фиктивных байт?
Danis
Цитата(sidy @ Dec 18 2012, 17:47) *
Не получается: 1. Прочесть DR - после этого флаг RXNE не устанавливается (У меня разрешены прерывания по RXNE). Если сперва что-то записать в DR, то тогда RXNE устанавливается и происходит прерывание.

Еще вопрос как я понимаю при работе с SPI необходимо Мастером всегда толкать данные? Например data-flash at45db имеет команду для чтения manufacture id и device id длиной 1 байт=0x9FH, а ответ 6 байт, т.е. после подачи первого байта я должен еще подать 5 фиктивных байт?


В любом случае микросхема SPI памяти не будет выталкивать из себя данные сама, для чтения нужно слать что-нибудь мастером, какие либо незначащие байты.
sidy
Цитата(KnightIgor @ Nov 17 2012, 02:37) *
1. Прочесть DR.
2. Записать в DR байт для передачи.
3. Ждать RXNE (будь-то тупо или путем реакции на прерывание).
4. Перейти к п.1., если еще есть данные для передачи.

И еще один момент если я осуществляю обмен таким образом, то часть байтов затирается. Например: я отсылаю следующие данные: 0x9F; 0; 0x9F; 0x9F; 0x9F; 0x9F. На осциллограмме первый байт правильный, второй тоже правильный остальные не правильные. Вместо 0x9F (0b10011111) судя по всему 1F (0b11111).Нажмите для просмотра прикрепленного файла
AHTOXA
Цитата(sidy @ Dec 19 2012, 15:25) *
И еще один момент если я осуществляю обмен таким образом, то часть байтов затирается.

Скорее всего косяк у вас в коде. Потому что описанный алгоритм - рабочий.
cyb
Похоже у меня подобная проблема на 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 );

AHTOXA
Цитата(cyb @ Dec 19 2012, 19:58) *
Похоже у меня подобная проблема на STM32F103VE. После отсылки байта, не происходит задержи при проверки флага.

У вас другая проблема. Вы отключаете CS сразу после записи байта в DR, не дожидаясь, пока он уйдёт в линию.
Если вы прочитаете эту ветку сначала, то найдёте пару рекомендаций, как это сделать.
sidy
Цитата(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++];            //Передаем следующий байт
  }
}
cyb
Цитата(AHTOXA @ Dec 19 2012, 16:22) *
У вас другая проблема. Вы отключаете CS сразу после записи байта в DR, не дожидаясь, пока он уйдёт в линию.
Если вы прочитаете эту ветку сначала, то найдёте пару рекомендаций, как это сделать.

Ок, спасибо. Я правильно понимаю, что момент когда отпускать CS нужно смотреть по флагу BSY?
AHTOXA
Цитата(sidy @ Dec 19 2012, 21:35) *
Привожу кусок кода:

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

Цитата(cyb @ Dec 19 2012, 23:02) *
Ок, спасибо. Я правильно понимаю, что момент когда отпускать CS нужно смотреть по флагу BSY?

Да, он именно для этого и предназначен.
sidy
Цитата(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++];            //Передаем следующий байт
  }
}

AHTOXA
А чему равно Rx_Data?
Как настроен SPI, какие прерывания разрешены?
Почему вы проверяете if(Rx_Data>=6) вне ветки if(SPI3->SR&SPI_SR_RXNE)?
sidy
Цитата(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
Посмотрел я сейчас осциллограммы и кажется (если я правильно понял, что в SPI нет пауз между байтами) передаю я, то что записываю в буфер передачи (см осциллограмму).
Нажмите для просмотра прикрепленного файла

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

Как я понял для поднятия CS нужно ждать когда снимется флаг BSY. Но в прерывании не есть хорошо ждать while(!(SPI3->SR&SPI_SR_BSY)).
AHTOXA
Цитата(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 ждать максимум пол-бита. Так что ничего страшного.
cyb
Цитата
Как я понял для поднятия CS нужно ждать когда снимется флаг BSY. Но в прерывании не есть хорошо ждать while(!(SPI3->SR&SPI_SR_BSY)).

По идеи ОСРВ должно перехватывать и выполнять параллельно задачи, поэтому зависонов как бы не будет. Только не все ОСРВ, у FreeRTOS например может возникнуть затык, там есть специальная функция для передачи управления другим задачам taskYIELD()
sidy
Спасибо за разъяснения. Задам еще вопрос здесь по поводу data-flash at45db поскольку уже упоминалась в данной теме. Пытаюсь считать с нее device id и manufacture id для этого подаю код команды 0х9F и дополнительно 5 фиктивных байтов (см осциллограммы). На выходе SO получаю не понятную картину. Что это может быть (сигналы WP=1, RESET=1, Vcc=3.3 В)? Или может просто попалась неисправная микросхема.
Нажмите для просмотра прикрепленного файла
Нажмите для просмотра прикрепленного файла
Нажмите для просмотра прикрепленного файла
AHTOXA
Похоже, MISO сконфигурирован как выход.
ViKo
Цитата(AHTOXA @ Nov 19 2012, 18:47) *
Кстати, не факт, что после. В зависимости от режима SPI, RXNE может возникать на середине последнего такта (если данные на приёме защёлкиваются по переднему фронту). Вот тут-то наверное и может пригодиться BSY. (Хотя я лично просто делаю несколько nop-ов перед отпусканием CS)

Пробую понять SPI от STM32. Действие битов SSM, SSI не соответствует описанным в документации. В Интернете фантазируют, кто во что горазд.
Насчет RXNE и BSY. Похоже, они переключаются одновременно в конце передачи.
Но задержка на полтакта для программного снятия CS не нужна. Потому что выборка (защелкивание) данных ведомым устройством как раз и произойдет в момент, когда возникнет RXNE. А дальше пусть такт заканчивается, все равно. Главное, чтобы время удержания данных на входе ведомого устройства не оказалось меньше нормы. Но это наносекунды. С учетом работы программы, беспокоиться не о чем.
Если же ведомое устройство - какой-нибудь регистр, то нужно правильно выбрать полярность тактов SCK.
HHIMERA
Цитата(ViKo @ Jan 9 2013, 17:22) *
Пробую понять SPI от STM32. Действие битов SSM, SSI не соответствует описанным в документации.

Не совсем понял... что там не так???
Небольшие расхождения есть только в описании SPI STM32F0XX... но здесь простительно, сравнительно новый камень, "злокопипаст" и т.д. ...
По SPI STM32F3XX ничего не скажу, не мучал...
По остальным сериям - всё работает как положено...
Цитата
В Интернете фантазируют, кто во что горазд.

Да и пусть... Кто не хочет читать даташит - пусть фантазирует...
В последнее время темы по SPI просто стараюсь игнорировать...
Цитата
Насчет RXNE и BSY. Похоже, они переключаются одновременно в конце передачи.
Но задержка на полтакта для программного снятия CS не нужна. Потому что выборка (защелкивание) данных ведомым устройством как раз и произойдет в момент, когда возникнет RXNE. А дальше пусть такт заканчивается, все равно. Главное, чтобы время удержания данных на входе ведомого устройства не оказалось меньше нормы. Но это наносекунды. С учетом работы программы, беспокоиться не о чем.

Это заблуждения... можно нарваться на непонятный глюк... если напрямую махать регистрами...
Проверяем BSY, потом снимаем CS...
ViKo
Цитата(HHIMERA @ Jan 9 2013, 18:36) *
Это заблуждения... можно нарваться на непонятный глюк... если напрямую махать регистрами...
Проверяем BSY, потом снимаем CS...

Непонятных глюков не бывает. Бывают не понятые.
Я проверяю RXNE. Это - то же самое. Микроконтроллер пользую STM32F207.
HHIMERA
Цитата(ViKo @ Jan 9 2013, 21:28) *
Я проверяю RXNE. Это - то же самое.

Пусть будет "Это - то же самое."... )))
Сами подумайте... по вашему, STM прилепила в SPI "левый", никому не нужный, бит BSY...
Так поверьте, это не так... При всей своей кажущейся "простоте и непонятности" у STM получился SPI с довольно таки широкими возможностями...
ViKo
Цитата(HHIMERA @ Jan 9 2013, 21:19) *
Пусть будет "Это - то же самое."... )))
Сами подумайте... по вашему, STM прилепила в SPI "левый", никому не нужный, бит BSY...
Так поверьте, это не так... При всей своей кажущейся "простоте и непонятности" у STM получился SPI с довольно таки широкими возможностями...

Вам надо разжевывать каждое выражение? "То же самое" с точки зрения обнаружения окончания передачи. На картинки в руководстве взгляните. Или мне для вас специально вырезать и запостить?
HHIMERA
Ещё раз... не то же самое!!!
Когда нарвётесь, тогда и поймёте о чём речь... референс мануал полистайте, в конце концов...
(Поэтому и стараюсь игнорировать темы по SPI... вечно "глюки" и "косяки" там, где их нет и никогда и не было... )
Когда начинал работать с STM32... меня тоже, местами, SPI шокировал...
Теперь это всё вспоминаю с улыбкой... а регистры и биты SPI "кручу как цыган солнце"... невзирая на даташит... он теперь мне вообще не нужен...
Просто пришло понимание, что и как работает... и только...
ViKo
Цитата(HHIMERA @ Jan 9 2013, 21:39) *
Ещё раз... не то же самое!!!

Смотрим в книгу... Конец передачи - RXNE и BSY изменяются одновременно. То есть, при проверке окончания передачи можно использовать и тот, и другой биты, с одинаковым успехом. При передаче многобайтовых последовательностей для записи байтов в DR лучше проверять TXE, а конец передачи определять, как сказано выше. Хотя можно записывать байты и по и RXNE, можно и по BSY . Но тогда появятся задержки между передачами байтов. Поскольку CS мы формируем программно, не страшно.
Нажмите для просмотра прикрепленного файла
Цитата
Просто пришло понимание, что и как работает... и только...

Проверим? Для связи STM32F207 с M25PE40 (мастер и слейв, соответственно, пишу для полного понимания) мне пришлось программировать SPI следующим образом. Вывод NSS я прицепил на /S памяти, рассчитывая управлять аппаратно. Но не получилось. Пришлось использовать, как GPIO.
CODE

/* SPI1 -- связь с SFM M25PE40
8-bit, MSB first, SPEn, Fpclk2 / 4 (15 MHz), Master, CPOL=0, CPHA=0 */
SPI1->CR1 =
SPI_CR1_CPHA * 0 | // Clock Phase
SPI_CR1_CPOL * 0 | // Clock Polarity
SPI_CR1_MSTR * 1 | // Master Selection
SPI_CR1_BR_0 * 1 | // Baud Rate Control - fpclk2 / 4 = 15 MHz
SPI_CR1_BR_1 * 0 | //
SPI_CR1_BR_2 * 0 | //
SPI_CR1_SPE * 1 | // SPI Enable
SPI_CR1_LSBFIRST * 0 | // Frame Format
SPI_CR1_SSI * 1 | // Internal slave select
SPI_CR1_SSM * 1 | // Software slave management
SPI_CR1_RXONLY * 0 | // Receive only
SPI_CR1_DFF * 0 | // Data Frame Format
SPI_CR1_CRCNEXT * 0 | // Transmit CRC next
SPI_CR1_CRCEN * 0 | // Hardware CRC calculation enable
SPI_CR1_BIDIOE * 0 | // Output enable in bidirectional mode
SPI_CR1_BIDIMODE * 0; // Bidirectional data mode enable
SPI1->CR2 =
SPI_CR2_RXDMAEN * 0 | // Rx Buffer DMA Enable
SPI_CR2_TXDMAEN * 0 | // Tx Buffer DMA Enable
SPI_CR2_SSOE * 0 | // SS Output Enable
SPI_CR2_FRF * 0 | // Protocol format - 0: SPI Motorola mode, 1: SPI TI mode
SPI_CR2_ERRIE * 0 | // Error Interrupt Enable
SPI_CR2_RXNEIE * 0 | // RX buffer Not Empty Interrupt Enable
SPI_CR2_TXEIE * 0; // Tx buffer Empty Interrupt Enable

Обратите внимание на SSM и SSI. Ни при каких других комбинациях SPI не работал. В отличие от STM32F103, где была другая комбинация магических битов.
Объясните, зачем нужны эти биты, если ногой NSS я управляю, как GPIO. Покажите, в каком месте руководства это написано. Покажите, как работает у вас.

P.S. А мануал я листаю в начале начал, а не в конце концов.
AHTOXA
Цитата(ViKo @ Jan 9 2013, 20:22) *
Насчет RXNE и BSY. Похоже, они переключаются одновременно в конце передачи.

Что значит "похоже"? Как вы это выяснили?
Нет, не одновременно.
Цитата(ViKo @ Jan 9 2013, 20:22) *
Но задержка на полтакта для программного снятия CS не нужна. Потому что выборка (защелкивание) данных ведомым устройством как раз и произойдет в момент, когда возникнет RXNE.

А если на пару наносекунд позже? sm.gif
Понимаете, базируясь на RXNE, вы устраиваете гонки - кто первый примет последний бит. Если сначала примет устройство, потом STM-ка, то всё в порядке. А если в гонке победит STM-ка, то CS будет сброшен раньше чем нужно, и вся посылка будет потеряна.
HHIMERA
Цитата(ViKo @ Jan 9 2013, 23:09) *
Покажите, как работает у вас.

Вытащил из "мусорника"...
Код
   do
             { 
// здесь то, что нужно                
             } while (--cnt);

            while(SPI2->SR & SPI_SR_BSY);        // Wait for SPI Rx Buffer Empty 

Ничего примечательного... вроде... кроме комента... "Wait for SPI Rx Buffer Empty"...
Он остался от проверки RXNE (неудачный копипаст)... Если вернуть проверку RXNE, то происходит потеря данных...

А это то, что реально работает... SPI 9bit на STM32F100...

Нажмите для просмотра прикрепленного файла
ViKo
Цитата(AHTOXA @ Jan 9 2013, 22:18) *
Что значит "похоже"? Как вы это выяснили?

по картинке
Цитата
А если на пару наносекунд позже? sm.gif

У нас есть команды проверки флага, перехода, если установился, подготовки байта (CS) для засылки в порт, засылки в порт. Даже на 168 MHz тактовой это займет не один десяток ns. Пара nop, что вы добавляете, составит ~1/4 от всего количества команд.

Цитата(HHIMERA @ Jan 9 2013, 22:33) *
Вытащил из "мусорника"...

вытащите из чего угодно не "мусор", а программирование битов SSM и SSI.

Цитата(AHTOXA @ Jan 9 2013, 22:18) *
Понимаете, базируясь на RXNE, вы устраиваете гонки - кто первый примет последний бит. Если сначала примет устройство, потом STM-ка, то всё в порядке. А если в гонке победит STM-ка, то CS будет сброшен раньше чем нужно, и вся посылка будет потеряна.

Грубо говоря, они примут одновременно. Если не обращать внимания на скорость распространения сигналов по плате (~ 20 sm за 1 ns) и на разные пороги срабатывания триггеров в STM и ведомом устройстве (при нормальных фронтах SCK вряд ли разбежка будет больше 1 ns). Если SCK в ведомое устройство доберется с опозданием, то, очевидно, и CS так же опоздает.
Во всяком случае, задержка именно на полтакта не нужна. Нужно смотреть на время удержания для конкретного ведомого устройства. В некоторых тормозных оно может быть большим, в некоторых равно 0.
HHIMERA
Цитата(ViKo @ Jan 9 2013, 23:36) *
а программирование битов SSM и SSI.

А правильную инициализацию я тоже за вас писать буду???
Настраиваем всё как надо, а потом только SPI_CR1_SPE...
А ведь в даташите это написано...
ViKo
Цитата(HHIMERA @ Jan 9 2013, 22:48) *
А правильную инициализацию я тоже за вас писать буду???
Настраиваем всё как надо, а потом только SPI_CR1_SPE...
А ведь в даташите это написано...

Ржу-нимагу! Я проверил экспериментально. Делал SPE отдельно. Делал SPE вместе с MSTR, как написано в руководстве. Сделал одновременно с конфигурацией. Один ... результат, отвечаю! Именно на STM32F207. НА STM32F103 разрешал отдельной командой. Иначе - никак.
Вы по прежнему будете утверждать, что в STM всё идеально?
HHIMERA
Цитата(ViKo @ Jan 9 2013, 23:55) *
Ржу-нимагу! Я проверил экспериментально.

Продолжайте... авось и заработает...
ViKo
Цитата(HHIMERA @ Jan 9 2013, 23:03) *
Продолжайте... авось и заработает...

Работает с 16.00
HHIMERA
Цитата(ViKo @ Jan 9 2013, 23:55) *
Вы по прежнему будете утверждать, что в STM всё идеально?

Да!
"Почему у меня всё работает, что я делаю не так?" (С)
AHTOXA
Цитата(ViKo @ Jan 10 2013, 01:47) *
по картинке

Думаю, что врёт картинка. Потому что в тексте не так. (И из опыта - тоже не так.)
BSY сделан для управления чипселектом, а чипселект надо держать до конца байта, а не до гипотетического момента, когда нам думается, что ведомое устройство уже приняло байт.
Цитата(ViKo @ Jan 10 2013, 01:47) *
У нас есть команды проверки флага, перехода, если установился, подготовки байта (CS) для засылки в порт, засылки в порт. Даже на 168 MHz тактовой это займет не один десяток ns. Пара nop, что вы добавляете, составит ~1/4 от всего количества команд.

Да ради бога, если вам нравится делать устройства, работа которых зависит от погоды на Марсе - делайте, как вам угодно. Только потом не удивляйтесь, если ваш девайс перестанет работать с новой партией микросхем. Вам два человека хором говорят, что RXNE и BSY - это не одно и то же, и что они ходили по этим граблям. Но выбор, конечно, за вами.

Цитата(ViKo @ Jan 10 2013, 01:55) *
Именно на STM32F207. НА STM32F103 разрешал отдельной командой. Иначе - никак.

У меня на 10x тоже одной командой:
Код
    RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;
    SPIx->I2SCFGR &= ~SPI_I2SCFGR_I2SMOD;
    SPIx->CR2 = 0;
    SPIx->CR1 = SPI_CR1_MSTR | divisor | SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_SPE | phase | cpol;

И работает. ЧЯДНТ?
ViKo
Цитата(AHTOXA @ Jan 9 2013, 23:30) *
... а чипселект надо держать до конца байта, а не до гипотетического момента...

Не надо
Цитата
И работает. ЧЯДНТ?

Что нам скажет товарищ HHIMERA?

103-й я программировал так. Возможно, при другом сочетании можно было бы сразу разрешить.
Код
  SPI1->CR1 = SPI_CR1_SSI | SPI_CR1_BR_0 | SPI_CR1_MSTR;        // Fpclk/4
  SPI1->CR2 = SPI_CR2_SSOE;
...
  SPI_Cmd(SPI1, ENABLE);        // разрешить SPI1


Цитата(AHTOXA @ Jan 9 2013, 23:30) *
два человека хором говорят, что RXNE и BSY - это не одно и то же, и что они ходили по этим граблям

И я прошелся когда-то давным-давно, и ничего не заметил:
Код
inline uint8_t SFMByte_send(uint8_t data) {
  while (!(SPI1->SR & SPI_SR_TXE));    // ждать освобождения
  SPI1->DR = data;            // послать данные
  while (!(SPI1->SR & SPI_SR_RXNE));    // ждать байта в приемнике (конца передачи)
//  while (SPI1->SR & SPI_SR_BSY);    // другой способ дождаться конца передачи
  return SPI1->DR;
HHIMERA
Что вы референс не читали...
RXNE говорит только о том, что можно/нельзя забирать данные из приёмного буфера, но это, увы, не признак окончания передачи... вернее, не всегда является признаком...
По поводу SPI_CR1_SSM и SPI_CR1_SSI... всегда их устанавливал... во всей линейке STM32...
ViKo
Цитата(HHIMERA @ Jan 10 2013, 00:00) *
Что вы референс не читали...
RXNE говорит только о том, что можно/нельзя забирать данные из приёмного буфера, но это, увы, не признак окончания передачи... вернее, не всегда является признаком...

Да ну? А вы в курсе, что прием и передача происходят синхронно? Один битик выдвинули, один задвинули.
HHIMERA
Цитата(ViKo @ Jan 9 2013, 23:53) *
И я прошелся когда-то давным-давно, и ничего не заметил:
Код
inline uint8_t SFMByte_send(uint8_t data) {
  while (!(SPI1->SR & SPI_SR_TXE));    // ждать освобождения
  SPI1->DR = data;            // послать данные
  while (!(SPI1->SR & SPI_SR_RXNE));    // ждать байта в приемнике (конца передачи)
//  while (SPI1->SR & SPI_SR_BSY);    // другой способ дождаться конца передачи
  return SPI1->DR;

Конечно не заметили...
while (!(SPI1->SR & SPI_SR_TXE)); здесь и даром не нужна... смело можно выкинуть...
И вполне логично, если возвращать return SPI1->DR, то и проверять нужно while (!(SPI1->SR & SPI_SR_RXNE)); ...
О дёргании CS тут не слова... увы...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.