krishnaiah.vv
Posts: 19
Joined: Wed Jun 24, 2015 7:34 am

Problems in using RPi as SPI Slave

Tue Aug 25, 2015 5:49 pm

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#
##############################
Signal Master Slave
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: Select all

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

2.

Code: Select all

###################################################################################################
###########################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: Select all

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;
}
Your findings are highly helpful and appreciated

User avatar
joan
Posts: 14004
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Problems in using RPi as SPI Slave

Tue Aug 25, 2015 8:05 pm

It might be worth searching for code. I'm fairly sure one of the bare metal guys had some working code. It wouldn't be directly usable by you but it would show one method of correctly configuring the registers.

krishnaiah.vv
Posts: 19
Joined: Wed Jun 24, 2015 7:34 am

Re: Problems in using RPi as SPI Slave

Wed Aug 26, 2015 11:20 am

joan wrote:It might be worth searching for code. I'm fairly sure one of the bare metal guys had some working code. It wouldn't be directly usable by you but it would show one method of correctly configuring the registers.
Hi Joan,
I found some spi slave examples using the bit banging SPI(unfortunately which is not a great idea for my project).
And, i configured SPI slave with few modifications to https://github.com/rsta2/circle/tree/ma ... ping/slave.

But, i wonder that the RX FIFO Empty flag is always 1.!!

Sorry, inspite of my search for bare metal spi slave examples, I couldn't find it. :(
It will be really helpful, if you have time and can route me to the bare metal example code.

Thank you
Krish

Return to “Interfacing (DSI, CSI, I2C, etc.)”