Fox G20 SPI NOTES =-=-=-=-=-=-=-=-= Introduction ============ The Serial Peripheral Interface Bus (SPI) bus is a synchronous serial data link standard. As usual, Wikipedia has a good explanatory article: http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus SPI is relatively simple from an electrical point of view (compared with something like USB) and can typically run at higher speeds (e.g. over 25 MHz) than classical (asynchronous) serial and I2C. SD cards support multiple protocols including SPI (see the "Transfer modes" section of http://en.wikipedia.org/wiki/Secure_Digital). SPI can be done with "bit banging" in the user space using GPIO lines but the clock speed would be in the 10 kHz range. Linux has a SPI bit banging kernel driver (called SPI_GPIO) which would be a bit better. This note will concentrate on the kernel driver for SPI hardware support in the AT91SAM9G20 chip (called SPI_ATMEL). Higher SPI clock speeds require shorter and better wiring plus a "clean" 3.3 volt supply. As usual there is a trade-off between speed and reliability. In my experiments a SPI 15 MHz clock roughly wired to a SD card read data at about 1.3 MB/sec (approximately the SPI clock speed divided by 11) but with the occasional error. At a SPI clock of 10 MHz the read speed dropped to 970 kB/sec without any READ errors. Fox G20 hardware SPI basics and pins ==================================== The AT91SAM9G20 has two independent SPI controllers which can be configured as either SPI masters or slaves. | SPI0 SPI1 --------|------------------------------ MISO | PA0 PB0 MOSI | PA1 PB1 SPCK | PA2 PB2 CS0 | PA3 PB3 CS1 | PC11 PC5,PC18 CS2 | PC16 PC4,PC19 CS3 | PC17 PC3,PC20 PA0, PA1 and PA3 are used by the MMC interface (G20 MCI unit) to access the microSD card. Since the microSD card on the FoxG20 main board is needed to run the G20, then SPI0 is not available. Also PC16 and above are used to access the RAM on the Netus board so are not available for other uses. PC4 and PC5 have a 1.8 volt rail (so should not exceed 2.1 volts) while PC3 is on the AVDD (analog) supply which is probably set to 3.3 volts. The PA* and PB* lines have a 3.3 volt rail. The Daisy-1 "mother" board names its D7 connector "SPI". It has pins for PB0 (pin 3), PB1 (2), PB2 (4) and PB3 (5). Pin 7 is PC4_33 (i.e. PC4 level translated to 3.3 volts) and pin 6 is PC5_33 (i.e. PC5 level translated to 3.3 volts). Pin 8 is PC3 whose power rail is AVDD which is probably 3.3 volts. On the FoxG20 the AT91SAM9G20 "master" clock (MCLK) is 132 MHz and SPCK (i.e. clock driven by the SPI master) divides MCLK by a number in the range 1 to 255. The 'net suggests that the SPI clock to a SD card can be in the range 0 MHz (DC) to 25 MHz. The SPI speed in this case is set in the arch/arm/mach-at91/board-foxg20.c file (after my spi patch is applied); look for ".max_speed_hz". SD card with SPI interface example ================================== A table follows which shows the mapping from GPIO lines (with their SPI name equivalents) to the Daisy-1 board D7 connector. The corresponding SD (SPI transfer mode) names are also shown: GPIO SPI D7 SD Notes line name pin name --------------------------------------------------- PB0 MISO 3 DO PB1 MOSI 2 DI PB2 MSCK 4 SCK PB3 NPCS0 5 CS ** - - - CD Card Detect *** - - 1 Vcc 3.3 volts - - 10 Gnd ground (0 volts) - - 9 - 5 volts (not used) --------------------------------------------------- ** PB3 corresponds to .chip_select=0 in board-foxg20.c . [Could use PC5_33 with .chip_select=1 (but my spi patch would need a small edit).] *** kernel doesn't seem to support CD. Could use gpio line and user space code to do sensible things when a card is inserted or removed My test setup was based on the lk 3.1.0 kernel with patches found at http://sg.danny.cz/foxg20/ applied. The patch for hardware SPI on PB0, PB1, PB2, PB3 (and PC5) is fg20_spi304.patch . That patch does the following: a) configures PB0, PB1, PB2 and PB3 (chip select) for a SD card and calls the mmc_spi module (which should result in the /dev/mmcblk1 (plus its partition devices) appearing). b) configures PB0, PB1, PB2 and PC5 (chip select) to be a SPI pass-through device with a name like /dev/spidev1.1 [See Documentation/spi/spidev in the linux kernel source.] Note that PB0, PB1, PB2 (and PB3 or PC5) cannot be used as "normal" GPIO lines if the hardware SPI facility is required. Since this might interfere with existing usage (it does in some of my systems) then a kernel configuration parameters called CONFIG_SAM9G20_SPI1 is added by the above patch. After applying that patch to select it use 'make menuconfig' and then under 'System type' and then 'Atmel AT91 System-on-Chip' check 'SPI on PB0 to PB2'. The lsmod output on my test machine is as follows: Module Size Used by ipv6 223167 10 mmc_spi 8161 0 crc7 743 1 mmc_spi spidev 4278 0 Since the SPI hardware is detected (look at the output of dmesg) then the kernel autoloads the mmc_spi and spidev modules. Obviously they need to be build in the kernel. The 310.config_spi file on my site is a copy of my '.config' file at the top level of my kernel source tree. The 310_PATCHES file lists the patches I have applied to the kernel source. With a Sparkfun microSD breakout card wired to a Daisy-12 prototyping board as indicated above, and a Daisy cable connecting the Daisy-12 to D7 ("SPI") on a Daisy-1 "mother" card, I see the following in the dmesg output: ... atmel_spi atmel_spi.1: Atmel SPI Controller at 0xfffcc000 (irq 13) ... mmc_spi spi1.0: ASSUMING 3.2-3.4 V slot power mmc_spi spi1.0: SD/MMC host mmc1, no WP, no poweroff ... mmc1: host does not support reading read-only switch. assuming write-enable. mmc1: new SDHC card on SPI mmcblk1: mmc1:0000 SU04G 3.69 GiB mmcblk1: p1 p2 p3 The speed is reasonable (IMO): # dd if=/dev/mmcblk1p2 bs=16k of=/dev/null count=1k 1024+0 records in 1024+0 records out 16777216 bytes (17 MB) copied, 17.3201 s, 969 kB/s and file systems can be mounted: # mount /dev/mmcblk1p1 /mnt/extra/ # df -hT Filesystem Type Size Used Avail Use% Mounted on /dev/mmcblk0p2 ext4 886M 626M 252M 72% / tmpfs tmpfs 30M 0 30M 0% /lib/init/rw varrun tmpfs 30M 24K 30M 1% /var/run udev tmpfs 10M 144K 9.9M 2% /dev tmpfs tmpfs 30M 0 30M 0% /dev/shm /dev/mmcblk1p1 vfat 64M 7.7M 57M 12% /mnt/extra Note that the kernel does not detect an SD card being inserted or removed. If you are aware the SD card is about to be removed then any file system on it should be unmounted and doing a 'rmmod mmc_spi' command will clean things up (failing that, use some 'sync' commands). Then after a SD card is inserted doing a 'modprobe mmc_spi' command should make the corresponding device nodes (e.g. /dev/mmcblk1p1) available (perhaps check the end of the dmesg output). SD card pinout ============== For those that don't have a SD card breakout board the pinout on the actual SD card follows. Holding a SD card with the pins up and facing you, the angle should be on the upper left. Then the pins are numbered: 9, 1, 2, 3, 4, 5, 6, 7, 8 from left (the angle) to right: pin name used by SPI ---|-----------|--------------- 9 | DAT2 | - 1 | CS/DAT3 | CS 2 | DI/CMD | DI 3 | Vss | ground 4 | Vdd | 3.3 volts 5 | SCLK | SCK (clock) 6 | Vss2 | ground 7 | DO/DAT0 | DO 8 | DAT1 | - FoxG20 red LED improvement ========================== The red LED on the FoxG20 is set to a "heartbeat" pattern after a Debian kernel is loaded successfully. Aparting from being annoying (after a while) it isn't very useful in showing that the G20 is actually running, for example the heartbeat continues to run after the G20 is halted or if the kernel crashes (an oops). Someone [name] pointed out a better use for that red LED (driven by the PC7 gpio line), and that is to show "disk" usage (reads or writes). That can be done with this one-liner: # echo mmc0 > /sys/class/leds/user_led/trigger That would be for the microSD card on the FoxG20 card. To associate the red LED with this SPI-based SD card discussed in this note use: # echo mmc1 > /sys/class/leds/user_led/trigger or to turn off the red LED: # echo none > /sys/class/leds/user_led/trigger Douglas Gilbert [dgilbert@interlog.com] 20111026