AnsweredAssumed Answered

Problem configuring STM32F4 Discovery as SPI slave

Question asked by khorvongkarn.prach on Jul 4, 2014
Latest reply on Jul 5, 2014 by khorvongkarn.prach

Hi,

I'm currently trying to make SPI communication between PIC18F2580 as master and STM32F4 Discovery as slave.
The communication doesn't work, both master and slave receives 0xFF all the time.

I have it working in the opposite direction where I configure STM32F4 Discovery as master and PIC18F2580 as slave.
The working code is as follows:

STM32F4 Discovery SPI master code:

// this function initializes the SPI1 peripheral
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_100MHz;
 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);
   
 // enable peripheral clock
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
   
 /* configure SPI1
  * CPOL = 1 --> clock is high when idle
  * CPHA = 0 --> data is sampled at the second 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 high when idle
 SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;      // data sampled at second edge
 SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; // set the NSS management to internal and pull internal NSS high
 SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; // 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_send(uint8_t data){
  
 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_RXNE) ); // wait until receive complete
 while( SPI1->SR & SPI_I2S_FLAG_BSY ); // wait until SPI is not busy anymore
 return SPI1->DR; // return received data from SPI data register
}
  
int main(void) {
 init_SPI1();
 while(1){
  SPI1_send(0x00);  // transmit data
 }
}

PIC18F2580 slave code:

/*********************************************************************
*
*                             Defines
*
*********************************************************************/
#define _MASTER_MODE     0
#define _SLAVE_MODE      1
  
#define _SMP            0    /*  0 = Input data sampled at middle of data output time (SMP must be cleared in slave mode) */
#define _CKE            0     /* 0 = Transmit occurs on transition from idle to active clock state */
#define _CKP            1     /* 1 = Idle state for clock is a high level */
#define _SSPM_MASTER    0b0000     /* 0000 = Master mode, clock = Fosc/4 */
#define _SSPM_SLAVE     0b0101      /*  0101 = Slave mode, clock = SCK pin, SS pin disabled (can be used as I/O pin) */
  
void SPI_init(unsigned char mode) {
    TRISA = 0x00;               /* set all port A pins as output pins */
    ADCON1 = 0x0F;              /* set all port A pins, including SS (RA5), as digital I/O */
  
    if (mode == _MASTER_MODE) {
    TRISC = 0b00010000;         /* Set SCK pin (RC3) as output
                                 * SDI pin (RC4) as input
                                 * SDO pin (RC5) as output */
    } else {
    TRISC = 0b00011000;         /* Set SCK pin (RC3) as input
                                 * SDI pin (RC4) as input
                                 * SDO pin (RC5) as output */
    }
  
    SSPSTAT = 0b00000000;       /* Initialize SSPSTAT register to POR state */
    SSPSTATbits.SMP = _SMP;     /* Configure sample bit */
    SSPSTATbits.CKE = _CKE;     /* Configure clock select bit */
  
    SSPCON1 = 0b00000000;       /* Initialize SSPCON1 register to POR state */
    SSPCON1bits.CKP = _CKP;     /* Configure clock polarity select bit */
    SSPCON1bits.SSPEN = 1;      /* Enable SPI (set SCK, SDO, SDI, and SS as serial port pins)*/
  
    if (mode == _MASTER_MODE)
        SSPCON1bits.SSPM = _SSPM_MASTER;    /* Configure sync mode bits for master */
    else
        SSPCON1bits.SSPM = _SSPM_SLAVE;     /* Configure sync mode bits for slave */
}
  
unsigned char SPI_send(unsigned char data) {
    unsigned char TempVar;
  
    TempVar = SSPBUF;           /* Clears BF */
    PIR1bits.SSPIF = 0;         /* Clear interrupt flag */
    SSPCON1bits.WCOL = 0; /* Clear any previous write collision */
    SSPBUF = data;              /* clock out data */
    while(!PIR1bits.SSPIF);     /* wait until transmission completed */
    PIR1bits.SSPIF = 0;         /* clear interrupt flag bit */
    return (SSPBUF);
}
  
int main(void) {
    SPI_init(_SLAVE_MODE);
  
    while (1) {
        SPI_send('A');
    }
  
    return (EXIT_SUCCESS);
}

The above code work fine. STM32F4 discovery (master) send 0x00 and receive 'A' while PIC18F2580 send 'A' and receive 0x00.

However, I need STM32F4 to be slave and PIC18F2580 to be master. I modify above code as follow:

Modify 1 line for STM32F4 Discovery code

.....
SPI_InitStruct.SPI_Mode = SPI_Mode_Slave;     // transmit in slave mode
.....

And modify the call to SPI_init() function to be initialized as master

....
SPI_init(_MASTER_MODE);
....

As I mention earlier, this doesn't work as both slave and master receive 0xFF.
I don't have access to oscilloscope or logic analyzer, so the best I can do is to set breakpoint as watch the values while debugging.

I doubt that this maybe because PIC18 run at slower CPU speed (40 Mhz) while STM32F4 runs at 168 Mhz.
But why does it work in one way (STM32 as master) and not another (PIC18 as master)?
Or it is the code that cause the problem?

If you spot something wrong in the code or the concepts, please let me know.

Thank you in advance for your suggestions, any help will be highly appreciated.

Best Regards,
Pat

Outcomes