====== Use the IO Expansion Board ======
Schematic : {{http://dn.odroid.com/ODROID-XU/Expansion_Board/ExpansionBoard.pdf|ExpansionBoard.pdf}}\\
Driver source code : [[https://github.com/hardkernel/linux/tree/odroidxu3-3.10.y/drivers/hardkernel]]\\
Android Example source code : [[http://dn.odroid.com/ODROID-XU/Expansion_Board]]
Test O/S : Ubuntu 15.04 (20150710, Kernel version should be 3.10.82 or higher. Otherwise, update the kernel first)
==== I2C Driver Probe ====
sudo modprobe i2c-gpio-custom bus0=10,33,23,10,10
sudo modprobe ioboard-bmp180
sudo echo ioboard-bmp180 0x77 > /sys/class/i2c-dev/i2c-10/device/new_device
sudo modprobe ioboard-bh1780
sudo echo ioboard-bh1780 0x29 > /sys/class/i2c-dev/i2c-10/device/new_device
=== Get Sensors value on Expansion Board ===
Enable Sensors
BMP180
echo 1 > /sys/class/i2c-dev/i2c-10/device/10-0077/enable
BH1780
echo 1 > /sys/class/i2c-dev/i2c-10/device/10-0029/enable
Get values
BMP180
cat /sys/class/i2c-dev/i2c-10/device/10-0077/temperature
cat /sys/class/i2c-dev/i2c-10/device/10-0077/pressure
BH1780
cat /sys/class/i2c-dev/i2c-10/device/10-0029/lux
==== SPI Flash Control on Expansion Board ====
=== Compile & run SPI test example source code ===
gcc -o spi_flash_test spi_flash_test.c
sudo ./spi_flash_test
/*
* SPI testing program (using spidev driver)
*
* Copyright (c) 2007 MontaVista Software, Inc.
* Copyright (c) 2007 Anton Vorontsov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* Cross-compile with cross-gcc -I/path/to/cross-kernel/include
*/
/*
IOBOARD SST25WF020A SPI Flash Test (Use spidev driver)
*/
/*---------------------------------------------------------------------------*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*---------------------------------------------------------------------------*/
#define FLASH_SECTOR_4K (4 * 1024)
#define FLASH_TEST_SIZE 256
const char *SPIDEV_NODE = "/dev/spidev1.0";
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Read Flash ID */
#define CMD_READ_ID 0xAB /* 0x90 or 0xAB */
/* Read memory */
#define CMD_READ 0x03
#define CMD_HIGH_SPEED_READ 0x0B
#define CMD_READ_STATUS 0x05
/* Erase memory */
#define CMD_ERASE_4KB 0x20
#define CMD_ERASE_32KB 0x52
#define CMD_ERASE_64KB 0xD8
#define CMD_ERASE_ALL 0xC7 /* 0xC7 or 0x60 */
/* BYTE write command */
#define CMD_BYTE_WRITE 0x02
/* Write Enable/Disable CMD */
#define CMD_WRITE_ENABLE 0x06
#define CMD_WRITE_DISABLE 0x04
#define CMD_WRITE_PROTECT 0x01
/*
BUSY
1 : internal write operation is in progress
0 : no internal write operation is in progress
*/
#define STATUS_BUSY 0x01 /* (Read) */
/*
WEL
1 : Device is memory write enabled
0 : Device is not memory write enabled
*/
#define STATUS_WEL 0x02 /* (Read) */
/*
BP1 BP0
0 0 : none protected memory
0 1 : 030000H-03FFFFH protected
1 0 : 020000H-03FFFFH protected
1 1 : 000000H-03FFFFH protected (Power-up default value)
*/
#define STATUS_BP0 0x04 /* (R/W) */
#define STATUS_BP1 0x08 /* (R/W) */
/*
BPL
1 : BP1 and BP0 are read-only bits
0 : BP1 and BP0 are read/writable (Power-up default value)
*/
#define STATUS_BPL 0x80 /* (R/W) */
/*---------------------------------------------------------------------------*/
#define FLASH_SPI_MODE 0
#define FLASH_SPI_SPEED 500000
#define FLASH_SPI_BITS 8
struct spi_flash {
/* spidev file descriptor */
int fd;
/* SPI mode H/W control */
unsigned char mode; /* SPI_MODE */
unsigned char bits; /* SPI Data bits */
unsigned int speed; /* SPI Control Speed */
/* Flash control variable */
unsigned char cmd;
union {
unsigned int addr;
unsigned char data[sizeof(unsigned int)];
};
unsigned char tx_data[10];
unsigned int tx_len;
unsigned char rx_data[FLASH_SECTOR_4K];
unsigned int rx_len;
};
/*---------------------------------------------------------------------------*/
static void pabort(const char *s)
{
perror(s);
abort();
}
/*---------------------------------------------------------------------------*/
static void transfer (struct spi_flash *flash)
{
struct spi_ioc_transfer tr[2];
memset(tr, 0, sizeof(tr));
memset(flash->rx_data, 0x00, sizeof(flash->rx_data));
flash->tx_data[0] = flash->cmd;
flash->tx_data[1] = (flash->addr & 0x00FF0000) >> 16;
flash->tx_data[2] = (flash->addr & 0x0000FF00) >> 8;
flash->tx_data[3] = (flash->addr & 0x000000FF);
flash->tx_data[4] = flash->data[3]; /* Dummy Cycle */
tr[0].tx_buf = (unsigned long)flash->tx_data;
tr[0].len = flash->tx_len < 5 ? flash->tx_len : 5;
if (flash->rx_len) {
tr[1].rx_buf = (unsigned long)flash->rx_data;
tr[1].len = flash->rx_len;
if (ioctl(flash->fd, SPI_IOC_MESSAGE(2), &tr[0]) < 2)
pabort("can't send SPI message");
flash->rx_len = 0;
} else {
if (ioctl(flash->fd, SPI_IOC_MESSAGE(1), &tr[0]) < 1)
pabort("can't send SPI message");
}
}
/*---------------------------------------------------------------------------*/
static void spidev_init (struct spi_flash *flash)
{
int ret;
flash->fd = open(SPIDEV_NODE, O_RDWR);
if (flash->fd < 0)
pabort("can't open /dev/spidev1.0");
/*
SPI H/W Init
SPI Mode = 0, Data bits = 8, Speed = 500Kbps
*/
flash->mode = FLASH_SPI_MODE;
flash->bits = FLASH_SPI_BITS;
flash->speed = FLASH_SPI_SPEED;
/* SPI mode */
ret = ioctl(flash->fd, SPI_IOC_WR_MODE, &flash->mode);
if (ret == -1)
pabort("can't set SPI mode");
ret = ioctl(flash->fd, SPI_IOC_RD_MODE, &flash->mode);
if (ret == -1)
pabort("can't get SPI mode");
/* bits per word */
ret = ioctl(flash->fd, SPI_IOC_WR_BITS_PER_WORD, &flash->bits);
if (ret == -1)
pabort("can't set bits per word");
ret = ioctl(flash->fd, SPI_IOC_RD_BITS_PER_WORD, &flash->bits);
if (ret == -1)
pabort("can't get bits per word");
/* max speed hz */
ret = ioctl(flash->fd, SPI_IOC_WR_MAX_SPEED_HZ, &flash->speed);
if (ret == -1)
pabort("can't set max speed Hz");
ret = ioctl(flash->fd, SPI_IOC_RD_MAX_SPEED_HZ, &flash->speed);
if (ret == -1)
pabort("can't get max speed Hz");
/* H/W Setup Info Display */
printf("SPI mode: %d\n", flash->mode);
printf("bits per word: %d\n", flash->bits);
printf("max speed: %d Hz (%d KHz)\n" , flash->speed
, flash->speed/1000);
}
/*---------------------------------------------------------------------------*/
static int flash_read_id (struct spi_flash *flash)
{
flash->cmd = CMD_READ_ID;
flash->addr = 0;
flash->tx_len = 4;
flash->rx_len = 2;
transfer (flash);
printf("%s : rdata[0] = 0x%02X, rdata[1] = 0x%02X\n",
__func__,
flash->rx_data[0],
flash->rx_data[1]);
if ((flash->rx_data[0] == 0xBF) && (flash->rx_data[1] == 0x03)) {
printf("Flash Memory Product is SST(SST25WF020)\n");
return 0;
}
if (flash->rx_data[0] == 0x34) {
printf("Flash Memory Product is Microcphis(SST25WF020A)\n");
return 0;
}
pabort("Unknown Flash Memory Product!\n");
return -1;
}
/*---------------------------------------------------------------------------*/
static int flash_busy_check(int spi_fd, int udelay)
{
struct spi_flash flash;
unsigned char retry_cnt = 0;
do {
flash.fd = spi_fd;
flash.cmd = CMD_READ_STATUS;
flash.tx_len = 1;
/* Status read len */
flash.rx_len = 1;
transfer(&flash);
usleep(udelay);
if (retry_cnt++ > 1000) {
printf("%s : Timeout Error!\n", __func__);
return -1;
}
} while(flash.rx_data[0] & STATUS_BUSY);
return 0;
}
/*---------------------------------------------------------------------------*/
static void flash_access_enable(int spi_fd, unsigned char enable)
{
struct spi_flash flash;
flash.fd = spi_fd;
flash.cmd = enable ? CMD_WRITE_ENABLE : CMD_WRITE_DISABLE;
flash.tx_len = 1;
flash.rx_len = 0;
transfer(&flash);
if (flash_busy_check(spi_fd, 100) != 0) {
pabort("Busy check Error!\n");
}
}
/*---------------------------------------------------------------------------*/
static void flash_data_erase(struct spi_flash *flash)
{
flash->cmd = CMD_ERASE_4KB;
flash->addr = 0;
flash->tx_len = 4;
flash->rx_len = 0;
flash_access_enable(flash->fd, 1);
transfer(flash);
flash_access_enable(flash->fd, 0);
if (flash_busy_check(flash->fd, 100) != 0) {
pabort("Busy check Error!\n");
}
}
/*---------------------------------------------------------------------------*/
static void flash_data_write(struct spi_flash *flash)
{
int i;
flash->cmd = CMD_BYTE_WRITE;
flash->addr = 0;
flash->tx_len = 5;
flash->rx_len = 0;
for (i = 0; i < FLASH_TEST_SIZE; i++) {
flash->addr = i;
flash->data[3] = i;
flash_access_enable(flash->fd, 1);
transfer(flash);
flash_access_enable(flash->fd, 0);
if (flash_busy_check(flash->fd, 100) != 0) {
pabort("Busy check Error!\n");
}
}
}
/*---------------------------------------------------------------------------*/
static void flash_data_dump(struct spi_flash *flash)
{
int i;
flash->cmd = CMD_READ;
flash->addr = 0;
flash->tx_len = 4;
flash->rx_len = FLASH_TEST_SIZE;
transfer(flash);
if (flash_busy_check(flash->fd, 100) != 0) {
pabort("Busy check Error!\n");
}
for (i = 0; i < FLASH_TEST_SIZE; i++) {
if((i % 16) == 0) printf("\n");
printf("0x%02X ", flash->rx_data[i]);
}
printf("\n");
}
/*---------------------------------------------------------------------------*/
static void flash_write_protect(int spi_fd, unsigned char status)
{
struct spi_flash flash;
flash_access_enable(spi_fd, 1);
flash.fd = spi_fd;
flash.cmd = CMD_WRITE_PROTECT;
flash.data[2] = status;
flash.tx_len = 2;
flash.rx_len = 0;
transfer(&flash);
flash_access_enable(spi_fd, 0);
}
/*---------------------------------------------------------------------------*/
int main (void)
{
struct spi_flash *flash;
flash = (struct spi_flash *)malloc(sizeof(struct spi_flash));
if (flash == NULL)
pabort("Can't allocation for spi flash!\n");
spidev_init(flash);
/* flash id read */
flash_read_id(flash);
/* software write protect disable */
flash_write_protect(flash->fd, 0);
printf("\nFlash Memory Dump : Size = %d\n", FLASH_TEST_SIZE);
flash_data_dump(flash);
flash_data_erase(flash);
printf("\nFlash Memory Dump (after erase) : Size = %d\n",
FLASH_TEST_SIZE);
flash_data_dump(flash);
flash_data_write(flash);
printf("\nFlash Memory Dump (after write) : Size = %d\n",
FLASH_TEST_SIZE);
flash_data_dump(flash);
close(flash->fd);
free(flash);
return 0;
}
/*---------------------------------------------------------------------------*/
If you use an old kernel, you must edit/compile the device-tree source first to enable spidev on your **ODROID-XU4/XU3**
=== How to fix device tree blob with command line ===
Install device tree compiler package.
sudo apt-get install device-tree-compiler
Generate an exynos5422-odroidxu3.dts file from the stock dtb file.
sudo -s
cd /media/boot
dtc -I dtb -O dts ./exynos5422-odroidxu3.dtb > ./exynos5422-odroidxu3.dts
Edit dts file to use vi editor.
vi ./exynos5422-odroidxu3.dts
Find string "spi@12d3" & add spi control data.
...
spi@12d30000 {
compatible = "samsung,exynos5410-spi";
reg = <0x12d30000 0x100>;
interrupts = <0x0 0x45 0x0>;
dma-mode;
dmas = <0x43 0x5 0x43 0x4>;
dma-names = "tx", "rx";
swap-mode;
#address-cells = <0x1>;
#size-cells = <0x0>;
clocks = <0x2 0x5cb 0x2 0x1027>;
clock-names = "spi", "spi_busclk0";
pinctrl-names = "default";
pinctrl-0 = <0x44>;
status = "okay";
cs-gpios = <0x45 0x5 0x0>;
/* ADD Line Start(spi control data) */
samsung,spi-src-slk = <0>;
num-cs = <0>;
spidev {
compatible = "spidev";
reg = <0>;
spi-max-frequency = <20000000>;
controller-data {
cs-gpio = <0x45 0x5 0x0>;
samsung,spi-feedback-delay = <0>;
};
};
/* ADD Line Ebd */
};
...
The value of **cs-gpio** must be identical to **cs-gpios** in controller-data section.
Compile dts file & update
dtc -O dtb -o ./exynos5422-odroidxu3.dtb ./exynos5422-odroidxu3.dts
Reboot.
reboot
Check your SPI node.
ls /dev/spidev*
After update, you might need a hard-boot. Reboot doesn't access the updated dtb file from time to time.