2009年9月16日星期三

DM355的SPI调试

对于dm355evm
/dev文件夹下没有spi设备,只有一个eeprom设备,这个设备用spi接口进行控制。该设备的设备文件是/dev/mtdblock5.他的驱动程序是at25xxA_eeprom.c。为什么他的设备文件是/dev/mtdblock5呢?在at25xxA_eeprom.c中的eeprom_probe函数中,调用了
ret = add_mtd_device(mtd)将该eeprom加入了mtdblock的链表中。其源码如下:

将DEBUG(0, "mtd: Giving out device %d to %s\n",i,
mtd->name);一句打印出来是:
drivers/spi/spi.cmtd: Giving out device 5 to spi_eeprom

同样我们可以看到。
mtd: Giving out device 0 to bootloader
mtd: Giving out device 1 to params
mtd: Giving out device 2 to kernel
mtd: Giving out device 3 to filesystem1
mtd: Giving out device 4 to filesystem2

如果不需要EEPROM那么可以将这个驱动程序进行一些修改 改成SPI的驱动程序
主要的底层驱动文件有四个spi.c spi.h dm355_spi_master.h dm355_spi_master.c
spi.c 和spi.h主要进行了SPI驱动的上层封装 dm355_spi_master.h
dm355_spi_master.c则是对底层的寄存器进行访问

一开始调试的时候发现一个bug 当发送N个字节的时候老是会多发一个数
而且在最后一个数发送之前CS会有一个小毛刺。
后来去阅读代码
发现最后那个字节是作者故意加上的
为了防止这个毛刺对访问eeprom控制数据的影响。
看了DM355底层的spi寄存器,发现问题处在SPIDAT1寄存器上。
去网上查解决办法 搜到了DM355的勘误表 原来是一个芯片BUG 靠!
根据勘误表上的解决办法修改成功后的SPI
调用spi write连续写数(或spi read读数 )C S是一直使能的。
但是 先写数再读数 CS中间是有一段不使能。
进行速度测试后的结果是:
SPI 的clk是4MHz
Spi 读写速度是300000Bytes/s
linux下寄存器各字节分开访问的接口函数在include » asm-arm » arch-davinci
的io.h中

00001 /*
00002 * DaVinci IO address definitions
00003 *
00004 * Copied from include/asm/arm/arch-omap/io.h
00005 *
00006 * 2007 (c) MontaVista Software, Inc. This file is licensed under
00007 * the terms of the GNU General Public License version 2. This program
00008 * is licensed "as is" without any warranty of any kind, whether
express
00009 * or implied.
00010 */
00011 #ifndef __ASM_ARCH_IO_H
00012 #define __ASM_ARCH_IO_H
00013
00014 #define IO_SPACE_LIMIT 0xffffffff
00015
00016 /*
00017 *
----------------------------------------------------------------------------
00018 * I/O mapping
00019 *
----------------------------------------------------------------------------
00020 */
00021 #define IO_PHYS 0x01c00000
00022 #define IO_OFFSET 0xfd000000 /* Virtual IO = 0xfec00000 */
00023 #define IO_SIZE 0x00400000
00024 #define IO_VIRT (IO_PHYS + IO_OFFSET)
00025 #define io_p2v(pa) ((pa) + IO_OFFSET)
00026 #define io_v2p(va) ((va) - IO_OFFSET)
00027 #define IO_ADDRESS(x) io_p2v(x)
00028
00029 /*
00030 * We don't actually have real ISA nor PCI buses, but there is so many
00031 * drivers out there that might just work if we fake them...
00032 */
00033 #define PCIO_BASE 0
00034 #define __io(a) ((void __iomem *)(PCIO_BASE + (a)))
00035 #define __mem_pci(a) (a)
00036 #define __mem_isa(a) (a)
00037
00038 #ifndef __ASSEMBLER__
00039
00040 /*
00041 * Functions to access the DaVinci IO region
00042 *
00043 * NOTE: - Use davinci_read/write[bwl] for physical register addresses
00044 * - Use __raw_read/write[bwl]() for virtual register addresses
00045 * - Use IO_ADDRESS(phys_addr) to convert registers to virtual
addresses
00046 * - DO NOT use hardcoded virtual addresses to allow changing
the
00047 * IO address space again if needed
00048 */
00049 #define davinci_readb(a) (*(volatile unsigned char
*)IO_ADDRESS(a))
00050 #define davinci_readw(a) (*(volatile unsigned short
*)IO_ADDRESS(a))
00051 #define davinci_readl(a) (*(volatile unsigned int
*)IO_ADDRESS(a))
00052
00053 #define davinci_writeb(v,a) (*(volatile unsigned char
*)IO_ADDRESS(a) = (v))
00054 #define davinci_writew(v,a) (*(volatile unsigned short
*)IO_ADDRESS(a) = (v))
00055 #define davinci_writel(v,a) (*(volatile unsigned int
*)IO_ADDRESS(a) = (v))
00056
00057 /* 16 bit uses LDRH/STRH, base +/- offset_8 */
00058 typedef struct { volatile u16 offset[256]; } __regbase16;
00059 #define __REGV16(vaddr) ((__regbase16 *)((vaddr)&~0xff)) \
00060 ->offset[((vaddr)&0xff)>>1]
00061 #define __REG16(paddr) __REGV16(io_p2v(paddr))
00062
00063 /* 8/32 bit uses LDR/STR, base +/- offset_12 */
00064 typedef struct { volatile u8 offset[4096]; } __regbase8;
00065 #define __REGV8(vaddr) ((__regbase8 *)((vaddr)&~4095)) \
00066 ->offset[((vaddr)&4095)>>0]
00067 #define __REG8(paddr) __REGV8(io_p2v(paddr))
00068
00069 typedef struct { volatile u32 offset[4096]; } __regbase32;
00070 #define __REGV32(vaddr) ((__regbase32 *)((vaddr)&~4095)) \
00071 ->offset[((vaddr)&4095)>>2]
00072
00073 #define __REG(paddr) __REGV32(io_p2v(paddr))
00074 #else
00075
00076 #define __REG(x) (*((volatile unsigned long *)io_p2v(x)))
00077
00078

没有评论: