ããã¯ãLinuxã§ã®ã¹ã¬ãŒãSPIããã€ã¹çšãã©ã€ããŒã®éçºã«é¢ããç§ã®èšäºã®ç¬¬2éšã§ãã åã®éšåã¯
ãã¡ãã§ãã
3. spidevã䜿çšãããŠãŒã¶ãŒç©ºéãããã³ã«SPIãã©ã€ããŒã®éçº
åè¿°ã®ããã«ãSPIããã€ã¹ã®ãŠãŒã¶ãŒç©ºéAPIã®ãµããŒãã¯å¶éãããŠãããã¹ã¬ãŒãSPIããã€ã¹ã«ã¢ã¯ã»ã¹ããããã®åºæ¬çãªåäºéèªã¿åãïŒïŒããã³æžã蟌ã¿ïŒïŒåŒã³åºãããµããŒããããŠããŸãã ioctlïŒïŒåŒã³åºãã䜿çšãããšãã¹ã¬ãŒãããã€ã¹ãšã®å
šäºéããŒã¿äº€æãå®è¡ã§ããã ãã§ãªããããã€ã¹ãã©ã¡ãŒã¿ã倿Žã§ããŸãã
ãã®ãŠãŒã¶ãŒã¹ããŒã¹APIã䜿çšããçç±ã¯ããã€ããããŸãã
- èŽåœçãªãšã©ãŒãçºçãã«ããç°å¢ã§ã®ãããã¿ã€ãã³ã°ã ãŠãŒã¶ãŒç©ºéã®ç¡å¹ãªãã€ã³ã¿ãŒã¯éåžžãã·ã¹ãã å
šäœãã¯ã©ãã·ã¥ãããããšã¯ã§ããŸããã
- ã¹ã¬ãŒãSPIããã€ã¹ã®ã¢ãŒãã§åäœãããã€ã¯ãã³ã³ãããŒã©ãŒãšã®ããŒã¿äº€æã«äœ¿çšãããåçŽãªãããã³ã«ã®éçºãããã¯ãã°ãã°å€æŽããå¿
èŠããããŸãã
ãã¡ããããŠãŒã¶ãŒç©ºéã§ã¯å©çšã§ããªãä»ã®ã«ãŒãã«ã€ã³ã¿ãŒãã§ã€ã¹ïŒããšãã°ãå²ã蟌ã¿ãã³ãã©ãŒããã©ã€ããŒã¹ã¿ãã¯ã®ä»ã®ãµãã·ã¹ãã ïŒã«ã¢ã¯ã»ã¹ããå¿
èŠãããããããŠãŒã¶ãŒç©ºéAPIã䜿çšããŠå®è£
ã§ããªããã©ã€ããŒããããŸãã
spidevãµããŒããæå¹ã«ããã«ã¯ïŒ
1. menuconfigã§ã«ãŒãã«ãæ§æãããšããã¢ã€ãã ãã¢ã¯ãã£ãã«ããŸãã
Device Drivers SPI support User mode SPI device driver support
2.ããŒããã¡ã€ã«ã§ãåã®æ®µèœã§èª¬æããæ§é äœã®é
åã«spi_board_infoã远å ããŸãã
{ .modalias = "spidev", .chip_select = 2, .max_speed_hz = 15 * 1000 * 1000, .mode = SPI_MODE_0, .bus_num = 1, },
æ°ããã«ãŒãã«ãåæ§ç¯ããŠããŒããããšã察å¿ããããã€ã¹ã/dev/spidevB.Cãšãã圢åŒã®ååã§ã·ã¹ãã ã«è¡šç€ºãããŸããããã§ãBã¯SPIãã¹çªå·ãCã¯ãããéžæçªå·ã§ãã ãã®ããã€ã¹ã¯mknodã䜿çšããŠæåã§äœæããããšã¯ã§ããŸãããudev/ mdevãªã©ã®ãµãŒãã¹ã¯èªåçã«äœæããå¿
èŠããããŸãã
çŽ æŽããããããã€ã¹ããããŸãã 圌ãšä»äºãããæ¹æ³ãåŠã¶ããšã¯æ®ã£ãŠããŸãã çªå·CS 2ã®SPI1ã«ã¶ãäžãã£ãŠããããã€ã¹ã«ãã€ã0x8Eãéä¿¡ãããšããŸããããããæãç°¡åãªæ¹æ³ã¯æ¬¡ã®ãšããã§ãã
echo -ne "\x8e">/dev/spidev1.2
ãã®åŸãç§ã®ãã¹ãããã€ã¹ã§ã次ã®åçãèŠãããšãã§ããŸããã

ãã¹ãããã€ã¹ã«ã€ããŠã®ããã€ãã®èšèã ããããæãéèŠãªããšã¯ãã»ãšãã©åœ¹ã«ç«ããªãããšã§ãããLinuxã§SPIã䜿çšããããšãç ç©¶ããããã ãã«è¡ãããããšã§ãã 1ã€ã®ã·ããã¬ãžã¹ã¿74HC164Nã§äœæããã74HC132Nããã®3Iãšã¬ã¡ã³ã2I-NOTã§ããçš®ã®ãããã»ã¬ã¯ããäœæãããå
¥åãCSã§äœã¬ãã«ã®åæä¿¡å·ã®ã¿ãèš±å¯ããŸãïŒããã«æ³šæããããã¯ãã74HC595ã®ååšãç¥ã£ãŠããŸãïŒããããç§ã¯èªåã®è¡ã§ãããåŸãããšãã§ããŸããã§ããïŒ ãã®ããã€ã¹ã«ã¯ãLEDã«æžã蟌ãŸããæåŸã®ãã€ãã衚瀺ããæ©èœã1ã€ãããããŸããã ç§ã®ããã€ã¹ã¯å®å
šã«ãæ£çŽãã§ã¯ãªãã®ã§ãããã€ã¹ããèªã¿åããšãïŒæ¬æ¥ããã¹ãããã«ïŒæžã蟌ãã ãã®ãååŸã§ããŸããããå€ã¯1ãããå·Šã«ã·ããããŸãã
ã¹ã¬ãŒãæäœãã©ã¡ãŒã¿ãŒã¯ãioctlïŒïŒåŒã³åºãã䜿çšããŠæ§æã§ããŸãã ãããã䜿çšãããšãããŒã¿è»¢éé床ãéä¿¡ã¯ãŒãã®ãµã€ãºãéä¿¡ã®ãã€ãé åºãããã³ãã¡ããSPIåäœã¢ãŒãã倿Žã§ããŸãã
次ã®ioctlïŒïŒèŠæ±ã«ãããã¹ã¬ãŒãããã€ã¹ã®ãã©ã¡ãŒã¿ãŒãå¶åŸ¡ã§ããŸãã
- SPI_IOC_RD_MODEãSPI_IOC_WR_MODE-ãã€ã³ã¿ãŒã転éããããã€ããèªã¿åãïŒRDïŒå ŽåãçŸåšã®SPIã¢ãŒãã®å€ãå²ãåœãŠãããŸãã èšé²ïŒWRïŒã®å Žåãããã€ã¹ã¯éä¿¡ããããã€ã³ã¿ãŒã®ãã€ãå€ã«å¯Ÿå¿ããã¢ãŒãã«èšå®ãããŸãã ã¢ãŒããèšå®ããã«ã¯ã宿°SPI_MODE_0 ... SPI_MODE_3ã䜿çšãããã宿°SPI_CPHAïŒåæãã§ãŒãºãèšå®ãããŠããå Žåã¯ãªãŒãã£ã³ã°ãšããžãã£ããã£ïŒãšSPI_CPOLïŒåææ¥µæ§ãåæä¿¡å·ã¯é«ã¬ãã«ããéå§ïŒããããåäœã®ããŸãã¯ãã§çµã¿åãããŸãã
- SPI_IOC_RD_LSB_FIRSTãSPI_IOC_WR_LSB_FIRST-SPIã¯ãŒããéä¿¡ãããšãã«ãããã®ã¢ã©ã€ã¡ã³ããæ±ºå®ãããã€ããžã®ãã€ã³ã¿ãŒãæž¡ããŸãã å€ãŒãã¯ãæäžäœããããæåïŒMSBãã¡ãŒã¹ãïŒã§ããããšã瀺ããä»ã®å€ã¯ããããŸããªããŒãžã§ã³ã䜿çšãããããšã瀺ããæäžäœããããæåïŒLSBãã¡ãŒã¹ãïŒã§ããããšã瀺ããŸãã ã©ã¡ãã®å Žåããåã¯ãŒãã¯å³æãããããããæªäœ¿çš/æªå®çŸ©ã®ãããã¯äžäœã«ãªããŸãã RD / WR-ã¯ãŒãåäœã®ãããã®ã¢ã©ã€ã¡ã³ããæ±ºå®ããèªã¿åã/æžã蟌ã¿ãã©ã¡ãŒã¿ãŒã
- SPI_IOC_RD_BITS_PER_WORDãSPI_IOC_WR_BITS_PER_WORD-SPIãä»ããŠããŒã¿ãéä¿¡ããå Žåãã¯ãŒããããã®ãããæ°ãæ±ºå®ãããã€ããžã®ãã€ã³ã¿ãŒãæž¡ããŸãã ãŒãå€ã¯8ãããã«å¯Ÿå¿ããŸãã RD / WR-ã¯ãŒããããã®ãããæ°ãããããèªã¿åã/æžã蟌ã¿ã
- SPI_IOC_RD_MAX_SPEED_HZãSPI_IOC_WR_MAX_SPEED_HZ-u32倿°ã«ãã€ã³ã¿ãŒãæž¡ããŸããããã¯ãSPIã®æå€§ããŒã¿ã¬ãŒããHzã§æ±ºå®ããŸãã ååãšããŠãã³ã³ãããŒã©ãŒã¯èšå®éåºŠãæ£ç¢ºã«èšå®ã§ããŸããã
åšæ³¢æ°ã倿Žããããšã§ããã¹ãããã€ã¹ãçŽ15 MHz以äžã®åšæ³¢æ°ã§åäœã§ããããšãããããŸãããã«ãŒãã®é·ããçŽ25 cmã§ãããåè·¯åºæ¿äžã®ã¢ã»ã³ããªãšMGTFã䜿çšããæ¥ç¹ã®æ¥ç¶ãèæ
®ãããšãããã»ã©æªãã¯ãããŸããã
ããã§ãã1ã€éèŠãªç¹ãè¿°ã¹ãŠãããŸãããããã®é åºã®å€æŽã¯ããã¹ãŠã®ã³ã³ãããŒã©ãŒã§ãµããŒããããŠããããã§ã¯ãããŸããã ã³ã³ãããŒã©ãŒããµããŒãããæ©èœã調ã¹ãã«ã¯ãããããã¹ã¯spi_master.mode_bitsã調ã¹ãå¿
èŠããããŸãã
spi_deviceæ§é äœã®ãã©ã°ã®å®çŸ©ããããã¹ã¯ã®ãããã®å€ã決å®ã§ããŸãã ããã§ã¯ãspi_deviceããã³
spi_masteræ§é ã®å®å
šãªèª¬æã¯è¡ããŸããããããã®
æ§é 㯠ããã®å Žåã®çè§£ã«ãšã£ãŠéèŠã§ã¯ãªãããã§ãã ãããã®ãã¹ãŠã®æ§é ã®èª¬æãèŠã€ããããšãã§ããããã¥ã¡ã³ããžã®ãªã³ã¯ã¯ãèšäºã®æåŸã«èšèŒããŸãã
åé ã§è¿°ã¹ãããã«ãspidevã¯ã察å¿ããioctlïŒïŒã³ãã³ãã䜿çšããŠåäºé転éãèš±å¯ããŸãã
int ret; ret = ioctl(fd, SPI_IOC_MESSAGE(num), tr);
numã¯ãspi_ioc_transferåã®æ§é äœã®é
åå
ã®è»¢éã®æ°ã§ã
tr-æ§é äœã®é
åãžã®ãã€ã³ã¿ãŒspi_ioc_transfer;
倱æããå Žåã¯è² ã®å€ãè¿ãããæåããå Žåã¯ãã¹ãŠã®è»¢éã§æ£åžžã«éä¿¡ããããã€ãã®ç·æ°ãè¿ãããŸãã
äŒéæ§é èªäœã®åœ¢åŒã¯æ¬¡ã®ãšããã§ãã
struct spi_ioc_transfer { __u64 tx_buf; __u64 rx_buf; __u32 len; __u32 speed_hz; __u16 delay_usecs; __u8 bits_per_word; __u8 cs_change; __u32 pad; };
tx_bufããã³rx_buf-ããŒã¿ãéåä¿¡ããããã®ãããã¡ãŒãžã®ãã€ã³ã¿ãŒããŠãŒã¶ãŒç©ºéã«ããããæ ŒçŽããŸãã tx_bufãNULLã®å ŽåããŒããããããããŸãã rx_bufãNULLã«èšå®ãããŠããå Žåãã¹ã¬ãŒãããåä¿¡ããããŒã¿ã¯ç¡èŠãããŸãã
lenã¯ãåä¿¡ããã³éä¿¡ãããã¡ãŒïŒrxããã³txïŒã®ãã€ãåäœã®é·ãã§ãã
speed_hz-æå®ã®è»¢éã®ããŒã¿ã¬ãŒããäžæžãããŸãã
bits_per_word-æå®ã®äŒéã®ã¯ãŒããããã®ãããæ°ãåå®çŸ©ããŸãã
delay_usecs-ããŒã¿ã®æåŸã®ããããéä¿¡ããåŸãããã€ã¹ãéã¢ã¯ãã£ãåããåïŒcs_deactivateãåŒã³åºãåïŒã®ãã€ã¯ãç§åäœã®é
å»¶ã
spi_ioc_transferæ§é äœã®ã»ãšãã©ãã¹ãŠã®ãã£ãŒã«ãã¯ãspi_transferæ§é äœã®ãã£ãŒã«ãã«å¯Ÿå¿ããŠããŸãã ããŒã¿ãããã¡ãŒã¯ãspidevãã©ã€ããŒã®è
žå
ã®copy_from_userïŒïŒ/ copy_to_userïŒïŒé¢æ°ã䜿çšããŠãã«ãŒãã«ã¹ããŒã¹ãšã®éã§äºåã«ã³ããŒãããŸãã
äžèšã§è¿°ã¹ãããã«ããã¹ãŠã®ã³ã³ãããŒã©ãŒãåéä¿¡ã®ã¯ãŒãã®é床ãšãµã€ãºãåå¥ã«å€æŽããæ©èœããµããŒãããŠããããã§ã¯ãªããããç§»æ€å¯èœãªã³ãŒããååŸãããå Žåã¯ãããã«ãŒãã眮ãããšããå§ãããŸãã ãã®ãããã«ãŒãã«ããã¥ã¡ã³ãã«ä»å±ããspidevãå
šäºéã¢ãŒãã§äœ¿çšããæšæºçãªäŸã¯ãat91ãã¡ããªã®ãããäžã®spi_ioc_transferæ§é äœã®åæåãä¿®æ£ããªããšæ©èœããŸããã
åèïŒ
- çŸæç¹ã§ã¯ããã®ããã€ã¹ã®ããŒã¿ãããã®ããã·ã¥/ãã£ããã£ãçºçããå®éã®é床ãååŸããæ¹æ³ã¯ãããŸããã
- çŸæç¹ã§ã¯ãspidevã䜿çšããŠãããéžæã®æ¥µæ§ãå転ããããšã¯ã§ããŸããã åã¹ã¬ãŒãããã€ã¹ã¯ãã¢ã¯ãã£ãã«äœ¿çšãããŠããªããšãã«éã¢ã¯ãã£ãåãããä»ã®ãã©ã€ããŒãããããã®ããã€ã¹ãšéä¿¡ã§ããããã«ããŸãã
- åI / OèŠæ±ã§éä¿¡ããããã€ãæ°ã«ã¯å¶éããããŸãã éåžžãå¶éã¯ã¡ã¢ãªã®1ããŒãžã®ãµã€ãºã«å¯Ÿå¿ããŸãã ãã®å€ã¯ãã«ãŒãã«ã¢ãžã¥ãŒã«ãã©ã¡ãŒã¿ãŒã䜿çšããŠå€æŽã§ããŸãã
- SPIã«ã¯é
ä¿¡ã確èªããäœã¬ãã«ã®æ¹æ³ããªããããéä¿¡ã«ãšã©ãŒããããã©ããã確èªããæ¹æ³ã¯ãããŸãããããšãã°ãååšããªãããã€ã¹ãéžæããå Žåãªã©ã§ãã
次ã«äŸã瀺ããŸããããã¯ãã«ãŒãã«ã«ãã³ãã«ãããŠããspidevãæäœããããã®ããã°ã©ã ã®ç°¡æããŒãžã§ã³ã§ãã ãã®äŸã§ã¯æç€ºçã«ç€ºãããŠããŸããããåäºééä¿¡ã§readïŒïŒããã³writeïŒïŒã·ã¹ãã ã³ãŒã«ã䜿çšããããšãçŠæ¢ãã人ã¯ããŸããã
#include <stdint.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <getopt.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/types.h> #include <linux/spi/spidev.h> static void pabort(const char *s) { perror(s); abort(); } static uint8_t mode = SPI_MODE_0; static uint8_t bits = 0; static uint32_t speed = 500000; int main(int argc, char *argv[]) { int ret = 0; int fd; uint8_t tx[] = { 0x81, 0x18 }; uint8_t rx[] = {0, 0 }; if(argc!=2) { fprintf(stderr, "Usage: %s <spidev>\n", argv[0]); exit(1); } fd = open(argv[1], O_RDWR); if (fd < 0) pabort("can't open device"); /* spi mode */ ret = ioctl(fd, SPI_IOC_WR_MODE, &mode); if (ret == -1) pabort("can't set spi mode"); ret = ioctl(fd, SPI_IOC_RD_MODE, &mode); if (ret == -1) pabort("can't get spi mode"); /* bits per word */ ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); if (ret == -1) pabort("can't set bits per word"); ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits); if (ret == -1) pabort("can't get bits per word"); /* max speed hz */ ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); if (ret == -1) pabort("can't set max speed hz"); ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); if (ret == -1) pabort("can't get max speed hz"); printf("spi mode: %d\n", mode); printf("bits per word: %d\n", bits); printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); /* full-duplex transfer */ struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)tx, .rx_buf = (unsigned long)rx, .len = 2, .delay_usecs = 0, .speed_hz = 0, .bits_per_word = bits, }; ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); if (ret < 1) pabort("can't send spi message"); for (ret = 0; ret < 2; ret++) { printf("%.2X ", rx[ret]); } puts(""); close(fd); return ret; }
ããã§ã¯ãã¹ãŠãæããã§ãããšæããŸããioctlïŒïŒãä»ããŠããã€ã¹ã«éä¿¡ããããã¹ãŠã®ãªã¯ãšã¹ããæ¢ã«ãœãŒãããŠããŸãã Makefileããã«ãããããã ãã«æ®ããŸãïŒ
all: spidev_test CC = /opt/arm-2010q1/bin/arm-none-linux-gnueabi-gcc INCLUDES = -I. CCFLAGS = -O2 -Wall clean: rm -f spidev_test spidev_test: spidev_test.c $(CC) $(INCLUDES) $(CCFLAGS) spidev_test.c -o spidev_test
å¯äžã®ããšã¯ãCC倿°ã§ã¯ãã¹ã³ã³ãã€ã©ãžã®ãã¹ãæå®ããå¿
èŠããããšããããšã§ãã
4.ãããã³ã«SPIã«ãŒãã«ã¬ãã«ãã©ã€ããŒã®éçº
ã«ãŒãã«ã¢ãžã¥ãŒã«ã®éçºã¯ã¯ããã«åºç¯ãªãããã¯ã§ããããããã®å Žåã¯å¥ã®æ¹æ³ã§èª¬æããŸããæåã«ã³ãŒãã®äŸã瀺ããæ¬¡ã«ãã®åäœã®ç°¡åãªèª¬æãè¡ããäœ¿çšæ¹æ³ã説æããŸãã ãã¹ãŠã®è©³çްã説æããããã§ã¯ãããŸããããããªããšãååãªèšäºããããŸãããæãéèŠãªãã€ã³ãã瀺ãã ãã§ããããã¥ã¡ã³ãã®èšäºã®ã»ã¯ã·ã§ã³ã§ã¯ãå¿
èŠãªãã¹ãŠã®æ
å ±ãžã®ãªã³ã¯ãèŠã€ããããšãã§ããŸãã ãã®äŸã§ã¯ãsysfsãä»ããŠããã€ã¹å±æ§ã䜿çšå¯èœã«ããæ¹æ³ã瀺ããŸãã ããã€ã¹ãã¡ã€ã«ãä»ããŠããã€ã¹ãžã®ã¢ã¯ã»ã¹ãæäŸãããã©ã€ããŒãå®è£
ããæ¹æ³ã«ã€ããŠã¯ããã§ã«èª¬æããŸããïŒ
one ã
two ã
ç§ã®ãã©ã€ããŒã¯ããŠãŒã¶ãŒã«2ã€ã®å±æ§ã倿Žããæ©èœãæäŸããŸãã
å€-ãã®äžã«ãLEDã䜿çšããŠãã€ããªåœ¢åŒã§è¡šç€ºããæ°å€ãæžã蟌ãããšãã§ããŸãã
mode-ã¢ãŒãã¹ã€ããã3ã€ã®åäœã¢ãŒãã®ãããããèšå®ã§ããŸãã æ¬¡ã®ã¢ãŒãããµããŒããããŠããŸãã0-ãã€ããªåœ¢åŒã§æ°å€ã衚瀺ããããã®æšæºã¢ãŒãã1-å·Šããå³ãžã®è¡šç€ºã䌎ãããã°ã¬ã¹ããŒã¢ãŒãã2-å³ããå·Šãžã®è¡šç€ºã䌎ãããã°ã¬ã¹ããŒã¢ãŒãã
ããã°ã¬ã¹ããŒã¢ãŒãã§ã¯ãããã€ã¹ã¯LEDã®åã£ãŠãåããªãè¡ã衚瀺ããvalueã«èšé²ãããå€ã256ããäœããŒã»ã³ãã§ãããã瀺ããŸãã
ã¢ãŒãçªå·ã®3çªç®ã®ããããèšå®ãããšãspi_writeïŒïŒããã³spi_readïŒïŒãžã®éåæåŒã³åºãã®ä»£ããã«ãå
šäºéã¢ãŒãïŒfdx_transferïŒïŒé¢æ°ïŒã䜿çšãããŸãã éå
šäºéã¢ãŒãã¯ãããã4.5.6ã«ãªããŸãã ã¢ãŒãçªå·3ã¯0ã«å¯Ÿå¿ããŸãã
ããŠãä»ã§ã¯ã³ãŒãèªäœïŒ
#include <linux/module.h> #include <linux/init.h> #include <linux/spi/spi.h> #define SPI_LED_DRV_NAME "spi_led" #define DRIVER_VERSION "1.0" static unsigned char led_mode=0; static unsigned char fduplex_mode=0; unsigned char retval=0; char *mtx, *mrx; static unsigned char stbl_tmp; enum led_mode_t {LED_MODE_DEF, LED_MODE_L2R, LED_MODE_R2L }; static inline unsigned char led_progress(unsigned long val) { unsigned char i, result=0x00; val++; val/=32; for(i = 0; i < val; i++) { if(led_mode==LED_MODE_R2L) result|=(0x01<<i); else result|=(0x80>>i); } return (unsigned char)result; } static int fdx_transfer(struct spi_device *spi, unsigned char *val) { int ret; struct spi_transfer t = { .tx_buf = mtx, .rx_buf = mrx, .len = 1, }; struct spi_message m; mtx[0]=*val; mrx[0]=0; spi_message_init(&m); spi_message_add_tail(&t, &m); if((ret=spi_sync(spi, &m))<0) return ret; retval=mrx[0]; return ret; } static ssize_t spi_led_store_val(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct spi_device *spi = to_spi_device(dev); unsigned char tmp; unsigned long val; if (strict_strtoul(buf, 10, &val) < 0) return -EINVAL; if (val > 255) return -EINVAL; switch(led_mode) { case LED_MODE_L2R: case LED_MODE_R2L: tmp = led_progress(val); break; default: tmp = (unsigned char)val; } stbl_tmp=tmp; if(fduplex_mode) fdx_transfer(spi, &tmp); else spi_write(spi, &tmp, sizeof(tmp)); return count; } static ssize_t spi_led_show_val(struct device *dev, struct device_attribute *attr, char *buf) { unsigned char val; struct spi_device *spi = to_spi_device(dev); if(!fduplex_mode) spi_read(spi, &val, sizeof(val)); return scnprintf(buf, PAGE_SIZE, "%d\n", fduplex_mode ? retval : val); } static ssize_t spi_led_store_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long tmp; if (strict_strtoul(buf, 10, &tmp) < 0) return -EINVAL; if(tmp>6) return -EINVAL; led_mode = (unsigned char)tmp&0x03; fduplex_mode = ((unsigned char)tmp&0x04)>>2; return count; } static ssize_t spi_led_show_mode(struct device *dev, struct device_attribute *attr, char *buf) { return scnprintf(buf, PAGE_SIZE, "%d\n", led_mode); } static DEVICE_ATTR(value, S_IWUSR|S_IRUSR, spi_led_show_val, spi_led_store_val); static DEVICE_ATTR(mode, S_IWUSR|S_IRUSR, spi_led_show_mode, spi_led_store_mode); static struct attribute *spi_led_attributes[] = { &dev_attr_value.attr, &dev_attr_mode.attr, NULL }; static const struct attribute_group spi_led_attr_group = { .attrs = spi_led_attributes, }; static int __devinit spi_led_probe(struct spi_device *spi) { int ret; spi->bits_per_word = 8; spi->mode = SPI_MODE_0; spi->max_speed_hz = 500000; ret = spi_setup(spi); if(ret<0) return ret; return sysfs_create_group(&spi->dev.kobj, &spi_led_attr_group); } static int __devexit spi_led_remove(struct spi_device *spi) { sysfs_remove_group(&spi->dev.kobj, &spi_led_attr_group); return 0; } static struct spi_driver spi_led_driver = { .driver = { .name = SPI_LED_DRV_NAME, .owner = THIS_MODULE, }, .probe = spi_led_probe, .remove = __devexit_p(spi_led_remove), }; static int __init spi_led_init(void) { mtx=kzalloc(1, GFP_KERNEL); mrx=kzalloc(1, GFP_KERNEL); return spi_register_driver(&spi_led_driver); } static void __exit spi_led_exit(void) { kfree(mtx); kfree(mrx); spi_unregister_driver(&spi_led_driver); } MODULE_AUTHOR("Lampus"); MODULE_DESCRIPTION("spi_led 8-bit"); MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRIVER_VERSION); module_init(spi_led_init); module_exit(spi_led_exit);
次ã«ãããŒããã¡ã€ã«å
ã®SPIããã€ã¹ã®ãªã¹ãã«ããã€ã¹ã远å ããå¿
èŠããããŸãã SK-AT91SAM9260ã§ã¯ããã¡ã€ã«arch / arm / mach-at91 / board-sam9260ek.cãéããŠãããã€ã¹ã®æ§é äœspi_board_infoã®é
åã«è¿œå ããå¿
èŠããããŸãïŒspidevãšåæ§ïŒã
{ .modalias = "spi_led", .chip_select = 1, .max_speed_hz = 15 * 1000 * 1000, .mode = SPI_MODE_0, .bus_num = 1, },
äžèšã®ã³ãŒããããããããã«ãç§ã®ããã€ã¹ã¯15 MHzã®åšæ³¢æ°ã§åäœããCSçªå·1ã®SPI1ã§ãã³ã°ããŸãããããè¡ãããªãå Žåãã¢ãžã¥ãŒã«ãããŒãããããšããã©ã€ããŒã¯ããã€ã¹ã«é¢é£ä»ããããŸããã
ã¢ãžã¥ãŒã«ããã«ãããã«ã¯ã次ã®Makefileã䜿çšããŸãã
ifneq ($(KERNELRELEASE),) obj-m := spi_led.o else KDIR := /media/stuff/StarterKit/new_src/linux-2.6.39.1_st3 all: $(MAKE) -C $(KDIR) M=`pwd` modules endif
KDIR倿°ã¯ãã«ãŒãã«ãœãŒã¹ãå«ããã¹ãæãå¿
èŠããããŸãã
çµã¿ç«ãŠã¯æ¬¡ã®ãšããã§ãã
ARCH=arm CROSS_COMPILE=/opt/arm-2010q1/bin/arm-none-linux-gnueabi- make
CROSS_COMPILE倿°ã¯ãã¯ãã¹ã³ã³ãã€ã©ãã¬ãã£ãã¯ã¹ã瀺ããŸãã
次ã«ãã«ãŒãã«ãåæ§ç¯ããã¢ãžã¥ãŒã«ãããŒãã«è»¢éããŠããŒãããŸãã
insmod /path/to/spi_led.ko
ãã®åŸãã·ã¹ãã ã«ããã€ã¹å±æ§ã衚瀺ãããæ¬¡ã®å³ã衚瀺ãããŸãã
ls /sys/module/spi_led/drivers/spi:spi_led/spi1.1 driver modalias mode power subsystem uevent value
次ã«ãã³ãŒãã«çŽæ¥æ»ããŸãã ãŠã©ããã¯æåŸããéå§ããå¿
èŠããããŸãã ãã¯ãMODULE_AUTHORãMODULE_DESCRIPTIONãMODULE_LICENSEãMODULE_VERSIONã¯ãããããmodinfoã³ãã³ãã䜿çšããŠå©çšã§ããæ
å ±ãäœæè
åãã¢ãžã¥ãŒã«ã®èª¬æãã©ã€ã»ã³ã¹ãããŒãžã§ã³ã決å®ããŸãã GPL以å€ã®ã©ã€ã»ã³ã¹ã䜿çšããŠããå ŽåãGPLã©ã€ã»ã³ã¹ã䜿çšããŠã¢ãžã¥ãŒã«ããã³ãŒãããã«ã§ããªããããã©ã€ã»ã³ã¹ã®è¡šç€ºãæãéèŠã§ãã
module_initïŒïŒããã³
module_exitïŒïŒãã¯ãã¯ãããããã¢ãžã¥ãŒã«ã®åæåããã³ã¢ã³ããŒã颿°ãå®çŸ©ããŸãã ã¢ãžã¥ãŒã«ãéçã«æ§ç¯ãããŠããå Žåãmodule_exitãã¯ãã§æå®ããã颿°ã¯åŒã³åºãããŸããã
æ§é
äœspi_driver spi_led_driverã§ããã©ã€ããŒããããã€ã¹ãžã®ãã€ã³ãã£ã³ã°é¢æ°ïŒãããŒãïŒãããã€ã¹åæé¢æ°ïŒåé€ïŒãžã®ãªã³ã¯ãèšå®ããããã©ã€ããŒåãææè
ã§ãã ãŸããçãšãã¢ãŒããžã®ç§»è¡ïŒãµã¹ãã³ãïŒããã³çµäºïŒåéïŒã®æ©èœãžã®ãªã³ã¯ãèšå®ã§ããŸãã ãã©ã€ããåãã¯ã©ã¹ã®è€æ°ã®ç°ãªãããã€ã¹ããµããŒãããå Žåããããã®èå¥åã¯id_tableãã£ãŒã«ãã«ä¿åãããŸãã
SPIãã©ã€ããŒã®ã·ã¹ãã ãžã®ç»é²ã¯ã
spi_register_driver颿°
ïŒstruct spi_driver * sdrvïŒã䜿çšããŠè¡ãããŸãã ç»é²åŸãããã€ã¹ãšãã©ã€ããŒãé¢é£ä»ããããšãã§ããŸãã ãã¹ãŠããŸãããã°ã次ã®é¢æ°ã¯ãããŒããã€ã³ã¿ãŒã§å®çŸ©ããããšããã«åŒã³åºãããŸãã
spi_unregister_driver颿°
ïŒstruct spi_driver * sdrvïŒã䜿çšããŠãã·ã¹ãã ãããã©ã€ããŒç»é²ãåé€ã§ã
ãŸããspi_led_probeïŒïŒé¢æ°ã¯ã以å
spi_board_infoã§å®çŸ©ãããspi_deviceæ§é å
ã®ããã€ã¹ãæäœããããã®ã³ã³ãããŒã©ãŒãã©ã¡ãŒã¿ãŒãèšå®ããŸãã spi_deviceæ§é ã®å¿
èŠãªãã£ãŒã«ãããªãŒããŒã©ã€ãããåŸã
spi_setupïŒïŒã³ã³ãããŒã©ãŒæ§æé¢æ°ãåŒã³åºãããŸãã
次ã«ã屿§ã«ã€ããŠèª¬æããŸãã Documentation / filesystems / sysfs.txtãã¡ã€ã«ã®sysfsãä»ããŠããã€ã¹å±æ§ã®æäœã«ã€ããŠèªãããšãã§ããŸãã DEVICE_ATTRãã¯ãã¯ãdevice_attributeã®æ§é ãå®çŸ©ããããã«äœ¿çšãããŸãã ããšãã°ããã®ãããªå®çŸ©
static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo);
以äžãšåçïŒ
static struct device_attribute dev_attr_foo = { .attr = { .name = "foo", .mode = S_IWUSR | S_IRUGO, .show = show_foo, .store = store_foo, }, };
ããã§ãshowã¯ã屿§ãã¡ã€ã«ãéããããšãã«å®è¡ãã颿°ãžã®ãã€ã³ã¿ãŒã§ãã
store-屿§ãã¡ã€ã«ãžã®æžãèŸŒã¿æã«å®è¡ããã颿°ãžã®ãã€ã³ã¿ãŒã
ã¢ãŒã-屿§ãã¡ã€ã«ãžã®ã¢ã¯ã»ã¹æš©ãå®çŸ©ããŸãã
name-屿§ãã¡ã€ã«ã®ååã
äŸã«ã€ããŠã¯ãè¡ãèŠãŠ
static DEVICE_ATTR(value, S_IWUSR|S_IRUSR, spi_led_show_val, spi_led_store_val);
ãŠãŒã¶ãŒãèªã¿æžãã§ããååã®å€ã§ããã€ã¹å±æ§ãå®çŸ©ããŸãã屿§ã®ã¬ã³ãŒãã®ããã»ããµé¢æ°ã¯spi_led_store_valã屿§ãèªã¿åãããã»ããµé¢æ°ã¯spi_led_show_valã§ãã ãã®å±æ§ã®æžã蟌ã¿/èªã¿åããæäŸãããªãå Žåãä¿å/è¡šç€ºé¢æ°ãžã®ãã€ã³ã¿ãŒã®1ã€ãNULLã«ãªãããšããããŸãã
ãã®å±æ§ã®åäœãã©ã®ããã«èŠãããèŠãŠã¿ãŸãããïŒ
cd /sys/module/spi_led/drivers/spi:spi_led/spi1.1 ls -l value -rw------- 1 root root 4096 Jun 29 14:10 value echo "32">value cat value 64
èŠããŠãããŠãç§ã®ããŒããŠã§ã¢ã¯ãèªã¿åãæã«ããŒã¿ã1ãããå·Šã«ã·ããããããšãè¿°ã¹ãŸãããïŒ ãããã32ã®ä»£ããã«64ãèšé²ããçç±ã§ãã æ°å€ã屿§ãã¡ã€ã«ã«æžã蟌ãŸãããšã©ããªããŸããïŒstrict_strtoulïŒïŒé¢æ°ã¯åä¿¡ããæååãããã¡ãŒãæ°å€ã«å€æããããšããŸãããã®åŸãæãè
ããã®ä¿è·ããããŸã-æ°å€ã255ãè¶
ããªãããšã確èªããŸããããã§ããã以äžã§ããã°ããšã©ãŒãè¿ããŸãã ãŠãŒã¶ãŒã«ãšã£ãŠãããã¯æ¬¡ã®ããã«ãªããŸãã
次ã«ãçŸåšã®åäœã¢ãŒãã確èªããããã«å¿ããŠtmp倿°ãèšå®ããŸãã ããã°ã¬ã¹ããŒã¢ãŒãã®å Žåããäžæçããªåäœããããæã€æ°å€ãååŸãããŸãããã以å€ã®å ŽåããŠãŒã¶ãŒã倿Žããã«æå®ãããã€ããSPIã«è¡šç€ºãããŸãã fduplex_modeãã©ã°ã«å¿ããŠãäŒéæ¹åŒãéžæãããŸãïŒåäºéãŸãã¯å
šäºéã
åè
ã®å Žåã¯
spi_writeïŒïŒé¢æ°ã䜿çšããã
åŸè
ã®å Žåã¯èªå·±èšè¿°ã®spd_writeïŒïŒé¢æ°ã䜿çšãããŸãã
次ã«ãå®å
šãªããŒã¿è»¢éãè¡ããŸãã ã芧ã®ãšãããéä¿¡çšã®ãããã¡ãŒïŒmtxãmrxãã€ã³ã¿ãŒïŒã®ã¡ã¢ãªãŒã¯ãkzmalloc颿°ã䜿çšããŠå²ãåœãŠãããŸãã å
ã»ã©èšã£ãããã«ãããã¯ãDMAã«äœ¿çšå¯èœãªã¡ã¢ãªé åã«ãããã¡ãé
眮ããå¿
èŠãããããã§ãã ããã§ãfdx_transferïŒïŒé¢æ°èªäœãèŠãŠãã ããã å®éãspi_messageã¡ãã»ãŒãžãåéãã
spi_syncïŒïŒé¢æ°ã䜿çšããŠãããæž¡ããŸã
ãã¡ãã»ãŒãžãéä¿¡ãããšãã«åä¿¡ãããã€ãã¯ãã°ããŒãã«å€æ°retvalã«æ ŒçŽãããŸãã
mode屿§ã®æäœã¯ã転éã¢ãŒãã®è§£æã衚瀺ã¢ãŒããšãã¥ãã¬ãã¯ã¹ãããããæ±ºå®ãã2ã€ã®ã°ããŒãã«å€æ°led_modeãšfduplex_modeã«è§£æããããšã®ã¿ã§æ§æãããŸãã
確ãã«å€ãã®äººããåæã«è€æ°ã®ã¢ããªã±ãŒã·ã§ã³ãã屿§ãã¡ã€ã«ãæžã蟌ãããšãããšã©ããªãããæç¢ºã§ãªãããšã«æ°ã¥ããŸããã 確ãã«è¯ãããšã¯äœãèµ·ãããŸãããããã§ã¯æç€ºçãªç«¶åç¶æ
ããããŸãã ç§ã¯ã³ãŒããäžå¿
èŠã«è€éã«ããªãããã«ããŸãããããã®ãããªå Žåã«äœããã¹ããèå³ããã人ã®ããã«ãç§ã¯
ããã¯ã«ä¿¡é Œã§ããªãã¬ã€ããèªãããšããå§ãããŸã
çè§£ã®ããã®æ®ãã®åé¡ãçºçããªãããšãé¡ã£ãŠããŸãã
5.ããã¥ã¡ã³ã
ã³ã¢ããã¥ã¡ã³ããæ€çŽ¢ããåé¡ã¯ãã§ã«
ããã§è°è«ãããŠã
ãŸã ã
ã«ãŒãã«ãœãŒã¹ã«ã¯ãDocumentation /ãã£ã¬ã¯ããªã«äžé£ã®ããã¥ã¡ã³ããä»å±ããŠããŸããååãšããŠãããããå§ãã䟡å€ããããŸããã«ãŒãã«ã¯ãç¬èªã®kerneldocãœãŒã¹ã³ãŒãããã¥ã¡ã³ãã·ã¹ãã ã§åäœããŸããããã䜿çšãããšãã«ãŒãã«ãœãŒã¹ãã©ã«ããŒããæ¬¡ã®ã³ãã³ãã䜿çšããŠãã«ãŒãã«ã·ã¹ãã ãšAPIã«é¢ããããã¥ã¡ã³ããçæã§ããŸãã sudo apt-get install xmlto make htmldocs
ææ°ã®å®å®ããã«ãŒãã«ããŒãžã§ã³ã®ããã¥ã¡ã³ãã¯ãåžžã«www.kernel.org/docãã å
¥æã§ããŸããããããããŸãæåã«èªãã¹ããã®ã¯ãLinuxã«ãŒãã«ã®ãããã³ã°ã«é¢ããä¿¡é Œæ§ã®äœãã¬ã€ãã§ãïŒwww.kernel.org/doc/htmldocs/kernel-hacking.htmlLearning Linuxã§SPIã䜿çšããå Žåã¯ãDocumentation / spiãã£ã¬ã¯ããªã®æŠèŠããã¥ã¡ã³ããç¹ã«spi-summaryãšspidevããå§ããå¿
èŠããããŸãããŸããspidevã䜿çšããäœæ¥ã®çŽ æŽãããäŸããããŸãïŒspidev_fdx.cããã³spidev_test.cãäžéšã®ã³ã³ãããŒã©ãŒã§ã¯ãè¥å¹²ã®ä¿®æ£ãå¿
èŠã«ãªãããšãå¿ããªãã§ãã ãããDocumentation / filesystems / sysfs.txtãã¡ã€ã«ã®sysfsãä»ããŠããã€ã¹å±æ§ã®æäœã«ã€ããŠèªãããšãã§ããŸããã«ãŒãã«ã§SPIãæäœããããã«äœ¿çšãããAPIå
šäœã«ã€ããŠã¯ãSPI Linuxã«ãŒãã«APIã®èª¬æãåç
§ããŠãã ãããwww.kernel.org/doc/htmldocs/device-drivers/spi.html- Linux Cross Reference:
lxr.linux.no lxr.free-electrons.comFree Electrons:
free-electrons.com/docs Embedded Linux, .
, , .