1

I've been stuck with this one for a while. I've followed a few examples online, but with no success. I cannot get it working with my STM32F4Discovery. I have an external chip (SX1272 from Semtech to be more specific) with whom I try to have an SPI communication. It is all kids games when doing it via Arduino, but no luck with ST product. I've used oscilloscope and it showed that the MOSI command is sent, but there is no MISO going out. (With Arduino it's good). Here's my code:

#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); 
  } 
} 

All I get from MOSI is a random ~1.5V peak, which is out of sync.

K Manos
  • 507
  • 1
  • 3
  • 12
  • Update this with the code you say you tried that sets the MISO pin as an input. – Chris Stratton Apr 25 '15 at 00:59
  • Scratch what I said about communication. There is no response on MISO. The chip doesn't interpret the commands from MOSI. Something is wrong with the SPI communication protocol... With Arduino still everything works great. I see (on oscilloscope) clear response and everything works as expected. – K Manos Apr 27 '15 at 10:58
  • Make the program do SPI transactions repeatedly so you can get a stable picture even on an analog scope, and take a picture of the chip select and clock, then another of the clock and first byte of MOSI data. – Chris Stratton Apr 27 '15 at 14:39
  • Played around - made my own SPI communication protocol and it started to work... – K Manos Apr 28 '15 at 10:50
  • Not sure if you had any luck with this but did you try SPI_CPOL_Low? That and the SPI_CPHA_1Edge is specified in the SX1272 data also that your clock does not exceed 10MHz – dave.zap Sep 14 '16 at 18:26
  • Hi, @dave.zap! No, I did not. Thank you for the comment – K Manos Oct 07 '16 at 15:22

2 Answers2

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

This suggests that your MISO (master in, slave out) signal is on 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); 

But this configures PA6 as an output.

Configure PA6 as an input, and try again. If it still doesn't work try injecting a level there through a 1K or so resistor and see if you can get both the voltage to change on the scope and the received value to reflect that at all.

Chris Stratton
  • 39,853
  • 6
  • 84
  • 117
  • Why wouldn't Alternate Function work then? Isn't it supposed to be as SPI1 is configured from the registers? – K Manos Apr 24 '15 at 06:09
  • You still have to configure the direction of the I/O drivers, and you are configuring the input pin as an output. What happened when you tried injecting a level with a weak source? Did the voltage change? Did the received data? – Chris Stratton Apr 24 '15 at 14:28
0

Have you tried using the ST configuration tool STM32Cube to generate the initialisation and communications interface code. I used it to generate the clock setup USART, I2C and SPI comms interfaces using DMA transfers in about an hour. It includes a pre-defined configuration for the F4 discovery board. All I had to do was clear the CS line when the transfer was loaded into the DMA and set it again in the transfer complete interrupt callback function.

uɐɪ
  • 2,540
  • 1
  • 20
  • 23