SPI: mraa example code spi_mcp4261.c not work?

He Zhang
He Zhang New Member Posts: 6
Hi all:

I am a researcher working with the up-board. Currently I have been stuck in sending data through SPI interface from upboard to an Arduino. The first pic shows how we connect the upboard's SPI pins to the Arduino, and the second and the third picture shows the hardware connection.



On the upboard end, we run the SPI sample code spi_mcp4261.c (mraa library), to make it send data as master through SPI port, while on the arduino end, we run the following code to make it receive data as a slave.

However, it turns out when we connect upboard's SS Pin 26 (CS1) to Arduino Pin 10, the arduino end cannot receive any byte, and when we connect upboard's SS Pin 24 (CS0) to Arduino Pin 10, the arduino end can only receive a byte with value 0. As shown in the fourth and fifth pics, which is not right since we send different bytes from upboard.
#include <SPI.h>

int recv;
int i;

//Initialize SPI slave.
void SlaveInit(void) {
  // Initialize SPI pins.
  pinMode(SCK, INPUT);
  pinMode(MOSI, INPUT);
  pinMode(MISO, OUTPUT);
  pinMode(SS, INPUT);
  SPCR = 0x00;
  // Enable SPI as slave.
  SPCR |= (1 << SPE);
}

// SPI Transfer.
int SPItransfer(int send_data) {
  int recv_data;
  while(!(SPSR & (1<<SPIF)));//wait for complete tranfer
  recv_data=SPDR;
  // this part is for transmission
  SPDR=send_data;
  while(!(SPSR & (1<<SPIF)));//wait for complete tranfer
  //delay(10);
  return recv_data;
}

  void setup() {
  // Initialize serial for troubleshooting.
  Serial.begin(9600);
  // Initialize slave LED pin.
  //pinMode(led, OUTPUT);
 // digitalWrite(led, ledState);
  // Initialize SPI Slave.
  SlaveInit();
  i=10;
  Serial.println("Slave Initialized");
}

void loop()  {
 recv = SPItransfer(i);
 if (i == 0){
    i=10;  
  }
  i--;
  Serial.print("Received:");
  Serial.println(recv);
  }


So, can you help me out with this issue, or any suggestions that I can move forward to solve this problem ?

Any help will be greatly appreciated!

Thanks,

David

Comments

  • WereCatf
    WereCatf New Member Posts: 201
    // SPI Transfer.
    int SPItransfer(int send_data) {
      int recv_data;
      while(!(SPSR & (1<<SPIF)));//wait for complete tranfer
      recv_data=SPDR;
      // this part is for transmission
      SPDR=send_data;
      while(!(SPSR & (1<<SPIF)));//wait for complete tranfer
      //delay(10);
      return recv_data;
    }
    

    This function doesn't do what you intend to do. First of all, the example in libmraa sends two bytes: 0x00 and whatever value i currently is, but you're assigning only the 0x00 to recv_data and ignoring the second byte transmitted, so obviously your function is going to return 0x00 every single time. Secondly, you're not initializing SPDR to a known value at any given point, so you're possibly transmitting a garbage byte to master.
  • He Zhang
    He Zhang New Member Posts: 6
    Hi WereCatf:

    Thanks for your reply. We set the spi_frequency with 9600, which equals to the frequency in the Arduino part. Also, we change the code spi_mcp4.c to send just one byte each time as follows:
    #include "mraa.h"
    #include <unistd.h>
    #include <stdint.h>
    
    int
    main(int argc, char** argv)
    {
        mraa_init();
        //! [Interesting]
        mraa_spi_context spi;
        spi = mraa_spi_init(0); // 1, 0
        mraa_spi_frequency(spi, 9600); 
        printf("Hello, SPI initialised\n");
        uint8_t data; 
        uint8_t *recv; 
        uint8_t recv_int; 
    
        while (1) {
            int i;
            for (i = 0; i < 10; i++) {
                data = i;
                recv = mraa_spi_write_buf(spi, &data, 1);
                printf("RECIVED-%d\n", recv[0]);
    
                // recv_int = mraa_spi_write(spi, data); 
                // printf("Recived -%d\n", recv_int); 
                usleep(100000);
            }
        }
        //! [Interesting]
        return 0; 
    }
    

    However, we can as well only receive one byte with value 0.
  • He Zhang
    He Zhang New Member Posts: 6
    Hi WereCatf:

    We have also tried the code here http://www.raspberry-projects.com/pi/programming-in-c/spi/using-the-spi-interface
    without using the mraa library, and just using the SPI port "/dev/spidev2.0". However the result is still the same.

    Have you succeed in sending and receiving data with the upboard's SPI port? If yes, can you share with the code with us, so we can reproduce and figure out the reason why the code we use not work.

    Thanks!

    The source code we use is listed below:
    #include <fcntl.h>				//Needed for SPI port
    #include <sys/ioctl.h>			//Needed for SPI port
    #include <linux/spi/spidev.h>	//Needed for SPI port
    #include <unistd.h>			//Needed for SPI port
    #include <stdio.h>
    #include <stdlib.h>
    #include <string>
    #include <iostream>
    #include <unistd.h>
    #include <cstring>
    
    int spi_cs0_fd;				//file descriptor for the SPI device
    int spi_cs1_fd;				//file descriptor for the SPI device
    unsigned char spi_mode;
    unsigned char spi_bitsPerWord;
    unsigned int spi_speed;
    
    
    //***********************************
    //***********************************
    //********** SPI OPEN PORT **********
    //***********************************
    //***********************************
    //spi_device	0=CS0, 1=CS1
    int SpiOpenPort (int spi_device)
    {
        int status_value = -1;
        int *spi_cs_fd;
    
    
        //----- SET SPI MODE -----
        //SPI_MODE_0 (0,0) 	CPOL = 0, CPHA = 0, Clock idle low, data is clocked in on rising edge, output data (change) on falling edge
        //SPI_MODE_1 (0,1) 	CPOL = 0, CPHA = 1, Clock idle low, data is clocked in on falling edge, output data (change) on rising edge
        //SPI_MODE_2 (1,0) 	CPOL = 1, CPHA = 0, Clock idle high, data is clocked in on falling edge, output data (change) on rising edge
        //SPI_MODE_3 (1,1) 	CPOL = 1, CPHA = 1, Clock idle high, data is clocked in on rising, edge output data (change) on falling edge
        spi_mode = SPI_MODE_0;
        
        //----- SET BITS PER WORD -----
        spi_bitsPerWord = 8;
        
        //----- SET SPI BUS SPEED -----
        spi_speed = 1000000;		//1000000 = 1MHz (1uS per bit) 
    
    
        if (spi_device)
        	spi_cs_fd = &spi_cs1_fd;
        else
        	spi_cs_fd = &spi_cs0_fd;
    
    
        if (spi_device)
        	*spi_cs_fd = open(std::string("/dev/spidev2.1").c_str(), O_RDWR);
        else
        	*spi_cs_fd = open(std::string("/dev/spidev2.0").c_str(), O_RDWR);
    
        if (*spi_cs_fd < 0)
        {
            perror("Error - Could not open SPI device");
            exit(1);
        }
    
        status_value = ioctl(*spi_cs_fd, SPI_IOC_WR_MODE, &spi_mode);
        if(status_value < 0)
        {
            perror("Could not set SPIMode (WR)...ioctl fail");
            exit(1);
        }
    
        status_value = ioctl(*spi_cs_fd, SPI_IOC_RD_MODE, &spi_mode);
        if(status_value < 0)
        {
          perror("Could not set SPIMode (RD)...ioctl fail");
          exit(1);
        }
    
        status_value = ioctl(*spi_cs_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bitsPerWord);
        if(status_value < 0)
        {
          perror("Could not set SPI bitsPerWord (WR)...ioctl fail");
          exit(1);
        }
    
        status_value = ioctl(*spi_cs_fd, SPI_IOC_RD_BITS_PER_WORD, &spi_bitsPerWord);
        if(status_value < 0)
        {
          perror("Could not set SPI bitsPerWord(RD)...ioctl fail");
          exit(1);
        }
    
        status_value = ioctl(*spi_cs_fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed);
        if(status_value < 0)
        {
          perror("Could not set SPI speed (WR)...ioctl fail");
          exit(1);
        }
    
        status_value = ioctl(*spi_cs_fd, SPI_IOC_RD_MAX_SPEED_HZ, &spi_speed);
        if(status_value < 0)
        {
          perror("Could not set SPI speed (RD)...ioctl fail");
          exit(1);
        }
        return(status_value);
    }
    
    
    
    //************************************
    //************************************
    //********** SPI CLOSE PORT **********
    //************************************
    //************************************
    int SpiClosePort (int spi_device)
    {
    	int status_value = -1;
        int *spi_cs_fd;
    
        if (spi_device)
        	spi_cs_fd = &spi_cs1_fd;
        else
        	spi_cs_fd = &spi_cs0_fd;
    
    
        status_value = close(*spi_cs_fd);
        if(status_value < 0)
        {
        	perror("Error - Could not close SPI device");
        	exit(1);
        }
        return(status_value);
    }
    
    
    
    //*******************************************
    //*******************************************
    //********** SPI WRITE & READ DATA **********
    //*******************************************
    //*******************************************
    //data		Bytes to write.  Contents is overwritten with bytes read.
    int SpiWriteAndRead (int spi_device, unsigned char *data, int length)
    {
    	struct spi_ioc_transfer spi[length];
    	int i = 0;
    	int retVal = -1;
        int *spi_cs_fd;
    
        if (spi_device)
        	spi_cs_fd = &spi_cs1_fd;
        else
        	spi_cs_fd = &spi_cs0_fd;
    
    	//one spi transfer for each byte
    
    	for (i = 0 ; i < length ; i++)
    	{
    		memset(&spi[i], 0, sizeof (spi[i]));
    		spi[i].tx_buf        = (unsigned long)(data + i); // transmit from "data"
    		spi[i].rx_buf        = (unsigned long)(data + i) ; // receive into "data"
    		spi[i].len           = sizeof(*(data + i)) ;
    		spi[i].delay_usecs   = 0 ;
    		spi[i].speed_hz      = spi_speed ;
    		spi[i].bits_per_word = spi_bitsPerWord ;
    		spi[i].cs_change = 0;
    	}
    
    	retVal = ioctl(*spi_cs_fd, SPI_IOC_MESSAGE(length), &spi) ;
    
    	if(retVal < 0)
    	{
    		perror("Error - Problem transmitting spi data..ioctl");
    		exit(1);
    	}
    
    	return retVal;
    }
    
    
    int main(int argc, char* argv[])
    {
      unsigned char buf[]  = {0x01}; 
      int spi_device = 0; 
      SpiOpenPort(spi_device); 
      printf("succeed to open device /dev/spidev2.0\n");
    
      while(1)
      {
        for(int i = 1; i<100; i++)
        {
          buf[0] = i; 
          int retV = SpiWriteAndRead(spi_device, buf, 1); 
          printf("succeed to write data = %d with return value = %d\n", i, retV);
          usleep(100*1000);
        }
        printf("send 100 numbers again? press Q to exist"); 
        char key ; 
        std::cin >> key; 
        if(key == 'Q' || key == 'q')
          break;
        
        usleep(1000*1000);
      }
      
      SpiClosePort(spi_device);
    
      return 0; 
    }
    
  • WereCatf
    WereCatf New Member Posts: 201
    If you're only transmitting one byte at a time, then your Arduino-side code is wrong and you don't understand how SPI works: with SPI, both the master and slave transmit simultaneously, but your Arduino-side code tries to first receive a byte from the master, then send one after that -- that's just not how it works.

    You need to transmit and receive simultaneously, as follows:
    // SPI Transfer.
    int SPItransfer(int send_data) {
      SPDR=send_data;
      while(!(SPSR & (1<<SPIF)));//wait for complete tranfer
      return SPDR;
    }
    
  • WereCatf
    WereCatf New Member Posts: 201
    "We set the spi_frequency with 9600, which equals to the frequency in the Arduino part."

    This bit bothers me, as this is another example of you not really knowing what you're doing: the 9600-frequency on the Arduino that you're referring to is the speed of the UART, not the SPI-bus; they are not the same thing and you can set the SPI-bus frequency higher if you wish. Also, the SPI slave uses the master's clock, so it automatically uses the same frequency as you set on the master.