精华内容
下载资源
问答
  • STM32的串口转I2C

    2012-02-17 10:15:17
    请问坛里的各位,STM32的串口接收到的数据如何I2C数据格式发送出去呢?给些意见吧!
  • TERAWINS(宏芯)系列TFT屏显示控制芯片专用I2C在线调试工具: T100A/T101A/T103/T107/T108/T113/T116/T118/T122/T128/T138/T515A/T376屏驱动芯片。可驱动控制所有品牌的TFT LCD液晶屏输入信号类型支持1、模拟的CVBS...
  • ML302-OpenCpu开发-HTTP https://blog.csdn.net/qq_33259323/article/details/109020904 https://www.bilibili.com/read/cv7923054 中移4G模块-ML302-OpenCpu开发-51单片机串口转I2C 因为ML302模块的I2C口是3.3v,...

    B站:https://space.bilibili.com/309103931

    中移4G模块-ML302专栏:https://blog.csdn.net/qq_33259323/category_10453372.html

    中移4G模块-ML302文集:https://www.bilibili.com/read/readlist/rl328642

    1.中移4G模块-ML302-OpenCpu开发-(固件编译和烧录)

    https://blog.csdn.net/qq_33259323/article/details/108586847

    https://www.bilibili.com/read/cv7876504

    2.中移4G模块-ML302-OpenCpu开发-(MQTT连接阿里云)

    https://blog.csdn.net/qq_33259323/article/details/108638945

    https://www.bilibili.com/read/cv7876527

    2.1中移4G模块-ML302-OpenCpu开发-(MQTT连接阿里云-订阅主题)

    https://blog.csdn.net/qq_33259323/article/details/108960540

    https://www.bilibili.com/read/cv7879954

    2.2中移4G模块-ML302-OpenCpu开发-(MQTT连接阿里云-接收和发送数据)

    https://blog.csdn.net/qq_33259323/article/details/108964810

    https://www.bilibili.com/read/cv7886836

    2.3中移4G模块-ML302-OpenCpu开发-(MQTT连接阿里云-RRPC通讯)

    https://blog.csdn.net/qq_33259323/article/details/108965071

    https://www.bilibili.com/read/cv7888259

    3.中移4G模块-ML302-OpenCpu开发-串口开发

    https://blog.csdn.net/qq_33259323/article/details/108974888

    https://www.bilibili.com/read/cv7888865

    4.中移4G模块-ML302-OpenCpu开发-51单片机串口转I2C

    https://blog.csdn.net/qq_33259323/article/details/109020642

    https://www.bilibili.com/read/cv7922942

    5.中移4G模块-ML302-OpenCpu开发-MCP23017输入/输出

    https://blog.csdn.net/qq_33259323/article/details/109109136

    https://www.bilibili.com/read/cv7969395

    7.中移4G模块-ML302-OpenCpu开发-PCF8591测量电压

    https://blog.csdn.net/qq_33259323/article/details/109109266

    https://www.bilibili.com/read/cv7969365

    8.中移4G模块-ML302-OpenCpu开发-GPIO

    https://blog.csdn.net/qq_33259323/article/details/108960947

    https://www.bilibili.com/read/cv7877192

    9.中移4G模块-ML302-OpenCpu开发-ADC

    https://blog.csdn.net/qq_33259323/article/details/109020864

    https://www.bilibili.com/read/cv7922958

    10.中移4G模块-ML302-OpenCpu开发-CJSON

    https://blog.csdn.net/qq_33259323/article/details/109020898

    https://www.bilibili.com/read/cv7923020

    11.中移4G模块-ML302-OpenCpu开发-HTTP

    https://blog.csdn.net/qq_33259323/article/details/109020904

    https://www.bilibili.com/read/cv7923054

    中移4G模块-ML302-OpenCpu开发-51单片机串口转I2C

    因为ML302模块的I2C口是3.3v,其他设备的I2C都是上拉5V,然后我用PCA9306模块进行电平转换,但是发现还是不行,所以我准备使用51单片机串口转I2c。我使用的是STC15W408AS单片机,有个启动标志P1.1。

    ML302发送数据格式:10 90 43 00 0d   

    10:写数据标识符       90:I2C地址         43:地址         00:数据          0d:结束符

    ML302读取格式:11 90 43 0D

    11:读数据标识符       90:I2C地址         43:地址         0D:结束符

    ML302接收格式:90 ff

    90:I2C地址  ff数据

    #define	RX1_Lenth	60
    #include	"STC15Fxxxx.H"
    #include <stdio.h>
    #include <string.h>
    
    char xdata RX1_Buffer[RX1_Lenth];	
    int	TX1_Cnt=0;	
    int	RX1_Cnt=0;	
    bit	B_TX1_Busy=0;
    bit	B_RX1_Busy=0;
    
    unsigned char result_iic_address;
    
    
    
    
    //----------------IIC
    
    int IIC_RESULT = -1;
    unsigned char * IIC_RESULT_DATA;
    
    #define I2C_DELAY_TIME 5
    
    sbit I2C_SCL = P3^4;
    sbit I2C_SDA = P3^5;
    sbit I2C_START = P1^1;
    sbit I2C_ST = P1^0;
    
    void I2C_Send_Start();
    void I2C_Send_Stop();
    bit I2C_Get_Ack_From_Slave();
    bit I2C_Write_Byte(unsigned char Data);
    bit I2C_Read_Byte(unsigned char* recv);
    bit I2C_Sync_The_Clock_T0();
    void I2C_Delay();
    
    void sendLen(char * sendData,int length);
    void sendbit(unsigned char d);
    
    
    
    
    
    //--------------------------------------------------------------------------------------   
    //  函数名称:void I2C_Send_Start() 
    //  函数功能:IIC开始信号  
    //--------------------------------------------------------------------------------------   
    void I2C_Send_Start()
    {
        I2C_SCL = 1; 					//总线复位
        I2C_SDA = 1; 
    
        I2C_Delay(); 
    
        I2C_SDA = 0; 					//产生开始信号
        I2C_Delay(); 
    
        I2C_SCL = 0; 
        I2C_Delay();
    
        return;
    }
    //--------------------------------------------------------------------------------------   
    //  函数名称:void I2C_Send_Stop()
    //  函数功能:IIC停止信号  
    //--------------------------------------------------------------------------------------   
    void I2C_Send_Stop()
    {
    
        I2C_SDA = 0; 
        I2C_Delay(); 
    
        I2C_SCL = 1;  
        I2C_Delay();
     
        I2C_SDA = 1;  
    
        return;
    }
    //--------------------------------------------------------------------------------------   
    //  函数名称:bit I2C_Get_Ack_From_Slave()
    //  函数功能:IIC等待从设备的ACK信号
    //	说明:这里使用主从通信协议,CPU是主设备 
    //--------------------------------------------------------------------------------------   
    bit I2C_Get_Ack_From_Slave()
    {
        bit ack;
    
        I2C_SDA = 1; 					//总线复位
        I2C_SCL = 1;
    
        if(!I2C_Sync_The_Clock_T0())
        {
            return (bit)0; 				//'同步'错误
        }
    
        I2C_Delay(); 					//同步时钟
    
        ack = I2C_SDA;        
    
        I2C_SCL = 0; 					//产生一个时钟
     
        if (ack)
            return (bit)0;
        else
            return (bit)1;     			//从设备发送了ACK信号
    }
    //--------------------------------------------------------------------------------------   
    //  函数名称:bit I2C_Write_Byte(unsigned char Data)
    //  函数功能:IIC向从设备写一个字节的数据
    //--------------------------------------------------------------------------------------   
    bit I2C_Write_Byte(unsigned char Data)
    {
        unsigned char Bit = 0;  
    
        for (Bit = 0; Bit < 8; Bit++ )		//发送一个字节数据,MSB先发送
        {
            I2C_SDA = (bit)(Data & 0x80);
            I2C_SCL = 1;  
                          
            if (!I2C_Sync_The_Clock_T0())
            {
                return (bit)0; 				//同步失败
            }
    
            I2C_Delay(); 
            I2C_SCL = 0;                     
    
            Data = Data << 1;               //准备发送下一个bit     
        }
        return (I2C_Get_Ack_From_Slave());	//确保从设备发送了ACK信号
    }
    //--------------------------------------------------------------------------------------   
    //  函数名称:bit I2C_Read_Byte(unsigned char* recv)
    //  函数功能:IIC从从设备读一个字节的数据
    //--------------------------------------------------------------------------------------   
    bit I2C_Read_Byte(unsigned char* recv)
    {
        unsigned char result  = 0;  
        unsigned char Bit = 0;  
    
        for (Bit = 0; Bit < 8; Bit++ )
        {
            I2C_SDA = 1;           			//释放SDA
            I2C_SCL = 1;           			//释放SCL
    
            if (!I2C_Sync_The_Clock_T0())
            {
               return (bit)0; 				//同步失败
            }
    
            result = result<< 1;      		
    
            if (I2C_SDA)					//如果I2C_SDA线是1,则result用自增1的方式将LSB置1
            {								//如果I2C_SDA线是0,则保持resultLSB的0
                result++;  
            }
    
            I2C_SCL = 0;             
        }
    
        (*recv) = result;
    		
    		//printf("data: %d \r\n",(*recv));
    		
    		//返回格式	地址+数据
    		sendbit(result_iic_address);
    		sendbit(result);
    
        return (bit)1;
    }
    //--------------------------------------------------------------------------------------   
    //  函数名称:bit I2C_Sync_The_Clock_T0()
    //  函数功能:IIC传输同步
    //--------------------------------------------------------------------------------------   
    bit I2C_Sync_The_Clock_T0()
    {
        unsigned int delay = 0xffff;
    
        while ((!I2C_SCL) && delay)			//试图同步时钟
            delay--;
    
        if (!delay)
            return (bit)0;  				//同步超时
    
        return (bit)1;  					//同步成功
    }
    //--------------------------------------------------------------------------------------   
    //  函数名称:void I2C_Delay()
    //  函数功能:IIC短暂的软件延时
    //	说明:对于标准IIC设备,最短延时5.425us,对于最新的IIC设备,或许可以缩短此延时
    //--------------------------------------------------------------------------------------   
    void I2C_Delay()
    {
        char x = I2C_DELAY_TIME;
    
        while(x--);
    
        return;
    }
    
    
    int IIC_WRITE_DATA(unsigned char driver_address,unsigned char data_address,unsigned char content){
    	I2C_Send_Start();
    	if(!I2C_Write_Byte(driver_address)){
    		return 0;
    	}
    	if(!I2C_Write_Byte(data_address)){
    		return 0;
    	}
    	if(!I2C_Write_Byte(content)){
    		return 0;
    	}
    	I2C_Send_Stop();
    	
    	return 1;
    }
    
    
    
    int IIC_READ_DATA(unsigned char driver_address,unsigned char data_address,unsigned char* recv){
    	int result = 0;
    	I2C_Send_Start();
    	result_iic_address = driver_address;
    	if(!I2C_Write_Byte(driver_address)){
    		return 0;
    	}
    	if(!I2C_Write_Byte(data_address)){
    		return 0;
    	}
    	I2C_Send_Stop();
    	
    	I2C_Send_Start();
    	if(!I2C_Write_Byte(driver_address | 0x01)){
    		return 0;
    	}
    	result = I2C_Read_Byte(recv);
    	I2C_Send_Stop();
    	
    	return result;
    }
    
    //----------------IIC
    
    
    
    void UartInit(void){
    				SCON = 0x50;		
    				AUXR |= 0x01;		
    				AUXR |= 0x04;	
    				T2L = 0xE8;		
    				T2H = 0xFF;		
    				AUXR |= 0x10;		
    	
    				ES=1; 
    				EA=1; 
    				TI=1;
    }
    
    void delay(unsigned int xms){
        unsigned int x,y;
        for(x=xms;x>0;x--)
            for(y=110;y>0;y--);
    }
    
    void sendLen(char * sendData,int length){
    	int i=0;
    	for(i=0;i<length;i++){
    		while(1){
    			if(!B_TX1_Busy){
    				B_TX1_Busy = 1;
    				SBUF = sendData[i];
    				break;
    			}
    		}
    	}
    }
    
    void sendbit(unsigned char d){
    	while(1){
    			if(!B_TX1_Busy){
    				B_TX1_Busy = 1;
    				SBUF = d;
    				break;
    			}
    		}
    }
    
    void get(){
    	memset(RX1_Buffer,0,RX1_Lenth);
    	while(1){
    		if(B_RX1_Busy == 1){
    			B_RX1_Busy = 0;
    			break;
    		}
    	}
    }
    
    
    
    
    void main(void){
    	  
    		UartInit();
    	
    		I2C_ST = 0;
    		if(I2C_START == 1){
    			delay(100);
    			if(I2C_START == 0){
    				I2C_ST = 1;
    				while(1){
    					get();
    					if(RX1_Buffer[0] == 0x10){
    						if(IIC_WRITE_DATA(RX1_Buffer[1],RX1_Buffer[2],RX1_Buffer[3]) == 0){
    							I2C_ST=0x00;
    							sendLen("ok2",3);
    						}else{
    							I2C_ST=0xFF;
    							sendLen("ok3",3);
    						}
    						//sendLen("ok1",3);
    						//sendLen(RX1_Buffer,4);
    					}else if(RX1_Buffer[0] == 0x11){
    						if(IIC_READ_DATA(RX1_Buffer[1],RX1_Buffer[2],IIC_RESULT_DATA) == 0){
    							I2C_ST=0x00;
    						}else{
    							I2C_ST=0xFF;
    						}
    					}else{
    						sendLen("error",5);
    						sendLen(RX1_Buffer,5);
    					}
    					memset(RX1_Buffer,0,RX1_Lenth);
    				}
    			}
    		}
    }
    
    void UART1_int (void) interrupt UART1_VECTOR
    {
    	if(RI){
    		RI = 0;
    		RX1_Buffer[RX1_Cnt] = SBUF;	
    		
    		if(RX1_Buffer[RX1_Cnt] == 0x0D){
    			RX1_Cnt = 0;
    			B_RX1_Busy = 1;
    		}else{
    			RX1_Cnt++;
    		}
    	}
    
    	if(TI){
    		TI = 0;
    		B_TX1_Busy = 0;
    	}
    }

     

    展开全文
  • 谁可以帮我看看下面的代码,使用串口转I2C实现数据的收发总是出现丢数据的现象,里面的函数调用基本上是使用库函数,我是使用神舟王STM32F207ZGT的开发板,根据里面的例程65EEPROM读写程序来改写的。 通过串口1中断...
  • 我在网上看到有一个产品可以做到串口转I2C的,但是太贵了要几百块钱,一般I2C控制的芯片都不会超过十块钱,一个转换器就要那么贵,不值得啊,不知道大家知不知道有关方法或者芯片能做到电脑串口转I2C啊(在不适用MCU...
  • 利用STM8S003做的 I2C转串口,iic收到的数据利用STM8的串口转发出去
  • i2c转串口驱动移植

    2021-03-08 17:37:55
    i2c转串口驱动移植欢迎使用Markdown编辑器新的改变思路与使用方式合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左...

    硬件相关

    传输协议

    P1,P0:为器件地址,这个由芯片引脚IA1、IA0控制。C1,CO:子串口通道号,00~11分别对应子串口1到子串口4。A3,A2,A1,A0:子串口寄存器地址。
    在这里插入图片描述

    驱动实现

    设备树节点

    设备树是现行的linux驱动与设备匹配体系,设备树文件在arch\arm64\boot\dts文件夹下,我这里需要匹配的就是i2c设备节点。

        i2c_3: i2c@0x9801B900 {
            compatible = "socname,soc-i2c";
            reg = <0x9801B900 0x400>;
            interrupt-parent = <&mux_intc>;
            interrupts = <0 23>;
            i2c-num = <3>;
            status = "okay";
            #address-cells = <1>;
            #size-cells = <0>;
            wkxxxx {
                compatible = "company,wkxxxx";
                reg = <0x70>;
                irq_gpio = <&rtk_misc_gpio 15 0 0>;/*igpio15, intput, default low*/
            };
        };
    

    compatible属性是设备与驱动匹配的核心,reg是用到的寄存器资源,wkxxxx的reg与i2c总线上的设备地址有关,有些硬件手册给出的设备地址是加上读写位的8位地址,设备树这里的话就需要转换为7位地址,irq_gpio是申请的中断引脚资源。

    驱动加载与卸载

    static int __init wk2xxx_init(void)
    {
            int retval;
            retval = i2c_add_driver(&wk2xxx_i2c_driver);
            printk(KERN_ALERT "rgister i2c_driver return v = :%d\n",retval);
            return retval;
    }
    
    static void __exit wk2xxx_exit(void)
    {
            printk(KERN_ERR "%s, wk2xxx_i2c_driver:quit\n", __func__);
    	    return i2c_del_driver(&wk2xxx_i2c_driver);
    }
    
    module_init(wk2xxx_init);
    module_exit(wk2xxx_exit);
    
    MODULE_AUTHOR("WKMIC Ltd");
    MODULE_DESCRIPTION("wk2xxx generic serial port driver");
    MODULE_LICENSE("GPL");
    

    驱动匹配

    linux为了规范化代码,设计了将驱动和设备分开存放的模式,并提供了匹配机制,系统会对比驱动和设备的compatible属性进行匹配,匹配成功则会调用probe函数根据设备树存储的硬件信息进行驱动初始化。

    static const struct i2c_device_id wk2xxx_i2c_id_table[]={
      {"wkxxxx_i2c",0},
      {}
     };
    static struct of_device_id wk2xxx_i2c_dt_ids[] = {
    	{.compatible = "company,wkxxxx", },
    	{}
    };
    MODULE_DEVICE_TABLE(of, wk2xxx_i2c_dt_ids);
    static struct i2c_driver wk2xxx_i2c_driver = {
    	.driver = {
    		.name       = "wkxxxx_i2c",
    		.owner      = THIS_MODULE,
    		.of_match_table = of_match_ptr(wk2xxx_i2c_dt_ids),
    	},
    	.probe          = wk2xxx_probe,
    	.remove         = wk2xxx_remove,
    	.id_table       = wk2xxx_i2c_id_table,
    };
    

    驱动功能初始化与注销

    static int wk2xxx_probe(struct i2c_client *client,const struct i2c_device_id *dev_id)
    {
        uint8_t i;
        int status, irq;
        uint8_t dat[1];
    	irq = rockchip_i2c_parse_dt(&client->dev);  //申请中断
    	if(irq<0)
    	{
    		return 1;
    	}
        	wk2xxx_read_global_reg(client,WK2XXX_GENA,dat);
        	if((dat[0]&0xf0)!=0xb0)
            { 
              printk(KERN_ALERT "wk2xxx_probe()  GENA = 0x%X\n",dat[0]);
              printk(KERN_ERR "i2c driver error!!!!\n");
              return 1;
            }
        	mutex_lock(&wk2xxxs_lock);
        	if(!uart_driver_registered)
        	{
            	    uart_driver_registered = 1;
            	    status = uart_register_driver(&wk2xxx_uart_driver);  //注册串口驱动
            	if (status)
            	{
                 	printk(KERN_ERR "Couldn't register wk2xxx uart driver\n");
                	mutex_unlock(&wk2xxxs_lock);
                	return status;
            	}
        	}
    
        	for(i =0;i<NR_PORTS;i++)
        	{
            	    struct wk2xxx_port *s = &wk2xxxs[i];//container_of(port,struct wk2xxx_port,port);
            	    s->tx_done       =0;
            	    s->wk2xxx_i2c_client        = client;
    			    s->port.line     = i;
    				s->port.ops      = &wk2xxx_pops;
    				s->port.uartclk  = WK_CRASTAL_CLK;
    				s->port.fifosize = 256;
    				s->port.iobase   = i+1;
    				s->port.irq      = irq;
    				s->port.iotype   = SERIAL_IO_PORT;
    				s->port.flags    = ASYNC_BOOT_AUTOCONF;
    		        status = uart_add_one_port(&wk2xxx_uart_driver, &s->port);
           		if(status<0)
              	{
                      printk(KERN_ALERT "uart_add_one_port failed for line i:= %d with error %d\n",i,status);
    		          mutex_unlock(&wk2xxxs_lock);
    		          return status;
               	}
        	}
        	mutex_unlock(&wk2xxxs_lock);
        	return status;
    }
    
    static int wk2xxx_remove(struct i2c_client *i2c_client)
    {
    
        	int i;
        	mutex_lock(&wk2xxxs_lock);
        	for(i =0;i<NR_PORTS;i++)
           	{
            	struct wk2xxx_port *s = &wk2xxxs[i];
            	uart_remove_one_port(&wk2xxx_uart_driver, &s->port);
           	}
        	printk( KERN_ERR"removing wk2xxx driver\n");
        	uart_unregister_driver(&wk2xxx_uart_driver);
        	mutex_unlock(&wk2xxxs_lock);
        	return 0;
    }
    

    内核提供的打包串口功能的结构体

    在probe函数执行的过程中,打包串口功能实现指针的结构体被加载进内核。

    static struct uart_ops wk2xxx_pops = {
            tx_empty:       wk2xxx_tx_empty,
            set_mctrl:      wk2xxx_set_mctrl,
            get_mctrl:      wk2xxx_get_mctrl,
            stop_tx:        wk2xxx_stop_tx,
            start_tx:       wk2xxx_start_tx,
            stop_rx:        wk2xxx_stop_rx,
            enable_ms:      wk2xxx_enable_ms,
            break_ctl:      wk2xxx_break_ctl,
            startup:        wk2xxx_startup,
            shutdown:       wk2xxx_shutdown,
            set_termios:    wk2xxx_termios,
            type:           wk2xxx_type,
            release_port:   wk2xxx_release_port,
            request_port:   wk2xxx_request_port,
            config_port:    wk2xxx_config_port,
            verify_port:    wk2xxx_verify_port,
    };
    static struct uart_driver wk2xxx_uart_driver = {
            owner:                  THIS_MODULE,
            major:               SERIAL_WK2XXX_MAJOR,
            driver_name:            "ttySWK",
            dev_name:               "ttysWK",
            minor:                  MINOR_START,
            nr:                     NR_PORTS,
            cons:                   NULL
    };
    

    申请中断

    static int rockchip_i2c_parse_dt(struct device *dev)
    {
    	int irq_gpio, irq_flags, irq;
    	//从设备树获取IRQ——GPIO
    	irq_gpio = of_get_named_gpio_flags(dev->of_node, "irq_gpio", 0,(enum of_gpio_flags *)&irq_flags);
    
        if (!gpio_is_valid(irq_gpio))
        	{
    			printk(KERN_ERR"invalid wk2xxx_irq_gpio: %d\n", irq_gpio);
    			return -1;
        	}
        if(gpio_request(irq_gpio, "gpio15"))
            {
                printk(KERN_ERR"gpio_request gpio15 failed!\n");
                return -1;
            }
       
        irq = gpio_to_irq(irq_gpio);
        if(!irq)
        	{
    		printk(KERN_ERR"wk2xxx_irqGPIO: %d get irq failed!\n", irq);
    		return -1;
        	}
    	printk(KERN_ERR"wk2xxx_irq_gpio: %d, irq: %d", irq_gpio, irq);
    	return irq;
    }
    

    i2c操作函数

    /*
    * This function write wk2xxx of Global register:
    */
    static int wk2xxx_write_global_reg(struct i2c_client *client,uint8_t greg,uint8_t dat)
    {
            struct i2c_msg msg;
            uint8_t cmd_addr,wk_addr = 0;
            uint8_t status = 0;
            uint8_t wk_buf[2];
            cmd_addr=(((client->addr)<<1)|(greg&0x30)>>2)>>1;  //根据硬件手册的指令协议
            mutex_lock(&wk2xxxs_reg_lock);
            wk_buf[0] = greg&0x0f;
            wk_buf[1] = dat;
            msg.addr = cmd_addr;
            msg.flags = 0;
            msg.len = 2;
            msg.buf = wk_buf;
            if (i2c_transfer(client->adapter, &msg, 1) < 0) {
                printk(KERN_ALERT "wk2xxx_write_global_reg1(i2c) w_error!\n");
                status = 1;
                mutex_unlock(&wk2xxxs_reg_lock);
                return status;
            }
            mutex_unlock(&wk2xxxs_reg_lock);
            return status;
    }
    /*
    * This function read wk2xxx of slave register:
    */
    static int wk2xxx_read_slave_reg(struct i2c_client *client,uint8_t port,uint8_t sreg,uint8_t *dat)
    {        struct i2c_msg msg[2];
             uint8_t cmd_addr,wk_addr = 0;
             uint8_t ret, status = 0;
             uint8_t wk_reg[1],wk_dat[1];
             cmd_addr=(((client->addr)<<1)|(port-1)<<2)>>1;
             mutex_lock(&wk2xxxs_reg_lock);
             /***********************************************/
             wk_reg[0] = sreg&0x0f;
             msg[0].addr = cmd_addr;
             msg[0].flags = 0;
             msg[0].len = 1;
             msg[0].buf = wk_reg;
             if (i2c_transfer(client->adapter, &msg[0], 1) < 0) {
                  printk(KERN_ALERT "wk2xxx_read_slave_reg1(i2c) w_error!\n");
                  status = 1;
                  mutex_unlock(&wk2xxxs_reg_lock);
                  return status;
             }
    
             /**********************************************/
             msg[1].addr = cmd_addr;
             msg[1].flags = I2C_M_RD;
             msg[1].len = 1;
             msg[1].buf = wk_dat;
             ret=i2c_transfer(client->adapter, &msg[1], 1);
             if(ret!=1){
                 printk(KERN_ALERT "wk2xxx_read_slave_reg2(i2c) w_error!\n");
                 *dat=0x0;
                 status = 1;
                 mutex_unlock(&wk2xxxs_reg_lock);
                 return status;
             }
             *dat=wk_dat[0];
             mutex_unlock(&wk2xxxs_reg_lock);
             return status;
    
    }
    /*
    * This function write wk2xxx of Slave register:
    */
    static int wk2xxx_write_slave_reg(struct i2c_client *client,uint8_t port,uint8_t sreg,uint8_t dat)
    {
            struct i2c_msg msg;
            uint8_t cmd_addr,wk_addr = 0;
            uint8_t status = 0;
            uint8_t wk_buf[2];
            cmd_addr=(((client->addr)<<1)|(port-1)<<2)>>1;
            mutex_lock(&wk2xxxs_reg_lock);
            wk_buf[0] = sreg&0x0f;
            wk_buf[1] = dat;
            msg.addr = cmd_addr;
            msg.flags = 0;
            msg.len = 2;
            msg.buf = wk_buf;
            if (i2c_transfer(client->adapter, &msg, 1) < 0) {
                printk(KERN_ALERT "wk2xxx_write_slave_reg1(i2c) w_error!\n");
                status = 1;
                mutex_unlock(&wk2xxxs_reg_lock);
                return status;
            }
            mutex_unlock(&wk2xxxs_reg_lock);
            return status;
    }
    
    #define MAX_RFCOUNT_SIZE 256
    
    /*
    * This function read wk2xxx of fifo:
    */
    static int wk2xxx_read_fifo(struct i2c_client *client,uint8_t port,uint8_t fifolen,uint8_t *dat)
    {
            struct i2c_msg msg;
            uint8_t cmd_addr,wk_addr = 0;
            wk_addr = 0x03;
            int i, status = 0;
            uint8_t fifo_data[256] = {0};
            cmd_addr = (((client->addr)<<1)|(port-1)<<2|0x03) >> 1;
    	    if(!(fifolen>0)){
    			printk(KERN_ERR "%s,read fifolen error!!\n", __func__);
    			return 1;
    		 }
            mutex_lock(&wk2xxxs_reg_lock);
            msg.addr = cmd_addr;
            msg.flags = I2C_M_RD;
            msg.len = fifolen;
            msg.buf = fifo_data;
            if (i2c_transfer(client->adapter, &msg, 1) < 0) {
                printk(KERN_ALERT " wk2xxx_read_fifo1(i2c) w_error!\n");
                status = 1;
                mutex_unlock(&wk2xxxs_reg_lock);
                return status;
            }
            for (i = 0; i < fifolen; i++)
            	*(dat + i) = fifo_data[i];
            mutex_unlock(&wk2xxxs_reg_lock);
            return status;
            
    }
    /*
    * This function write wk2xxx of fifo:
    */
    static int wk2xxx_write_fifo(struct i2c_client *client,uint8_t port,uint8_t fifolen,uint8_t *dat)
    {
            struct i2c_msg msg;
            uint8_t cmd_addr,wk_addr = 0;
            int i, status = 0;
            uint8_t fifo_data[256] = {0};
            cmd_addr = (((client->addr)<<1)|(port-1)<<2|0x02) >> 1;
    	    if(!(fifolen>0)){
    			printk(KERN_ERR "%s,wrire fifolen error!!\n", __func__);
    			return 1;
    		  }
    	    for (i = 0; i < fifolen; i++)
    		    fifo_data[i] = *(dat + i);
    
            mutex_lock(&wk2xxxs_reg_lock);
            msg.addr = cmd_addr;
            msg.flags = 0;
            msg.len = fifolen;
            msg.buf = fifo_data;
            if (i2c_transfer(client->adapter, &msg, 1) < 0) {
                printk(KERN_ALERT " wk2xxx_write_fifo1(i2c) w_error!\n");
                status = 1;
                mutex_unlock(&wk2xxxs_reg_lock);
                return status;
            }
            mutex_unlock(&wk2xxxs_reg_lock);
            return status;
            
    }
    

    串口工作函数

    struct wk2xxx_port 
    {
        //struct timer_list mytimer;
        struct uart_port port;//[NR_PORTS];
        struct i2c_client *wk2xxx_i2c_client;
        spinlock_t conf_lock;   /* shared data */
        struct workqueue_struct *workqueue;
        struct work_struct work;
        int suspending;
        void (*wk2xxx_hw_suspend) (int suspend);
        int tx_done;
    
        int force_end_work;
        int irq;
        int minor;      /* minor number */
        int tx_empty; 
        int tx_empty_flag;
    
        int start_tx_flag;
        int stop_tx_flag;
        int stop_rx_flag; 
        int irq_flag;
        int conf_flag;
    
        int tx_empty_fail;
        int start_tx_fail;
        int stop_tx_fail;
        int stop_rx_fail;
        int irq_fail;
        int conf_fail;
    
        uint8_t new_lcr;
    	uint8_t new_fwcr;
        uint8_t new_scr; 
        /*set baud 0f register*/
        uint8_t new_baud1;
        uint8_t new_baud0;
        uint8_t new_pres;
    };
    
    static int wk2xxx_dowork(struct wk2xxx_port *s)
    {    
        if (!s->force_end_work && !work_pending(&s->work) && !freezing(current) && !s->suspending)
        {
            queue_work(s->workqueue, &s->work);//
            #ifdef _DEBUG_WK2XXX
            printk( "--queue_work---ok---\n");
         // printk("work_pending =: %d s->force_end_work  = : %d freezing(current) = :%d s->suspending= :%d\n" ,work_pending(&s->work),s->force_end_work ,freezing(current),s->suspending);
            #endif
            return 1;   
        }
        else
        {
          	#ifdef _DEBUG_WK2XXX
          	printk( "--queue_work---error---\n");
          	#endif
          	return 0;
        }
    
    }
    
    static void wk2xxx_work(struct work_struct *w)
    {  
        struct wk2xxx_port *s = container_of(w, struct wk2xxx_port, work);
        uint8_t rx;
        int work_start_tx_flag; 
        int work_stop_rx_flag;
        int work_irq_flag;
        //int work_conf_flag;
    
        do {
                 mutex_lock(&wk2xxs_work_lock);
         
                 work_start_tx_flag = s->start_tx_flag;
                 if(work_start_tx_flag)
                     s->start_tx_flag = 0;
         
                 work_stop_rx_flag = s->stop_rx_flag;
                 if(work_stop_rx_flag)
                    s->stop_rx_flag = 0;
    
                 //work_conf_flag = s->conf_flag;
                 //if( work_conf_flag)
                 //   s->conf_flag = 0;
    
                 work_irq_flag = s->irq_flag;
                 if(work_irq_flag)
                    s->irq_flag = 0;
                 mutex_unlock(&wk2xxs_work_lock);
             
                 if(work_start_tx_flag)
                 {
                     wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIER,&rx);
                     rx |= WK2XXX_TFTRIG_IEN|WK2XXX_RFTRIG_IEN|WK2XXX_RXOUT_IEN;
                     wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIER,rx);
                 }
         
                 if(work_stop_rx_flag)
                 {
                     wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIER,&rx);
                     rx &=~WK2XXX_RFTRIG_IEN;
                     rx &=~WK2XXX_RXOUT_IEN;
                    wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIER,rx);
                 }
         
                 if(work_irq_flag)
                 {
                     wk2xxxirq_app(&s->port);
                     s->irq_fail = 1;
                 }
    
            }while (!s->force_end_work && !freezing(current) && \
            (work_irq_flag || work_stop_rx_flag ));
    
    
            if(s->start_tx_fail)
            {
                wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIER,&rx);
                rx |= WK2XXX_TFTRIG_IEN|WK2XXX_RFTRIG_IEN|WK2XXX_RXOUT_IEN;
                wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIER,rx);
            	s->start_tx_fail =0;
            }
            
            
           if(s->stop_rx_fail)
            {
                wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIER,&rx);
                rx &=~WK2XXX_RFTRIG_IEN;
                rx &=~WK2XXX_RXOUT_IEN;
                wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIER,rx);
                s->stop_rx_fail =0;
            }
            if(s->irq_fail)
            {
                s->irq_fail = 0;
                enable_irq(s->port.irq);
            }
    }
    
    
    static void wk2xxx_rx_chars(struct uart_port *port)
    {
        struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port);
        uint8_t fsr,lsr,dat[1],rx_dat[256]={0};
        unsigned int ch,flg,sifr, ignored=0,status = 0,rx_count=0;
        int rfcnt=0,rfcnt2=0,rx_num=0;
    
        wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SPAGE,WK2XXX_PAGE0);//set register in page0
        wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_FSR,dat);
        fsr = dat[0];
        wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_LSR,dat);
        lsr = dat[0];
        wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIFR,dat);
        sifr=dat[0];
    
    if(!(sifr&0x80))//no error
    {  
      flg = TTY_NORMAL;
      if (fsr& WK2XXX_RDAT)
      {
        wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_RFCNT,dat);
        rfcnt=dat[0];
    		wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_RFCNT,dat);
        rfcnt2=dat[0];
    		
    		if(!(rfcnt2>=rfcnt))
    		{rfcnt=rfcnt2;}
    		
    		rfcnt=(rfcnt==0)?255:rfcnt;	
    
    #if 1
        wk2xxx_read_fifo(s->wk2xxx_i2c_client,s->port.iobase, rfcnt,rx_dat);
    #else
    	  for(rx_num=0;rx_num<rfcnt;rx_num++)
    		 {
    		   wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_FDAT,dat);
    		   rx_dat[rx_num]=dat[0];
    		 }
    #endif
    
        s->port.icount.rx+=rfcnt;
        for(rx_num=0;rx_num<rfcnt;rx_num++)
        {
            if (uart_handle_sysrq_char(&s->port,rx_dat[rx_num]))//.state, ch))
               break;//
                   
     #ifdef _DEBUG_WK2XXX5
            printk(KERN_ALERT "rx_chars:0x%x----\n",rx_dat[rx_num]);
    #endif
             uart_insert_char(&s->port, status, WK2XXX_STATUS_OE, rx_dat[rx_num], flg);
             rx_count++;
             if ((rx_count >= 64 ) && (s->port.state->port.tty->port != NULL))
               {
                  tty_flip_buffer_push(s->port.state->port.tty->port);
                  rx_count = 0;
               }
        }//for
     if((rx_count > 0)&&(s->port.state->port.tty->port!= NULL))
      {
      #ifdef _DEBUG_WK2XXX
           printk(KERN_ALERT  "push buffer tty flip port = :%lx count =:%d\n",s->port.iobase,rx_count);
      #endif
             tty_flip_buffer_push(s->port.state->port.tty->port);
             rx_count = 0;
      }
    
      }
    }//ifm
    else//error
    {
        while (fsr& WK2XXX_RDAT)/**/
            {
                wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_FDAT,dat);
                ch = (int)dat[0];
    
    #ifdef _DEBUG_WK2XXX
            printk(KERN_ALERT "wk2xxx_rx_chars()----port:%lx--RXDAT:0x%x----\n",s->port.iobase,ch);
    #endif
    
            s->port.icount.rx++;
            flg = TTY_NORMAL;
            if (lsr&(WK2XXX_OE |WK2XXX_FE|WK2XXX_PE|WK2XXX_BI))
                    {
                   printk(KERN_ALERT "wk2xxx_rx_chars()----port:%lx error,lsr:%x!!!!!!!!!!!!!!!!!\n",s->port.iobase,lsr);
                            //goto handle_error;
                if (lsr & WK2XXX_PE)
                    {
                            s->port.icount.parity++;
                            status |= WK2XXX_STATUS_PE;
                            flg = TTY_PARITY;
                    }
                    if (lsr & WK2XXX_FE)
                    {
                            s->port.icount.frame++;
                            status |= WK2XXX_STATUS_FE;
                            flg = TTY_FRAME;
                    }
                    if (lsr & WK2XXX_OE)
                    {
                            s->port.icount.overrun++;
                            status |= WK2XXX_STATUS_OE;
                            flg = TTY_OVERRUN;
                    }
                    if(lsr&fsr & WK2XXX_BI)
                    {
                            s->port.icount.brk++;
                            status |= WK2XXX_STATUS_BRK;
                            flg = TTY_BREAK;
                    }
                    
                    if (++ignored > 100) 
                           goto out;
                    
                     goto ignore_char;       
        }
    
    error_return:
        if (uart_handle_sysrq_char(&s->port,ch))//.state, ch))
            goto ignore_char;
            
            uart_insert_char(&s->port, status, WK2XXX_STATUS_OE, ch, flg);
            rx_count++;
            
            if ((rx_count >= 64 ) && (s->port.state->port.tty->port != NULL)) 
            {
             tty_flip_buffer_push(s->port.state->port.tty->port);
             rx_count = 0;
            } 
            
    ignore_char:
                wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_FSR,dat);
                fsr = dat[0];
                wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_LSR,dat);
                lsr = dat[0];
            }
    out:
    	if((rx_count > 0)&&(s->port.state->port.tty->port != NULL))
    {
    #ifdef _DEBUG_WK2XXX1
            printk(KERN_ALERT  "push buffer tty flip port = :%lx count = :%d\n",s->port.iobase,rx_count);
    #endif
            tty_flip_buffer_push(s->port.state->port.tty->port);
            rx_count = 0;
    }
    
    }//if()else
    
          	return;
    #ifdef SUPPORT_SYSRQ
            s->port.state->sysrq = 0;
    #endif
            goto error_return;
    }
    
    static void wk2xxx_tx_chars(struct uart_port *port)
    {
        	struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port);
        	uint8_t fsr,tfcnt,dat[1],txbuf[256]={0};
        	int count,tx_count,i;
    
            if (s->port.x_char) 
            {   
                wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_FDAT,s->port.x_char);
                s->port.icount.tx++;
                s->port.x_char = 0;
                goto out;
            }
    
            if(uart_circ_empty(&s->port.state->xmit) || uart_tx_stopped(&s->port))
            {
                goto out;
            }
        	wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_FSR,dat);
        	fsr = dat[0];
    
        	wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_TFCNT,dat); 
        	tfcnt= dat[0];
    #ifdef _DEBUG_WK2XXX
    printk(KERN_ALERT "wk2xxx_tx_chars   fsr:0x%x,rfcnt:0x%x,port = %lx\n",fsr,tfcnt,s->port.iobase);
    #endif
        	if(tfcnt==0)
        	{
    	         tx_count=(fsr & WK2XXX_TFULL)?0:255;
    		#ifdef _DEBUG_WK2XXX
            printk(KERN_ALERT "wk2xxx_tx_chars2   tx_count:%x,port = %lx\n",tx_count,s->port.iobase);
    		#endif 
        	}
        	else
        	{
    		    tx_count=255-tfcnt;
    		#ifdef _DEBUG_WK2XXX
            printk(KERN_ALERT "wk2xxx_tx_chars2   tx_count:%x,port = %lx\n",tx_count,s->port.iobase);
    		#endif 
        	}
    
    #ifdef _DEBUG_WK2XXX
        printk(KERN_ALERT "fsr:%x\n",fsr);
    #endif
       
    
    	count = tx_count;
    	i=0;
    	do
    	{
      		if(uart_circ_empty(&s->port.state->xmit))
         			break;
    	   	txbuf[i]=s->port.state->xmit.buf[s->port.state->xmit.tail];
    	   	s->port.state->xmit.tail = (s->port.state->xmit.tail + 1) & (UART_XMIT_SIZE - 1);
    	   	s->port.icount.tx++;
    	   	i++;
    #ifdef _DEBUG_WK2XXX
            printk(KERN_ALERT "tx_chars:0x%x--\n",txbuf[i-1]);
    #endif
       
    }while(--count>0);
    
    
    #if 0
            printk(KERN_ALERT "tx_chars:port:%ld;tx_count:%x-\n",s->port.iobase,i);
    #endif
    
    #if 1
    	    wk2xxx_write_fifo(s->wk2xxx_i2c_client,s->port.iobase,i,txbuf);
    #else
    	for(count=0;count<i;count++)
    	{
       		wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_FDAT,txbuf[count]);	
    	}
    #endif
    
    
        	out:wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_FSR,dat);
              fsr = dat[0];
            if(((fsr&WK2XXX_TDAT)==0)&&((fsr&WK2XXX_TBUSY)==0))
            {
               if (uart_circ_chars_pending(&s->port.state->xmit) < WAKEUP_CHARS)
                   uart_write_wakeup(&s->port); 
    
               if (uart_circ_empty(&s->port.state->xmit))
                {
                   wk2xxx_stop_tx(&s->port);
                }
            }
    
    }
    
    static irqreturn_t wk2xxx_irq(int irq, void *dev_id)//
    {
            struct wk2xxx_port *s = dev_id;
        	disable_irq_nosync(s->port.irq);
    #if 0
            printk( "--wk2xxx_irq---in---\n");
    #endif       
            s->irq_flag = 1;
        	if(wk2xxx_dowork(s))
        	{
        	    ;
        	}
        	else
        	{
            	s->irq_flag = 0;
            	s->irq_fail = 1;    
        	}
    
        	return IRQ_HANDLED;
    }
    
    static void wk2xxxirq_app(struct uart_port *port)//
    {
        struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port);
        unsigned int  pass_counter = 0;
        uint8_t sifr,gifr,sier,dat[1];
    #ifdef _DEBUG_WK2XXX
        printk(KERN_ALERT "wk2xxxirq_app()------port:%lx--------------\n",s->port.iobase);
    #endif		
                
        wk2xxx_read_global_reg(s->wk2xxx_i2c_client,WK2XXX_GIFR ,dat);
        gifr = dat[0];
    #if 0
        wk2xxx_read_global_reg(s->wk2xxx_i2c_client,WK2XXX_GIER ,dat);
        gier = dat[0];
        wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,1,WK2XXX_SIFR,&sifr0);
        wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,2,WK2XXX_SIFR,&sifr1);
        wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,3,WK2XXX_SIFR,&sifr2);
        wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,4,WK2XXX_SIFR,&sifr3);
        wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,1,WK2XXX_SIER,&sier0);
        wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,2,WK2XXX_SIER,&sier1);
        wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,3,WK2XXX_SIER,&sier2);
        wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,4,WK2XXX_SIER,&sier3);
        printk(KERN_ALERT "irq_app....gifr:%x  gier:%x  sier1:%x  sier2:%x sier3:%x sier4:%x   sifr1:%x sifr2:%x sifr3:%x sifr4:%x \n",gifr,gier,sier0,sier1,sier2,sier3,sifr0,sifr1,sifr2,sifr3);
    #endif      
            
            switch(s->port.iobase)
            {
                    case 1 :
                        if(!(gifr & WK2XXX_UT1INT))
                        {
                            return;
                        }
                        break;
                    case 2 :
                        if(!(gifr & WK2XXX_UT2INT))
                        {            
                            return;
                        }                                     
                        break;
                    case 3 :
                        if(!(gifr & WK2XXX_UT3INT))
                        {            
                            return;
                        }
                        break;
                    case 4 :
                        if(!(gifr & WK2XXX_UT4INT))
                        {               
                            return;
                        }
                        break;
                        default:
                        break;                        
            }
            
            wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIFR,dat);
            sifr = dat[0];
            wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIER,dat);
            sier = dat[0];
    
            do {
                    if ((sifr&WK2XXX_RFTRIG_INT)||(sifr&WK2XXX_RXOVT_INT))
                    {
                        wk2xxx_rx_chars(&s->port);
                    }
            
                    if ((sifr & WK2XXX_TFTRIG_INT)&&(sier & WK2XXX_TFTRIG_IEN ))
                    {
                        wk2xxx_tx_chars(&s->port);
                        return;
                    }
                    if (pass_counter++ > WK2XXX_ISR_PASS_LIMIT)
                        break;
                    wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIFR,dat);
                    sifr = dat[0];
                    wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIER,dat);
                    sier = dat[0];
    	} while ((sifr&WK2XXX_RXOVT_INT)||(sifr & WK2XXX_RFTRIG_INT)||((sifr & WK2XXX_TFTRIG_INT)&&(sier & WK2XXX_TFTRIG_IEN)));
            
    }
    
    /*
     *   Return TIOCSER_TEMT when transmitter is not busy.
     */
    
    static u_int wk2xxx_tx_empty(struct uart_port *port)// or query the tx fifo is not empty?
    {
        uint8_t tx;
        struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port);
    #ifdef _DEBUG_WK2XXX
        printk(KERN_ALERT "wk2xxx_tx_empty()---------in---\n");
    #endif
    	mutex_lock(&wk2xxxs_lock);
    	if(!(s->tx_empty_flag || s->tx_empty_fail))
    	{
    	    wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_FSR,&tx);
    	    while((tx & WK2XXX_TDAT)|(tx&WK2XXX_TBUSY))
    	   	{
    	   		wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_FSR,&tx);
    	   	}
        	s->tx_empty = ((tx & WK2XXX_TDAT)|(tx&WK2XXX_TBUSY))<=0;
    		if(s->tx_empty)
    		{
    		    s->tx_empty_flag =0;
    		    s->tx_empty_fail=0;
    		}
    		else
    		{
    		    s->tx_empty_fail=0;
    		    s->tx_empty_flag =0;
    		}
    	}
    	mutex_unlock(&wk2xxxs_lock);
    
        return s->tx_empty;
    }
    
    static void wk2xxx_set_mctrl(struct uart_port *port, u_int mctrl)//nothing
    {
    #ifdef _DEBUG_WK2XXX
        printk(KERN_ALERT "%s!!\n", __func__);
    #endif
    }
    static u_int wk2xxx_get_mctrl(struct uart_port *port)// since no modem control line
    {       
            return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
    }
    
    
    /*
     *  interrupts disabled on entry
     */
    
    static void wk2xxx_stop_tx(struct uart_port *port)//
    {
        uint8_t sier;
    	struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port);
    #ifdef _DEBUG_WK2XXX
    printk(KERN_ALERT "-wk2xxx_stop_tx------in---\n");
    #endif 
        mutex_lock(&wk2xxxs_lock);
        wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIER,&sier);
        sier&=~WK2XXX_TFTRIG_IEN;
        wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIER,sier);
    	mutex_unlock(&wk2xxxs_lock); 
    #ifdef _DEBUG_WK2XXX4
        printk(KERN_ALERT "-wk2xxx_stop_tx------exit---\n");
    #endif
    }
    
    /*
     *  * interrupts may not be disabled on entry
    */
    static void wk2xxx_start_tx(struct uart_port *port)
    {
        
    		struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port);
            if(!(s->start_tx_flag||s->start_tx_fail))
            {    
    				s->start_tx_flag = 1;
                	if(wk2xxx_dowork(s))
                	{
                        ;
                	}
                	else
                	{
                        s->start_tx_fail = 1;
    					s->start_tx_flag = 0;
                	}
             }
    }
    
    /*
     *  * Interrupts enabled
    */
    
    static void wk2xxx_stop_rx(struct uart_port *port)
    {
            struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port);
    #ifdef _DEBUG_WK2XXX
    			printk(KERN_ALERT "%s!!\n", __func__);
    #endif
           	if(!(s->stop_rx_flag ||s->stop_rx_fail ))
            {
    				s->stop_rx_flag = 1;
                	if(wk2xxx_dowork(s))
                	{
                    	;
                	}
                	else
                	{
                    	s->stop_rx_flag = 0;
                    	s->stop_rx_fail = 1;
                	}
             }
    }
    
    /*
     *  * No modem control lines
     *   */
    static void wk2xxx_enable_ms(struct uart_port *port)    //nothing
    {
    #ifdef _DEBUG_WK2XXX
    			printk(KERN_ALERT "%s!!\n", __func__);
    #endif
    
    
    }
    /*
     *  * Interrupts always disabled.
    */   
    static void wk2xxx_break_ctl(struct uart_port *port, int break_state)
    {
    #ifdef _DEBUG_WK2XXX
    	printk(KERN_ALERT "%s!!\n", __func__);
    #endif
    }
    
    
    static int wk2xxx_startup(struct uart_port *port)//i
    {
    
            uint8_t gena,grst,gier,sier,scr,dat[1];
            struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port);
            char b[12];
            if (s->suspending)
                return 0;
            
            s->force_end_work = 0;
            sprintf(b, "wk2xxx-%d", (uint8_t)s->port.iobase);
    		s->workqueue = create_workqueue(b);
    	    
            if (!s->workqueue) 
            {
                dev_warn(&s->wk2xxx_i2c_client->dev, "cannot create workqueue\n");
                return -EBUSY;
            }
            
            INIT_WORK(&s->work, wk2xxx_work);
            
            if (s->wk2xxx_hw_suspend)
            	s->wk2xxx_hw_suspend(0);
              
            wk2xxx_read_global_reg(s->wk2xxx_i2c_client,WK2XXX_GENA,dat);
            gena=dat[0];
            switch (s->port.iobase)
            {
              case 1:
                      gena|=WK2XXX_UT1EN;
                      wk2xxx_write_global_reg(s->wk2xxx_i2c_client,WK2XXX_GENA,gena);
                      break;
              case 2:
                      gena|=WK2XXX_UT2EN;
                      wk2xxx_write_global_reg(s->wk2xxx_i2c_client,WK2XXX_GENA,gena);
                      break;
              case 3:
                     gena|=WK2XXX_UT3EN;
                     wk2xxx_write_global_reg(s->wk2xxx_i2c_client,WK2XXX_GENA,gena);
                      break;
              case 4:
                      gena|=WK2XXX_UT4EN;
                      wk2xxx_write_global_reg(s->wk2xxx_i2c_client,WK2XXX_GENA,gena);
                      break;
              default:
    		          printk(KERN_ALERT ":con_wk2xxx_subport bad iobase %d\n", (uint8_t)s->port.iobase);
                      break;
            }
     
            wk2xxx_read_global_reg(s->wk2xxx_i2c_client,WK2XXX_GRST,dat);
            grst=dat[0];
            switch (s->port.iobase)
            {
                 case 1:
                        grst|=WK2XXX_UT1RST;
                        wk2xxx_write_global_reg(s->wk2xxx_i2c_client,WK2XXX_GRST,grst);
                        break;
                 case 2:
                        grst|=WK2XXX_UT2RST;
                        wk2xxx_write_global_reg(s->wk2xxx_i2c_client,WK2XXX_GRST,grst);
                        break;
                 case 3:
                       grst|=WK2XXX_UT3RST;
                       wk2xxx_write_global_reg(s->wk2xxx_i2c_client,WK2XXX_GRST,grst);
                        break;
                 case 4:
                        grst|=WK2XXX_UT4RST;
                        wk2xxx_write_global_reg(s->wk2xxx_i2c_client,WK2XXX_GRST,grst);
                        break;
                default:
                       printk(KERN_ALERT "bad iobase %d\n", (uint8_t)s->port.iobase);
                       break;
            }
            
            wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIER,dat);
            sier = dat[0];
            sier &= ~WK2XXX_TFTRIG_IEN;
            sier |= WK2XXX_RFTRIG_IEN;
            sier |= WK2XXX_RXOUT_IEN;
            wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIER,sier);
    
            wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SCR,dat);
            scr = dat[0] | WK2XXX_TXEN|WK2XXX_RXEN;
            wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SCR,scr);
    
        //initiate the fifos
            wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_FCR,0xff);//initiate the fifos
            wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_FCR,0xfc);
        //set rx/tx interrupt 
            wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SPAGE,1);  
            wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_RFTL,0x40);
            wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_TFTL,0X20);
            wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SPAGE,0);  
        //enable the sub port interrupt
            wk2xxx_read_global_reg(s->wk2xxx_i2c_client,WK2XXX_GIER,dat);
            gier = dat[0];
            
            switch (s->port.iobase)
    	{
              case 1:
                    gier|=WK2XXX_UT1IE;
                    wk2xxx_write_global_reg(s->wk2xxx_i2c_client,WK2XXX_GIER,gier);
                    break;
              case 2:
                    gier|=WK2XXX_UT2IE;
                    wk2xxx_write_global_reg(s->wk2xxx_i2c_client,WK2XXX_GIER,gier);
                    break;
              case 3:
                    gier|=WK2XXX_UT3IE;
                    wk2xxx_write_global_reg(s->wk2xxx_i2c_client,WK2XXX_GIER,gier);
                    break;
              case 4:
                    gier|=WK2XXX_UT4IE;
                    wk2xxx_write_global_reg(s->wk2xxx_i2c_client,WK2XXX_GIER,gier);
                    break;
            default:
                    printk(KERN_ALERT ": bad iobase %d\n", (uint8_t)s->port.iobase);
                    break;
            }
    
            if (s->wk2xxx_hw_suspend)
                s->wk2xxx_hw_suspend(0);
            msleep(50);
    
    
            uart_circ_clear(&s->port.state->xmit);
            wk2xxx_enable_ms(&s->port);
    
          // request irq
            if(request_irq(s->port.irq, wk2xxx_irq,IRQF_SHARED|IRQF_TRIGGER_LOW, "wk2xxx_irq_gpio", s) < 0)
            {
                    dev_warn(&s->wk2xxx_i2c_client->dev, "cannot allocate irq %d\n", s->irq);
                    s->port.irq = 0;
                    destroy_workqueue(s->workqueue);
                    s->workqueue = NULL;
                    return -EBUSY;
            }       udelay(100);
            udelay(100);
    #ifdef _DEBUG_WK2XXX
    	   printk(KERN_ALERT "%s!!**finish**\n", __func__);
    #endif
    
           return 0;
    }
    //* Power down all displays on reboot, poweroff or halt *
    
    static void wk2xxx_shutdown(struct uart_port *port)
    {
    
        uint8_t gena,dat[1];
        struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port);
    #ifdef _DEBUG_WK2XXX
    	printk(KERN_ALERT "%s!!**start**\n", __func__);
    #endif
        	if (s->suspending)
           		return;
           	s->force_end_work = 1;
        	if (s->workqueue) 
        	{
        	    flush_workqueue(s->workqueue);
    			destroy_workqueue(s->workqueue);
    			s->workqueue = NULL;
        	}
        
        	if (s->port.irq)
        	{    
              free_irq(s->port.irq, s);//释放中断
        	}
         
         	wk2xxx_read_global_reg(s->wk2xxx_i2c_client,WK2XXX_GENA,dat);
            gena=dat[0];
            switch (s->port.iobase)
        	{
            	case 1:
                    gena&=~WK2XXX_UT1EN;
                    wk2xxx_write_global_reg(s->wk2xxx_i2c_client,WK2XXX_GENA,gena);
                    break;
              case 2:
                     gena&=~WK2XXX_UT2EN;
                     wk2xxx_write_global_reg(s->wk2xxx_i2c_client,WK2XXX_GENA,gena);
                     break;
              case 3:
                     gena&=~WK2XXX_UT3EN;
                     wk2xxx_write_global_reg(s->wk2xxx_i2c_client,WK2XXX_GENA,gena);
                     break;
              case 4:
                     gena&=~WK2XXX_UT4EN;
                      wk2xxx_write_global_reg(s->wk2xxx_i2c_client,WK2XXX_GENA,gena);
                      break;
              default:
                      printk(KERN_ALERT "bad iobase %d\n", (uint8_t)s->port.iobase);
                      break;
              } 
    }
    
    static void conf_wk2xxx_subport(struct uart_port *port)//i
    {   
    	struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port);
    	uint8_t old_sier,fwcr,lcr,scr,scr_ss,dat[1],baud0_ss,baud1_ss,pres_ss;
    
    	lcr = s->new_lcr;
    	scr_ss = s->new_scr;
    	baud0_ss=s->new_baud0;
    	baud1_ss=s->new_baud1;
    	pres_ss=s->new_pres;
    	fwcr=s->new_fwcr;
    	wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIER ,dat);
    	old_sier = dat[0];
    	wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIER ,old_sier&(~(WK2XXX_TFTRIG_IEN | WK2XXX_RFTRIG_IEN | WK2XXX_RXOUT_IEN)));
        //local_irq_restore(flags);
    	do{
           	wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_FSR,dat);
    	  } while (dat[0] & WK2XXX_TBUSY);
            // then, disable tx and rx
            wk2xxx_read_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SCR,dat);
            scr = dat[0];
            wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SCR ,scr&(~(WK2XXX_RXEN|WK2XXX_TXEN)));
            // set the parity, stop bits and data size //
            wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_LCR ,lcr);
    		/*set cts  and rst*/
    		if(fwcr>0){  
    #ifdef _DEBUG_WK2XXX
            printk(KERN_ALERT "-conf_wk2xxx_subport-set ctsrts--fwcr=0x%X\n",fwcr);
    #endif
    				wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_FWCR,fwcr);
    				wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SPAGE ,1);
    				wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_FWTH,0XF0);
    				wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_FWTL,0X80);
    				wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SPAGE ,0);
    		}
        
            wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SIER ,old_sier);
            // set the baud rate //
            wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SPAGE ,1);
            wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_BAUD0 ,baud0_ss);
            wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_BAUD1 ,baud1_ss);
            wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_PRES ,pres_ss);
             wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SPAGE ,0);
             wk2xxx_write_slave_reg(s->wk2xxx_i2c_client,s->port.iobase,WK2XXX_SCR ,scr|(WK2XXX_RXEN|WK2XXX_TXEN));
    
    }
    
    
    // change speed
    static void wk2xxx_termios( struct uart_port *port, struct ktermios *termios,
                struct ktermios *old)
    {
    
    	struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port);
    	int baud = 0;
    	uint8_t lcr=0,fwcr,baud1,baud0,pres;
    	unsigned short cflag;
    	unsigned short lflag;
    	
    	cflag = termios->c_cflag;
    	lflag = termios->c_lflag;
    
    	baud1=0;
    	baud0=0;
    	pres=0;
    	baud = tty_termios_baud_rate(termios);
        printk(KERN_ALERT "wk2xxx_termios()----baud = tty_termios_baud_rate(termios);- baud:%d--\n",baud);
    
    	switch (baud) {
    		case 600:
    			baud1=0x4;
    			baud0=0x7f;
    			pres=0;
    			break;
    		case 1200:
    			baud1=0x2;
    			baud0=0x3F;
    			pres=0;
    			break;
    		case 2400:
    			baud1=0x1;
    			baud0=0x1f;
    			pres=0;
    			break;
    		case 4800:
    			baud1=0x00;
    			baud0=0x8f;
    			pres=0;
    			break;
    		case 9600:
    			baud1=0x00;
    			baud0=0x47;
    			pres=0;
    			break;
    		case 19200:
    			baud1=0x00;
    			baud0=0x23;
    			pres=0;
    			break;
    		case 38400:
    			baud1=0x00;
    			baud0=0x11;
    			pres=0;
    			break;
    		case 76800:
    			baud1=0x00;
    			baud0=0x08;
    			pres=0;
    			break;  
    		case 1800:
    			baud1=0x01;
    			baud0=0x7f;
    			pres=0;
    			break;
    		case 3600:
    			baud1=0x00;
    			baud0=0xbf;
    			pres=0;
    			break;
    		case 7200:
    			baud1=0x00;
    			baud0=0x5f;
    			pres=0;
    			break;
    		case 14400:
    			baud1=0x00;
    			baud0=0x2f;
    			pres=0;
    			break;
    		case 28800:
    			baud1=0x00;
    			baud0=0x17;
    			pres=0;
    			break;
    		case 57600:
    			baud1=0x00;
    			baud0=0x0b;
    			pres=0;
    			break;
    		case 115200:
    			baud1=0x00;
    			baud0=0x05;
    			pres=0;
    			break;
    		case 230400:
    			baud1=0x00;
    			baud0=0x02;
    			pres=0;
    			break;
    		default:  
    			baud1=0x00;
    			baud0=0x00;
    			pres=0;
    			break;
    	}
    	tty_termios_encode_baud_rate(termios, baud, baud);
    
    	/* we are sending char from a workqueue so enable */
    
        lcr =0;
        if (cflag & CSTOPB)
            lcr|=WK2XXX_STPL;//two  stop_bits
        else
            lcr&=~WK2XXX_STPL;//one  stop_bits
    
       if (cflag & PARENB) {
            lcr|=WK2XXX_PAEN;//enbale spa
            if (!(cflag & PARODD)){
            	lcr |= WK2XXX_PAM1;
            	lcr &= ~WK2XXX_PAM0;
            }
            else{
            	lcr |= WK2XXX_PAM0;//PAM0=1
            	lcr &= ~WK2XXX_PAM1;//PAM1=0
            }
       }
       else{
       		lcr&=~WK2XXX_PAEN;
       }
    
    	/*set rts and cts*/
    	fwcr=(termios->c_cflag&CRTSCTS)?0X30:0;
    
    	s->new_baud1=baud1;
    	s->new_baud0=baud0;	
    	s->new_pres=pres;
    	s->new_lcr = lcr;
    	s->new_fwcr = fwcr;
    
    	conf_wk2xxx_subport(&s->port);  
    
    }
    
    static const char *wk2xxx_type(struct uart_port *port)
    {
    	return port->type == PORT_WK2XXX ? "wk2xxx" : NULL;//this is defined in serial_core.h
    }
    
    
    static void wk2xxx_release_port(struct uart_port *port)
    {
    	//Not implement
    }
    
    static int wk2xxx_request_port(struct uart_port *port)//no such memory region needed for wk2xxx
    {
    	//Not implement
        return 0;
    }
    
    
    static void wk2xxx_config_port(struct uart_port *port, int flags)
    {
            struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port);
    
            if (flags & UART_CONFIG_TYPE && wk2xxx_request_port(port) == 0)
                   s->port.type = PORT_WK2XXX;
    }
    
    
    static int wk2xxx_verify_port(struct uart_port *port, struct serial_struct *ser)
    {
            int ret = 0;
    
            if (ser->type != PORT_UNKNOWN && ser->type != PORT_WK2XXX)
                    ret = -EINVAL;
            if (port->irq != ser->irq)
                    ret = -EINVAL;
            if (ser->io_type != SERIAL_IO_PORT)
                    ret = -EINVAL;
            //if (port->uartclk / 16 != ser->baud_base)
            //      ret = -EINVAL;
            if (port->iobase != ser->port)
                    ret = -EINVAL;
            if (ser->hub6 != 0)
                    ret = -EINVAL;
            return ret;
    }
    
    展开全文
  • 本程序基于串口扩展芯片WK2204.实现了i2c转4个串口。本源程序在为开微电子的网站也有。
  • FT232H USB串口,I2C,JTAG高速芯片

    千次阅读 2019-11-08 13:04:42
    此款多功能的单通道USBUART/FIFO接口设备可通过EEPROM配置为各种不同的串行或并行接口。与FTDI建设完备精良的USB设备驱动一起,这套方案使工程师可以轻松的将高速 USB连接引入新的和传统的外设设计中。另外,还有...

    随着FT232H USB2.0高速芯片的发布,英商飞特蒂亚公司(FTDI)进一步巩固了其在USB接口集成电路产品的地位。此款多功能的单通道USB转UART/FIFO接口设备可通过EEPROM配置为各种不同的串行或并行接口。与FTDI建设完备精良的USB设备驱动一起,这套方案使工程师可以轻松的将高速 USB连接引入新的和传统的外设设计中。另外,还有相关的UM232H评估模块帮助工程师快速建立设计样机,测试FT232H集成到新的系统设计的适用性。其高度集成的USB设备控制器包含USB, 串行和并行协议引擎,而不需要开发USB专用固件。设备支持3.3V的IO接口电平,允许5V输入,使之适用于连接各种逻辑,MPU和FPGA。

    FT232H不仅支持异步串行接口(UART),还通过其内建的多协议同步串行引擎(MPSSE)支持许多同步IO接口,比如SPI, I2C,JTAG以及FPGA编程接口,MPSSE通信速度能够达到30M比特/秒。另外,MPSSE可用于执行设计工程师自己的同步串行总线协议。

    新的FT1248 总线是FT232H集成的一个接口功能,为专有的同步半双工串行/并行接口,与外部逻辑通信速率可以达到30M Byte/秒。FT1248 总线独特之处在于能够根据可用物理数据总线的数量(1,2,4或8)调整FT232H与外部逻辑连接的带宽, 从而为系统设计提供最优的适应性。

    集成的1.8V和3.3V低压差稳压器减少了所需外部元件,同时与现有的USB2.0兼容的全速产品相比较而言,1 K字节大的收发数据缓存加上USB2.0高速技术大大改善了数据吞吐量, 缩减了延迟响应时间。FTDI网站可下载用于Windows, Linux, MAC 和 WinCE操作系统的免税驱动。

    FT232H的封装选择有48针LQFP(FT232HL)或48针QFN(FT232HQ)无铅封装。这两种FT232H工作范围是-40⁰C ~ +85⁰C。FT232HL定价为$2.75(1,000片以上),FT232HQ定价为$2.60(1000片以上)。UM232H用户评估模块有助于快速建立原型或测试FT232H平台,与一个标准的0.6英寸宽,28针的DIP插座连接。UM232H模块单价定为$20(1~9片)。

    Operating at USB Hi-Speed 480Mbps rate, this fast single channel bridge chip features either a flexible serial interface or parallel FIFO interface, with data transfer speeds up to 40Mbytes/s. Using a serial EEPROM interface, this device can be configured for a wide variety of asynchronous and synchronous serial standards, such as JTAG, SPI, I2C and UART as well as synchronous and asynchronous parallel FIFO interfaces. In addition, this device features the new synchronous, half-duplex FT1248 bus, which allows an engineer to trade off bandwidth for pin count using 1, 2, 4, or 8 data lines at up to 30Mbytes/s. The I/O structure is 3.3V with built-in tolerance for 5V, allowing the designer maximum flexibility when interfacing with FPGAs.  On-board voltage regulation provides 3.3V and 1.8V supplies from a 5V source, as well as a power-on-reset function. FTDI provides royalty-free virtual com port and D2XX drivers for Microsoft Windows (XP – Windows7), Apple Mac OSX, and Linux. This 48 pin device is available in either LQFP or QFN packaging, and is ROHS compliant. 

    • Single channel USB to serial / parallel ports with a variety of configurations.
    • Entire USB protocol handled on the chip. No USB specific firmware programming required.
    • USB 2.0 Hi-Speed (480Mbits/Second) and Full Speed (12Mbits/Second) compatible.
    • Multi-Protocol Synchronous Serial Engine (MPSSE) to simplify synchronous serial protocol (USB to JTAG, I2C, SPI or bit-bang) design.
    • UART transfer data rate up to 12Mbaud. (RS232 Data Rate limited by external level shifter).
    • USB to asynchronous 245 FIFO mode for transfer data rate up to 8 MByte/Sec.
    • USB to synchronous 245 parallel FIFO mode for transfers up to 40 Mbytes/Sec
    • Supports a half duplex FT1248 interface with a configurable width, bi-directional data bus (1, 2, 4 or 8 bits wide).
    • CPU-style FIFO interface mode simplifies CPU interface design.
    • Fast serial interface option.
    • FTDI's royalty-free Virtual Com Port (VCP) and Direct (D2XX) drivers eliminate the requirement for USB driver development in most cases.
    • Adjustable receive buffer timeout.
    • Option for transmit and receive LED drive signals.
    • Bit-bang Mode interface option with RD# and WR strobes
    • Highly integrated design includes 5V to 3.3/+1.8V LDO regulator for VCORE, integrated POR function
    • Asynchronous serial UART interface option with full hardware handshaking and modem interface signals.
    • Fully assisted hardware or X-On / X-Off software handshaking.
    • UART Interface supports 7/8 bit data, 1/2 stop bits, and Odd/Even/Mark/Space/No Parity.
    • Auto-transmit enable control for RS485 serial applications using TXDEN pin.
    • Operation configuration mode and USB Description strings configurable in external EEPROM over the USB interface.
    • Configurable I/O drives strength (4, 8, 12 or 16mA) and slew rate.
    • Low operating and USB suspend current.
    • Supports self powered, bus powered and high-power bus powered USB configurations.
    • UHCI/OHCI/EHCI host controller compatible.#
    • USB Bulk data transfer mode (512 byte packets in Hi-Speed mode).
    • +1.8V (chip core) and +3.3V I/O interfacing (+5V Tolerant).
    • Extended -40°C to 85°C industrial operating temperature range.
    • Compact 48-pin Lead Free LQFP or QFN package
    • Configurable ACBUS I/O pins.

     

    This mode uses a synchronous interface to get high data transfer speeds. The chip drives a 60 MHz CLKOUT clock for the external system to use.
    Note that Asynchronous FIFO mode must be selected in the EEPROM before selecting the Synchronous FIFO mode in software.


    4.4.1 FT245 Synchronous FIFO Read Operation

    A read operation is started when the chip drives RXF# low. The external system can then drive OE# low to turn the data bus drivers around before acknowledging the data with the RD# signal going low. The first data byte is on the bus after OE# is low. The external system can burst the data out of the chip by keeping RD# low or it can insert wait states in the RD# signal. If there is more data to be read it will change on the clock following RD# sampled low. Once all the data has been consumed, the chip will drive RXF# high. Any data that appears on the data bus, after RXF# is high, is invalid and should be ignored.


    4.4.2 FT245 Synchronous FIFO Write Operation

    A write operation can be started when TXE# is low. WR# is brought low when the data is valid. A burst operation can be done on every clock providing TXE# is still low. The external system must monitor TXE# and its own WR# to check that data has been accepted. Both TXE# and WR# must be low for data to be accepted.

    4.12 Send Immediate / Wake Up (SIWU#)
    The SIWU# pin is available in the FIFO modes and in bit bang mode.
    The Send Immediate portion is used to flush data from the chip back to the PC. This can be used to force
    short packets of data back to the PC without waiting for the latency timer to expire.
    To avoid overrunning, this mechanism should only be used when a process of sending data to the chip
    has been stopped.
    The data transfer is flagged to the USB host by the falling edge of the SIWU# signal. The USB host will
    schedule the data transfer on the next USB packet.

    Figure 4.25: Using SIWU#
    When the pin is being used for a Wake Up function to wake up a sleeping PC a 20ms negative pulse on
    this pin is required. When the pin is used to immediately flush the buffer (Send Immediate) a 250ns
    negative pulse on this pin is required.
    Notes
    1. When using remote wake-up, ensure the resistors are pulled-up in suspend. Also ensure peripheral
    designs do not allow any current sink paths that may partially power the peripheral.
    2. If remote wake-up is enabled, a peripheral is allowed to draw up to 2.5mA in suspend. If remote
    wake-up is disabled, the peripheral must draw no more than 500uA in suspend.
    3. If a Pull-down is enabled, the FT232H will not wake up from suspend when using SIWU#
    4.In UART mode the RI# pin acts as the wake up pin.

    展开全文
  • xr20m117x i2c转串口官方驱动源码 有需求的可以下载
  • USB转多路urat、USB同时转I2C,JETK,SPI,URAT,原理图和PCB,项目做过可用
  • USB转I2C USB转I2C模块

    千次阅读 2018-06-12 16:50:18
    学习单片机的过程中,会接触各种各样的通信协议,类似串口、iic、spi、can等。... 下面推荐一块usbiic的模块,同时也支持usb串口。所以针对学习单片机的同学来说是非常好的工具了: 点击打开链接 ...

      学习单片机的过程中,会接触各种各样的通信协议,类似串口、iic、spi、can等。一般学习单片机的时候,第一个接触的就是串口。iic主要用于一些传感器、eeprom芯片等,spi的话主要就是控制一些液晶屏了。iic学习起来比较抽象,如果可以像串口那样使用就好了。

      下面推荐一块usb转iic的模块,同时也支持usb转串口。所以针对学习单片机的同学来说是非常好的工具了:

      点击打开链接

     

    工具下载:

     链接:https://pan.baidu.com/s/1QqJU624px8_bvCzyZkTWGw

    提取码:11ad

    展开全文
  • SPI I2C UART(即串口)

    2021-03-26 17:09:19
    I2C(IC之间总线):是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备,是微电子通信控制领域广泛采用的一种总线标准。 UART(通用异步收发器):是电脑硬件的一部分,他把将要传输的资料在串行通信...
  • 将RS232串口转换为I2C数据格式,用来配置EEPROM。支持多字节数据的读写操作
  • 一,基础操作A,相关文件下载1,在官网下载CH341PRT.zip(并口+同步串口驱动)CH341SER.EXE(异步串口驱动)2,在官网上面下载动态库文件和相应的头文件:CH341dll.dll(CH341dll.h针对并口、同步串口),CH341PT.dll(CH...
  • 前言:i2c-tools,跟linux里的工具类似,可以命令行访问i2c设备。 1、编译、下载examples\i2c\i2c_tools例程 2、正确连接i2c设备 这里连接0.96吋 oled,也是比较常用的一个i2c设备,连接在gpio21和gpio22上。 3、从...
  • FT4232 USBSPI I2C

    2016-06-14 14:56:57
    FT4232 USB双通道SPI, I2C, JTAG协议,并可以支持4通道的串口传输,整板支持电平转换,可以运行在3.3V, 1.2V, 5V逻辑电平
  • 典型应用:- I2C总线设备,芯片控制、调试- I2C接口传感器测试- I2C存储器EEPROM数据读写- I2C总线设备故障检测维修- PMBus和SMBus总线接口芯片控制- 协助开发I2C主机程序- 脉冲计数器- 模拟电压测量,GPIO输入输出...
  • 本适配器为多功能合一产品,涉及接口有SPI接口,I2C接口,UART接口,I2C与 UART接口,异步串口预留接口,打印并口
  • 库函数版本,运行后通过串口通讯发送四路数模转换数据至电脑,波特率9600,本工程引脚对应SDA->PB7 SCLK->PB6,I2C不固定I2C引脚,可自行在i2c.c文件更改。此工程也适用于F103其他型号(需修改工程)
  • 我们一般使用的串口 (半双工异步串行通信)与I2C 有什么区别呢。 串口(半双工异步串行通信):就是好像朋友在对话。我可以主动和你讲话,你也可以主动和我讲话。 I2C:就好像上下级对话。一个领导面对一个或者...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 381
精华内容 152
关键字:

串口转i2c