ilkz 0 9 сентября, 2015 Опубликовано 9 сентября, 2015 (изменено) · Жалоба Друзья, не могу понять в чем дело. Завожу SPI в режиме мастера, сигналом CS управляю как отдельным пином. Ожидаю поведения, когда он (CS) нулем подчеркивает все данные, но он почему-то этого не делает (см картинку). Самое интересное, что если в начало тела while(1) дописать что-то типа printf("spi send %X\n", 0xC1);, то CS начинает формироваться правильно. Код привожу ниже. 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 сразу после отправки? Он что, не успевает встать? Изменено 9 сентября, 2015 пользователем IgorKossak [codeebox] для длинного кода, [code] - для короткого! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 9 сентября, 2015 Опубликовано 9 сентября, 2015 · Жалоба Какой-то странный флаг у ST-шников получился, да. Они это и сами признают: 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 0 9 сентября, 2015 Опубликовано 9 сентября, 2015 · Жалоба Какой-то странный флаг у ST-шников получился, да. Они это и сами признают: Ок, допустим. Но рекомендуемый ими флаг TXE имеет не совсем то поведение что нужно: он единичится, когда данные попадают в сдвиговый регистр, а не когда они из него улетели на улицу. Т.е. для управления собственным сигналом CS испоьзование флага TXE не подходит. Как вы выходите из положения? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 9 сентября, 2015 Опубликовано 9 сентября, 2015 · Жалоба Вопрос крайне интересен :-) Мне всегда был нужен двунаправленный SPI, в этом случае отлично работает метод "положили в DR, подождали RXNE, считали DR". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ilkz 0 9 сентября, 2015 Опубликовано 9 сентября, 2015 · Жалоба :-) С приемом да - все понятно. Вопрос с только передачей. Переадресую его к аудитории: как вы управляете сигналом CS, если SPI работает только на отправку? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Obam 34 9 сентября, 2015 Опубликовано 9 сентября, 2015 · Жалоба "…как вы управляете сигналом CS, если SPI работает только на отправку?…" Вот именно так и управляем :) RXNE==1 равнозначен полностью завершённой транзакции. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 9 сентября, 2015 Опубликовано 9 сентября, 2015 · Жалоба Можно поилить TXE и BSY, или действительно что проще по RXNE, Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ilkz 0 9 сентября, 2015 Опубликовано 9 сентября, 2015 · Жалоба Ну ок, логика вида: void spi2_send(uint8_t value) { SPI_I2S_SendData(SPI2, value); while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); } не работает - все равно нужна задержка между send() и while(). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Obam 34 9 сентября, 2015 Опубликовано 9 сентября, 2015 (изменено) · Жалоба Удалено. Согласен с rudy_b Изменено 9 сентября, 2015 пользователем Obam Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rudy_b 1 9 сентября, 2015 Опубликовано 9 сентября, 2015 · Жалоба Это стандартная проблема для всей криворукой периферии Stm32, особенно раздражает в RTC. Хардовый автомат тактируется не клоками проца, а деленными клоками периферии. Соответственно, busy устанавливается с задержкой по клоку периферии. А догадаться асинхронно установить busy по загрузке данных DR сразу у них ума не хватило. Рекомендованные действия: 1. Wait until TXE=1 2. Then wait until BSY=0 Вероятно можно использовать и RXNE, но не проверял его работу при настройке только на передачу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ilkz 0 9 сентября, 2015 Опубликовано 9 сентября, 2015 · Жалоба 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: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rudy_b 1 9 сентября, 2015 Опубликовано 9 сентября, 2015 · Жалоба Рекомендация - из их даташита (stm32F207). Ну, какой-то прогресс есть. Можно попробовать еще (до анализа busy) подождать RXNE. P.S. А можно попробовать сначала дождаться busy=1, а, потом, busy=0. Но аккуратно, это чревато осложнениями при наличии прерываний. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 9 сентября, 2015 Опубликовано 9 сентября, 2015 · Жалоба Ну может тогда еще проще 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 34 9 сентября, 2015 Опубликовано 9 сентября, 2015 (изменено) · Жалоба SPI в 8 раз медленней ядра (пост #1); на какой частоте ядро "молотит" что флаги не успевают (с т.з. ядра) высталяться\сниматься? Изменено 9 сентября, 2015 пользователем Obam Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ilkz 0 9 сентября, 2015 Опубликовано 9 сентября, 2015 · Жалоба Вроде как 168МГц. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться