We're no longer updating This wiki!!

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
en:xu3_expansionboard [2016/05/18 15:20]
charles.park
en:xu3_expansionboard [2017/06/07 17:46] (current)
odroid
Line 31: Line 31:
 BH1780 BH1780
   cat /​sys/​class/​i2c-dev/​i2c-10/​device/​10-0029/​lux   cat /​sys/​class/​i2c-dev/​i2c-10/​device/​10-0029/​lux
 +  ​
 +==== SPI Flash Control on Expansion Board ====
 +
 +=== Compile & run SPI test example source code ===
 +
 +<​code>​
 +gcc -o spi_flash_test spi_flash_test.c
 +sudo ./​spi_flash_test
 +</​code>​
 +
 +<file c spi_flash_test.c>​
 +/*
 + * SPI testing program (using spidev driver)
 + *
 + * Copyright (c) 2007  MontaVista Software, Inc.
 + * Copyright (c) 2007  Anton Vorontsov <​avorontsov@ru.mvista.com>​
 + *
 + * 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 <​stdint.h>​
 +#include <​string.h>​
 +#include <​unistd.h>​
 +#include <​stdio.h>​
 +#include <​stdlib.h>​
 +#include <​fcntl.h>​
 +#include <​sys/​ioctl.h>​
 +#include <​pthread.h>​
 +#include <​linux/​spi/​spidev.h>​
 +
 +/​*---------------------------------------------------------------------------*/​
 +#​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;
 +}
 +
 +/​*---------------------------------------------------------------------------*/​
 +
 +</​file>​
 +
 +
 +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.
 +<​code>​
 +sudo -s
 +cd /media/boot
 +dtc -I dtb -O dts ./​exynos5422-odroidxu3.dtb > ./​exynos5422-odroidxu3.dts
 +</​code>​
 +
 +Edit dts file to use vi editor.
 +<​code>​
 +vi ./​exynos5422-odroidxu3.dts
 +</​code>​
 +
 +Find string "​spi@12d3"​ & add spi control data.
 +
 +<​code>​
 +...
 + 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 */
 + };
 +...
 +</​code>​
 +
 +<WRAP center round important 100%>
 +The value of **cs-gpio** must be identical to **cs-gpios** in controller-data section.
 +</​WRAP>​
 +
 +Compile dts file & update
 +<​code>​
 +dtc -O dtb -o ./​exynos5422-odroidxu3.dtb ./​exynos5422-odroidxu3.dts
 +</​code>​
 +
 +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.
 +
 +
en/xu3_expansionboard.1463554214.txt.gz ยท Last modified: 2016/05/18 15:20 by charles.park
CC Attribution-Share Alike 3.0 Unported
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0