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ãè¿œå ããŸãã
{ /* spidev */ .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ãšåæ§ïŒã
{ /* LED SPI */ .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ãè¶ ããªãããšã確èªããŸããããã§ããã以äžã§ããã°ããšã©ãŒãè¿ããŸãã ãŠãŒã¶ãŒã«ãšã£ãŠãããã¯æ¬¡ã®ããã«ãªããŸãã
# echo "257">value bash: echo: write error: Invalid argument
次ã«ãçŸåšã®åäœã¢ãŒãã確èªããããã«å¿ããŠ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.html
Learning 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.com
Free Electrons: free-electrons.com/docs Embedded Linux, .
, , .