技术开发 频道

自己动手编写嵌入式Bootloader之二

  2. CS8900A以太网驱动程序

  硬件电路决定了CS8900的物理地址是在BANK3的区间内,CS8900是16位的寄存器,故我们设置BANK3的BUS WIDTH也为16位。设置BANK3: 总线宽度16,使能nWait,使能UB/LB

  BANKCON3:0x1F7C

  网卡CS8900的访问基址为0x19000000,之所以再偏移0x300是由它的特性决定的

  #define CS8900_BASE 0x19000300

  CS8900 读写寄存器的方式有些特别。要读一个寄存器,先向CS8900_PPTR中写入该寄存器地址,再从CS8900_PDATA中读出该寄存器值;要写一个寄存器,先向CS8900PPTR中写入该寄存器地址,再向CS8900_PDATA中写入要写入的值。不管是寄存器地址还是要读写的数值,都是16位的,也就是说都是unsigned short类型的。因此,读写寄存器的函数如下:

  static unsigned short get_reg (int regno)

  {

  CS8900_PPTR
= regno;

  
return CS8900_PDATA;

  }

  
static void put_reg (int regno, unsigned short val)

  {

  CS8900_PPTR
= regno;

  CS8900_PDATA
= val;

  }

  读芯片ID: CS8900的芯片ID存放在PP_ChipID寄存器中,读该寄存器得到的正确值应该是0x630E,这可以初步判断一些地址/引脚的设置是否正确,如果读出的不是0x630E,那么CS8900肯定不能正常工作。

  设置MAC地址:

  MAC地址并不是固定的,可以由我们随意设置。从寄存器PP_IA开始的6个字节存放MAC地址。比如下面的代码把MAC地址设为 00 09 58 D8 11 22:

  put_reg (PP_IA + 0, 0x00 | 0x09 << 8);

  put_reg (PP_IA + 2, 0x58 | 0xD8 << 8);

  put_reg (PP_IA + 4, 0x11 | 0x22 << 8);

  因为是Little Endian, 所以0x09<<8, 但是在寄存器内存中还是 0x00放在前面。

  寄存器初始化: 设置CS8900的工作模式

  /* 只接收目标地址为本网卡的无错误数据包 */

  put_reg (PP_RxCTL, PP_RxCTL_IA | PP_RxCTL_Broadcast | PP_RxCTL_RxOK);

  /* 当进行接收操作时,不要产生任何中断 */

  put_reg (PP_RxCFG, 0);

  /* 当进行发送操作时,不要产生任何中断 */

  put_reg (PP_TxCFG, 0);

  /* 当进行缓存操作时,不要产生任何中断 */

  put_reg (PP_BufCFG, 0);

  /* 使能发送和接收模式 */

  put_reg (PP_LineCTL, PP_LineCTL_Rx | PP_LineCTL_Tx);

  发送数据包:

  int eth_send (volatile void *packet, int length)

  两个参数:要发送的数据包首地址、长度

  TxCMD 和TxLen寄存器用来初始化数据包的发送,其具体含义见CS8900数据手册第70页。这里PP_TxCmd_TxStart_Full被定义为 0x00C0,表示直到整个数据侦都加载到CS8900内部缓存之后才开始发送,数据侦的长度为CS8900_TxLEN.

  /* initiate a transmit sequence */

  CS8900_TxCMD
= PP_TxCmd_TxStart_Full;

  CS8900_TxLEN
= length;

  使用TxCMD下达发送数据的命令后,再读取 PP_BusSTAT 总线状态寄存器判断是否做好发送数据的准备。当get_reg (PP_BusSTAT) & PP_BusSTAT_TxRDY 不等于零时表示可以发送了。 使用一个循环进行实际的发送操作:

  for (addr = packet; length > 0; length -= 2)

  {

  CS8900_RTDATA
= *addr++;

  }

  这里 addr 也是unsigned short类型的指针, 每次向CS8900_RTDATA写入两个字节数据。这里假设要发送的数据包长度为偶数。

  最后,通过读取PP_TER寄存器可以知道是否发送完毕,是否发送成功。

  接收数据包:

  首先,通过读取PP_RER寄存器判断是否接收到数据。如果接收到数据,则连续两次读取 CS8900_RTDATA 的值,

  status = CS8900_RTDATA; /* stat */

  rxlen = CS8900_RTDATA; /* len */

  rxlen 为接收到的数据长度。

  然后用一个循环连续读取 rxlen 长度的数据:

  for (addr = (unsigned short *) &RxBuf[0], i = rxlen >> 1; i > 0;

  i
--)

  
*addr++ = CS8900_RTDATA;

  
if (rxlen & 1)

  
*addr++ = CS8900_RTDATA;

  其中 RxBuf 为预先在内存中开辟的一块接收缓冲区。 每次循环读取两个字节,还需要处理长度为奇数的情况。

  最后,把RxBuf交给上层的协议处理:net_receive( &RxBuf[0], rxlen );

0
相关文章