Problems in using RPi as SPI slave

1,159 views
Skip to first unread message

Krishnaiah Vemula

unread,
Aug 25, 2015, 1:52:31 PM8/25/15
to bcm2835
Hello , 

I started developing SPI slave driver taking BCM2835(Mike McCauley) drivers as base(from userland) since, I didn't find any working examples for SPI slave in RPi 2 Model B(J8-40Pin) so far.

I have implemented with few assumptions from the documentation. It would be great that someone clarifies them.

Currently, the SW polls for the "RX FIFO Empty flag" in FR register to see if there is any incoming data. When there is data from master, I "assume" that the flag goes to '0'.
Now, the DR register will be masked with 0xFF(for lower byte) to read the incoming data. 

My initial experiments shows no data reception. It always prints the message "Receive buffer is Empty".

Following questions are popped up while development.
1. How much is the size of the FIFO buffers? Its not explicitly mentioned in the docu. 
   The Data Register(DR) simply mentions that reading lower 8 bytes will read the data from the RX FIFO buffer and writing to this 8 bytes writes to Tx FIFO.
   Why is not mentioned separately as like in the master?
 
2. The clock phase and polarity configuration simply says "SPI related". In which mode should the master communicate with slave Pi??

I have made the HW connections btwn Master Pi and Slave Pi as follows.  I can give the complete files when someone wants to have a deeper look.


##############################
##Pin numbers on J8 connector#
##############################
[b]Signal      Master Slave[/b]
Clock Pin 23  -->  Pin 35
MOSI Pin 19 <---> Pin 12
MISO Pin 21 <---> Pin 38
CE        Pin 24    ---> Pin 40
##############################

Following are the code snippets, 
[code]
1.#define BCM2835_BSC_SPI_SLV_BASE 0x214000 
bcm2835_spislv = bcm2835_peripherals + BCM2835_BSC_SPI_SLV_BASE/4; /*SPI Slave base address*/ 


/* Defines for SPI Slave
   GPIO register offsets from BCM2835_SPI_SLAVE_BASE. 
   Offsets into the SPI Slave Peripheral block in bytes as per Chapter 11 SPI/BSC Slave Register Map
 */
 
/* BSC SLAVE register offsets */
#define BCM2835_SPI_SLV_DR          0x00
#define BCM2835_SPI_SLV_RSR          0x04
#define BCM2835_SPI_SLV_SLV          0x08
#define BCM2835_SPI_SLV_CR            0x0c
#define BCM2835_SPI_SLV_FR              0x10
#define BCM2835_SPI_SLV_IFLS          0x14
#define BCM2835_SPI_SLV_IMSC          0x18
#define BCM2835_SPI_SLV_RIS          0x1c
#define BCM2835_SPI_SLV_MIS          0x20
#define BCM2835_SPI_SLV_ICR          0c24
#define BCM2835_SPI_SLV_DMACR          0x28
#define BCM2835_SPI_SLV_TDR               0x2c
#define BCM2835_SPI_SLV_GPUSTAT          0x30
#define BCM2835_SPI_SLV_HCTRL          0x34
#define BCM2835_SPI_SLV_DEBUG1          0x38
#define BCM2835_SPI_SLV_DEBUG2          0x3c

/* Bitfields in DR */
#define BCM2835_SPI_SLV_DR_RXFLEVEL_MASK 0xF8000000
#define BCM2835_SPI_SLV_DR_TXFLEVEL_MASK 0x07c00000
#define BCM2835_SPI_SLV_DR_RXBUSY      0x00200000
#define BCM2835_SPI_SLV_DR_TXFE        0x00100000  // Tx FIFO Empty
#define BCM2835_SPI_SLV_DR_RXFF        0x00080000  // Rx FIFO Full
#define BCM2835_SPI_SLV_DR_TXFF        0x00040000  // Tx FIFO Full
#define BCM2835_SPI_SLV_DR_RXFE        0x00020000  // Rx FIFO Empty
#define BCM2835_SPI_SLV_DR_TXBUSY      0x00010000  // Transmit Busy
#define BCM2835_SPI_SLV_DR_DATA_MASK    0x000000FF  // Data Mask-1B

/* Registers RSR and Slave are NOT Used/Required!*/
#define BCM2835_SPI_SLV_RSR_UE (1 << 1)
#define BCM2835_SPI_SLV_RSR_OE (1 << 0)

/*Bitfields in CR*/
#define BCM2835_SPI_SLV_CR_INVTXF      0x00004000
#define BCM2835_SPI_SLV_CR_HOSTCRTEN      0x00001000
#define BCM2835_SPI_SLV_CR_TESTFIFO    0x00000800
#define BCM2835_SPI_SLV_CR_INVRXF      0x00000800
#define BCM2835_SPI_SLV_CR_RXE            0x00000200
#define BCM2835_SPI_SLV_CR_TXE            0x00000100
#define BCM2835_SPI_SLV_CR_BRK            0x00000080
#define BCM2835_SPI_SLV_CR_CPOL           0x00000010
#define BCM2835_SPI_SLV_CR_CPHA           0x00000008
#define BCM2835_SPI_SLV_CR_I2C            0x00000004
#define BCM2835_SPI_SLV_CR_SPI          0x00000002
#define BCM2835_SPI_SLV_CR_EN            0x00000001

/*Bitfields in FR*/
#define BCM2835_SPI_SLV_FR_RXFLEVEL(reg) (((reg) >> 11) & 0x1F)
#define BCM2835_SPI_SLV_FR_TXFLEVEL(reg) (((reg) >> 6)  & 0x1F)
#define BCM2835_SPI_SLV_FR_RXBUSY (1 << 5)
#define BCM2835_SPI_SLV_FR_TXFE (1 << 4)
#define BCM2835_SPI_SLV_FR_RXFF (1 << 3)
#define BCM2835_SPI_SLV_FR_TXFF (1 << 2)
#define BCM2835_SPI_SLV_FR_RXFE (1 << 1)
#define BCM2835_SPI_SLV_FR_TXBUSY (1 << 0)


/* Bitfields in IMSC */
#define BCM2835_SPI_SLV_IMSC_OEIM         0x00000008   
#define BCM2835_SPI_SLV_IMSC_BEIM         0x00000004   
#define BCM2835_SPI_SLV_IMSC_TXIM         0x00000002
#define BCM2835_SPI_SLV_IMSC_RXIM      0x00000001

/* Bitfields in RIS */
#define BCM2835_SPI_SLV_RIS_OERIS         0x00000008   
#define BCM2835_SPI_SLV_RIS_BERIS         0x00000004   
#define BCM2835_SPI_SLV_RIS_TXRIS         0x00000002
#define BCM2835_SPI_SLV_RIS_RXRIS      0x00000001

/* Bitfields in MIS */
#define BCM2835_SPI_SLV_MIS_OEMIS         0x00000008
#define BCM2835_SPI_SLV_MIS_BEMIS         0x00000004
#define BCM2835_SPI_SLV_MIS_TXMIS         0x00000002
#define BCM2835_SPI_SLV_MIS_RXMIS      0x00000001

/* Bitfields in ICR - Interrupt clear Register*/
#define BCM2835_SPI_SLV_ICR_OEIC      0x00000008
#define BCM2835_SPI_SLV_ICR_BEIC      0x00000004
#define BCM2835_SPI_SLV_ICR_TXIC      0x00000002
#define BCM2835_SPI_SLV_ICR_RXIC      0x00000001

[/code]

2.
[code]###################################################################################################
###########################Slave Init/ Begin function definition###################################
###################################################################################################
void bcm2835_spi_slv_begin(void)
{
    volatile uint32_t* paddr;

    /* Set the SPI0 pins to the Alt 0 function to enable SPI0 access on them */
    bcm2835_gpio_fsel(RPI_BPLUS_GPIO_J8_12, BCM2835_GPIO_FSEL_ALT3); /* MOSI */
    bcm2835_gpio_fsel(RPI_BPLUS_GPIO_J8_35, BCM2835_GPIO_FSEL_ALT3); /* CLK */
    bcm2835_gpio_fsel(RPI_BPLUS_GPIO_J8_38, BCM2835_GPIO_FSEL_ALT3); /* MISO */
    bcm2835_gpio_fsel(RPI_BPLUS_GPIO_J8_40, BCM2835_GPIO_FSEL_ALT3); /* CE */
    
    /*Get the base address to Control Register(CR) and Reset the CR to 0*/
    paddr = bcm2835_spislv + BCM2835_SPI_SLV_CR/4;
    bcm2835_peri_write(paddr, 0); /* All 0s */
    
    /*Enable Device*/
    bcm2835_peri_set_bits(paddr, BCM2835_SPI_SLV_CR_EN, BCM2835_SPI_SLV_CR_EN);

    /*Set Clock Polarity and phase*/
    bcm2835_peri_set_bits(paddr, BCM2835_SPI_SLV_CR_CPOL, BCM2835_SPI_SLV_CR_CPOL);
    bcm2835_peri_set_bits(paddr, BCM2835_SPI_SLV_CR_CPHA, BCM2835_SPI_SLV_CR_CPHA);
    
    /*Disable I2C behaviour*/
    bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI_SLV_CR_I2C);
    
    /*Enable SPI Mode*/
    bcm2835_peri_set_bits(paddr, BCM2835_SPI_SLV_CR_SPI, BCM2835_SPI_SLV_CR_SPI);
    
    #if (DEBUG_SPI_SLV==1)
    if(bcm2835_peri_read(paddr) == 27)
      printf("Slave Init done successfully now.\n");
    #endif  
}
[/code]

[code]
3.###################################################################################################
##################################Slave Read function definition###################################
###################################################################################################

/* Read a stream of bytes from SPI Master */
uint8_t bcm2835_spislv_read(uint8_t* buffer_rx, uint8_t nCount)
{

  volatile uint32_t* ErrReg = bcm2835_spislv + BCM2835_SPI_SLV_RSR/4;
  volatile uint32_t* CtrlReg = bcm2835_spislv + BCM2835_SPI_SLV_CR/4;
  volatile uint32_t* DataReg = bcm2835_spislv + BCM2835_SPI_SLV_DR/4;
  volatile uint32_t* FlagReg = bcm2835_spislv +  BCM2835_SPI_SLV_FR/4;
  uint8_t nresult;
  
  bcm2835_peri_write(ErrReg, 0); // Clear the OE and UE errors if any
  
  if (nCount == 0)
    {
      return -1; // Read 0 bytes
    }
    
    uint8_t* pData=  ( uint8_t*)buffer_rx;
    if(pData == 0)
    { 
      printf("Buffer Not allocated!\n");
      return -1;
    }
     
  //Enable reception    
  bcm2835_peri_set_bits(CtrlReg, BCM2835_SPI_SLV_CR_RXE, BCM2835_SPI_SLV_CR_RXE);
  
  //check if the reception is enabled or not
  if((bcm2835_peri_read(CtrlReg) & BCM2835_SPI_SLV_CR_RXE) == BCM2835_SPI_SLV_CR_RXE)
      printf("Reception enabled");
      
  while (nCount-- > 0)
    {
    while (bcm2835_peri_read(FlagReg) & BCM2835_SPI_SLV_FR_RXFE)
        {
          // do nothing // When the data comes from Master will this flag be set to ZERO by HW?
          printf("Recieve buffer is Empty\n");
        }
        
        if(bcm2835_peri_read(ErrReg) & BCM2835_SPI_SLV_RSR_OE)
        {
          printf("Over Run Error 1\n");
          nresult= -1;
          break;
        }
        // Read the DR(Data Register) and mask for the the data
        *pData++ =  bcm2835_peri_read(DataReg) & BCM2835_SPI_SLV_DR_DATA_MASK;
        
        nresult++;
     }

      if(nresult > 0)
      {
        // Wait for transfer to Stop
        while(bcm2835_peri_read(DataReg) & BCM2835_SPI_SLV_DR_RXBUSY)
        {
          if(bcm2835_peri_read(ErrReg) & BCM2835_SPI_SLV_RSR_OE)
          {
           printf("Over Run Error 2\n");
            nresult = -1;
            break;
          }
        }
      
      }
    // Disable reception  
    bcm2835_peri_set_bits(CtrlReg, 0, BCM2835_SPI_SLV_CR_RXE);  
    return nresult;
}
[/code]

Your findings are highly helpful and appreciated

Thank you in advance

Arjan van Vught

unread,
Feb 4, 2017, 10:55:15 AM2/4/17
to bcm2835
Hi Krishnaiah,

Did you make any progress? Is it working?

I am about to start a project where I need a SPI Slave on the Raspberry Pi.

And I am happy to do some research.

Greets, Arjan
http://www.raspberrypi-dmx.org/

VenkataKrishnaiah Vemula

unread,
Feb 5, 2017, 3:07:51 PM2/5/17
to bcm2835
Hi Arjan,

Nice to hear from you. Unfortunately there is no response from Rpi in bcm slave interface after my preliminary tests from virtual address space. So i didn't invest time in developing a kernel IO device.

We have taken a decision to replace Rpi with FDTI(spi slave) for our use case.

Sorry that I couldn't help you in this situation.

Best wishes
Krishnaiah
--
You received this message because you are subscribed to a topic in the Google Groups "bcm2835" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/bcm2835/chJfQQWXFMo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to bcm2835+u...@googlegroups.com.
To post to this group, send email to bcm...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/bcm2835/b52eaab9-92aa-465f-8d1a-05dc28281692%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Marina Costermans

unread,
Jan 4, 2018, 5:12:11 PM1/4/18
to bcm2835
Hi Krishnaiah,

I've been looking a long time for a way to use the RPi as an SPI slave.  In 2013 I reverted to a SBC that caught fire recently so now I want to give it another try.  I took a look at the datasheet and at your code and get quite confused.  The SPI1 (BSC_SPI) is a master only peripheral but you label it as a slave.  There is no code for the master, but if you are setting SPI (=SPI0 ?) as master (as the pin diagram suggests), you have two masters tied together.  The pin diagram table is surprising.  I would expect to use the same 4 pins (19,  21, 23, 24) on both sides but with different settings.

Did you make any progress ?  Do you still need the SPI slave on the RPI ?  I'm willing to help.

 .

Rick Cv

unread,
Feb 15, 2019, 4:52:22 PM2/15/19
to bcm2835
Hi Marina,

Do you know how to use a SPI slave on the RPI?

Arjan van Vught

unread,
Feb 16, 2019, 5:25:18 AM2/16/19
to bcm...@googlegroups.com
The SPI slave on the Raspberry Pi boards does not work. 

Many people, including me, have spent several debug hours in getting it to work. But with no luck.

However, on the same GPIO pins, the I2C slave is working fine.

- Arjan
Reply all
Reply to author
Forward
0 new messages