前段时间研究网卡移植到开发板,小有成果。
开发板类型: tcc-8900
网卡型号: enc28j60 (28个针脚)
操作系统:Linux 2.6.28
网卡是通过spi总线与mcu 进行数据与命令的传输,即网卡是挂载到spi总线下的设备,在驱动网卡之前要先驱动起spi总线。很佩服做linux的一些前辈,在kenerl 中已经把大部分的程序给我写好了只需要做一些改动即可。
我做的具体过程:
刚开始的终端输入 :make menuconfig
进行内核的一些配置
即选中device driver 下的spi support 下的 spi master controller (如果全选也可以)
还有device driver 下 network support 下 (10 M/100 M )ether 下的enc28j60 选项
另外就是要注意你的芯片的内存是128 m 还是256M 的设置
下面是过程
(1)/../linux-2.6.28/arch/arm/mach-tcc8900目录下找到board-tcc8900.c文件找到结构体tcc8900_spi0_board_info
把该结构体中的变量 .modalias = spidev ,改为 .modalias = enc28j60 ,这样网卡enc28j60就挂载到spi0 总线下了,tcc8900 下默认开启两个spi总线 spi0 和spi1,你可以任选一个,如果选spi1 就在tcc8900_spi1_board_info下改
.modalias = enc28j60 即可。一般说来一个spi总线下可以挂载的设备数目可达127个,相同总线下每个设备的名称不一样。
(2)/../linux-2.6.28/drivers/net 目录下找到enc28j60.c这个文件,基本上不要修改什么东东,添加一些初始化设置。
该文件中最主要的函数就是enc28j60_probe,这个是网卡的探测函数,在内核中会有个设备列表,当注册进去的硬件名称与列表中名称相同的话,就会执行probe函数。步骤1中的修改就是为了,可以在设备列表里添加硬件的名称。所以你会在board-tcc8900.c中看到spi_register_board_info函数,这个应该相当于设备资源注册吧,在enc28j60.c中看到spi_register_driver函数。这个就是设备驱动注册,两个注册函数的设备名称相同,就可以执行探测probe函数。
(3)还是在enc28j60.c文件下添加初始化设置。这个可能要根据不同的硬件电路图配置。我的情况是用到了tcc8900芯片的GPIOF[11 :17] 分别接enc28j60 芯片的针脚如下;
GPIOF[11] : wol (中断唤醒)貌似没什么用
[12] : rst (复位脚)
[13] : int (中断脚)
[14] : si (spi 接口数据输入引脚)
[15] : so (spi接口数据输出引脚)
[16] : sck(spi 接口时钟输入引脚)
[17] : cs(spi 接口的片选引脚)
然后就是对这些引脚进行初始化设置(参照tcc8900 的datasheet)
volatile PPIC pic_regs = (volatile PPIC)tcc_p2v(HwPIC_BASE);
volatile PGPIO gpio_regs = (volatile PGPIO)tcc_p2v(HwGPIO_BASE);
volatile PGPSBPORTCFG gpsb_pcf_regs = (volatile PGPSBPORTCFG)tcc_p2v(HwGPSBPORTCFG_BASE);
BITCSET(gpsb_pcf_regs->PCFG0, Hw8-Hw0, Hw3); 设置选择spi0 的通道 为8
注:如果你用的是spi1 设备,就要改为
BITCSET(gpsb_pcf_regs->PCFG0, Hw16-Hw8, Hw3);
/gpiof [14 :16]/ si so sck 等针脚设置为功能2 。
BITCSET(gpio_regs->GPFFN1, Hw32-Hw24, Hw29|Hw25);
BITCSET(gpio_regs->GPFFN2, Hw4-1, Hw1);
/gpiof 17/ 片选这个脚设置
BITCSET(gpio_regs->GPFFN2 , Hw8 - Hw4 ,0);作为功能0 即为i/o口
BITSET(gpio_regs->GPFEN , Hw17);作为输出模式
BITCLR(gpio_regs->GPFDAT,Hw17); gpiof[17] 输出为低电平
以上的初始化可以放在专门一个函数中,就暂且叫enc28j60_hard_init吧 区别于enc28j60.c中原来的函数 enc28j60_hw_init
下面是写另一个函数enc28j60_hard_reset
/gpio12 / 复位这个脚
BITCSET(gpio_regs->GPFFN1 , Hw20 - Hw16 ,0);作为功能0 ,i/o口
BITSET(gpio_regs->GPFEN , Hw12);作为输出模式
BITCLR(gpio_regs->GPFDAT,Hw12); gpiof[12] 输出低电平
udelay(2000) ;要延迟至少1ms
BITSET(gpio_regs->GPFDAT,Hw12); 输出高电平
udelay(200000);这个也要延迟很长时间
到现在为止初试化的一些工作就完成的差不多了,把两个函数放在probe函数中靠前的位置。要记住顺序,先复位enc28j60_hard_reset,在enc28j60_hard_init。
然后就可以编译啦,这样的结果还是会错的。错在什么地方呢。
在移植过程中出现的一些错误,和解决方法会在另一篇文章《enc28j60网卡移植的总结续》给出。
不是在卖关子,是太饿啦,先去吃饭。回来再写
/ gpiof 13 中断引脚/这个配置可能要多一些
BITCSET(gpio_regs->GPFFN1 , Hw24 - Hw20 ,0);作为功能0 ,i/o口
BITCLR(gpio->GPFEN ,Hw13);作为输入模式
BITCSET(pic_regs-> EINTSEL2 , Hw22 - Hw16 ,Hw21 | Hw28 | Hw16);我们用了外部中断号INT_EI10
BITSET(pic->POL , Hw13);设置为低电平有效
BITCLR(pic->MODE0 ,Hw13),设置为边缘触发
BITCLR(pic->MODEA0 ,Hw13);设置为单边缘触发
BITSET(pic->IEN0 ,Hw13);是外部中断10有效
/gpiof 11 / 中断唤醒引脚
BITCSET(gpio_regs->GPFFN1 , Hw16 - Hw12 ,0);作为功能0 ,i/o口
BITCLR(gpio_regs->GPFEN , Hw11);作为输入模式