CH390使用注意事项
CH390替换DM90xx硬件注意事项
1、CH390L替换DM9000
- AVDD33的对地电容建议1uF贴近芯片放置,42脚为主电源AVDD33需10uF并联0.1uF。各AVDD33需分别接电容,供电电压都为3.3V;
- AVDDK和DVDDK需要分别外接电容并贴近芯片放置。两个AVDDK引脚建议任选一个外接1uF,另一个外接0.1uF。DVDDK外接0.1uF对地电容,DM9000 1脚接外置电阻的位置应改成0.1uF电容;
- VDDIO为CH390L的I/O电源,VDDIO支持3.3V或者2.5V,外接0.1uF对地电容;
- 43脚和44脚XI、XO不要接电阻,由于芯片内置12pf负载电容,因此如果晶振的负载电容是12pf则不需要再接负载电容,如果晶体负载电容为20pF时建议贴15pF的负载电容;晶振必须是25MHz优选贴片晶振;如果是外部时钟输入,需要从43脚XI输入;
- 芯片已内置终端电阻,因此不要接49.9欧或50欧等任何电阻;
- 网络变压器的中心抽头分别通过0.1uF~1uF电容接地,不要接任何电源;
2、CH390H替换DM9051
- AVDD33的对地电容建议1uF贴近芯片放置,42脚为主电源AVDD33需10uF并联0.1uF。各AVDD33需分别接电容,供电电压都为3.3V;
- AVDDK和DVDDK需要分别外接电容并贴近芯片放置。两个AVDDK引脚建议任选一个外接1uF,另一个外接0.1uF。DVDDK外接0.1uF对地电容,DM9051 1脚接外置电阻的位置应改成0.1uF电容;
- VDDIO为CH390H的I/O电源,VDDIO支持3.3V或者2.5V,外接0.1uF对地电容;
- 30脚和31脚XI、XO不要接电阻,由于芯片内置12pf负载电容,因此如果晶振的负载电容是12pf则不需要再接负载电容,如果晶体负载电容为20pF时建议贴15pF的负载电容;晶振必须是25MHz优选贴片晶振;如果是外部时钟输入,那么从30脚XI输入;
- 芯片已内置终端电阻,因此不要接49.9欧或50欧等任何电阻;
- 网络变压器的中心抽头分别通过0.1uF~1uF电容接地,不要接任何电源;
PS:如果采用杜邦线或飞线连接评估板调试,因CH390支持最高50M的SPICLK为防止串扰需要注意MCU与CH390之间可靠接地其他联络线尽量短且可靠连接,若出现SPI读写多数据或少数据的情况可以考虑在MCU与CH390的CS与CLK两端分别接10到20pF电容到地。
CH390DS1手册注意事项
CH390DS1手册中寄存器描述(H)对应CH390H,(L)对应CH390L;未标明(H)或(L)则适用于CH390H与CH390L。
引脚:I=输入;O=输出;I/O=输入/输出;P=电源;PD=内置下拉电阻;PU=内置上拉电阻。
寄存器描述中,默认形式如下:
复位值:
1位设置为逻辑1;
0位设置为逻辑0;
X没有默认值;
P=上电复位默认值;
H=硬件复位默认值;
S=软件复位默认值;
E=来自EEPROM的默认值;
T=配置引脚的默认值;
h=十六进制。
访问类型:
RO=只读;
WO=只写;
RW=读/写;
R/C=读和清除。
RW/C1=读写、通过写1清除;
保留位在读写访问时未定义
以中断屏蔽寄存器(IMR)为例,如果用的是CH390H需要访问的地址是7Fh,如果是CH390L则需要访问FFh,该寄存器的上电复位与软件复位默认值是00h,除第6位保留位为只读外其他位可读可写。
附CH390DS1手册:https://www.wch.cn/downloads/CH390DS1_PDF.html
手册描述的漏电流为浮空引脚的漏电流。
软件注意事项
可以先尝试读CH390的VID/PID验证SPI或并口通信是否正常,如果读VID/PID异常需确认接口通信是否满足CH390的时序要求。
1、CH390H支持从模式SPI模式0与SPI模式3。
SPI模式0
SPI模式3
需要注意的是一次SPI操作于SCS下降沿启动,于SCS上升沿停止,因此每次读写寄存器都需要拉低SCS直到读写完毕。
2、CH390L支持16位或者8位的被动并行总线接口
通过片选CS来选择访问CH390L。CS引脚默认为低电平有效,可以通过EEPROM配置重新定义。通过主机接口可以访问两个端口,一个是INDEX地址索引端口,另一个是DATA数据端口。引脚CMD=0时,选择INDEX端口,CMD=1时,选择DATA端口。INDEX端口的内容是DATA端口的寄存器地址。在访问任何寄存器之前,该寄存器的地址必须保存在INDEX端口中。
CH390数据包收发
1.数据包发送
首先通过写指令寄存器MWCMD将数据写入发送缓冲区,然后将字节数写入TXPLL和TXPLH寄存器,最后将TCR寄存器位0置1开启数据包发送。上电默认从索引A开始发送数据,在数据包A发送结束之前,可以将下一个(索引B)数据包的数据写入发送缓冲区。在数据包A的传输完成后,将数据包B的长度写入TXPLL和TXPLH寄存器,并置位TCR寄存器即可发送数据包B。后续数据包以A,B,A,B…交替的顺序以同样的方式发送。
1 /** 2 * @name ch390_write_mem 3 * @brief Write data to TX SRAM 4 * @param data - Data buffer 5 * @param length - Length to write 6 */ 7 void ch390_write_mem(uint8_t *data, int length) 8 { 9 int i; 10 ch390_if.scs(0); 11 ch390_if.spi_exc_data(OPC_MEM_WRITE); 12 for(i = 0; i < length; i++) { 13 ch390_if.spi_exc_data(data[i]); 14 } 15 ch390_if.scs(1); 16 }
1 /** 2 * @name ch390_send_request 3 * @brief Issue transmit request 4 */ 5 void ch390_send_request() 6 { 7 uint8_t tcr = ch390_read_reg(CH390_TCR); 8 ch390_write_reg(CH390_TCR, tcr | TCR_TXREQ); 9 }
1 /** 2 * @name ch390_send_packet 3 * @brief Send packet 4 * @param buff - Data to be sent 5 * @param length - Less than 3k bytes. 6 */ 7 void ch390_send_packet(uint8_t *buff, uint16_t length) 8 { 9 // Write data to SRAM 10 ch390_write_mem(buff, length); 11 // Wait until last transmit complete 12 while(ch390_read_reg(CH390_TCR) & TCR_TXREQ); 13 // Set current packet length 14 ch390_write_reg(CH390_TXPLL, length & 0xff); 15 ch390_write_reg(CH390_TXPLH, (length >> 8) & 0xff); 16 // Issue transmit request 17 ch390_send_request(); 18 }
2.数据包接受
接收缓冲区是一个环形缓冲区。系统复位后,接收缓冲区的起始地址为0C00h。每个数据包包含4字节的帧头,数据域,以及CRC。4字节帧头的格式为:01h,状态,数据长度低字节,数据长度高字节。
接收数据时需要先读两次无地址递增内存数据预取读命令寄存器(MRCMDX),第一次读为执行预取命令,第二次读才是取该寄存器里的实际值。通过该值判断接收到的是否为有效数据,如果为有效数据则需要通过地址递增的内存数据读命令寄存器(MRCMD)取数据即可。
1 /** 2 * @name ch390_receive_packet 3 * @brief Receive packet 4 * @param buff - Size equal to CH390_PKT_MAX 5 * @param rx_status - Output abnormal status while receiving packet. 6 * It has the same meaning as RSR(06h). 7 * @return Packet length 8 */ 9 uint32_t ch390_receive_packet(uint8_t *buff, uint8_t *rx_status) 10 { 11 uint8_t rx_ready; 12 uint16_t rx_len = 0; 13 uint8_t ReceiveData[4]; 14 15 // Check packet ready or not 16 ch390_read_reg(CH390_MRCMDX); 17 rx_ready = ch390_read_reg(CH390_MRCMDX); 18 19 // if rxbyte != 1 or 0 reset device 20 if (rx_ready & CH390_PKT_ERR) 21 { 22 // Reset RX FIFO pointer 23 ch390_write_reg(CH390_RCR, 0); //RX disable 24 ch390_write_reg(CH390_MPTRCR, 0x01); //Reset RX FIFO pointer 25 ch390_write_reg(CH390_MRRH, 0x0c); 26 ch390_if.delay_us(1000); 27 ch390_write_reg(CH390_RCR, RCR_RXEN); //RX Enable 28 return 0; 29 } 30 if (!(rx_ready & CH390_PKT_RDY)) 31 { 32 return 0; 33 } 34 35 ch390_read_mem(ReceiveData, 4); 36 37 *rx_status = ReceiveData[1]; //对应RSR寄存器 38 rx_len = ReceiveData[2] | (ReceiveData[3] << 8); //接收数据长度 39 40 if(rx_len <= CH390_PKT_MAX) 41 { 42 ch390_read_mem(buff, rx_len); 43 } 44 45 if ((*rx_status & 0x3f) || (rx_len > CH390_PKT_MAX)) 46 { 47 return 0; 48 } 49 return rx_len; 50 }
1 /** 2 * @name ch390_read_mem 3 * @brief Read data from RX SRAM 4 * @param data - Data buffer 5 * @param length - Length to read 6 */ 7 void ch390_read_mem(uint8_t *data, int length) 8 { 9 int i; 10 ch390_if.scs(0); 11 ch390_if.spi_exc_data(OPC_MEM_READ); 12 13 for(i = 0; i < length; i++) { 14 data[i] = ch390_spi_dummy_read(); 15 } 16 ch390_if.scs(1); 17 }
CH390中断说明
中断状态寄存器(ISR)写1清零,其中第五位LINKCHG位比较特殊需要如下处理否则可能会出现不报中断状态的情况。
1 /** 2 * @name ch390_int_handler 3 * @brief Handle CH390 interrupt events, include packet receive 4 */ 5 void ch390_int_handler() 6 { 7 uint8_t int_status = ch390_get_int_status(); 8 // Link status changed 9 if(int_status & ISR_LNKCHG) 10 { 11 Delay_Ms(100); 12 ch390_write_phy(0x1f, 0); 13 while(ch390_read_phy(0x1e)); 14 phy_linked = ch390_get_link_status(); 15 printf("Link status: %d\r\n", phy_linked); 16 ch390_write_reg(CH390_ISR, ISR_LNKCHG); 17 } 18 // Receive overflow 19 if(int_status & ISR_ROS) printf("Receive overflow\r\n"); 20 // Receive overflow counter overflow 21 if(int_status & ISR_ROO) printf("Overflow counter overflow\r\n"); 22 // Packet transmitted 23 if(int_status & ISR_PT) printf("Packet sent\r\n"); 24 // Packet received 25 if(int_status & ISR_PR) 26 { 27 /* Multiple packets may be received in a single packet receive 28 * event. So "ch390_receive_packet" should be called until the 29 * return value is 0. Otherwise data will accumulate in RX SRAM 30 * and cause overflow. */ 31 uint8_t rx_status = 0; 32 while(rx_fifo.write_p->valid == 0) 33 { 34 rx_fifo.write_p->length = ch390_receive_packet( 35 rx_fifo.write_p->data, 36 &rx_status); 37 if(rx_fifo.write_p->length != 0) 38 { 39 rx_fifo.write_p->valid = 1; 40 rx_fifo.write_p = rx_fifo.write_p->next; 41 } 42 else break; 43 } 44 } 45 }
附CH390EVT例程:https://www.wch.cn/downloads/CH390EVT_ZIP.html