|
STM32F4Discovery SPI, сигнал CS, что-то пошло не так |
|
|
|
Sep 9 2015, 10:49
|
Частый гость
 
Группа: Участник
Сообщений: 135
Регистрация: 9-09-11
Пользователь №: 67 084

|
Друзья, не могу понять в чем дело. Завожу 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 сразу после отправки? Он что, не успевает встать?
Сообщение отредактировал IgorKossak - Sep 9 2015, 19:36
Причина редактирования: [codeebox] для длинного кода, [code] - для короткого!
|
|
|
|
|
Sep 9 2015, 11:23
|

Профессионал
    
Группа: Свой
Сообщений: 1 032
Регистрация: 13-03-08
Из: Маськва
Пользователь №: 35 877

|
Какой-то странный флаг у 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
--------------------
Тут обсуждается творческий порыв, а не соответствие каким-либо стандартам ©
|
|
|
|
|
Sep 9 2015, 11:28
|
Частый гость
 
Группа: Участник
Сообщений: 135
Регистрация: 9-09-11
Пользователь №: 67 084

|
Цитата(esaulenka @ Sep 9 2015, 14:23)  Какой-то странный флаг у ST-шников получился, да.
Они это и сами признают: Ок, допустим. Но рекомендуемый ими флаг TXE имеет не совсем то поведение что нужно: он единичится, когда данные попадают в сдвиговый регистр, а не когда они из него улетели на улицу. Т.е. для управления собственным сигналом CS испоьзование флага TXE не подходит. Как вы выходите из положения?
|
|
|
|
|
Sep 9 2015, 12:06
|
Частый гость
 
Группа: Участник
Сообщений: 135
Регистрация: 9-09-11
Пользователь №: 67 084

|
Ну ок, логика вида: Код void spi2_send(uint8_t value) { SPI_I2S_SendData(SPI2, value); while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); } не работает - все равно нужна задержка между send() и while().
|
|
|
|
|
Sep 9 2015, 12:53
|
Частый гость
 
Группа: Участник
Сообщений: 135
Регистрация: 9-09-11
Пользователь №: 67 084

|
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 клок
|
|
|
|
|
Sep 10 2015, 04:43
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(ilkz @ Sep 9 2015, 15:49)  Друзья, не могу понять в чем дело. На эту тему уже было большое обсуждение. Вкратце вывод таков: надо ждать RXNE, и потом ещё несколько тактов, в зависимости от скорости и режима SPI.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Sep 10 2015, 07:58
|
Частый гость
 
Группа: Участник
Сообщений: 135
Регистрация: 9-09-11
Пользователь №: 67 084

|
Ладно, с этм разберусь когда железяку запущу хоть как-то. Идея в целом понятна. По результатам дам знать. Спасибо за разжевывание ))) Пока что возник следующий проблем: Что-то записываю в слейв, потом пытаюсь прочитать и... не вижу клока для чтения. Код 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). Соответственно, никакие прерывания не дергаются.
Сообщение отредактировал ilkz - Sep 10 2015, 08:03
|
|
|
|
|
Sep 10 2015, 08:57
|

Профессионал
    
Группа: Свой
Сообщений: 1 032
Регистрация: 13-03-08
Из: Маськва
Пользователь №: 35 877

|
Потому что 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;
--------------------
Тут обсуждается творческий порыв, а не соответствие каким-либо стандартам ©
|
|
|
|
|
Sep 11 2015, 06:30
|
Частый гость
 
Группа: Участник
Сообщений: 135
Регистрация: 9-09-11
Пользователь №: 67 084

|
Цитата(esaulenka @ Sep 10 2015, 11:57)  Потому что StdLib - ад и ужас.
Клок на шине выставляет мастер. Чтобы он это сделал, ему надо сказать "передавай". Этот StdLib так не делает, хотя, если судить только по названиям функций, должен. Т.е. берём и делаем ОДНУ функцию Т.е., чтобы что-то прочитать - надо что-то записать. Люююто. А как быть, если нужно прочитать много байт, а слейв не допускает dummy-записей? Ну, то есть, во время записи dummy-слов слейв может на них как-то отреагировать, т.к. для него это будут команды какие-нибудь.
|
|
|
|
|
Sep 11 2015, 10:06
|
Частый гость
 
Группа: Участник
Сообщений: 135
Регистрация: 9-09-11
Пользователь №: 67 084

|
Цитата(Obam @ Sep 11 2015, 11:10)  ilkz, попробуете замедлить ядро чтобы SPI успевал обновлять флаги к опросу? Да, только позже. Я напишу.
|
|
|
|
|
Sep 11 2015, 11:58
|
Частый гость
 
Группа: Участник
Сообщений: 135
Регистрация: 9-09-11
Пользователь №: 67 084

|
Цитата(Genadi Zawidowski @ Sep 11 2015, 13:11)  Сейчас применяются STM32F4 и STM32F7 уже... Так я про STM32F4 и вел речь.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|