SPI BeagleBoneBlack

Hello together,

I am trying to use an ADX345 acceleration sensor with QNX 7.0 for BeagleBoneBlack.

I am using the following code. I do not get error messages, but all I am able to read is 0.

The functions are from the spitest example. I get the message that a TSC-2046 is present.

I would be nice if anyone could give me some advice.

Regards,

Eberhard Binder

int tspi_getdrvinfo();

int tspi_getdev();

are


#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/neutrino.h>
#include <hw/spi-master.h>
#include <hw/inout.h>
#include <math.h>    // wegen sqrt-operation
#include <devctl.h>
#include <unistd.h>
#include <string.h>


int tspi_getdrvinfo();

int tspi_getdev();

//From Table 19. of the ADXL345 Data sheet
#define DEVID          0x00   //Device ID
#define THRESH_TAP     0x1D   //Tap Threshold
#define OFSX           0x1E   //X-axis Offset
#define OFSY           0x1F   //Y-axis Offset
#define OFSZ           0x20   //Z-axis Offset
#define DUR            0x21   //Tap duration
#define LATENT         0x22   //Tap latency
#define WINDOW         0x23   //Tap window
#define THRESH_ACT     0x24   //Activity threshold
#define THRESH_INACT   0x25   //Threshold inactivity
#define TIME_INACT     0x26   //Inactivity time
#define ACT_INACT_CTL  0x27   //Axis enable control for activity and inactivity detection
#define THRESH_FF      0x28   //Free-fall threshold
#define TIME_FF        0x29   //Free-fall time
#define TAP_AXES       0x2A   //Axis control for single tap/double tap
#define ACT_TAP_STATUS 0x2B   //Source of single tap/double tap
#define BW_RATE        0x2C   //Data rate and power mode control
#define POWER_CTL      0x2D   //Power-saving features control
#define INT_ENABLE     0x2E   //Interrupt enable control
#define INT_MAP        0x2F   //Interrupt mapping control
#define INT_SOURCE     0x30   //Source of interrupts
#define DATA_FORMAT    0x31   //Data format control
#define DATAX0         0x32   //X-axis Data 0
#define DATAX1         0x33   //X-axis Data 1
#define DATAY0         0x34   //Y-axis Data 0
#define DATAY1         0x35   //Y-axis Data 1
#define DATAZ0         0x36   //Z-axis Data 0
#define DATAZ1         0x37   //Z-axis Data 1
#define FIFO_CTL       0x38   //FIFO control
#define FIFO_STATUS    0x39   //FIFO status

#define SLAVE_ID       0x53

// Defines for REGSTER 0x00 Device ID

#define DEVID_VALUE 0xE5

// Defines for REGSTER 0x2D POWER_CTL

// MEASURE         D3

#define MEASURE    0x08

// Defines for REGSTER 0x31 Data Format Control

// RANGE            D1 D0

#define RANGE_2G    0x00
#define RANGE_4G    0x01
#define RANGE_8G    0x02
#define RANGE_16G   0x03

// JUSTIFY          D2

#define JUSTIFY     0x04

// FULL RES         D3

#define FULL_RES    0x08

// READBIT        	D7

#define READBIT		0x40

// MBBIT        	D6

#define MBBIT		0x80


#define N			10

int main(){

   int fd;

   spi_cfg_t spicfg;
   spi_drvinfo_t spidrvinfo;
   spi_devinfo_t spidevinfo;

   uint32_t device;

   unsigned char txBuf[N];
   unsigned char rxBuf[N];

   int len, clen, rlen;

   int DataX;

   int ret;

   int j;

   float a_x;

   tspi_getdrvinfo();

   tspi_getdev();

   fd = spi_open("/dev/spi0");

   if(fd < 0)
   {

      fprintf(stderr, "spi_open() failed\n");
      perror("spi_open() failed\n");
      exit(EXIT_FAILURE);

   }

   if (EOK != spi_getdrvinfo(fd, &spidrvinfo))
   {

      fprintf(stderr, "spi_getdrvinfo() call failed\n");
      perror("spi_getdrvinfo() failed\n");
      spi_close(fd);
      exit(EXIT_FAILURE);

   }
   else
   {

      fprintf(stdout, "spi_getdrvinfo: version %u\n", spidrvinfo.version);
      fprintf(stdout, "spi_getdrvinfo: name %s\n", spidrvinfo.name);
      fprintf(stdout, "spi_getdrvinfo: feature %u\n", spidrvinfo.feature);

   }

   if (EOK != spi_getdevinfo(fd, SPI_DEV_ID_NONE, &spidevinfo))
   {

        fprintf(stderr, "spi_getdevinfo() call failed\n");
        perror("spi_getevinfo() failed\n");
        spi_close(fd);
        exit(EXIT_FAILURE);

   }
   else
   {

        fprintf(stdout, "spi_getdevinfo: device %u\n", spidevinfo.device);
        fprintf(stdout, "spi_getdevinfo: name %s\n", spidevinfo.name);
        fprintf(stdout, "spi_getdevinfo: mode %u\n", spidevinfo.cfg.mode );
        fprintf(stdout, "spi_getdevinfo: clock rate %u\n", spidevinfo.cfg.clock_rate);

   }


   device = spidevinfo.device;

   if (EOK != spi_getdevinfo(fd, device | SPI_DEV_DEFAULT, &spidevinfo))
    {

         fprintf(stderr, "spi_getdevinfo() call failed\n");
         perror("spi_getevinfo() failed\n");
         spi_close(fd);
         exit(EXIT_FAILURE);

    }
    else
    {

         fprintf(stdout, "spi_getdevinfo: device %u\n", spidevinfo.device);
         fprintf(stdout, "spi_getdevinfo: name %s\n", spidevinfo.name);
         fprintf(stdout, "spi_getdevinfo: mode %u\n", spidevinfo.cfg.mode );
         fprintf(stdout, "spi_getdevinfo: clock rate %u\n", spidevinfo.cfg.clock_rate);

    }


   //spicfg.mode = ((8 & SPI_MODE_CHAR_LEN_MASK) | SPI_MODE_CKPOL_HIGH | SPI_MODE_CKPHASE_HALF | SPI_MODE_BODER_MSB);
   spicfg.mode = ((8 & SPI_MODE_CHAR_LEN_MASK) | SPI_MODE_CKPOL_HIGH | SPI_MODE_CKPHASE_HALF);
   spicfg.clock_rate = 500;

   if (EOK != spi_setcfg(fd, device | SPI_DEV_DEFAULT , &spicfg))
   {

      fprintf(stderr, "spi_setcfg() call failed\n");
      perror("spi_setcfg() failed\n");
      spi_close(fd);
      exit(EXIT_FAILURE);

   }

   if (EOK != spi_getdevinfo(fd, device | SPI_DEV_DEFAULT, &spidevinfo))
   {

      fprintf(stderr, "spi_getdevinfo() call failed\n");
      perror("spi_getevinfo() failed\n");
      spi_close(fd);
      exit(EXIT_FAILURE);

   }
   else
   {

      fprintf(stdout, "spi_getdevinfo: device %u\n", spidevinfo.device);
      fprintf(stdout, "spi_getdevinfo: name %s\n", spidevinfo.name);
      fprintf(stdout, "spi_getdevinfo: mode %u\n", spidevinfo.cfg.mode );
      fprintf(stdout, "spi_getdevinfo: clock rate %u\n", spidevinfo.cfg.clock_rate);

   }

   //memset(txBuf, 0, 2);
   //memset(rxBuf, 0, 2);

   memset(txBuf, 0, N);
   memset(rxBuf, 0, N);

   txBuf[0] = DEVID | READBIT;
   len = 1;

   ret = spi_write(fd, device | SPI_DEV_DEFAULT, (void *)txBuf, len);

   if (ret == -1)
   {

      fprintf(stderr, "POWER_CTL spi_write() call failed\n");
      perror("spi_write() failed\n");
      spi_close(fd);
      exit(EXIT_FAILURE);
   }
   else if (ret != len)
   {
      fprintf(stderr, "DEVID spi_write: len %u, ret %d\n", len, ret);
   }

   //memset(txBuf, 0, 2);
   //memset(rxBuf, 0, 2);

   memset(txBuf, 0, N);
   memset(rxBuf, 0, N);

   len = 1;

   ret = spi_read(fd, device | SPI_DEV_DEFAULT, rxBuf, len);

   if (ret == -1)
   {

      fprintf(stderr, "DEVID spi_read() call failed\n");
   	  perror("spi_read() failed\n");
   	  spi_close(fd);
      exit(EXIT_FAILURE);

   }
   else if (ret != len)
   {
      fprintf(stderr, "DEVID spi_read: len %u, ret %d\n", len, ret);
   }

   printf("DEVID %d %x\n", rxBuf[0], rxBuf[0]);

   memset(txBuf, 0, N);
   memset(rxBuf, 0, N);

   txBuf[0] = DEVID | READBIT;
   txBuf[1] = 0;
   len = 2;

   ret = spi_xchange(fd, device  | SPI_DEV_DEFAULT, (void *)txBuf, (void *)rxBuf, len);

   if (ret == -1)
   {

      fprintf(stderr, "DEVID spi_xchange() call failed\n");
      perror("spi_xchange() failed\n");
      spi_close(fd);
      exit(EXIT_FAILURE);

   }

   printf("DEVID %d %x\n", rxBuf[1], rxBuf[1]);

   memset(txBuf, 0, N);
   memset(rxBuf, 0, N);

   txBuf[0] = DEVID | READBIT;
   txBuf[1] = 0;
   clen = 1;
   rlen = 1;

   ret = spi_cmdread(fd, device | SPI_DEV_DEFAULT, (void *)txBuf, clen, (void *)rxBuf, rlen);

   if (ret == -1)
    {

       fprintf(stderr, "DEVID spi_cmdread() call failed\n");
       perror("spi_cmdread() failed\n");
       spi_close(fd);
       exit(EXIT_FAILURE);

    }
   printf("DEVID %d %x\n", rxBuf[0], rxBuf[0]);

   memset(txBuf, 0, N);
   memset(rxBuf, 0, N);

   txBuf[0] = DATA_FORMAT;
   txBuf[1] = RANGE_16G | FULL_RES;
   len = 2;

   ret = spi_write(fd, 0, (void *)txBuf, len);

   if (ret == -1)
   {

      fprintf(stderr, "DATA_FORMAT spi_write() call failed\n");
      perror("spi_write() failed\n");
      spi_close(fd);
      exit(EXIT_FAILURE);

   }
   else if (ret != len)
   {
      fprintf(stderr, "DATA_FORMAT spi_write: len %u, ret %d\n", len, ret);
   }

   memset(txBuf, 0, N);
   memset(rxBuf, 0, N);

   txBuf[0] = POWER_CTL;
   txBuf[1] = MEASURE;
   len = 2;

   ret = spi_write(fd, device | SPI_DEV_DEFAULT, (void *)txBuf, len);

   if (ret == -1)
   {

      fprintf(stderr, "POWER_CTL spi_write() call failed\n");
      perror("spi_write() failed\n");
      spi_close(fd);
      exit(EXIT_FAILURE);

   }
   else if (ret != len)
   {
      fprintf(stderr, "POWER_CTL spi_write: len %u, ret %d\n", len, ret);
   }


   while(1) {

	  goto l1;

	  memset(txBuf, 0, N);
	  memset(rxBuf, 0, N);

      txBuf[0] = DATAX0 | READBIT;
      clen = 1;
      rlen = 1;

      ret = spi_cmdread(fd, device | SPI_DEV_DEFAULT, (void *)txBuf, clen, (void *)rxBuf, rlen);

      if (ret == -1)
	  {

	     fprintf(stderr, "DATAX0 spi_cmdread() call failed\n");
	     perror("spi_cmdread() failed\n");
	     spi_close(fd);
	     exit(EXIT_FAILURE);

	  }
	  else if (ret != rlen)
	  {
	     fprintf(stderr, "DATAX0 spi_cmdread: len %u, ret %d\n", len, ret);
	  }

      printf("DATAX0 %d\n", rxBuf[0]);

      DataX = rxBuf[0];

      memset(txBuf, 0, N);
      memset(rxBuf, 0, N);

	  txBuf[0] = DATAX1 | READBIT;
	  len = 1;

      ret = spi_write(fd, 0, (void *)txBuf, len);

	  if (ret == -1)
	  {

	     fprintf(stderr, "DATAX1 spi_write() call failed\n");
	     perror("spi_write() failed\n");
	     spi_close(fd);
	     exit(EXIT_FAILURE);

	  }
	  else if (ret != len)
	  {
	     fprintf(stderr, "DATAX1 spi_write: len %u, ret %d\n", len, ret);
	  }

 	  ret = spi_read(fd, device | SPI_DEV_DEFAULT, (void *)rxBuf, len);

      if (ret == -1)
      {

         fprintf(stderr, "DATAX1 spi_read() call failed\n");
         perror("spi_read() failed\n");
         spi_close(fd);
         exit(EXIT_FAILURE);

      }
      else if (ret != len)
      {
         fprintf(stderr, "DATAX1 spi_read: len %u, ret %d\n", len, ret);
	  }

      printf("DATAX1 %d\n", rxBuf[1]);

      DataX += rxBuf[1]<<8;

      printf("DataX %d\n", DataX);

      a_x = (float)DataX / 255.0;

      printf("a_x = %.2f\n", a_x);

l1:

      memset(txBuf, 0, N);
      memset(rxBuf, 0, N);

      txBuf[0] = DATAX0 | READBIT | MBBIT;
      clen = 1;
      rlen = 6;

      ret = spi_cmdread(fd, device | SPI_DEV_DEFAULT, (void *)txBuf, clen, (void *)rxBuf, rlen);

      printf("\nMessung, %d Bytes\n", ret);

      for(j = 0; j <= 5; j+=2)
    	  printf("%u %d\n", j, (rxBuf[j]<<8)+rxBuf[j+1]);

      usleep(2000000);


   }

   spi_close(fd);

}




int tspi_getdrvinfo()
{
	spi_drvinfo_t	info;
	int				i, fd;

	fprintf(stderr, "\n########### spi_getdrvinfo() test ###########\n");

	/*
	 * Open
	 */

	if ((fd = spi_open("/dev/spi0")) < 0) {
		fprintf(stderr, "SPI open failed, fd = %d errno = %d\n", fd, errno);
		strerror(errno);
		return(-1);
	}

	i = spi_getdrvinfo(fd, &info);
	if (i == EOK) {
		fprintf(stderr, "version     = %x\n", info.version);
		fprintf(stderr, "driver name = %s\n", info.name);
		fprintf(stderr, "feature     = %x\n", info.feature);
	}
	else
		fprintf(stderr, "get driver info failed\n");

	spi_close(fd);

	return 0;
}




int tspi_getdev()
{
	spi_devinfo_t	info;
	int				i, fd, dev;

	fprintf(stderr, "\n########### spi_getdevinfo() test ###########\n");

	/*
	 * Open
	 */
	if ((fd = spi_open("/dev/spi0")) < 0) {
		fprintf(stderr, "SPI open failed, fd = %d errno = %d\n", fd, errno);
		strerror(errno);
		return(-1);
	}


	fprintf(stderr, "\n----- Detect all devices info -----\n\n");
	dev = 0;
	while (1) {
        fprintf(stderr, "----- get  device 0x%04x info -----\n", dev);

		i = spi_getdevinfo(fd, dev, &info);
		if (i == EOK) {
			fprintf(stderr, "device     = %x\n", info.device);
			fprintf(stderr, "name       = %s\n", info.name);
			fprintf(stderr, "mode       = %x\n", info.cfg.mode);
			fprintf(stderr, "clock_rate = %d\n", info.cfg.clock_rate);
			dev = info.device & SPI_DEV_ID_MASK;
		}
		else {
			break;
		}
        dev++;
	}

	fprintf(stderr, "----- get next device 0x%04x info -----\n", 0xFFFF);
	dev = SPI_DEV_ID_NONE;
	while (1) {
		i = spi_getdevinfo(fd, dev, &info);
		if (i == EOK) {
			fprintf(stderr, "device     = %x\n", info.device);
			fprintf(stderr, "name       = %s\n", info.name);
			fprintf(stderr, "mode       = %x\n", info.cfg.mode);
			fprintf(stderr, "clock_rate = %d\n", info.cfg.clock_rate);
			dev = info.device & SPI_DEV_ID_MASK;
		}
		else {
			fprintf(stderr, "get devinfo failed\n");
			break;
		}
	}

	spi_close(fd);

	return 0;
}

Hi,

I can’t see any ADX345 chip in BeagleBoneBlack schematics.
I suppose you use an add-on board. What are the schematics of this board ? How is it connected on the BeagleBoneBlack board ?

Nicolas

Hi,

I use the SparkFun Breakout Board.

https://www.sparkfun.com/products/9836

However, I am sure the board is correctly connected as i can read out the data in Linux using the spidev functionality.

The board is connected to SPI 0, CS 0.

Eberhard

Have you checked the QNX BSP configure the necessary pins has SPI pins ?

I think so:

in init_pinmux.c

i have:

void init_pinmux()
{
init_i2c0_pin_mux();
init_leds_pin_mux();
init_gmii1_pin_mux();
init_mmc0_pin_mux();
init_uart0_pin_mux();
init_spi0_pin_mux();
init_spi1_pin_mux();
}

//#if 0
static void init_spi0_pin_mux(void)
{
out32(conf_spi0_sclk , MODE(0) | PULLUDEN | RXACTIVE); /* [P9 22] SPI0_SCLK /
out32(conf_spi0_d0 , MODE(0) | PULLUDEN | PULLUP_EN | RXACTIVE); /
[P9 21] SPI0_D0 /
out32(conf_spi0_d1 , MODE(0) | PULLUDEN | RXACTIVE); /
[P9 18] SPI0_D1 /
out32(conf_spi0_cs0 , MODE(0) | PULLUDEN | PULLUP_EN | RXACTIVE); /
[P9 17] SPI0_CS0 */
}
//#endif

Pin numbers are given in comments but nothing shows they are effectively the good ones. I guess conf_spi0_sclk and others are containing the real pin number.
SPI module also has to be enabled and clocked correctly (this might be done in the driver).

Have you a scope to look at SPI signals ?
This is to check if all/some/no signals are ok.
This also permits to check if the clock is at the right speed.

during startup I see

All ClockCycles offsets within tolerance
Welcome to QNX Neutrino 7.0 on the Texas Instruments AM335x BeagleBone (ARMv7 Cortex-A8 core) - Board
Starting MMC/SD driver…
starting I2C driver…
starting WDT reset utility…
Starting random service …
starting Board ID driver…
Board ID
header: ee3355aa
name: A335BNLT
version: 00C0
serial: 4215BBBK0AFD
config: ÿÿÿÿÿÿ
Setting OS Clock from on-board RTC
Sat Jan 01 00:00:01 GMT 2000
Starting USB OTG Host driver…
Path=0 - omap
target=0 lun=0 Direct-Access(0) - SDMMC: SL16G Rev: 3.f
Starting SPI driver…
Starting network driver…
starting leds driver…
Setting environment variables…
done.

So I believe the driver is started.

Device is present:

ls /dev

yields

ls /dev

bdid name ptyp6 socket ttyp2 tymem
bpf null ptyp7 spi0 ttyp3 urandom
bpf0 pipe random stderr ttyp4 usb
console profiler sd0 stdin ttyp5 zero
crypto ptyp0 sd0t12 stdout ttyp6
emmc0 ptyp1 sem tap ttyp7
emmc0t131 ptyp2 ser1 text tun0
i2c0 ptyp3 shmem tty tun1

The driver is started in the build file
#######################################################################
## SPI driver
## SPI 0 ioport 0x48030100 irq 65
## SPI 1 ioport 0x481a0100 irq 125
#######################################################################
display_msg Starting SPI driver…
# SPI0
spi-master -u0 -d dm816x base=0x48030100,irq=65,edma=1,edmairq=529,edmachannel=17
#spi-master -d dm816x base=0x48030100,irq=65,edma=1,edmairq=529,edmachannel=17
# SPI1
#spi-master -d dm816x base=0x481A0100,irq=125,edma=1,edmairq=555,edmachannel=43

Of course, the BSP might contain errors and the comments could be wrong, but the comments are from QNX.

My test code yields

spi_getdrvinfo: version 65536
spi_getdrvinfo: name DM816X SPI
spi_getdrvinfo: feature 2147483648
spi_getdevinfo: device 0
spi_getdevinfo: name ADXL345-0
spi_getdevinfo: mode 1800
spi_getdevinfo: clock rate 375000

So at least the driver is present. Clock should be fine (375000 Hz, max is 5 MHz).

I will check the clock signal.

I checked the clock signal, it looks fine. I will try to check the remaining signals.

As I suspected: the CS signal is missing.

I checked the pins, they are fine. The pinux is somewhat different from Linux. I changed the pinmux to the working one from the device tree overlay for SPI0, but to no avail.

I can see several possibilities :

  • The pinmux init is still not correct.
  • Another piece of code (init, driver…) reconfigures the pin to another function.
  • The SPI driver does not use the correct CS.

I use device 0 and there is only one device configured.
My assumption is that device 0 uses CS 0, but I am not sure about that.
I cannot find any other configuration for that pin.

You have access to the SPI drivers in the BSP.
You can look at them to check if these drivers suit your application.

Yes, I had a look at the driver, and it seems hat device 0 means CS 0.

I get now CS and MOSI, but I am still not sure about the pinmux. The pinmux in the driver is strange. My logic analyzer show a correct answer from the sensor, but I cannot read it in my code. Maybe the MISO pin is still misconfigured. I will check that. Unfortunately, there is no documentation about the API functions, so I am not sure the code is correct.

If you want to be really sure of the configuration of the pinmux and of the SPI “driver” code, you can write a test app with everything in it.
Initialise pinmux and do some basic SPI operations in this app. This should not be very complex.
When this test app works, you’ll be able to narrow down the problem : Remove pinmux config and see if SPI operations still work.

Now the connection is working.

I used this pinmux:

static void init_spi0_pin_mux(void)
{
out32(conf_spi0_sclk , 0x30); /* [P9 22] SPI0_SCLK /
out32(conf_spi0_d0 , 0x30); /
[P9 21] SPI0_D0 /
out32(conf_spi0_d1 , 0x10); /
[P9 18] SPI0_D1 /
out32(conf_spi0_cs0 , 0x10); /
[P9 17] SPI0_CS0 */
}

I still have to check if the original pinmux is working, but this one is a working one from a Linux device tree.

I used this configuration:

spicfg.mode = (((8 & SPI_MODE_CHAR_LEN_MASK) |
SPI_MODE_CKPHASE_HALF | SPI_MODE_BODER_MSB ));

That is SPI mode 3. I had some problems to understand how the mode is configured.

Finally, I had to change the wire for the physical connection to read data.