Почему SPI не работает с моим STM32f4DISCOVERY?

Я застрял с этим на некоторое время. Я следил за несколькими примерами в Интернете, но безуспешно. Я не могу заставить его работать с моим STM32F4Discovery. У меня есть внешний чип (точнее, SX1272 от Semtech), с которым я пытаюсь установить связь по SPI. Это все детские игры, если делать это через Arduino, но не повезло с продуктом ST. Я использовал осциллограф, и он показал, что команда MOSI отправляется, но MISO не выходит. (С Ардуино это хорошо). Вот мой код:

#include "main.h"

void init_SPI1(void){   


  GPIO_InitTypeDef GPIO_InitStruct; 
  SPI_InitTypeDef SPI_InitStruct; 

  // enable clock for used IO pins 
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); 

  /* configure pins used by SPI1 
  * PA5 = SCK 
  * PA6 = MISO 
  * PA7 = MOSI 
  */ 
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5; 
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; 
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; 
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; 
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; 
  GPIO_Init(GPIOA, &GPIO_InitStruct); 

  // connect SPI1 pins to SPI alternate function 
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1); 
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1); 
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1); 

  // enable clock for used IO pins 
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); 

  /* Configure the chip select pin 
  in this case we will use PE7 */ 
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7; 
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; 
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; 
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; 
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; 
  GPIO_Init(GPIOE, &GPIO_InitStruct); 

  GPIO_SetBits(GPIOE, GPIO_Pin_7); // set PE7 high 

  // enable peripheral clock 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); 

  /* configure SPI1 in Mode 0  
  * CPOL = 0 --> clock is low when idle 
  * CPHA = 0 --> data is sampled at the first edge 
  */ 
  SPI_InitStruct.SPI_Direction =                SPI_Direction_2Lines_FullDuplex;        // set to full duplex mode, seperate MOSI and MISO lines 
  SPI_InitStruct.SPI_Mode =                     SPI_Mode_Master;                        // transmit in master mode, NSS pin has to be always high 
  SPI_InitStruct.SPI_DataSize =                 SPI_DataSize_8b;                        // one packet of data is 8 bits wide 
  SPI_InitStruct.SPI_CPOL =                     SPI_CPOL_High;                           // clock is low when idle 
  SPI_InitStruct.SPI_CPHA =                     SPI_CPHA_1Edge;                         // data sampled at first edge 
  SPI_InitStruct.SPI_NSS =                      SPI_NSS_Soft | SPI_NSSInternalSoft_Set; // set the NSS management to internal and pull internal NSS high 
  SPI_InitStruct.SPI_BaudRatePrescaler =        SPI_BaudRatePrescaler_64;                // SPI frequency is APB2 frequency / 4 
  SPI_InitStruct.SPI_FirstBit =                 SPI_FirstBit_MSB;                       // data is transmitted MSB first 
  SPI_Init(SPI1, &SPI_InitStruct);  

  SPI_Cmd(SPI1, ENABLE); // enable SPI1 
} 


/* This funtion is used to transmit and receive data  
* with SPI1 
*           data --> data to be transmitted 
*           returns received value 
*/ 
uint8_t SPI1_read(uint8_t data){   
  GPIO_ResetBits(GPIOE, GPIO_Pin_7); // set PE7 (CS) low 

  SPI1->DR = data; // write data to be transmitted to the SPI data register 
  while( !(SPI1->SR & SPI_I2S_FLAG_TXE) ); // wait until transmit complete 
  while( SPI1->SR & SPI_I2S_FLAG_BSY ); // wait until SPI is not busy anymore 

  GPIO_SetBits(GPIOE, GPIO_Pin_7); // set PE7 (CS) high
  uint8_t ret = SPI1->DR;
  return ret; // return received data from SPI data register 
} 


void SPI1_write(uint8_t address, uint8_t data){ 

  uint16_t comb = (address << 8) | data;
  GPIO_ResetBits(GPIOE, GPIO_Pin_7); // set PE7 (CS) low 

  SPI1->DR = address; // write data to be transmitted to the SPI data register 
  while( !(SPI1->SR & SPI_I2S_FLAG_TXE) ); // wait until transmit complete 
  //while( SPI1->SR & SPI_I2S_FLAG_BSY ); // wait until SPI is not busy anymore 

  SPI1->DR = data; // write data to be transmitted to the SPI data register 
  while( !(SPI1->SR & SPI_I2S_FLAG_TXE) ); // wait until transmit complete 
  while( SPI1->SR & SPI_I2S_FLAG_BSY ); // wait until SPI is not busy anymore 

  GPIO_SetBits(GPIOE, GPIO_Pin_7); // set PE7 (CS) high   
} 

int main(void){ 

  init_SPI1(); 

  while(1){  
    SPI1_read(0x01); 
  } 
} 

Все, что я получаю от MOSI, это случайный пик ~ 1,5 В, который не синхронизирован.


person K Manos    schedule 23.04.2015    source источник
comment
Обновите это с помощью кода, который, как вы говорите, пробовал, который устанавливает вывод MISO в качестве входа.   -  person Chris Stratton    schedule 25.04.2015
comment
Сотрите то, что я сказал об общении. На МИСО нет ответа. Чип не интерпретирует команды от MOSI. Что-то не так с протоколом связи SPI... С Ардуино по-прежнему все отлично работает. Я вижу (на осциллографе) четкий ответ, и все работает как положено.   -  person K Manos    schedule 27.04.2015
comment
Заставьте программу многократно выполнять транзакции SPI, чтобы вы могли получить стабильное изображение даже на аналоговом осциллографе, и сделайте снимок выбора микросхемы и часов, затем еще один из часов и первый байт данных MOSI.   -  person Chris Stratton    schedule 27.04.2015
comment
Поигрался - сделал свой протокол связи SPI и он заработал...   -  person K Manos    schedule 28.04.2015
comment
Не уверен, что вам повезло с этим, но пробовали ли вы SPI_CPOL_Low? Это и SPI_CPHA_1Edge указано в данных SX1272, а также то, что ваши часы не превышают 10 МГц.   -  person dave.zap    schedule 14.09.2016
comment
Привет, @dave.zap! Нет, я не делал. Спасибо за комментарий   -  person K Manos    schedule 07.10.2016


Ответы (2)


/* configure pins used by SPI1 
 * PA5 = SCK 
 * PA6 = MISO 
 * PA7 = MOSI 
 */

Это говорит о том, что ваш сигнал MISO (главный вход, подчиненный выход) находится на PA6.

  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5; 
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; 
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; 
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; 
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; 
  GPIO_Init(GPIOA, &GPIO_InitStruct); 

Но это настраивает PA6 как выход.

Настройте PA6 как вход и повторите попытку. Если это все еще не работает, попробуйте ввести туда уровень через резистор 1 кОм или около того и посмотрите, сможете ли вы изменить как напряжение на осциллографе, так и полученное значение, чтобы отразить это вообще.

person Chris Stratton    schedule 23.04.2015
comment
Почему тогда не работает альтернативная функция? Разве не должно быть, так как SPI1 настраивается из регистров? - person K Manos; 24.04.2015
comment
Вам все еще нужно настроить направление драйверов ввода-вывода, и вы настраиваете входной контакт как выход. Что произошло, когда вы попытались ввести уровень со слабым источником? Напряжение изменилось? Соответствовали ли полученные данные? - person Chris Stratton; 24.04.2015

Пробовали ли вы использовать инструмент конфигурации ST STM32Cube для создания инициализации и обмена данными? код интерфейса. Я использовал его для создания интерфейсов связи USART, I2C и SPI для настройки часов с использованием передачи DMA примерно за час. Он включает предустановленную конфигурацию платы обнаружения F4. Все, что мне нужно было сделать, это очистить линию CS, когда передача была загружена в DMA, и снова установить ее в функции обратного вызова прерывания завершения передачи.

person uɐɪ    schedule 24.04.2015
comment
Нет у меня нет. Попытаюсь - person K Manos; 27.04.2015