====== 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.