Exif_JPEG_420


Guide How To Connect SPI Device To BeagleBone AI-64

As example we use the GC9A01 SPI display.




SPI Connection Diagram between GC9A01 and BBAI64


To add some funcionality we also connect the AHT15 – Temperature and humidity sensor



I2C Connection Diagram between ATH15 and BBAI64


BBAI64 Configuration


Install the Device Tree configuration for BBAI64

In the BBAI64 terminal type:

debian@BeagleBone:~$ cd /opt/source/dtb-5.10-ti-arm64/
debian@BeagleBone:/opt/source/dtb-5.10-ti-arm64$ git pull
debian@BeagleBone:/opt/source/dtb-5.10-ti-arm64$ make
debian@BeagleBone:/opt/source/dtb-5.10-ti-arm64$ sudo make install
debian@BeagleBone:/opt/source/dtb-5.10-ti-arm64$ git pull

To the /boot/firmware/extlinux/extlinux.conf add line: 
fdtoverlays /overlays/BONE-SPI0_0.dtbo

debian@BeagleBone:~$ cat /boot/firmware/extlinux/extlinux.conf
label Linux microSD
kernel /Image
append console=ttyS2,115200n8 earlycon=ns16550a,mmio32,0x02800000 root=/dev/mmcblk1p2 ro rootfstype=ext4 rootwait net.ifnames=0
fdtdir /
fdtoverlays /overlays/BONE-SPI0_0.dtbo
initrd /initrd.img

Reboot the BBAI64

debian@BeagleBone:~$ sudo reboot
Connection to 192.168.7.2 closed by remote host.
Connection to 192.168.7.2 closed.

After reboot check if the SPI0_0 overlay is active.

debian@BeagleBone:~$ sudo beagle-version | grep UBOOT
UBOOT: Booted Device-Tree:[k3-j721e-beagleboneai64.dts]
UBOOT: Loaded Overlay:[BONE-SPI0_0.kernel]

To configure the BBAI64 to load SPI module at boot at time,
add spidev line to /etc/modules file.

# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
spidev

Configure BBAI64 to access SPI without root permissions:

Create file /etc/udev/rules.d/80-spi-noroot.rules

# /etc/udev/rules.d/80-spi-noroot.rules
#
# udevadm test $(udevadm info --query=path --name=spidev0.0)
#
SUBSYSTEM=="spidev", GROUP="gpio", ACTION=="add", \
        RUN+="/bin/chgrp -R gpio '/sys%p'", \
        RUN+="/bin/chmod -R g=u '/sys%p'"

See the BeagleBone AI-64 – I2C to check how to enable I2C for AHT15

Example how to control SPI and GPIO from BBAI64 with C/C++ :

/* Outputs.h */

#ifndef OUTPUTS_H_
#define OUTPUTS_H_

#include <iostream>
#include <string>
#include <stdio.h>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>
#include <linux/ioctl.h>
#include <sys/stat.h>
#include <linux/types.h>


class Outputs{
private :
	FILE *RSTHandle;
	FILE *DCHandle;
	DIR *pDir;
	int spi_dev;

	/*GPIO P9_15*/
	const char *RSTDirection = "/sys/class/gpio/gpio347/direction";
	const char *RSTValue = "/sys/class/gpio/gpio347/value";
	const char *RSTExport = "/sys/class/gpio/export";
	const char *RSTDir = "/sys/class/gpio/gpio347";

	/*GPIO P9_23*/
	const char *DCDirection = "/sys/class/gpio/gpio310/direction";
	const char *DCValue = "/sys/class/gpio/gpio310/value";
	const char *DCExport = "/sys/class/gpio/export";
	const char *DCDir = "/sys/class/gpio/gpio310";

	std::string spi_device;
	uint32_t mode;
	uint8_t bits;
	uint32_t speed;
	uint16_t delay;

public:
	Outputs();
	bool configureDC(void);
	bool configureRST(void);
	void writeRST(uint8_t value);
	void writeDC(uint8_t value);

	bool openSPI (void);
	void transferSPI(const uint8_t *data, size_t len);
	void closeSPI (void);

};

#endif /* OUTPUTS_H_ */
/* Outputs.cpp */


/* Configure the SPI as spidev0.0 */
Outputs::Outputs(){
	this->spi_device = "/dev/spidev0.0";
	this->bits = 8;
	this->speed = 125000000L;
	this->delay = 0;
}

/* Configure RST output as P9_15 (gpio347) */

bool Outputs::configureRST(void){
	RSTHandle = nullptr;
	pDir = nullptr;

	bool RSTConfigured = true;
	pDir = opendir (RSTDir);

		if (pDir != nullptr) {
	 	    cout << "gpio347 configured" << endl;
	 	    closedir(pDir);
		} else {
			 cout << "gpio347 not configured" << endl;
			 if ((RSTHandle = fopen(RSTExport,"a")) != nullptr) {
				fwrite("347",sizeof(char),3,RSTHandle);
				fclose(RSTHandle);
				cout << "gpio347 added to /sys/class/gpio/" << endl;
				usleep(10000L);
			} else {
				cout << "Failed to open /sys/class/gpio/export" << endl;
				 RSTConfigured = false;
			}
		}

		if (RSTConfigured && ((RSTHandle = fopen(RSTDirection,"a")) != nullptr)) {
					fwrite("out",sizeof(char),3,RSTHandle);
					fclose(RSTHandle);
					cout << "gpio347 configured as output" << endl;
					usleep(10000L);
				} else {
					cout << "Failed to open /sys/class/gpio/gpio347/direction" << endl;
					RSTConfigured = false;
		}

		return RSTConfigured;

}

/* Configure DC (Data Command) as P9_23 (gpio310) */

bool Outputs::configureDC(void){

	RSTHandle = nullptr;
	pDir = nullptr;

	bool DCConfigured = true;
	pDir = opendir (DCDir);

		if (pDir != nullptr) {
	 	    cout << "gpio310 configured" << endl;
	 	    closedir(pDir);
		} else {
			 cout << "gpio310 not configured" << endl;
			 if ((DCHandle = fopen(DCExport,"a")) != nullptr) {
				fwrite("310",sizeof(char),3,DCHandle);
				fclose(DCHandle);
				cout << "gpio310 added to /sys/class/gpio/" << endl;
				usleep(10000L);
			} else {
				cout << "Failed to open /sys/class/gpio/export" << endl;
				 DCConfigured = false;
			}
		}

		if (DCConfigured && ((DCHandle = fopen(DCDirection,"a")) != nullptr)) {
					fwrite("out",sizeof(char),3,DCHandle);
					fclose(DCHandle);
					cout << "gpio310 configured as output" << endl;
					usleep(10000L);
				} else {
					cout << "Failed to open /sys/class/gpio/gpio310/direction" << endl;
					DCConfigured = false;
		}

		return DCConfigured;

}

/* Control RST signal - output  P9_15 (gpio347) */

void Outputs::writeRST(uint8_t value){
	if ((RSTHandle = fopen(RSTValue,"r+")) != nullptr) {


			fwrite((value == 0) ? "0" : "1",sizeof(char),1,RSTHandle);
			fclose(RSTHandle);
		}	else {
			cout << "Failed to open /sys/class/gpio/gpio347/value" << endl;
		}

}

/* Control Data Command signal - output  P9_23 (gpio310) */

void Outputs::writeDC(uint8_t value){
	if ((DCHandle = fopen(DCValue,"r+")) != nullptr) {


			fwrite((value == 0) ? "0" : "1",sizeof(char),1,DCHandle);
			fclose(DCHandle);
		}	else {
			cout << "Failed to open /sys/class/gpio/gpio310/value" << endl;
		}

}

/* Open and configure SPI */

bool Outputs::openSPI (void){
   bool spi_OK = true;
   int ret = 0;
   spi_dev = -1;
   spi_dev = open(spi_device.c_str(), O_RDWR);
   	if (spi_dev < 0) {
   		cout << "Failed to open " << spi_device << endl;
   		spi_OK = false;
   	}

   	ret = ioctl(spi_dev, SPI_IOC_WR_MODE, &mode);
   		if (ret == -1)
   			cout << "can't set spi mode" << endl;

   		ret = ioctl(spi_dev, SPI_IOC_RD_MODE, &mode);
   		if (ret == -1)
   			cout << "can't get spi mode" << endl;

   		/*
   		 * bits per word
   		 */
   		ret = ioctl(spi_dev, SPI_IOC_WR_BITS_PER_WORD, &bits);
   		if (ret == -1)
   			cout << "can't set bits per word" << endl;

   		ret = ioctl(spi_dev, SPI_IOC_RD_BITS_PER_WORD, &bits);
   		if (ret == -1)
   			cout << "can't get bits per word" << endl;

   		/*
   		 * max speed hz
   		 */
   		ret = ioctl(spi_dev, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
   		if (ret == -1)
   			cout << "can't set max speed hz" << endl;

   		ret = ioctl(spi_dev, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
   		if (ret == -1)
   			cout << "can't get max speed hz" << endl;

   		cout << "spi mode: " << mode << endl;
   		cout << "bits per word: " << bits << endl;
   		cout << "max speed: " << speed/1000 << " [kHz] : " << speed/1000000 << " [MHz]" << endl;


   	return spi_OK;
}

/* Write data over SPI */

void Outputs::transferSPI(const uint8_t *data, size_t len) {

	int ret;
	struct spi_ioc_transfer tr = {
			.tx_buf = (unsigned long)data,
			.rx_buf = 0,
			.len = (unsigned int)len,
			.speed_hz = speed,
			.delay_usecs = delay,
			.bits_per_word = bits,
		};

		ret = ioctl(spi_dev, SPI_IOC_MESSAGE(1), &tr);
			if (ret < 1)
			cout << "Failed write to " << spi_device << endl;
}

/* Close SPI */
void Outputs::closeSPI (void){
	close(spi_dev);
}

GC9A01 BBAI64