Hi Aniket,

The main limitation for the number of SPI slave devices allowed in an 
independent slave configuration is the number of CS lines available to you 
and the ability for data and clock lines to meet threshold high and low 
logic levels.

In the Arduino code provided in the tutorial you followed, I'm not sure how 
the interrupt was set up for operating the Pro Mini in SPI slave mode, 
since I haven't used Interrupts on the Arduino before.
Two things I would recommend checking in the Arduino code:

   1. Ensure that a low-going CS signal is the only thing that makes the 
   Arduino enter the SPI interrupt service routine. I don't explicitly see in 
   the tutorial code how pin 10 of the Pro Mini triggers the interrupt.
   2. Ensure that the Pro Mini slaves are not going to cause bus contention 
   on the MISO line. Unselected slaves should not be driving the MISO line 
   high or low. Not sure how you can make sure of this. maybe temporarily set 
   the MISO pin of unselected slaves as inputs, rather than outputs?
   
For your BBBlack, I don't easily see in the tutorial code how the CS line 
is being controlled.

You likely need to manually control the slave select lines using GPIO. For 
example: select one slave by driving its CS line low, send/receive serial 
data, then deselect the slave by driving its CS line high.

Only one slave CS line may be driven low at a time when reading data from 
individual slaves.


Since I used the BBBlue (which is basically a BBBlack with the Robotics 
Cape integrated into it), I modified the Robotics Cape API functions, 
rather than directly using ioctl and spidev. I've attached my modified SPI 
functions here.

I've tested the functions rc_spi_init_mod, rc_manual_select_mod, and 
rc_manual_deselect_mod with a 3-to-8 line decoder and a Bus Pirate for 
sniffing the SPI bus.

You probably won't need a line decoder for only 4 SPI slaves, so you can 
just directly drive the CS lines using GPIO.


It'll be another couple of weeks before I receive my prototype slave 
devices, so I haven't had the chance to fully test my functions just yet.

I would dig around in the Robotics Cape library code. The SPI functions in 
the library are more readable and better documented than the tutorial code, 
to be honest.

https://github.com/StrawsonDesign/Robotics_Cape_Installer/blob/master/libraries/serial_ports/rc_spi.c


The simplest solution I can think of would be to try installing the 
Robotics Cape API on your BBBlack and see if you can use their API 
functions without the Robotics Cape hardware.

Hopefully this helps. 


Regards,


Robert

On Thursday, December 14, 2017 at 11:02:42 AM UTC-8, Aniket Mazumder wrote:
>
> Hi Robert
>
> I am facing a problem simiar to yours. My project involvs connecting 4 
> arduino pro mini's as slaves to a Beaglebone black. I am able to share data 
> between one arduino and the beaglbone by following the link below
> :http://www.ulasdikme.com/projects/arduino/BBB_Arduino_SPI.php
>
> I Understand that I need to Use GPIO's as CS pins to active the 
> corresponding arduino,
>
> However whenever I try the same for more than one slave devices ,  I 
> receive data from one arduino only.. I am using SPI 0 
> Are there any limitations as to the number of slave devices that can be 
> attached to SPI 0. 
>
> I need the data from the arduino's as quickly as possible preferably 
> without any delay. Could you suggest a method of doing the same.  
>
> Were u able to achieve the same for yorr project.. If yes, could you let 
> me know how. 
>

-- 
For more options, visit http://beagleboard.org/discuss
--- 
You received this message because you are subscribed to the Google Groups 
"BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to beagleboard+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/beagleboard/a37e630a-f867-4a51-890a-76b9dc724f90%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
#ifndef _RC_SPI_MOD_H_
#define _RC_SPI_MOD_H_
#include <roboticscape.h>

int rc_spi_init_mod(ss_mode_t ss_mode, int spi_mode, int speed_hz, int slave);
int rc_manual_select_spi_slave_mod(int slave);
int rc_manual_deselect_spi_slave_mod();

#endif
/*******************************************************************************
* rc_spi.c
*
* Functions for interfacing with SPI1 on the beaglebone and Robotics Cape
*******************************************************************************/

#include "libraries/roboticscape.h"
#include "libraries/rc_defs.h"
#include "libraries/mmap/rc_mmap_gpio_adc.h"	// for toggling gpio pins
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>	// for memset
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include "rc_spi_mod.h"

#define SPI10_PATH			"/dev/spidev1.0"
#define SPI11_PATH			"/dev/spidev1.1"
#define SPI_MAX_SPEED		24000000 	// 24mhz
#define SPI_MIN_SPEED		1000		// 1khz
#define SPI_BITS_PER_WORD 	8
#define SPI_BUF_SIZE		2

int fd[2];			// file descriptor for SPI1_PATH device cs0, cs1
int initialized[2];	// set to 1 after successful initialization 
int gpio_ss[4];		// holds gpio pins for slave select lines

struct spi_ioc_transfer xfer[2]; // ioctl transfer structs for tx & rx
char tx_buf[SPI_BUF_SIZE];
char rx_buf[SPI_BUF_SIZE];

/*******************************************************************************
* @ int rc_spi_init_mod(ss_mode_t ss_mode, int spi_mode, int speed_hz, int slave)
*
* Functions for interfacing with SPI1 on the beaglebone and Robotics Cape
* choose either slave=1 or slave=2. it won't matter since data lines are shared
* use ss_mode = SS_MODE_MANUAL to manually control SS over GPIO
*******************************************************************************/
int rc_spi_init_mod(ss_mode_t ss_mode, int spi_mode, int speed_hz, int slave){
	int bits = SPI_BITS_PER_WORD;
	int mode_proper;
	int i = 0;
	// sanity checks
	if(speed_hz>SPI_MAX_SPEED || speed_hz<SPI_MIN_SPEED){
		printf("ERROR: SPI speed_hz must be between %d & %d\n", SPI_MIN_SPEED,\
																SPI_MAX_SPEED);
		return -1;
	}
	if(rc_get_bb_model()!=BB_BLUE && slave==2 && ss_mode==SS_MODE_AUTO){
		printf("ERROR: Can't use SS_MODE_AUTO on slave 2 with Cape\n");
		return -1;
	}
	// switch 4 standard SPI modes 0-3. return error otherwise
	switch(spi_mode){
		case 0: mode_proper = SPI_MODE_0; break;
		case 1: mode_proper = SPI_MODE_1; break;
		case 2: mode_proper = SPI_MODE_2; break;
		case 3: mode_proper = SPI_MODE_3; break;
		default: 
			printf("ERROR: SPI mode must be 0, 1, 2, or 3\n");
			printf("check your device datasheet to see which to use\n");
			return -1;
	}
	// get file descriptor for spi1 device
	switch(slave){
	case 1: 
		fd[0] = open(SPI10_PATH, O_RDWR);
		if(fd[0] < 0) {
			printf("ERROR: %s missing\n", SPI10_PATH); 
		return -1; 
		}
		break;
	case 2:
		fd[1] = open(SPI11_PATH, O_RDWR);
		if(fd[1] < 0) {
			printf("ERROR: %s missing\n", SPI11_PATH); 
		return -1; 
		}
		break;
	default:
		printf("ERROR: SPI slave must be 1 or 2\n");
		return -1;
	}
	// set settings
	if(ioctl(fd[slave-1], SPI_IOC_WR_MODE, &mode_proper)<0){
		printf("can't set spi mode");
		close(fd[slave-1]);
		return -1;
	}if(ioctl(fd[slave-1], SPI_IOC_RD_MODE, &mode_proper)<0){
		printf("can't get spi mode");
		close(fd[slave-1]);
		return -1;
	}if(ioctl(fd[slave-1], SPI_IOC_WR_BITS_PER_WORD, &bits)<0){
		printf("can't set bits per word");
		close(fd[slave-1]);
		return -1;
	}if(ioctl(fd[slave-1], SPI_IOC_RD_BITS_PER_WORD, &bits)<0){
		printf("can't get bits per word");
		close(fd[slave-1]);
		return -1;
	} if(ioctl(fd[slave-1], SPI_IOC_WR_MAX_SPEED_HZ, &speed_hz)<0){
		printf("can't set max speed hz");
		close(fd[slave-1]);
		return -1;
	} if(ioctl(fd[slave-1], SPI_IOC_RD_MAX_SPEED_HZ, &speed_hz)<0){
		printf("can't get max speed hz");
		close(fd[slave-1]);
		return -1;
	}

	// store settings
	xfer[0].cs_change = 1;
	xfer[0].delay_usecs = 0;
	xfer[0].speed_hz = speed_hz;
	xfer[0].bits_per_word = SPI_BITS_PER_WORD;
	xfer[1].cs_change = 1;
	xfer[1].delay_usecs = 0;
	xfer[1].speed_hz = speed_hz;
	xfer[1].bits_per_word = SPI_BITS_PER_WORD;

	// set up 4 slave select pins on GP0 header
	if(rc_get_bb_model()==BB_BLUE){
		gpio_ss[0] = BLUE_GP0_PIN_3;//G1 (active-high enable)
		gpio_ss[1] = BLUE_GP0_PIN_4;//C select
		gpio_ss[2] = BLUE_GP0_PIN_5;//B select
		gpio_ss[3] = BLUE_GP0_PIN_6;//A select
	}
	else{//only modified the file to work with BBBlue. modify below for cape
		gpio_ss[0] = CAPE_SPI_PIN_6_SS1;
		gpio_ss[1] = CAPE_SPI_PIN_6_SS2;
	}
	if(ss_mode==SS_MODE_AUTO){
		if(rc_set_pinmux_mode(gpio_ss[slave-1], PINMUX_SPI)){
			printf("ERROR: failed to set slave select pin to SPI mode\n");
			return -1;
		}
	}
	else{
		/*
		rc_set_pinmux_mode(gpio_ss[slave-1], PINMUX_GPIO);
		if(rc_gpio_export(gpio_ss[slave-1])){
			printf("ERROR: failed to export gpio %d for manual slave select\n",\
															 gpio_ss[slave-1]);
			return -1;
		}
		*/
		//export gpios and set them as outputs
		for(i = 0; i < 4; i++)
		{
			rc_gpio_export(gpio_ss[i]);
			rc_gpio_set_dir(gpio_ss[i], OUTPUT_PIN);
		}
		
		rc_manual_deselect_spi_slave_mod();
	}
	// all done
	initialized[slave-1] = 1;
	return 0;
}

/*******************************************************************************
* int rc_spi_fd(int slave)
*
* Returns the file descriptor for spi1 once initialized.
* Use this if you want to do your own reading and writing to the bus instead
* of the basic functions defined here. If the bus has not been initialized, 
* return -1
*******************************************************************************/
/*
int rc_spi_fd(int slave){
	switch(slave){
	case 1:
		if(initialized[0]==0){
			printf("ERROR: SPI1 slave 1 not initialized yet\n");
			return -1;
		}
		else return fd[0];
	case 2:
		if(initialized[1]==0){
			printf("ERROR: SPI1 slave 2 not initialized yet\n");
			return -1;
		}
		else return fd[1];
	}
	printf("ERROR: SPI Slave must be 1 or 2\n");
	return -1;
}

*/
/*******************************************************************************
* @ int rc_spi_close(int slave)
*
* Closes the file descriptor and sets initialized to 0.
*******************************************************************************/
/*
int rc_spi_close(int slave){
	switch(slave){
	case 1:
		rc_manual_deselect_spi_slave(slave);
		close(fd[0]);
		initialized[0] = 0;
		return 0;
	case 2:
		rc_manual_deselect_spi_slave(slave);
		close(fd[1]);
		initialized[1] = 0;
		return 0;
	}
	printf("ERROR: SPI Slave must be 1 or 2\n");
	return -1;
}
*/
/*******************************************************************************
* @ int manual_select_spi_slave(int slave)
*
* Selects a slave (1 through 8) by pulling the corresponding slave select pin
* to ground. It also ensures the other slave is not selected.
*******************************************************************************/
int rc_manual_select_spi_slave_mod(int slave){
	switch(slave){
		case 1://Y0 low
			//pull enable low while changing select bits
			rc_gpio_set_value_mmap(gpio_ss[0], LOW);
			
			rc_gpio_set_value_mmap(gpio_ss[1], LOW);
			rc_gpio_set_value_mmap(gpio_ss[2], LOW);
			rc_gpio_set_value_mmap(gpio_ss[3], LOW);
			
			//pull enable high to bring selected SS low
			rc_gpio_set_value_mmap(gpio_ss[0], HIGH);
			break;
			
		case 2://Y1 low
			//pull enable low while changing select bits
			rc_gpio_set_value_mmap(gpio_ss[0], LOW);
			
			rc_gpio_set_value_mmap(gpio_ss[1], LOW);
			rc_gpio_set_value_mmap(gpio_ss[2], LOW);
			rc_gpio_set_value_mmap(gpio_ss[3], HIGH);
			
			//pull enable high to bring selected SS low
			rc_gpio_set_value_mmap(gpio_ss[0], HIGH);
			break;
		
		case 3://Y2 low
			//pull enable low while changing select bits
			rc_gpio_set_value_mmap(gpio_ss[0], LOW);
			
			rc_gpio_set_value_mmap(gpio_ss[1], LOW);
			rc_gpio_set_value_mmap(gpio_ss[2], HIGH);
			rc_gpio_set_value_mmap(gpio_ss[3], LOW);
			
			//pull enable high to bring selected SS low
			rc_gpio_set_value_mmap(gpio_ss[0], HIGH);
			break;
		
		case 4://Y3 low
			//pull enable low while changing select bits
			rc_gpio_set_value_mmap(gpio_ss[0], LOW);
			
			rc_gpio_set_value_mmap(gpio_ss[1], LOW);
			rc_gpio_set_value_mmap(gpio_ss[2], HIGH);
			rc_gpio_set_value_mmap(gpio_ss[3], HIGH);
			
			//pull enable high to bring selected SS low
			rc_gpio_set_value_mmap(gpio_ss[0], HIGH);
			break;
			
		case 5://Y4 low
			//pull enable low while changing select bits
			rc_gpio_set_value_mmap(gpio_ss[0], LOW);
			
			rc_gpio_set_value_mmap(gpio_ss[1], HIGH);
			rc_gpio_set_value_mmap(gpio_ss[2], LOW);
			rc_gpio_set_value_mmap(gpio_ss[3], LOW);
			
			//pull enable high to bring selected SS low
			rc_gpio_set_value_mmap(gpio_ss[0], HIGH);
			break;
			
		case 6://Y5 low
			//pull enable low while changing select bits
			rc_gpio_set_value_mmap(gpio_ss[0], LOW);
			
			rc_gpio_set_value_mmap(gpio_ss[1], HIGH);
			rc_gpio_set_value_mmap(gpio_ss[2], LOW);
			rc_gpio_set_value_mmap(gpio_ss[3], HIGH);
			
			//pull enable high to bring selected SS low
			rc_gpio_set_value_mmap(gpio_ss[0], HIGH);
			break;
		
		case 7://Y6 low
			//pull enable low while changing select bits
			rc_gpio_set_value_mmap(gpio_ss[0], LOW);
			
			rc_gpio_set_value_mmap(gpio_ss[1], HIGH);
			rc_gpio_set_value_mmap(gpio_ss[2], HIGH);
			rc_gpio_set_value_mmap(gpio_ss[3], LOW);
			
			//pull enable high to bring selected SS low
			rc_gpio_set_value_mmap(gpio_ss[0], HIGH);
			break;
		
		case 8://Y7 low
			//pull enable low while changing select bits
			rc_gpio_set_value_mmap(gpio_ss[0], LOW);
			
			rc_gpio_set_value_mmap(gpio_ss[1], HIGH);
			rc_gpio_set_value_mmap(gpio_ss[2], HIGH);
			rc_gpio_set_value_mmap(gpio_ss[3], HIGH);
			
			//pull enable high to bring selected SS low
			rc_gpio_set_value_mmap(gpio_ss[0], HIGH);
			break;
		
		default:
			printf("SPI slave number must be 1 through 8\n");
			return -1;
	}
	return 0;
}

/*******************************************************************************
* @ int rc_manual_deselect_spi_slave()
*
* Deselects all slaves by pulling the slave select pins high
* sets enable of line decoder to low
*******************************************************************************/
int rc_manual_deselect_spi_slave_mod(){
	rc_gpio_set_value_mmap(gpio_ss[0], LOW);
	return 0;
}

/*******************************************************************************
* int rc_spi_send_bytes(char* data, int bytes, int slave)
*
* Like rc_uart_send_bytes, this lets you send any byte sequence you like.
*******************************************************************************/
/*
int rc_spi_send_bytes(char* data, int bytes, int slave){
	int ret;
	// sanity checks
	if(slave!=1 && slave!=2){
		printf("ERROR: SPI slave must be 1 or 2\n");
		return -1;
	}
	if(initialized[slave-1]==0){
		printf("ERROR: SPI slave %d not yet initialized\n", slave);
		return -1;
	} 
	if(bytes<1){
		printf("ERROR: rc_spi_send_bytes, bytes to send must be >=1\n");
		return -1;
	}
	// fill in ioctl xfer struct. speed and bits were already set in initialize
	xfer[0].rx_buf = 0;
	xfer[0].tx_buf = (unsigned long) data;
	xfer[0].len = bytes;
	// send
	ret = ioctl(fd[slave-1], SPI_IOC_MESSAGE(1), xfer);
	if(ret<0){
		printf("ERROR: SPI_IOC_MESSAGE_FAILED\n");
		return -1;
	}
	return ret;
}
*/
/*******************************************************************************
* int rc_spi_read_bytes(char* data, int bytes, int slave)
*
* Like rc_uart_read_bytes, this lets you read a byte sequence without sending.
*******************************************************************************/
/*
int rc_spi_read_bytes(char* data, int bytes, int slave){
	int ret;
	// sanity checks
	if(slave!=1 && slave!=2){
		printf("ERROR: SPI slave must be 1 or 2\n");
		return -1;
	}
	if(initialized[slave-1]==0){
		printf("ERROR: SPI slave %d not yet initialized\n", slave);
		return -1;
	} 
	if(bytes<1){
		printf("ERROR: rc_spi_read_bytes, bytes to read must be >=1\n");
		return -1;
	}
	// fill in ioctl xfer struct. speed and bits were already set in initialize
	xfer[0].rx_buf = (unsigned long) data;;
	xfer[0].tx_buf = 0;
	xfer[0].len = bytes;
	// receive
	ret=ioctl(fd[slave-1], SPI_IOC_MESSAGE(1), xfer);
	if(ret<0){
		printf("ERROR: SPI_IOC_MESSAGE_FAILED\n");
		return -1;
	}
	return ret;
}
*/
/*******************************************************************************
* @ int rc_spi_transfer(char* tx_data, int tx_bytes, char* rx_data, int slave)
*
* This is a generic wrapper for the ioctl spi transfer function. It lets the
* user send any sequence of bytes and read the response. The return value is
* the number of bytes received or -1 on error.
*******************************************************************************/
/*
int rc_spi_transfer(char* tx_data, int tx_bytes, char* rx_data, int slave){
	int ret;
	// sanity checks
	if(slave!=1 && slave!=2){
		printf("ERROR: SPI slave must be 1 or 2\n");
		return -1;
	}
	if(initialized[slave-1]==0){
		printf("ERROR: SPI slave %d not yet initialized\n", slave);
		return -1;
	} 
	if(tx_bytes<1){
		printf("ERROR: spi1_transfer, bytes must be >=1\n");
	}
	// fill in send struct 
	xfer[0].tx_buf = (unsigned long) tx_data; 
	xfer[0].rx_buf = (unsigned long) rx_data;
	xfer[0].len = tx_bytes;
	ret=ioctl(fd[slave-1], SPI_IOC_MESSAGE(1), xfer);
	if(ret<0){
		printf("SPI_IOC_MESSAGE_FAILED\n");
		return -1;
	}
	return ret;
}
*/
/*******************************************************************************
* int rc_spi_write_reg_byte(char reg_addr, char data, int slave)
*
* Used for writing a byte value to a register. This sends in order the address
* and byte to be written. It also sets the MSB of the register to 1 which 
* indicates a write operation on many ICs. If you do not want this particular 
* functionality, use spi1_send_bytes() to send a byte string of your choosing.
*******************************************************************************/
/*
int rc_spi_write_reg_byte(char reg_addr, char data, int slave){
	// sanity checks
	if(slave!=1 && slave!=2){
		printf("ERROR: SPI slave must be 1 or 2\n");
		return -1;
	}
	if(initialized[slave-1]==0){
		printf("ERROR: SPI slave %d not yet initialized\n", slave);
		return -1;
	}
	//wipe TX buffer and fill in register address and data
	memset(tx_buf, 0, sizeof tx_buf);
	tx_buf[0] = reg_addr | 0x80; /// set MSBit = 1 to indicate it's a write
	tx_buf[1] = data;
	// fill in ioctl zfer struct. speed and bits were already set in initialize
	xfer[0].tx_buf = (unsigned long) tx_buf;
	xfer[0].len = 2;
	// send
	if(ioctl(fd[slave-1], SPI_IOC_MESSAGE(1), xfer)<0){
		printf("ERROR: SPI_IOC_MESSAGE_FAILED\n");
		return -1;
	}
	return 0;
}
*/
/*******************************************************************************
* char rc_spi_read_reg_byte(char reg_addr, int slave)
*
* Reads a single character located at address reg_addr. This is accomplished
* by sending the reg_addr with the MSB set to 0 indicating a read on many
* ICs. 
*******************************************************************************/
/*
char rc_spi_read_reg_byte(char reg_addr, int slave){
	// sanity checks
	if(slave!=1 && slave!=2){
		printf("ERROR: SPI slave must be 1 or 2\n");
		return -1;
	}
	if(initialized[slave-1]==0){
		printf("ERROR: SPI slave %d not yet initialized\n", slave);
		return -1;
	}
	// wipe buffers
	memset(tx_buf, 0, sizeof tx_buf);
	memset(rx_buf, 0, sizeof rx_buf);
	// fill in xfer struct 
	tx_buf[0] = reg_addr & 0x7f; // MSBit = 0 to indicate it's a read
	xfer[0].tx_buf = (unsigned long) tx_buf; 
	xfer[0].rx_buf = (unsigned long) rx_buf;
	xfer[0].len = 1;
	if(ioctl(fd[slave-1], SPI_IOC_MESSAGE(1), xfer)<0){
		printf("SPI_IOC_MESSAGE_FAILED\n");
		return -1;
	}
	return rx_buf[0];
}
*/
/*******************************************************************************
* int rc_spi_read_reg_bytes(char reg_addr, char* data, int bytes, int slave)
*
* Reads multiple bytes located at address reg_addr. This is accomplished
* by sending the reg_addr with the MSB set to 0 indicating a read on many
* ICs. 
*******************************************************************************/
/*
int rc_spi_read_reg_bytes(char reg_addr, char* data, int bytes, int slave){
	int ret;
	// sanity checks
	if(slave!=1 && slave!=2){
		printf("ERROR: SPI slave must be 1 or 2\n");
		return -1;
	}
	if(initialized[slave-1]==0){
		printf("ERROR: SPI slave %d not yet initialized\n", slave);
		return -1;
	} 
	if(bytes<1){
		printf("ERROR: spi1_read_reg_bytes, bytes must be >=1\n");
	}
	// wipe buffers
	memset(tx_buf, 0, sizeof tx_buf);
	memset(data, 0, bytes);
	// fill in send struct 
	tx_buf[0] = reg_addr & 0x7f; // MSBit = 0 to indicate it's a read
	xfer[0].tx_buf = (unsigned long) tx_buf; 
	xfer[0].rx_buf = 0;
	xfer[0].len = 1;
	// fill in receive struct
	xfer[1].tx_buf = 0;
	xfer[1].rx_buf = (unsigned long) data;
	xfer[1].len = bytes;
	ret=ioctl(fd[slave-1], SPI_IOC_MESSAGE(2), xfer);
	if (ret<0){
		printf("SPI_IOC_MESSAGE_FAILED\n");
		return -1;
	}
	return 0;
}
*/


Reply via email to