Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: stm32f407 SPI обнаружил косяк
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2
ViKo
Цитата(HHIMERA @ Jan 10 2013, 00:06) *
О дёргании CS тут не слова... увы...

Код
inline uint32_t SFMID_read(void)
{
  SFMSel_low();
  volatile uint32_t ID = 0;
  SFMByte_send(SFM_RDID);            // Send "RDID " instruction
  ID = SFMByte_send(SFM_DUMMY);            // Read a byte from the SFM
  ID = (ID<<8) | (SFMByte_send(SFM_DUMMY));    // Read a byte from the SFM
  ID = (ID<<8) | (SFMByte_send(SFM_DUMMY));    // Read a byte from the SFM
  SFMSel_high();
  return ID;
}
Tahoe
Цитата(ViKo @ Jan 10 2013, 01:02) *
Да ну? А вы в курсе, что прием и передача происходят синхронно? Один битик выдвинули, один задвинули.

И о чем нам это говорит? (с)

Какая еще такая "синхронная" связь, между "выдвижением битиков" и выставлением флагов, которые еще через стопицот разных шин, с не пойми какими частотами, доставляются до ядра? В каком порядке эти флаги выставляются, какие там буферизации/задержки, не видя исходного Verilog/VHDL ( на чем там был пИсан этот SPI модуль ), можно только гадать. Или просто воспользоваться описанием в документации.
HHIMERA
Цитата(ViKo @ Jan 10 2013, 00:02) *
Да ну? А вы в курсе, что прием и передача происходят синхронно? Один битик выдвинули, один задвинули.

Неужели???
Вы так и собираетесь мучаться со SPI STM32 на уровне АВР??? )))
Да дочитайте уже референс до конца... спокойно и без нервов... включите воображение...
В частности... для чего существует TXE... и что такое непрерывный режим передачи...
AHTOXA
Цитата(ViKo @ Jan 10 2013, 02:53) *
Не надо

Я лично сталкивался с устройствами, которые отбрасывали посылку, если чипселект не удерживать до окончания клоков. Но раз вам не надо, то конечно, дело ваше.
Вообще, у вас очень странная позиция. Если вы утверждаете, что нет разницы между RXNE и BSY, то почему вы упёрлись в использование RXNE? Чисто чтоб поспорить?
Короче, утомили вы меня, не стану больше вас отговаривать от глупых поступков. Да и вообще зря я это начал, сразу было понятно, что бесперспективняк.
ViKo
Цитата(HHIMERA @ Jan 10 2013, 00:06) *
while (!(SPI1->SR & SPI_SR_TXE)); здесь и даром не нужна... смело можно выкинуть...

это верно
Tahoe
Цитата(AHTOXA @ Jan 10 2013, 01:18) *
Я лично сталкивался с устройствами, которые отбрасывали посылку, если чипселект не удерживать до окончания клоков

Скажу больше, я даже сталкивался с камнем, который защелкивал CS фронтом последнего клока. sm.gif Хотя, формально, это не был SPI, просто serial interface.
ViKo
Цитата(AHTOXA @ Jan 10 2013, 00:18) *
Я лично сталкивался с устройствами, которые отбрасывали посылку, если чипселект не удерживать до окончания клоков. Но раз вам не надо, то конечно, дело ваше.

Взгляните на картинку еще раз. Среза при передаче последнего бита b7 нет. Ждать нечего.
Цитата
Вообще, у вас очень странная позиция. Если вы утверждаете, что нет разницы между RXNE и BSY, то почему вы упёрлись в использование RXNE? Чисто чтоб поспорить?

А вы?

Цитата(HHIMERA @ Jan 10 2013, 00:15) *
Вы так и собираетесь мучаться со SPI STM32 на уровне АВР??? )))
Да дочитайте уже референс до конца... спокойно и без нервов... включите воображение...
В частности... для чего существует TXE... и что такое непрерывный режим передачи...

Фантазии отбрасываем. Обсуждаем технические вопросы. Оценки личностных качеств оставляем при себе.

Меня больше интересуют биты SSM и SSI.

Цитата(Tahoe @ Jan 10 2013, 00:22) *
Скажу больше, я даже сталкивался с камнем, который защелкивал CS фронтом последнего клока. sm.gif Хотя, формально, это не был SPI, просто serial interface.

О сдвиговых регистрах я упоминал выше.

Цитата(Tahoe @ Jan 10 2013, 00:15) *
И о чем нам это говорит? (с)

Какая еще такая "синхронная" связь, между "выдвижением битиков" и выставлением флагов, которые еще через стопицот разных шин, с не пойми какими частотами, доставляются до ядра?

О том, что если флаги дошли до ядра, то битики уже выдвинуты и задвинуты. sm.gif
А пока от ядра дойдет до порта, пройдет ох... ох, сколько наносекунд! Так что ведомое устройство уже получит своё.
HHIMERA
Цитата(ViKo @ Jan 10 2013, 00:38) *
Фантазии отбрасываем. Обсуждаем технические вопросы.

А я технически и обсудил...
Приведённые вами примеры - "лишь бы работало"...
В них возможности SPI STM32 не раскрыты даже частично... но я не настаиваю...
Цитата
Меня больше интересуют биты SSM и SSI.

Всё сначала... Что с ними не так???
Tahoe
Цитата(ViKo @ Jan 10 2013, 01:48) *
О том, что если флаги дошли до ядра, то битики уже выдвинуты и задвинуты. sm.gif

Не надо приписывать флагу то, в чем он "не копенгаген". Битики может и задвинуты, но откуда RXNE знать, что SPI трансфер завершен?
ViKo
Подправил код для чтения идентификатора SPI Flash Memory, что показывал выше. Такты выдаются непрерывным потоком, сигнал SS стал короче в 1.5 раза.
CODE

uint32_t SFMID_read(void) {
SMSS_ON();
uint32_t id = 0;
SPI1->DR = SFM_RDID; // послать команду "RDID"
while (!(SPI1->SR & SPI_SR_TXE)); // ждать освобождение передатчика
SPI1->DR = SFM_DUMMY; // послать пустой байт
while (!(SPI1->SR & SPI_SR_RXNE)); // ждать байт в приемнике
id = SPI1->DR; // High Impedance
while (!(SPI1->SR & SPI_SR_TXE)); // ждать освобождение передатчика
SPI1->DR = SFM_DUMMY; // послать пустой байт
while (!(SPI1->SR & SPI_SR_RXNE)); // ждать байт в приемнике
id = SPI1->DR << 16; // Manufacturer
while (!(SPI1->SR & SPI_SR_TXE)); // ждать освобождение передатчика
SPI1->DR = SFM_DUMMY; // послать пустой байт
while (!(SPI1->SR & SPI_SR_RXNE)); // ждать байт в приемнике
id |= SPI1->DR << 8; // Memory type
// while (!(SPI1->SR & SPI_SR_TXE)); // ждать освобождение передатчика
while (!(SPI1->SR & SPI_SR_RXNE)); // ждать байт в приемнике
id |= SPI1->DR; // Memory capacity
// while (SPI1->SR & SPI_SR_BSY); // ждать, если SPI занят
SMSS_OFF();
// Test = id;
return id;
}
AHTOXA
Я тут проделал несколько опытов, чтобы разобраться с различиями в использовании RXNE и BSY. И вот что вышло.
Условия эксперимента. Я смотрел осциллограммы двух функций. Вот эта отключает чипселект по RXNE:
Код
void testRXNE(SPI_TypeDef* spi){
    CS::On();
    spi->DR = 0xAA;
    while (!(spi->SR & SPI_SR_RXNE));
    spi->DR;
    spi->DR = 0xAA;
    while (!(spi->SR & SPI_SR_RXNE));
    CS::Off();
    spi->DR;
}

А вот эта - по BSY:
Код
void testBSY(SPI_TypeDef* spi){
    CS::On();
    spi->DR = 0xAA;
    while (!(spi->SR & SPI_SR_TXE));
    spi->DR = 0xAA;
    while ((spi->SR & SPI_SR_BSY));
    CS::Off();
    spi->DR;
}

(Считывание DR в конце функций производится после сброса чипселекта, чтобы не влиять на время реакции.)
Проверял на F103 и F407. Результаты совпадают. (Картинки с F103)
Легенда: Жёлтый - клок, синий - чипселект.
Результаты.
Первое. Всё-таки BSY не ждёт окончания передачи последнего клока. На маленьких частотах это особенно заметно (картинка идентична для обеих функций):
Нажмите для просмотра прикрепленного файла
Второе. На больших скоростях BSY возникает даже раньше, чем RXNE! (100ns в клетке) :
Нажмите для просмотра прикрепленного файла
Вывод. Я не знаю, для чего придумали флаг BSY, но для управления чипселектом он точно не подходитsm.gif
HHIMERA
"Песец... серебристый."(С) biggrin.gif

Цитата(AHTOXA @ Jan 11 2013, 20:01) *
Код
    spi->DR = 0xAA;
    while ((spi->SR & SPI_SR_BSY));
}

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
. As a consequence, in transmit-only
mode, it is mandatory to wait first until TXE is set and then until BSY is cleared after writing
the last data.
Цитата
Проверял на F103 и F407.

А я думал, что на STM32F0XX... только там такое прокатывает...
Цитата
Вывод. Я не знаю, для чего придумали флаг BSY, но для управления чипселектом он точно не подходитsm.gif

Ну да!!! Если SPI запускать только на передачу, то придётся выдумать свой флаг... отличный от даташитовского... biggrin.gif

Вывод: не надо изобретать велосипед и плодить сущности... а читать даташит...
"Всё уже придумано до нас!"(С)
AHTOXA
Цитата(HHIMERA @ Jan 11 2013, 22:41) *
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
. As a consequence, in transmit-only
mode, it is mandatory to wait first until TXE is set and then until BSY is cleared after writing
the last data.

Дык, я так и делал, специально два байта отправляю, после первого жду TXE. То есть, после отправки второго у меня гарантированно "continuous communications".
Цитата(HHIMERA @ Jan 11 2013, 22:41) *
А я думал, что на STM32F0XX... только там такое прокатывает...

Ничего не понял. Что прокатывает? Какое "такое"?
Цитата(HHIMERA @ Jan 11 2013, 22:41) *
Ну да!!! Если SPI запускать только на передачу, то придётся выдумать свой флаг... отличный от даташитовского... biggrin.gif

Вывод: не надо изобретать велосипед и плодить сущности... а читать даташит...
"Всё уже придумано до нас!"(С)

Вы не согласны с моими выводами? Тогда покажите, как использовать "даташитовский флаг" BSY для управления чипселектом.
ViKo
Цитата(AHTOXA @ Jan 11 2013, 19:01) *
Первое. Всё-таки BSY не ждёт окончания передачи последнего клока. На маленьких частотах это особенно заметно (картинка идентична для обеих функций):

Развертка какая по времени?
Цитата
Второе. На больших скоростях BSY возникает даже раньше, чем RXNE! (100ns в клетке) :

Какая тактовая частота у процессора? Что-то много времени проходит.
Неплохо бы взглянуть на ассемблерный код. Возможно, разница по времени возникает из-за разных команд.
Проверил на своем коде. Обратите внимание, чип селект поднимается до объединения по или. А в другом случае - после!
Код
;;;1059     id |= SPI1->DR;                // Memory capacity
0005a0  8980              LDRH     r0,[r0,#0xc]
;;;1060     // while (SPI1->SR & SPI_SR_BSY);    // ждать, если SPI занят
;;;1061     SMSS_OFF();
0005a2  8311              STRH     r1,[r2,#0x18]
0005a4  4318              ORRS     r0,r0,r3            ;1059

Можно предположить, что BSY возникает после пересылки из DR в сдвиговый регистр, когда начинает работать автомат пересылки.
А заканчивается, когда прочитан последний бит (в середине последнего такта). Дальше слово пересылается из сдвигового регистра в DR, и устанавливается RXNE.
Цитата
Вывод. Я не знаю, для чего придумали флаг BSY, но для управления чипселектом он точно не подходитsm.gif

Вот с этим не согласен. Аргументы уже высказывал... "А по-моему, они одинаковые!" (с) - для данной задачи.
AHTOXA
Цитата(ViKo @ Jan 11 2013, 23:24) *
Развертка какая по времени?

1us в клетке.
Цитата(ViKo @ Jan 11 2013, 23:24) *
Какая тактовая частота у процессора? Что-то много времени проходит. Неплохо бы взглянуть на ассемблерный код. Возможно, разница по времени возникает из-за разных команд.

Частота 72Мгц. Код:
Код
    f012 0f01     tst.w    r2, #1
    d0fb          beq.n    8000a60 <testRXNE(SPI_TypeDef*)+0x20>
    f44f 5c80     mov.w    ip, #4096; 0x1000
    f2c4 0c01     movt    ip, #16385; 0x4001
    2110          movs    r1, #16
    f8cc 1010     str.w    r1, [ip, #16]

Во втором случае код идентичный (только бит другой проверяется).
То есть, собственно на установку ножки идёт 4 команды. Это всяко меньше, чем 250 нс. Так что полученная разница - это разница именно между RXNE и BSY.
Цитата(ViKo @ Jan 11 2013, 23:24) *
Проверил на своем коде. Обратите внимание, чип селект поднимается до объединения по или. А в другом случае - после!

Этой сентенции не осилил.
Цитата(ViKo @ Jan 11 2013, 23:24) *
Вот с этим не согласен. Аргументы уже высказывал... "А по-моему, они одинаковые!" (с) - для данной задачи.
Я свои тоже высказал, повторяться не буду.
ViKo
Цитата(AHTOXA @ Jan 11 2013, 21:27) *
Этой сентенции не осилил.

В моем листинге - три команды.
Первая читает из DR в R0.
Вторая загружает в GPIO BSRR, устанавливает CS в 1.
Третья объединяет по или старшие байты идентификатора в R3 с младшим, только что прочитанным в R0.
Хотя по C тексту установка CS идет последней. Компилятор Keil, оптимизация -O3. Зачем переставил, не знаю!

Когда же проверял по BSY (закомментированная команда), всё шло по написанному.

Насчет осциллограмм. (удалил неправильное)
Флаги сформировались по фронту последнего такта (в данном случае). Определяется установками CPHA, CPOL. И задержка - некая аппаратная, вдобавок к программной. Что позволяет надеяться, что CS для ведомого устройства будет выдержан с запасом. пмсм sm.gif
Tahoe
Цитата(AHTOXA @ Jan 11 2013, 20:01) *
Первое. Всё-таки BSY не ждёт окончания передачи последнего клока. На маленьких частотах это особенно заметно (картинка идентична для обеих функций):
Нажмите для просмотра прикрепленного файла

Насколько я понимаю, эта картинка сделна в SPI MODE == 00b
Сейчас не с руки посмотреть, но что-то мне подсказывает, что при SPI_MODE == 01b, поведение будет совсем иным, т.е. BSY сбросится после заднего clock edge.
ViKo
Цитата(Tahoe @ Jan 11 2013, 22:14) *
Сейчас не с руки посмотреть, но что-то мне подсказывает, что при SPI_MODE == 01b, поведение будет совсем иным, т.е. BSY сбросится после заднего clock edge.

Да, наверное. Только это не "совсем иное". BSY будет сброшен после перепада, по которому данные читаются. Дальше такты не нужны. И CS тоже.
Tahoe
На форуме ST были разборки с SPI_NSS и флагами, года полтора назад. Не могу никак ссылку найти, может кто поделится актуальной? Там про флаги, в т.ч. про BSY было разжевано.
HHIMERA
Не секрет, что все эти флаги не обязательны...
Что мешает заменить их NOP'ами и посмотреть... сколько тактов нужно на загрузку, сколько на трансфер и т.д. ???
AHTOXA
Цитата(Tahoe @ Jan 12 2013, 01:14) *
Насколько я понимаю, эта картинка сделна в SPI MODE == 00b
Сейчас не с руки посмотреть, но что-то мне подсказывает, что при SPI_MODE == 01b, поведение будет совсем иным, т.е. BSY сбросится после заднего clock edge.

Да. При смене фазы и BSY и RXNE срабатывают после заднего edge. Но тут есть ещё одно соображение - многие микросхемы работают в нескольких mode. Например, в 0 и 3. И далеко не факт, что они при этом допускают соответствующее изменение момента CS.

Цитата(ViKo @ Jan 12 2013, 01:20) *
BSY будет сброшен после перепада, по которому данные читаются. Дальше такты не нужны. И CS тоже.

Уф. Ну нельзя же так - тупо повторять голословные утверждения. Я ж вам аргументировал. Вон, и в википедии, по ссылке выше, - тоже SS нарисован после последнего такта.
Вот вам ещё. Диаграмма из даташита микросхемы AT25640:
Нажмите для просмотра прикрепленного файла
Как видите, она явно требует, чтобы CS держался до окончания последнего такта. Если вы думаете, что это просто приблизительная картинка, то вот вам другая, показывающая, что считать такты они умеют (обратите внимание, 15 тактов вместо 16):
Нажмите для просмотра прикрепленного файла
Кстати, именно с этой микросхемой я и имел проблемы "раннего отпускания чипселекта".
Огурцов
Можно я тут со своими аналогичными глупостями влезу ?
Вот тут я приводил тестовый код для F407, показывающий глюк SPI http://electronix.ru/forum/index.php?s=&am...t&p=1125779

CODE

uint8_t i;
// отправляем несколько байт
for(i = 11; i < 14; i++)
{
while (!(SPI1->SR & SPI_I2S_FLAG_TXE));
SPI1->DR = i;
// здесь необходимая задержка, чтобы SPI не клинило
Delay_us(1);
}
// очищаем буфер (м.б. FIFO) приемника
while ((SPI1->SR & SPI_I2S_FLAG_RXNE))
i = SPI1->DR;
// ждем готовности передатчика и отправляем байт
while (!(SPI1->SR & SPI_I2S_FLAG_TXE));
SPI1->DR = (uint8_t)123;
// ждем готовности приемника и принимаем отправленный байт
while (!(SPI1->SR & SPI_I2S_FLAG_RXNE));
// если SPI сглючил, зажигаем LED
if (SPI1->DR != (uint8_t)123)
STM_EVAL_LEDOn(LED5);


Глюк лечится как раз добавлением около 15 нопов при 168мгц. При понижении тактовой SPI относительно тактовой процессора количество нопово нужно пропорционально увеличить.
SPI1, мастер, CS программный, режимы 0 и 3, тактовые по максимуму.

Если считаете, что код кривой, поясните чайнику, как надо.
AHTOXA
Цитата(Огурцов @ Jan 12 2013, 07:12) *
Вот тут я приводил тестовый код для F407, показывающий глюк SPI

А если перенести задержку вот сюда:
Код
    // очищаем буфер (м.б. FIFO) приемника
    while ((SPI1->SR & SPI_I2S_FLAG_RXNE))
    {
        i = SPI1->DR;
        Delay_us(1);
    }

? Если тоже заработает, то получится, что сигнал RXNE снимается с задержкой. Такое может быть в F4, при большой разнице в частоте тактирования ядра и периферии.
Ну а вообще, для получения непрерывной приёмопередачи надо делать примерно вот так. (И этот алгоритм, кстати, описан в даташите.)
Огурцов
Не проверял. По-любому проверки флага готовности обязано быть достаточно для выполнения дальнейшего действия, без какого-то там шаманства с задержками.
ViKo
Цитата(AHTOXA @ Jan 11 2013, 23:30) *
Вот вам ещё. Диаграмма из даташита микросхемы AT25640:
Как видите, она явно требует, чтобы CS держался до окончания последнего такта. Если вы думаете, что это просто приблизительная картинка, то вот вам другая, показывающая, что считать такты они умеют (обратите внимание, 15 тактов вместо 16):

Пусть будет так. Только в даташите по ссылке для RDSR у них нарисовано уже 16 тактов. rolleyes.gif Наверное, писатели временами читают форумы.
У меня на Atmel - давняя идиосинкразия. В частности, на их умение считать такты. laughing.gif
Огурцов
А что с атмелом не так ? у мег такой ерунды не было.

ViKo
Цитата(AHTOXA @ Jan 11 2013, 23:30) *
Кстати, именно с этой микросхемой я и имел проблемы "раннего отпускания чипселекта".

laughing.gif (с учетом вышесказанного)

Цитата(Огурцов @ Jan 12 2013, 10:43) *
А что с атмелом не так ? у мег такой ерунды не было.

Еще со времен какой-то 8952 нашел в даташите кучу ошибок, послал сообщение, получил ответное "у нас все хорошо". Пришлось по пунктам водить носом по ошибкам.
Потом, не нравилось регулярное изменение названия микросхем. Разрабатываешь с одной, потом, глядь, такой уже и нет! Зато есть другая, почти такая же, только с перламутровыми пуговицами.

Цитата(AHTOXA @ Jan 11 2013, 23:30) *
Я ж вам аргументировал.

Вот вы показали две осциллограммы, для малой тактовой частоты, и для большой. И обе работают, верно? Хотя на первой выбор оканчивается до окончания такта. Сами себе аргументировали.

Цитата(Огурцов @ Jan 12 2013, 04:12) *
Если считаете, что код кривой, поясните чайнику, как надо.

Как в сообщении №60. Нужно после каждой записи в регистр DR производить чтение из него же. Но, так как есть параллельный регистр Tx buffer, то в начале записать можно два раза подряд. Тогда в конце и прочитать придется два раза подряд. Помнить, какой записи соответствует какое чтение.
AHTOXA
Цитата(ViKo @ Jan 12 2013, 13:40) *
Пусть будет так. Только в даташите по ссылке для RDSR у них нарисовано уже 16 тактов. rolleyes.gif

А, ну значит выяснили, что и для чтения тоже нужны все такты. sm.gif
Или "поменяли техпроцесс". Уверены, что ваша M25PE40 не такая? А в следующей ревизии?
Кстати, вот картинка из даташита на M25PE40:
Нажмите для просмотра прикрепленного файла
Как видите, CS нужно удерживать до окончания клоков. Попробуйте снизить частоту SPI, и посмотрите, что получится.
Цитата(ViKo @ Jan 12 2013, 14:13) *
Вот вы показали две осциллограммы, для малой тактовой частоты, и для большой. И обе работают, верно? Хотя на первой выбор оканчивается до окончания такта. Сами себе аргументировали.

Так оно же просто "в воздух" работало! С реальными микросхемами на маленькой скорости - могли бы быть проблемы (в частности, с AT25640). Об этом я и талдычу уже который пост подрядsm.gif
ViKo
Цитата(AHTOXA @ Jan 12 2013, 12:01) *
Как видите, CS нужно удерживать до окончания клоков. Попробуйте снизить частоту SPI, и посмотрите, что получится.

Возможно. Даташит скачал только что, по первой же ссылке гугля. От вашего отличается. Но вопрос не в этом.
Нажмите для просмотра прикрепленного файла
Здесь отмеряется окончание S от фронта С (и составляет 5 или 10 ns, в зависимости от техпроцесса). По этому же фронту С данные и читаются.
Попробую поэкспериментировать с частотами. Я выдавал предельно допустимые, и голова не болела.
Тем более, что помимо проверки флага и перехода, и до подготовки и выдачи конца чип селекта еще производится чтение из DR и сохранение в нужной переменной.
В ближайшее время у меня по SPI нужно будет управлять поочередно то ЦАП, то сдвиговым регистром, по разным фронтам тактового сигнала. Если будет что-то любопытное, доложу.
Tahoe
Цитата
I've never used slave mode without DMA but i will present the code that works well without DMA for master mode. I think it should also work in slave mode with slight modification.

Sending a byte in master mode:

void Send_SPI_Byte( u8 B )
{
while (SPI1->SR & SPI_SR_BSY);
while (!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = b;
while (SPI1->SR & SPI_SR_BSY);
while (!(SPI1->SR & SPI_SR_RXNE));
tmp8 = SPI1->DR;
}

receivng a byte in master mode:

The above function may look strange especially because of the flags SPI_SR_BSY that are checked twice. However, the functions NEVER worked when i writte them in other way.

Microcontrollers > STM32 > Receiving SPI data through DMA - STM32 internal hardware error
AHTOXA
Цитата(Tahoe @ Jan 13 2013, 21:44) *
Цитата
SPI1->DR = b;
while (SPI1->SR & SPI_SR_BSY);
while (!(SPI1->SR & SPI_SR_RXNE));


Судя по заглавному сообщению этого топика, проверка BSY здесь совершенно лишняяsm.gif
Tahoe
Цитата(AHTOXA @ Jan 13 2013, 20:15) *
Судя по заглавному сообщению этого топика, проверка BSY здесь совершенно лишняяsm.gif

Не совсем так:
Цитата
I've never used slave mode without DMA but i will present the code that works well without DMA for master mode.
AHTOXA
Понятно, что этот код работает. Но точно так же он будет работать и без проверки BSY.
Tahoe
Речь про "сакральный смысл" флага BSY. На днях, как будет время, проверю его вариант.
AHTOXA
Так как раз его вариант и не раскрывает "сакральный смысл" флага BSY, ибо будет работать точно также и без проверок BSY! sm.gif
ViKo
Цитата(Tahoe @ Jan 14 2013, 09:56) *
Речь про "сакральный смысл" флага BSY. На днях, как будет время, проверю его вариант.

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

Возможно, для I2S найдется смысл его использовать.
Tahoe
Цитата(ViKo @ Jan 14 2013, 12:30) *
Смысл BSY - показать, что автомат последовательной пересылки работает. Смысл его использовать... нет, не вижу. sm.gif
Потому что флаги, показывающие, что буферы передачи и приема не свободны, логичнее использовать в программе.

Так вот как раз для управления SS, интересует именно состояние автомата, а не буферов. wink.gif
Другой вопрос, что BSY, который как раз и должен показывать состояние автомата, работает как-то не так.

Собственно, чего гадать-то, когда есть мануал:
Цитата(Handling data transmission and reception)
For some configurations, the BSY flag can be used during the last data transfer to wait until the completion of the transfer.
ViKo
Цитата(Tahoe @ Jan 14 2013, 12:05) *
Так вот как раз для управления SS, интересует именно состояние автомата, а не буферов. wink.gif
Другой вопрос, что BSY, который как раз и должен показывать состояние автомата, работает как-то не так.

Я проделал примерно те же эксперименты, что показывал АНТОХА, только на живом SPI устройстве M25PE40, MCU STM32F207. Код следующий. Конец Chip Select перенес до последнего чтения из DR. Первая закомментированная строка (проверка TXE) никогда не используется, осталась от прошлого. А использовалась проверка RXNE или проверка BSY. Скорость тоже выбиралась из двух вариантов: самая медленная (60 MHz / 256) и максимально допустимая (60 MHz / 4 = 15 MHz).
Код
uint32_t SFMID_read(void) {
  SMSS_ON();
  uint32_t id = 0;
  SPI1->DR = SFM_RDID;            // послать команду "RDID"
  while (!(SPI1->SR & SPI_SR_TXE));    // ждать освобождение передатчика
  SPI1->DR = SFM_DUMMY;            // послать пустой байт
  while (!(SPI1->SR & SPI_SR_RXNE));    // ждать байт в приемнике
  id = SPI1->DR;                // High Impedance
  while (!(SPI1->SR & SPI_SR_TXE));    // ждать освобождение передатчика
  SPI1->DR = SFM_DUMMY;            // послать пустой байт
  while (!(SPI1->SR & SPI_SR_RXNE));    // ждать байт в приемнике
  id = SPI1->DR << 16;                // Manufacturer
  while (!(SPI1->SR & SPI_SR_TXE));    // ждать освобождение передатчика
  SPI1->DR = SFM_DUMMY;            // послать пустой байт
  while (!(SPI1->SR & SPI_SR_RXNE));    // ждать байт в приемнике  
  id |= SPI1->DR << 8;                // Memory type
  // while (!(SPI1->SR & SPI_SR_TXE));    // ждать освобождение передатчика  
  // while (!(SPI1->SR & SPI_SR_RXNE));    // ждать байт в приемнике
  while (SPI1->SR & SPI_SR_BSY);    // ждать, если SPI занят
  SMSS_OFF();
  id |= SPI1->DR;                // Memory capacity
  // while (SPI1->SR & SPI_SR_BSY);    // ждать, если SPI занят
//  SMSS_OFF();
  // Test = id;
  return id;
}

Выводы у меня следующие.
Во всех 4-х случаях работоспособность сохраняется, идентификатор памяти читается правильно. Даже если тактовый сигнал продолжается после окончания сигнала выбора в случае малой скорости.
Проверки флагов RXNE и BSY совпадают по времени с точностью, с какой мог видеть осциллограмму.
На первой картинке - малая скорость, проверка RXNE. На второй картинке - большая скорость, проверка BSY. Есть и остальные варианты.
Нажмите для просмотра прикрепленного файлаНажмите для просмотра прикрепленного файла
Коль уж такое окончание выбора нормально работает, то конец выбора после чтения никаких проблем не создаст.
Упрямцы могут продолжать твердить свое, но уже без моего участия.
HHIMERA
Приведённый вами код, как частный случай, ни о чём не говорит и ничего не доказывает... wink.gif
AHTOXA
Цитата(ViKo @ Jan 15 2013, 18:57) *
Коль уж такое окончание выбора нормально работает, то конец выбора после чтения никаких проблем не создаст.

Здесь необходимо одно существенное уточнение: работает с конкретным экземпляром конкретной микросхемы памяти. Что совершенно не означает, что это будет работать всегда и со всеми микросхемами.
С другой стороны, имеющийся у меня негативный опыт неопровержимо доказывает, что с таким подходом могут быть проблемы.
Цитата(ViKo @ Jan 15 2013, 18:57) *
Упрямцы могут продолжать твердить свое, но уже без моего участия.

Ну наконец-то вы перестанете смущать неокрепшие умы начинающих читателей.
HHIMERA
Цитата(AHTOXA @ Jan 15 2013, 16:57) *
С другой стороны, имеющийся у меня негативный опыт неопровержимо доказывает, что с таким подходом могут быть проблемы.

Несомненно...
Приведённый код избыточен и работоспособен для низких скоростей...
На полной скорости (половинной) трансфер станет "дырявым" при 8 bit, где поведение BSY уже отличается... придётся всё пересматривать и т.д. ...
ViKo
Цитата(AHTOXA @ Jan 15 2013, 16:57) *
С другой стороны, имеющийся у меня негативный опыт неопровержимо доказывает, что с таким подходом могут быть проблемы.

Надо, все-таки, добавить ремарку. Может ваш негативный опыт обусловлен кривизной даташита? Помните про количество тактов 15 или 16?
AHTOXA
Цитата(ViKo @ Jan 15 2013, 22:18) *
Может ваш негативный опыт обусловлен кривизной даташита? Помните про количество тактов 15 или 16?
Вряд ли. Во-первых, я всё время передавал 16 бит. И во-вторых, как только я стал удерживать чипселект до окончания клоков, проблема ушла.
ViKo
Докладываю.
Посылаю в длинный последовательный регистр (или в ЦАП) последовательность из нескольких байтов. Читать ничего не читаю (не нужно, нечего). Так вот в таком случае определять завершение передачи способом
Код
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, что гарантирует, что началась пересылка последнего байта, и приемопередатчик занят.
ViKo
И еще.
Для переключения полярности синхроимпульсов при работе то на ЦАП, то на регистр, нужно запрещать SPI. Мелочь, об этом и в datasheet написано, но сразу я так не сделал.
Код
  SPI3->CR1 &= ~SPI_CR1_SPE;        // запретить SPI
  SPI3->CR1 |= SPI_CR1_CPOL;        // данные стабильные на срезе \_
  SPI3->CR1 |= SPI_CR1_SPE;        // разрешить SPI
ASDFG123
Как правильно написать функцию отправки 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);
}
Alechek
Подниму тут тему.
Странно, что обсуждают только STM32 SPI MASTER.
Хотя, судя по моим мучениям, проблемы с SPI SLAVE тоже имеется.

Работаю с STM32F0. Частота SPI максимальная (PCLK/2, PCLK = HCLK)
Нарвался на 1 косяк описанный в ERRATA (BUSY=1 навсегда) и еще штуки 4 не описанных никак:

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

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

3. При работе в BIDIMODE=1 при переходе с приема на передачу (у MASTER) должно пройти некоторое время, большее чем длительность 2-х байтов!.
Иначе при переключении в BIDIOE = 0 передача первого содержимого в FIFO теряется. Т.е. передача начинается, но первая запись (2 байта, если писали в 16 разрядный DR) на выходе неверная! Ну, или как минимум первый бит
Код
  static char txbuf[] = "0123456789ABCDEFG";

Нажмите для просмотра прикрепленного файла
Код
      DEBUG_PIN_HIGH();
      SPILINK->CR1 = SPI_MASTER_START_TX_CR1;
      SPILINK->DR = 0xAAAA;

Нажмите для просмотра прикрепленного файла

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

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

6. Что за "художества" возникают e MASTER на ноге CLK сразу после SPE=1?
При CPOL=1 CPHA=0 Нажмите для просмотра прикрепленного файла
При CPOL=0 CPHA=0 Нажмите для просмотра прикрепленного файла
последний бит крупным планом Нажмите для просмотра прикрепленного файла

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

PS. Задержка на вход в прерывание у F0 очень своеобразная... Такое ощущение, что где-то стоит делитель на 4: реакция на изменение значение COMPARE у таймера только каждые 4 значение (тактирование от PCLK = HCLK).
На примере:
Могу попасть либо сюда Нажмите для просмотра прикрепленного файла, либо сюда Нажмите для просмотра прикрепленного файла
но никак не попасть между ними!
Длительность входа я не измерял. но от прерывание таймера явно раза в 3-4 превышает заявленные 16 циклов
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.