Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F407 Проблемы с SPI
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2
BlackOps
Вот код:

Код
    while ( ( (SPI2 -> SR) & 0x2 ) == RESET)
    {
     //wait until TXE bit is 1
    }
    SPI2 -> DR = d0;



когда этот код исполняется на чипе, или в дебаггере без брейкпоинтов то на осциллографе я только вижу SCK поднятый а MOSI на нуле.
Но когда я исполняю этот код по очереди линию за линией в дебаггере, или же ставлю брейк поинт в дебаггере между циклом while и строчкой с записью в DR, а затем достигнув брейкпоинта опятй продолжаю исполнять код, то на осциллографе вижу переключение SCK и отсылку битов d0.

в чем может быть проблема?

Мне например кажется что SPI2 -> DR = d0; который сразу следует после цикла не дает возможности SPI контроллеру быстро среагировать и послать бит, а исполняя код строка за строкой все работает.

но ведь с другой стороны, я же циклом проверяю бит ТХЕ!? и если я вышел с цикла то буфер свободен и должен бит нормально отослатся?
(я пробовал тоже самое циклом проверять и бит BSY, тоже самое)

есть идеи?
ViKo
Вы только посылаете, ничего не читаете?
Покажите, что у вас до и после делается.
BlackOps
после - бесконечный цикл.
до - ничего касательно этого SPI порта.

да, я просто отсылаю один байт. ничего не принимаю.

простой тест, отсылаю, а на выходе ножки цепляю на осциллограф посмотреть.
ViKo
На тактовые частоты посмотрите, все ли такие, как задумано.
BlackOps
вот настройка SPI
Код
//=============================================================================
// SPI2 Related configuration
//=============================================================================
// enable SPI2 clock
((RCC_TypeDef *) (RCC_BASE))->APB1ENR |= RCC_APB1ENR_SPI2EN;


// configure SPI2
((SPI_TypeDef *) (SPI2_BASE)) -> CR1 |= (SPI_CR1_SPE | SPI_CR1_CPOL |
SPI_CR1_CPHA | SPI_CR1_MSTR |
SPI_CR1_BR_1 | SPI_CR1_SSM | SPI_CR1_SSI);


фпцлк=42MHz, BR=010, когда на осциллографе (в случае если между циклом проверки ТХЕ и записью в регистр DR стоит брейкпоинт) виден SCK , его период примерно 5 MHz.

что тут может быть не так?
с настройкой точно нет! Иначе вообще бы не работало! Но байт отсылается ведь! Но отсылается только когда поочередно в дебаггере те две линии кода исполняю.

я даже пробовал считывать в переменные содержимое регистра SRи CR1сразу после выхода из цикла проверки на бит ТХЕ. результат:
CR1=б1101010111
(SSM=1,SSI=1,SPE=1,BR=010,MSTR=1,CPOL=1,CPHA=1)
SR=0х2 (т.е. только ТХЕ=1)

а после этого идет запись в DR.
все же вроде правильно!

в чем может быть причина?
adnega
Цитата(BlackOps @ Apr 21 2013, 12:30) *
в чем может быть причина?

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

может вы не тот флажок смотрите, проверяете что освободился не передающий (сдвиговый) регистр, а проверяет что приемный свободен (в смысле тот в которые кладут данные, которые потом передаются в сдвиговый?)
BlackOps
Цитата(Golikov A. @ Apr 21 2013, 13:41) *
идея такая
данные в регистр
включили передатчик (данные из приемного регистра передаются в сдвиговый)
подождали когда освободиться передающий регистр.

может вы не тот флажок смотрите, проверяете что освободился не передающий (сдвиговый) регистр, а проверяет что приемный свободен (в смысле тот в которые кладут данные, которые потом передаются в сдвиговый?)

Вы кажется первый мой пост совсем пропустили.
вот же код:
Код
    while ( ( (SPI2 -> SR) & 0x2 ) == RESET)
    {
     //wait until TXE bit is 1
    }
    SPI2 -> DR = d0;


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

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

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

БЛИН!!!

while ( ( (SPI2 -> SR) & 0x2 ) == RESET) - ждете пока бит равен нулю
в коментах пишите //wait until TXE bit is 1, правильно я понимаю что ждать пока 1?

ну и как началась отправка вы сразу вылетаете из цикла, и заменяете отправляемый байт 0

SPI2 -> DR = d0;

готов спорить что написав
SPI2 -> DR = 0xAA; - увидите на выходе AA
BlackOps
Да нет же!
Все правильно сдесь!

while ( ( (SPI2 -> SR) & 0x2 ) == RESET)

* Если ТХЕ = 0, то (SPI2 -> SR) & 0x2 ) = 0, и 0 = RESET, цикл продолжает исполнятся
* Если ТХЕ = 1, то (SPI2 -> SR) & 0x2 ) = 1, и 0 != RESET, и мы вылетаем из цыкла!

Таким образом я и жду пока бит ТХЕ = 1.


Проблема значит в чем то другом?
Genadi Zawidowski
А что за константа RESET?

Вот мой вариант (медленный, вообще-то при выдаче группы бацт готовность проверяю только перед очередным байтом и отдельно - в конце блока для снятия CS):
Код
/* передача байта/слова, возврат считанного */
uint_fast16_t hardware_spi_word(
    uint_fast16_t v        /* значение байта для передачи */
    )
{
    (void) SPI1->DR;    /* clear SPI_SR_RXNE in status register */
    SPI1->DR = (v & SPI_DR_DR);

    // дождаться, пока последний байт выйдет из передатчика
    while ((SPI1->SR & SPI_SR_TXE) == 0)
    ;
    while(!(SPI1->SR & SPI_SR_RXNE))    /* Receive buffer Not Empty */
    ;

    return (SPI1->DR & SPI_DR_DR);
    
}


Обратите вниманире на первое чтние DR.
BlackOps
вот моя константа как объявлена: typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;

а зачем делать вот это: SPI1->DR & SPI_DR_DR ?
Genadi Zawidowski
Цитата
а зачем делать вот это: SPI1->DR & SPI_DR_DR ?

Забейте на это. Необходимости в этом нет. Наследство от AT91SAM7S.
У Вас заработало?
BlackOps
да нет не заработало, попробовал также один байт и без цикла послать, тоже самое..
Golikov A.
ну остается только последнее SPI2 или SPI1
точно через 2 посылаете? может пишите в 1 а статуса ждете от 2, а он всегда пустой?
BlackOps
Да, как яуже говорил, если например ставлю брейк межу циклом и между отправкой, то все работает (если SPI2 были бы сконфигурированы не верне, не работало бы вообще!)

еще работает тогда, когда я например в дебаггере по очереди пальцем жму на исполнение каждой строки этого кода..

а прогоняя весь код не работает! причем проблема именно в этих двух линиях! но какая именно понять не могу?

еще вот какой вариант работает:

никаких циклов, ничего, ставлю только это: SPI2->DR = d0;
НО! перед этой строкоы ставлю брейк!

в дебаггере исполняю, доходит до брейка, и на осциллографе вижу как преже поднятй SCK и нулевой MOSI! Но потом, нажимаю кнопку Run опять, и уже исполняыется вышеописанная команда!И вот вижу свой байт на осциллографе и переключение SCK!

А вот если без брейка... т.е. сразу запустить всю прогу! то только вижу приподнятй SCK и нулевой MOSI!


Это на какие либо мысли толкает? что это может быть?
Genadi Zawidowski
Покажите код, который получился после того, как Вы применили мой образец. Тот код, который сейчас не работает.
Как Вы понимаете, я из рабочего проекта прислал кусок, в котором проблемы из-за двойной буферизации в STM32 решены.
BlackOps
вот по вашему образцу код мой:

Код
(void) SPI2->DR;    /* clear SPI_SR_RXNE in status register */
// breakpoint here!
SPI2->DR = (d0 & SPI_DR_DR);

while ((SPI2->SR & SPI_SR_TXE) == 0)
;


Видите коммент где про breakpoint сказано?так вот если ставлю туда брейкпоинт, дохожу до него и опять стартую то работает! если без брейк поинта, то не работает когда исполняется все сразу!

не могу понать почему?
Golikov A.
у меня глупый вопрос, а скорости SPI хватает? вы частоту не превысили максимально допустимую?

все выглядит каким то чудом.
а вот так если сделать

int dummy = SPI2->DR;
SPI2->DR = 0xAA;
while(1);

что будет?
Genadi Zawidowski
Подсократили, однако...
Функцию выдачи байта на SPI целиком можно привести?
И как работает без дебаггера? МОжет, где-то статусы изменяются из-за чтения регистра данных дебаггером?
BlackOps
естесственно хватает, вот что вижу на осциллографе когда работает:
[DELETED]

а вот когда не работает:
[DELETED]


чтото пост большой какойто стал :Р

без дебаггера тоже не работает! т.е. если на чип заливаю, и включаю, то не работает!

Никакой функции нету! исполняю прямо кодом для простоты!

вот один из кодов привожу еще раз, где в комменте указано если там стоит брейк то работает, если нет брейка то не работает.
Код
(void) SPI2->DR;    /* clear SPI_SR_RXNE in status register */
// breakpoint here!
SPI2->DR = (d0 & SPI_DR_DR);

while ((SPI2->SR & SPI_SR_TXE) == 0)
;


да! я знаю! проблема сократилась! но дело в том что непонятно в чем сейчас дело... все просто...убираю брейк не работает если прогорняыется код сразу! ставлю брейк вижу сначала изображение №2 в посте, потом вновь запускаю как только достиг брейка, и вижу изображение №1 (т.е. рабочее)

а если нет брейка, т.е. сразу прогоняыется весь код, то тока изображение №2!
Genadi Zawidowski
Так... 1) А что с выходом чипселекта? Сказать что есть и не подкдючаться к нему:
const uint_fast32_t cr1bits = SPI_CR1_MSTR | SPI_CR1_SSM | SPI_CR1_SPE | baudrate;
const uint_fast32_t cr1bits16w = cr1bits | SPI_CR1_DFF;



0) У STM32F1xxx есть errata:
// Silicon errata:
// 2.6.7 I2C1 with SPI1 remapped and used in master mode
// Workaround:
// When using SPI1 remapped, the I2C1 clock must be disabled.


ВЫ не дожидаетесь пока байт передастся (когда примется обратно!). Зачем сократили мой код? Там же это было!
BlackOps
Цитата(Golikov A. @ Apr 21 2013, 22:50) *
все выглядит каким то чудом.
а вот так если сделать

int dummy = SPI2->DR;
SPI2->DR = 0xAA;
while(1);

что будет?


ничего не будет, тоже не работает!
а вот если ставлю брейк на линии int dummy = SPI2->DR; исполняю код, дохожу до брейка, затем опять исполняют, то работает! не могу понять в чем дело!


Цитата(Genadi Zawidowski @ Apr 21 2013, 23:12) *
Так... 1) А что с выходом чипселекта? Сказать что есть и не подкдючаться к нему:
const uint_fast32_t cr1bits = SPI_CR1_MSTR | SPI_CR1_SSM | SPI_CR1_SPE | baudrate;
const uint_fast32_t cr1bits16w = cr1bits | SPI_CR1_DFF;



0) У STM32F1xxx есть errata:
// Silicon errata:
// 2.6.7 I2C1 with SPI1 remapped and used in master mode
// Workaround:
// When using SPI1 remapped, the I2C1 clock must be disabled.


ВЫ не дожидаетесь пока байт передастся (когда примется обратно!). Зачем сократили мой код? Там же это было!


да но ведь я же использую SPI2 а не SPI1!
Genadi Zawidowski
Раз с глухим while не работает, точно с аппаратным выходом NSS Вам надо разбираться.
Цитату их errata я привёл как пример странных взаимосвязей и как намёк на что смотреть. Правда, при этом не работает совсем. Смотрите на NSS.
Golikov A.
Не ну тоды магия.

А во придумал!!! А если так?

while ( (SPI2->SR & SPI_SR_TXE) ==0 );
int dummy = SPI2->DR;
SPI2->DR = 0xAA;
while(1);


и как проверить что прием окончен?

Может у вас вызов идет во время приема потому ничего и не работает? А когда перед записью регистра есть брек поинт, проц успевает что-то принять или передать...
BlackOps
попробовал добавление SPI_CR1_DFF, тоже самое, не работает если прогонять код сразу.
NSS я не использую! И не используя его но исполняя код по строчкам все работает!

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

Ведь ллогически, если сам интерфейс работае в дебаггере когда исполняется по строчкам.. почему он не должен работать когда разом исполняется весь код! вот в чем дело я не думаю чтоэто какое то отношение имеет к NSS.

Просто я не могу понять что еще тут может быть?

Цитата(Golikov A. @ Apr 21 2013, 23:20) *
Не ну тоды магия.

А во придумал!!! А если так?

while ( (SPI2->SR & SPI_SR_TXE) ==0 );
int dummy = SPI2->DR;
SPI2->DR = 0xAA;
while(1);


и как проверить что прием окончен?

Может у вас вызов идет во время приема потому ничего и не работает? А когда перед записью регистра есть брек поинт, проц успевает что-то принять или передать...


нет. и так не работает!

И нет у меня никакого приема! все просто в тех строчках которые я привел! просто использую пины SCK и MOSI и подключаю их к осциллографу! никакого приема или ччего то еще!
Genadi Zawidowski
DFF вообще не нужно (этио 16 бит слова).
Вам надо разобраться с SPI_CR1_SSM в Вашей программе.
BlackOps
Ну а что там разбиратся?
у меня и SSM=1 и SSI = 1

Когда SSM=1 то програмное управление слейвом включено.
в таком случае значение бита SSI передается на ногу NSS, и то что на ноге NSS извне игнорируется!
Цитата
Bit 8SSI:Internal slave select
This bit has an effect only when the SSM bit isset. The value of this bit is forced onto the
NSS pin and the IO value of the NSS pin is ignored.

иными словами этим битом можно ногой NSS управлять.

в моемслучае это вообще не принципиально... т.е. с этим я разобрался и это думаю к данной проблеме не имеет отношения.
Ил я не прав в чем то?
Golikov A.
а проц то вообще запускается? без дебагера? Может не стартует?

ну я бы вот что сделал:
я бы статусные регистры выкидывал бы на порт UART если есть.
До
SPI2->DR = Data;
и после, во время while

может чего то оптимизируется?

Если нет порта UART то можно на порт GPIO какой то выводить и осциллографом смотреть...

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

вот как я считываю сейчас регистры: SR,CR1,CR2 кодом своим:

Код
while ( (SPI2->SR & SPI_SR_TXE) ==0 );
sr_t = SPI2->SR;
cr1_t = SPI2->CR1;
cr2_t = SPI2->CR2;
// breakpoint here!
SPI2->DR = 0xAA;



и вот что вижу в дебаггере, все вроде нормально
CR1=б1101010111
(SSM=1,SSI=1,SPE=1,BR=010,MSTR=1,CPOL=1,CPHA=1)
SR=0х2 (т.е. только ТХЕ=1)
CR2=0

сделал так как Вы предлагли через USART тоже. вот код:

Код
while ( (SPI2->SR & SPI_SR_TXE) ==0 )
    {
    while(!(USART3->SR & USART_SR_TXE)); // check if TXE bit is set
    USART3->DR = (uint8_t)( (SPI2->SR)>>8 ); // sending a byte
    while(!(USART3->SR & USART_SR_TC)); // check if TC bit is set

    while(!(USART3->SR & USART_SR_TXE)); // check if TXE bit is set
    USART3->DR = (uint8_t)( SPI2->SR); // sending a byte
    while(!(USART3->SR & USART_SR_TC)); // check if TC bit is set
    }


while(!(USART3->SR & USART_SR_TXE)); // check if TXE bit is set
USART3->DR = (uint8_t)( (SPI2->SR)>>8 ); // sending a byte
while(!(USART3->SR & USART_SR_TC)); // check if TC bit is set

while(!(USART3->SR & USART_SR_TXE)); // check if TXE bit is set
USART3->DR = (uint8_t)( SPI2->SR); // sending a byte
while(!(USART3->SR & USART_SR_TC)); // check if TC bit is set

SPI2->DR = d0;


в USART увидел только два полученных байта: 00 02

что говорит о том что, то что внутри while цикла не выполнилось, т.к. ТХЕбыл уже равен 1 (т.е. буфер отправки данных изначально ыл свободен)

А затем я получилдва байта 00 02, перед SPI2->DR = d0; как Вы и предлагали
изначение 02 говорит что ТХЕ по пренему равен 1, т.е. буфер свободен.

но не работает это! на осцилографе вижу подтянутый ввех SCK и нулевой MOSI

есть какие идеи?
Golikov A.
ну тогда только что есть какое то прерывание, которое непонятно как все ставит раком. Потому что я так понимаю данные попавшие в регистр DR должны выдавиться полюбому, а мы видим что они не выдавливаются...


а если в том месте где вы ставите брекпоинт поставить for(volatile int i=0;i<32000;i++) __NOP();
ну вообщем любую тупую задержку, да на побольше, чтобы секунда прям вышла... несколько раз цикл воткните... хотя отправки по уарту уже сделали эту задержку...

А воткните циклы выдачи на уарт значения SR после строчки
SPI2->DR = Data; ну так для полноты картины...


думаю что уже все проверили, может чип какой то подгоревший? Фиг же его знает, если бы SPI так странно не работал это бы все заметили...

Есть у меня последняя идея.

Может там какая просадка или помеха по питанию при попытке отправки по SPI, которая реально вешает проц... Циклы выдачи после DR=d0; Должны помочь понять. Если вы ставите брек поинт или медленно идете тока хватает, а если программа быстро летит, что-то проседает и кирдык?


BlackOps
ладно, мне кажется я частичто решил проблему.
Сейчас работаю БЕЗ дебаггера, компилирую заливаю на чип включаю плату (хотя в дебаггере поведение такоеже)

вот фрагмент кода №1, как уже знаете просто цикл проверки и отправка байта.
Код
while ( (SPI2->SR & SPI_SR_TXE) ==0 )
    {

    }

SPI2->DR = d0;



А вот фрагмент кода №2
Код
for(;;)
{

if ((USART3->SR & USART_SR_RXNE))
    if (USART3->DR == 0x01)
        break;
}


Этот код просто бесконечный цикл, пока с USART3 не будет получена команда 01, как только эта команда получена цикл прерывается, и исполнение программы переходит к фрагменту кода №1

Так вот, компилю, заливаю на флеш.
Затем включаю плату, естесственно ничег не происходит т.к. цикл фрагмента кода №2 работает, затем подаю команду 01 с USART3 и немедленно вижу свой байт на осциллографе!


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

Выходит проблема была в том что когда я подаю питание на плату (и на чип естесственно) то толи порт вывода толи SPI2 периферия еще не успела войти в рабочий режим необходимый для отправки данных?
Или чтото вроде того?
Что думаете?
Golikov A.
думаю стоит ли у вас микросхема рессета проца?

а в целом там же куча всяких клоков должно запуститься, настроиться всякие ПЛЛ, от них должны появиться клоки периферии и прочее, были ли сделаны все эти процедуры стабилизации клока и прочее?
BlackOps
да было иначе периферия не работала бы вообще.

Вот еще один интересный тест сделал(как вы говорили проверил также статус после записи), вот код (в этот раз убрал бесконечный цикл в начале):

Код
while ( (SPI2->SR & SPI_SR_TXE) ==0 )
    {
    while(!(USART3->SR & USART_SR_TXE)); // check if TXE bit is set
    USART3->DR = (uint8_t)( (SPI2->SR)>>8 ); // sending a byte
    while(!(USART3->SR & USART_SR_TC)); // check if TC bit is set

    while(!(USART3->SR & USART_SR_TXE)); // check if TXE bit is set
    USART3->DR = (uint8_t)( SPI2->SR); // sending a byte
    while(!(USART3->SR & USART_SR_TC)); // check if TC bit is set
    }


while(!(USART3->SR & USART_SR_TXE)); // check if TXE bit is set
USART3->DR = (uint8_t)( (SPI2->SR)>>8 ); // sending a byte
while(!(USART3->SR & USART_SR_TC)); // check if TC bit is set

while(!(USART3->SR & USART_SR_TXE)); // check if TXE bit is set
USART3->DR = (uint8_t)( SPI2->SR); // sending a byte
while(!(USART3->SR & USART_SR_TC)); // check if TC bit is set

SPI2->DR = d0;

while(!(USART3->SR & USART_SR_TXE)); // check if TXE bit is set
USART3->DR = (uint8_t)( (SPI2->SR)>>8 ); // sending a byte
while(!(USART3->SR & USART_SR_TC)); // check if TC bit is set

while(!(USART3->SR & USART_SR_TXE)); // check if TXE bit is set
USART3->DR = (uint8_t)( SPI2->SR); // sending a byte
while(!(USART3->SR & USART_SR_TC)); // check if TC bit is set



И вот некоторые наблюдения:

1) Когда я скомпилировал и зашил контроллер, то я не только не увиден на осциллографе свой байт, но я еще и не увидел байты полученные от USART3!! Интерестно нет?

2) Затем перед кодом который показан выше я добавляю фрагмент кода №2из моего предыдущего поста(непрерывный цикл с ожиданием команды от USART3), комилю, заливаю, включаю..естесственно ничего пока не происходит т.к. нет команды от USART3 на прерывание цикла, подаю команду на прерывание цикла, И вижу свой отправленныйбайт на осциллографе!
А также вижу уже 4 полученных байта, и вот они:
00 02 до посылки
00 03 после посылки!

Как видите интерестно то что после посылки не только TXE=1 но и RXNE=1 что говорит о том что приемник полный.. (хотя странно ничего я не принимаю..)


Тем не менее... явно видно то что некоторые периферии почемуто не хотят работать почти сразу после того как чип запустился..
Ну по крайней мере такой вывод можно сделать из этих наблюдений?

Если есть какие то еще идеи интерестно было бы узнать



Цитата(Golikov A. @ Apr 22 2013, 02:15) *
думаю стоит ли у вас микросхема рессета проца?


стоит просто ресет кнопка на плате, сбрасывание не помогало ничем
Golikov A.
sm.gif а как SPI должен отличить есть что-то на входе или нет? Входная нога в каком то состоянии, клоки тикают, значит через 8-9 клоков входной регистр наберет значение. В примере кода что вам давали выше, была проверка не только на отправку, ну и на прием, а перед отправкой байта всегда еще происходил забор пришедшего.

Такова суть СПИ, как включили клок генератор, так байт не только отправиться но и примется...

Кстати вот интересный момент, а где вы включаете клок генератор? Он в STM автоматом что ли включается по записи байта в DR?

Думаю что после загрузки первое что надо делать это настроить клоки, дождаться везде выставленных флагов, что все клоковые линии работают как надо, а уж потом инициализировать и включат периферию... Но в целом крайне странное поведение, что после старта и передачи управления в main процессор полурабочий. Там же должен быть еще файл стартапа....
HHIMERA
Цитата(BlackOps @ Apr 22 2013, 00:37) *
Интерестно нет?

Ничего интересного... подобная тема уже была...
SPI работает так, как заявлено в даташите... остальное всё от недопонимания...
Цитата
Если есть какие то еще идеи интерестно было бы узнать

Читать даташит до просветления... в части тактирования ядра, тактирования SPI и работы самого SPI...
Исходите из того, что транзакция начинается не сразу после загрузки DR... следовательно... и изменение TXE происходит не сразу...
Golikov A.
я вот поглядел даташит(как и реф мануал) и не увидел там упоминания о том что SPI может вообще не запуститься... А тем более упоминания о паузе перед посылкой которая влияет на его работоспособность. Также не нашел никаких битиков говорящих о неработоспособности или о том что еще не вышло время подготовки SPI.

Я просмотрел секцию бутлода из даташита и опять же не увидел упоминания о том что в начале какие то клоки не работают.

Так что если вы знаете что именно надо глядеть, подскажите, всем нам будет интересно. А если пишите из соображений что SPI простая штука, то увы...
BlackOps
Цитата(Golikov A. @ Apr 22 2013, 08:29) *
Кстати вот интересный момент, а где вы включаете клок генератор? Он в STM автоматом что ли включается по записи байта в DR?

Его я включаю перед тем как начать работать с СПИ. Вот так:
Код
//=============================================================================
// SPI2 Related configuration
//=============================================================================
// enable SPI2 clock
((RCC_TypeDef *) (RCC_BASE))->APB1ENR |= RCC_APB1ENR_SPI2EN;


// configure SPI2
((SPI_TypeDef *) (SPI2_BASE)) -> CR1 |= (SPI_CR1_SPE | SPI_CR1_CPOL |
SPI_CR1_CPHA | SPI_CR1_MSTR |
SPI_CR1_BR_1 | SPI_CR1_SSM | SPI_CR1_SSI);


Цитата(Golikov A. @ Apr 22 2013, 08:05) *
А тем более упоминания о паузе перед посылкой которая влияет на его работоспособность. Также не нашел никаких битиков говорящих о неработоспособности или о том что еще не вышло время подготовки SPI.


тоже самое делал и я после тех двух описанных мною тестов в посте №34 и №32.

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





Цитата(HHIMERA @ Apr 22 2013, 07:48) *
транзакция начинается не сразу после загрузки DR... следовательно... и изменение TXE происходит не сразу...

а это не важно, т.к. я отправляю первый байт, и ТХЕ уже заведомо имеет значение 1.
Об этом я тоже писал, Вы видимо не прочли ветку и поспешили дать банальный совет.

ViKo
HHIMERA выразился не точно. TXE выставляется сразу после загрузки данных в регистр. Пересылка (сдвиг) наружу начинается позже, через 2 такта шины. Тогда же устанавливается флаг BSY.
Кстати, за эти два такта периферийной шины процессор успевает наделать много чего.
BlackOps, поставьте задержку вместо точки останова.
HHIMERA
Цитата(Golikov A. @ Apr 22 2013, 07:05) *
то увы...

Как прочитали - так и работает... увы...

Цитата(BlackOps @ Apr 22 2013, 07:26) *
Вы видимо не прочли ветку и поспешили дать банальный совет.

Угу...
Ещё раз... разногласия/разночтения по SPI присутствуют только в F0 и F3...
Golikov A.
Цитата(HHIMERA @ Apr 22 2013, 11:07) *
Как прочитали - так и работает... увы...
Угу...
Ещё раз... разногласия/разночтения по SPI присутствуют только в F0 и F3...


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

Если же у вас есть что по сути посвятите нас темных... [DELETED]
HHIMERA
[DELETED]
adnega
Цитата(BlackOps @ Apr 22 2013, 08:26) *
Его я включаю перед тем как начать работать с СПИ. Вот так:
Код
//=============================================================================
// SPI2 Related configuration
//=============================================================================
// enable SPI2 clock
((RCC_TypeDef *) (RCC_BASE))->APB1ENR |= RCC_APB1ENR_SPI2EN;


// configure SPI2
((SPI_TypeDef *) (SPI2_BASE)) -> CR1 |= (SPI_CR1_SPE | SPI_CR1_CPOL |
SPI_CR1_CPHA | SPI_CR1_MSTR |
SPI_CR1_BR_1 | SPI_CR1_SSM | SPI_CR1_SSI);

Где-то есть упоминание (для F4), что между установкой битика включения тактирования блока и работы с блоком должно пройти какое-то время. У меня так FSMC не заработал)
Попробую найти это в доках...

UPD: STM32F405/407xx and STM32F415/417xx device limitations
2.1.12 Delay after an RCC peripheral clock enabling
Description
A delay between an RCC peripheral clock enable and the effective peripheral enabling
should be taken into account in order to manage the peripheral read/write to registers.
This delay depends on the peripheral’s mapping:
● If the peripheral is mapped on AHB: the delay should be equal to 2 AHB cycles.
● If the peripheral is mapped on APB: the delay should be equal to 1 + (AHB/APB
prescaler) cycles.
Workarounds
1. Use the DSB instruction to stall the Cortex-M CPU pipeline until the instruction is
completed.
2. Insert ”n” NOPs between the RCC enable bit write and the peripheral register writes
(n = 2 for AHB peripherals, n = 1 + AHB/APB prescaler in case of APB peripherals).
Genadi Zawidowski
Наконец-то увидел инициализацию.
Зачем SSI и SSM одновременно ставить? В моём (работающем) варианте только SSM стоит (на что я и обращал внимание).
А как следствие - отказ SPI работать, когда кто-то другой держит сигнал SS.
Golikov A.
[DELETED]
Цитата(Genadi Zawidowski @ Apr 22 2013, 14:48) *
Наконец-то увидел инициализацию.
Зачем SSI и SSM одновременно ставить? В моём (работающем) варианте только SSM стоит (на что я и обращал внимание).
А как следствие - отказ SPI работать, когда кто-то другой держит сигнал SS.


ну да, наверное правильнее было сразу попросить и инициализацию...
adnega
У меня хорошо работает такая инициализация:
CODE
void __inline init_SPI2(void)
{
SPI2->CR1 =
(0 << SPI_CR1_SPE)
| (0 << SPI_CR1_DFF)
| (1 << SPI_CR1_SSM)
| (1 << SPI_CR1_SSI)
| (1 << SPI_CR1_MSTR)
| (0 << SPI_CR1_BR);

SPI2->CR2 =
(0 << SPI_CR2_RXNEIE)
| (0 << SPI_CR2_TXDMAEN)
| (1 << SPI_CR2_SSOE);

SPI2->CR1 =
(1 << SPI_CR1_SPE)
| (0 << SPI_CR1_DFF)
| (1 << SPI_CR1_SSM)
| (1 << SPI_CR1_SSI)
| (1 << SPI_CR1_MSTR)
| (0 << SPI_CR1_BR);
}


И такая отправка/прием
Код
BYTE sd_send_byte(const BYTE data)
{
    BYTE spib;
    while((SPI2->SR & (1 << SPI_SR_TXE)) == 0);
    SPI2->DR = data;
    while((SPI2->SR & (1 << SPI_SR_RXNE)) == 0);
    spib = SPI2->DR;
    return spib;
}


Правда, битики я объявляю номером, а не маской...
ViKo
Я свои SPI в STM32F207 инициализировал так. Тактирование, естественно, задавал раньше, вместе с остальными устройствами. И больше не трогал.
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
// SPI1->CR1 |= SPI_CR1_MSTR | SPI_CR1_SPE; // Разрешить, Мастер

/* SPI2 -- конфигурирование EP3C5
CONF_N (NSS) переключается программно */
SPI2->CR1 =
SPI_CR1_CPHA * 0 | // Clock Phase
SPI_CR1_CPOL * 0 | // Clock Polarity
SPI_CR1_MSTR * 1 | // Master Selection
SPI_CR1_BR_0 * 0 | // Baud Rate Control - fpclk1 / 2 = 15 MHz
SPI_CR1_BR_1 * 0 | //
SPI_CR1_BR_2 * 0 | //
SPI_CR1_SPE * 1 | // SPI Enable (раньше включалось позже!)
SPI_CR1_LSBFIRST * 1 | // 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 - 8 bit
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
SPI2->CR2 =
SPI_CR2_RXDMAEN * 0 | // Rx Buffer DMA Enable
SPI_CR2_TXDMAEN * 0 | // Tx Buffer DMA Enable
SPI_CR2_SSOE * 0 | // SS Output Enable (все равно используется GPIO?)
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
// SPI2->CR1 |= SPI_CR1_SPE;

/* SPI3 -- регистр управления аналоговыми узлами
8-bit, MSB first, SPEn, Fpclk1 / 2 (15MHz), Master, CPOL=0, CPHA=0
74HC595 SCK - Pos, AD5314 SCK - Neg (изменить CPOL) */
SPI3->CR1 =
SPI_CR1_CPHA * 0 | // Clock Phase
SPI_CR1_CPOL * 0 | // Clock Polarity HC595
SPI_CR1_MSTR * 1 | // Master Selection
SPI_CR1_BR_0 * 0 | // Baud Rate Control - fpclk1 / 2 = 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 (8 bit)
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
SPI3->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
Golikov A.
Цитата(Genadi Zawidowski @ Apr 22 2013, 14:48) *
Наконец-то увидел инициализацию.
Зачем SSI и SSM одновременно ставить? В моём (работающем) варианте только SSM стоит (на что я и обращал внимание).
А как следствие - отказ SPI работать, когда кто-то другой держит сигнал SS.

нашел вот тут такое руководство http://chipspace.ru/stm32-spi/

в нем утверждается что если поставить SSM, чтобы устройство было мастером необходимо поставить и SSI, это будет двигать уровень NSS, тоже говорит и реф мануал...


Genadi Zawidowski
Цитата
в нем утверждается что если поставить SSM, чтобы устройство было мастером необходимо поставить и SSI, это будет двигать уровень NSS, тоже говорит и реф мануал...

В комментах к руководству есть подтверждения проблем. Кроме всего прочего, в статье указывается о диагностике, с которой SPI MASTER переходит в режим SLAVE из-за проблем с NSS. Нашему коллеге с проблемами в SPI может помочь.
Golikov A.
не понятно почему пауза перед записью в регистр помогала решить проблему... может все таки что-то схемное...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.