Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F4Discovery SPI, сигнал CS
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
ilkz
Друзья, не могу понять в чем дело.
Завожу SPI в режиме мастера, сигналом CS управляю как отдельным пином.
Ожидаю поведения, когда он (CS) нулем подчеркивает все данные, но он почему-то этого не делает (см картинку).
Самое интересное, что если в начало тела while(1) дописать что-то типа printf("spi send %X\n", 0xC1);, то CS начинает формироваться правильно.

Код привожу ниже.

CODE
void spi2_init(void){
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2); // sck
GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2); // mosi
GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_SPI2); // miso

GPIO.GPIO_Mode = GPIO_Mode_AF;
GPIO.GPIO_Speed = GPIO_Speed_50MHz;
GPIO.GPIO_OType = GPIO_OType_PP;
GPIO.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOB, &GPIO);

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI2, &SPI_InitStructure);
//SPI_I2S_ITConfig(SPI2,SPI_I2S_IT_RXNE,ENABLE);
SPI_Cmd(SPI2, ENABLE);
SPI_NSSInternalSoftwareConfig(SPI2, SPI_NSSInternalSoft_Set);

GPIO.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
GPIO.GPIO_Mode = GPIO_Mode_OUT;
GPIO.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init (GPIOB, &GPIO);
}

void spi2_send(uint8_t value) {
SPI_I2S_SendData(SPI2, value);
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
}

void ad_send(uint8_t value) {
GPIO_ResetBits(GPIOB, GPIO_Pin_12);
spi2_send(value);
GPIO_SetBits(GPIOB, GPIO_Pin_12);
}

int main(void) {
SystemInit();
TM_DELAY_Init();
TM_DISCO_LedInit();
spi2_init();
while (1) {
//printf("spi send %X\n", 0xC1);
ad_send(0xC1);
Delayms(1);
}
}


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




UPD:
Опытным путем выяснилось, что если вставить задержку между SPI_I2S_SendData() и ожиданием флага SPI_I2S_FLAG_BSY, то все начинает работать:

Код
void spi2_send(uint8_t value) {
    int i;
    SPI_I2S_SendData(SPI2, value);
    for(i=0; i<63; i++);
    while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
}


Получается что нельзя проверяь флаг SPI_I2S_FLAG_BSY сразу после отправки? Он что, не успевает встать?
esaulenka
Какой-то странный флаг у ST-шников получился, да.

Они это и сами признают:
Цитата(Reference manual)
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
ilkz
Цитата(esaulenka @ Sep 9 2015, 14:23) *
Какой-то странный флаг у ST-шников получился, да.

Они это и сами признают:


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

Как вы выходите из положения?
esaulenka
Вопрос крайне интересен :-)
Мне всегда был нужен двунаправленный SPI, в этом случае отлично работает метод "положили в DR, подождали RXNE, считали DR".
ilkz
:-)
С приемом да - все понятно.
Вопрос с только передачей.
Переадресую его к аудитории: как вы управляете сигналом CS, если SPI работает только на отправку?
Obam
"…как вы управляете сигналом CS, если SPI работает только на отправку?…"

Вот именно так и управляем sm.gif
RXNE==1 равнозначен полностью завершённой транзакции.
Golikov A.
Можно поилить TXE и BSY, или действительно что проще по RXNE,
ilkz
Ну ок, логика вида:

Код
void spi2_send(uint8_t value) {
    SPI_I2S_SendData(SPI2, value);
    while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
}


не работает - все равно нужна задержка между send() и while().
Obam
Удалено. Согласен с rudy_b
rudy_b
Это стандартная проблема для всей криворукой периферии Stm32, особенно раздражает в RTC. Хардовый автомат тактируется не клоками проца, а деленными клоками периферии. Соответственно, busy устанавливается с задержкой по клоку периферии. А догадаться асинхронно установить busy по загрузке данных DR сразу у них ума не хватило.

Рекомендованные действия:
1. Wait until TXE=1
2. Then wait until BSY=0

Вероятно можно использовать и RXNE, но не проверял его работу при настройке только на передачу.
ilkz
rudy_b, проверяем:

Код
void spi2_send(uint8_t value) {
    SPI_I2S_SendData(SPI2, value);
    while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == 1);
    while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == 0);
}


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

Как видим, сдвинулось на 1 клок laughing.gif
rudy_b
Рекомендация - из их даташита (stm32F207).

Ну, какой-то прогресс есть. Можно попробовать еще (до анализа busy) подождать RXNE.

P.S. А можно попробовать сначала дождаться busy=1, а, потом, busy=0. Но аккуратно, это чревато осложнениями при наличии прерываний.
Golikov A.
Ну может тогда еще проще
Код
void spi2_send(uint8_t value) {
    SPI_I2S_SendData(SPI2, value);
    while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == 1);
    while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == 0);
}
Obam
SPI в 8 раз медленней ядра (пост #1); на какой частоте ядро "молотит" что флаги не успевают (с т.з. ядра) высталяться\сниматься?
ilkz
Вроде как 168МГц.
Obam
Запустите ядро ядро мегагерцах на 30-ти. Что будет?
rudy_b
Делитель (1/8) работает с клоками APB1. А есть еще делитель самих клоков APB1 относительно клоков проца (APB1_Prescaler), его тоже нужно знать.

А макисмальная частота APB1 - 30 Мгц, т.е. делитель - не менее 1/8. В результате общее деление, скорее всего, равно 1/64. Но это данные для Stm32F207, для F4 частота APB1 может и отличаться.
Obam
Если уж исследовать, то не грех подтянуть частоту SPI к частоте ядра. Положим, ядро "затормозим", APB1_Prescaler=1 и fPCLK=4; вход\выход из подпрограмм занимает (нормально занимает) что-то, вот и будет видно как флаги в SPI успевают\не успевают к опросу. Надеюсь TS под JTAGом отлаживается?
jcxz
Цитата(ilkz @ Sep 9 2015, 17:28) *
Как вы выходите из положения?

Мы в такое положение не попадаем, так как всегда работаем с SPI через DMA или хотя-бы посредством прерываний. wink.gif
Чего и Вам советуем.
AHTOXA
Цитата(ilkz @ Sep 9 2015, 15:49) *
Друзья, не могу понять в чем дело.

На эту тему уже было большое обсуждение.
Вкратце вывод таков: надо ждать RXNE, и потом ещё несколько тактов, в зависимости от скорости и режима SPI.
ilkz
Ладно, с этм разберусь когда железяку запущу хоть как-то. Идея в целом понятна. По результатам дам знать. Спасибо за разжевывание )))

Пока что возник следующий проблем:
Что-то записываю в слейв, потом пытаюсь прочитать и... не вижу клока для чтения.
Код
void mcp_read(uint8_t addr) {
    GPIO_ResetBits(GPIOB, GPIO_Pin_11);
    spi2_send(0x41);
    spi2_send(addr);
    SPI_I2S_ReceiveData(SPI2);
    GPIO_SetBits(GPIOB, GPIO_Pin_11);
}

...

mcp_write(0x05, 0x20); // IOCON
mcp_write(0x00, 0x00); // IODIR
mcp_write(0x01, 0xA5); // IPOL
mcp_read(0x01); // IPOL


Я вижу что слейв что-то пытается выдать на свой SDO, но т.к. нет клока, то слейв обламывается и мой мастер ничего не принимает... Что за очередной бред? (Мы щас пока не трогаем всякие прерывания и прочие DMA).
Соответственно, никакие прерывания не дергаются.
esaulenka
Потому что StdLib - ад и ужас.

Клок на шине выставляет мастер. Чтобы он это сделал, ему надо сказать "передавай". Этот StdLib так не делает, хотя, если судить только по названиям функций, должен.
Т.е. берём и делаем ОДНУ функцию
Код
    uint8_t Rw(uint8_t out = 0xFF)
    {
        SPIx->DR = out;
        while (!(SPIx->SR & SPI_SR_RXNE));
        return SPIx->DR;
    }

(украдено из Stm32tpl авторства AHTOXA)
и вызываем (сиплюсплюс):

Код
mcp.Active ();
mcp.Rw (0x41);
mcp.Rw (addr);
uint8_t res = mcp.Rw ();
mcp.Deactive ();
return res;
ilkz
Цитата(esaulenka @ Sep 10 2015, 11:57) *
Потому что StdLib - ад и ужас.

Клок на шине выставляет мастер. Чтобы он это сделал, ему надо сказать "передавай". Этот StdLib так не делает, хотя, если судить только по названиям функций, должен.
Т.е. берём и делаем ОДНУ функцию


Т.е., чтобы что-то прочитать - надо что-то записать. Люююто. А как быть, если нужно прочитать много байт, а слейв не допускает dummy-записей? Ну, то есть, во время записи dummy-слов слейв может на них как-то отреагировать, т.к. для него это будут команды какие-нибудь.
Golikov A.
Ну тут надо немного подумать.
Как слейв узнает пишите вы или нетsm.gif? Клоки то чтобы данные забрать все равно идутsm.gif)))) Это же не РС232 где есть факт начала записи. Смотрите описание, там написано в каком состоянии нога должна быть
в 1 шлите FF, в 0 шлите 00, скорее всего там будет в состоянии пофиг....
Obam
"А как быть, если нужно прочитать много байт, а слейв не допускает dummy-записей?"

Тогда это не SPI: SCK тактируют одновременно и MOSI и MISO.
ilkz
Ну в принципе да, в командах всегда есть флаг R/W.
Obam
ilkz, попробуете замедлить ядро чтобы SPI успевал обновлять флаги к опросу?
jcxz
Цитата(AHTOXA @ Sep 10 2015, 10:43) *
Вкратце вывод таков: надо ждать RXNE, и потом ещё несколько тактов, в зависимости от скорости и режима SPI.

Жесть какая.... wacko.gif
Вот ответ на вопрос, почему я в своих проектах стараюсь не использовать STM32....
Genadi Zawidowski
Напоминаю, что дождавшись RXNE надо обязательно прочитать DR, нужен он Вам или нет... И дуло исчезнет... И жести не будет.
jcxz
Цитата(Genadi Zawidowski @ Sep 11 2015, 15:02) *
Напоминаю, что дождавшись RXNE надо обязательно прочитать DR, нужен он Вам или нет... И дуло исчезнет... И жести не будет.

Думаете всё-таки рискнуть и применить в следующей (как раз намечающейся) разработке STM32? rolleyes.gif
ilkz
Цитата(Obam @ Sep 11 2015, 11:10) *
ilkz, попробуете замедлить ядро чтобы SPI успевал обновлять флаги к опросу?

Да, только позже. Я напишу.
Genadi Zawidowski
Сейчас применяются STM32F4 и STM32F7 уже... В намечающихся, если не хватит производительности, будет RENESAS RZ1AL (напримкр http://www.eltech.spb.ru/item/r7s721020vcfpaa0).
С SPI проблем нет (если читать документацию на чип полнтсьью, а не по диагонали, как я иногда это делал)...
ilkz
Цитата(Genadi Zawidowski @ Sep 11 2015, 13:11) *
Сейчас применяются STM32F4 и STM32F7 уже...


Так я про STM32F4 и вел речь.
Genadi Zawidowski
Цитата
Думаете всё-таки рискнуть и применить в следующей

Вы спросили про будущие проекты на STM32F4 - у меня текущие, на которые требуется/хватает ресурсов этого семейства процессоров, уже делаются на них.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.