This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DSP28335通过I2C与外设进行通信时失败,SCL引脚无正常信号输出,求解

之前发帖子时发错了论坛分区了,经提醒后只能重新再这里发一下帖子,问题详细描述请移步步:e2echina.ti.com/.../523061

  • 平台描述:

    DSP28335,外部晶振30M,配置系统时钟150M,使能I2C时钟,I2Cmodule时钟为10M,配置通信波特率400K,采用硬件I2C通信方式,I2C的SCL和SDA硬件上拉4.7k,

    外设为SHT30温湿度传感器模块,供电3.3V,,和DSP的I2C引脚直连,SHT30模块的ADDR引脚连接到VDD上,其设备地址为0x45

    编译器版本CCS6.1,Win10

    现状描述:

    DSP通过I2C总线和外设SHT30进行通信,获取温度和湿度的数据。采用进行查询,判断状态为的方式进行,参考

    http://bbs.eeworld.com.cn/thread-535531-1-1.html这个网站上的程序,虽然在写数据时在打印消息上没有看到有出错,但是通过示波器看波形却是不正常的,本来一发送一个字节就要有8个时钟脉冲,实际只有1~2个。且程序在写完后,接着的读取操作中卡住了。且卡住时,此时的SCL输出变为低电平了。

    (上图为整个操作的波形)

    (上图为前两次写的波形)

    (上图为第二次写和第一次读的波形)

    还有一个问题,关于DSP的I2C读取操作的。对于那些在读取数据前,不需要先发送指定的地址,直接读取就可以的的外设,怎么做?目前我网上看到的都是需要先发送一个地址之类的。如上面提到的SHT30、TDF8541等外设都不需要发送指定地址才能读的。但是如果不先写,好像就不能用ARDY判断当前是否可读了?

    目前在google,查找TI等论坛后没有找到相关的解决方法,发帖求解各位TI工程师和论坛工程师。

    源码如下:

    1. 配置主时钟为150M:(外部晶振30M)

    InitPll(DSP28_PLLCR,DSP28_DIVSEL);//#define DSP28_PLLCR   10,#define DSP28_DIVSEL     2

    2. 使能I2C时钟:

    SysCtrlRegs.PCLKCR0.bit.I2CAENCLK = 1;   // I2C

    3. 配置I2C的引脚:

    InitI2CGpio()
    {
        EALLOW;
        
        //
        // Enable internal pull-up for the selected pins
        // Pull-ups can be enabled or disabled disabled by the user.  
        // This will enable the pullups for the specified pins.
        // Comment out other unwanted lines.
        //
        GpioCtrlRegs.GPBPUD.bit.GPIO32 = 0;    // Enable pull-up for GPIO32 (SDAA)
        GpioCtrlRegs.GPBPUD.bit.GPIO33 = 0;	   // Enable pull-up for GPIO33 (SCLA)
    
        //
        // Set qualification for selected pins to asynch only
        // This will select asynch (no qualification) for the selected pins.
        // Comment out other unwanted lines.
        //
        GpioCtrlRegs.GPBQSEL1.bit.GPIO32 = 3;  // Asynch input GPIO32 (SDAA)
        GpioCtrlRegs.GPBQSEL1.bit.GPIO33 = 3;  // Asynch input GPIO33 (SCLA)
    
        //
        // Configure SCI pins using GPIO regs
        // This specifies which of the possible GPIO pins will be I2C functional 
        // pins. Comment out other unwanted lines.
        //
        GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 1;   // Configure GPIO32 to SDAA 
        GpioCtrlRegs.GPBMUX1.bit.GPIO33 = 1;   // Configure GPIO33 to SCLA
    
        EDIS;
    }

    4. I2C初始化

    void I2CA_Init(Uint16 iSlaveAddress,CommunicateSpeed_Enum eCommunicateSpeed)
    {   
        //IRS must be 0 while you configure/reconfigure the i2c module
        I2caRegs.I2CMDR.bit.IRS = 0;
       
        // Initialize I2C
        I2caRegs.I2CSAR = iSlaveAddress;		// Slave address
    
        // Configure I2C Module Clock
        #if (CPU_FRQ_150MHZ)             // Default - For 150MHz SYSCLKOUT
            I2caRegs.I2CPSC.all = 13;   // Prescaler - need 7-12 Mhz on module clk (150/15 = 10MHz)
        #endif
        #if (CPU_FRQ_100MHZ)             // For 100 MHz SYSCLKOUT
         I2caRegs.I2CPSC.all = 9;	    // Prescaler - need 7-12 Mhz on module clk (100/10 = 10MHz)
        #endif
    
        // Configure Communicate Speed
        if ( CommunicateSpeed_100K == eCommunicateSpeed )
        {
            I2caRegs.I2CCLKL = 60;          // NOTE: must be non zero
            I2caRegs.I2CCLKH = 30;           // NOTE: must be non zero
        }
        else if ( CommunicateSpeed_400K == eCommunicateSpeed )
        {
            I2caRegs.I2CCLKL = 10;          // NOTE: must be non zero
            I2caRegs.I2CCLKH = 5;           // NOTE: must be non zero
        }
        else
        {
            printf("Current I2C Communicate Speed Not Support");
        }
    
        // Configure Interrupt Source Enable
        I2caRegs.I2CIER.all = 0x00;		// Disable interrupts
    
        I2caRegs.I2CMDR.all = 0x0020;    // Take I2C out of reset
                                         // Stop I2C when suspended
        
        //I2caRegs.I2CMDR.bit.IRS = 1;	// Take I2C out of reset
        									// Stop I2C when suspended
        I2caRegs.I2CFFTX.all = 0x0000;	// Disable FIFO mode and TXFIFO
        I2caRegs.I2CFFRX.all = 0x0000;	// Disable RXFIFO, clear RXFFINT,
    
        return;
    }

    5. I2C写参数

    Uint16 WriteData(Uint16 iSlaveAddress,Uint16 *pTxData,Uint16 iTxDataLen)
    {
        Uint16 i;
    
        // Wait until the STP bit is cleared from any previous master communication.
        // Clearing of this bit by the module is delayed until after the SCD bit is
        // set. If this bit is not checked prior to initiating a new message, the
        // I2C could get confused.    
        while(I2caRegs.I2CMDR.bit.STP == 1);
    
        // Check if bus busy
        while(I2caRegs.I2CSTR.bit.BB == 1);
        
        while(0 == I2caRegs.I2CSTR.bit.XRDY);
        
        I2caRegs.I2CSAR = iSlaveAddress;		// Slave address;
        I2caRegs.I2CCNT = iTxDataLen;
        I2caRegs.I2CDXR = pTxData[0];
        I2caRegs.I2CMDR.all = 0x6E20;
        
        for (i=0; i<iTxDataLen-1; i++)
        {
            printf("\r\n w1 here,I2CMDR:0x%04x,I2CSTR:0x%04x,I2CCNT:0x%04x,I2CDXR:0x%04x",I2caRegs.I2CMDR.all,I2caRegs.I2CSTR.all,I2caRegs.I2CCNT,I2caRegs.I2CDXR);
            while(0 == I2caRegs.I2CSTR.bit.XRDY);
            
            I2caRegs.I2CDXR = pTxData[i+1];
            if (I2caRegs.I2CSTR.bit.NACK == 1)
            {
                printf("\r\n w busy here1");
                return I2C_BUS_BUSY_ERROR;
            }
        } 
        return I2C_SUCCESS; 
    }

    6. I2C读函数

    Uint16 ReadData(Uint16 iSlaveAddress,Uint16 *pTxData,Uint16 iTxDataLen,Uint16 *pRxData,Uint16 iRxDataLen)
    {
        Uint16 i,Temp;
    	
        // Wait until the STP bit is cleared from any previous master communication.
        // Clearing of this bit by the module is delayed until after the SCD bit is
        // set. If this bit is not checked prior to initiating a new message, the
        // I2C could get confused.    
        while(I2caRegs.I2CMDR.bit.STP == 1);
    
        // Check if bus busy
        while(I2caRegs.I2CSTR.bit.BB == 1);
    
        I2caRegs.I2CSAR = iSlaveAddress;      // Slave address;;
    
        if ( (0 != iTxDataLen) && (NULL != pTxData) )	//判断是否需要在读取前先发送数据
        {
            while(0 == I2caRegs.I2CSTR.bit.XRDY);
                    
            I2caRegs.I2CCNT = iTxDataLen;
            I2caRegs.I2CDXR = pTxData[0];
            I2caRegs.I2CMDR.all = 0x2620; 
            if (I2caRegs.I2CSTR.bit.NACK == 1)
            {
                return I2C_BUS_BUSY_ERROR;
            }
            
            for (i=0; i<iTxDataLen-1; i++)
            {
                while(0 == I2caRegs.I2CSTR.bit.XRDY);
                
                I2caRegs.I2CDXR = pTxData[i+1];
                if (I2caRegs.I2CSTR.bit.NACK == 1)
                {
                    return I2C_BUS_BUSY_ERROR;
                }
            }
            
            DELAY_US(50); 
        }
        
        printf("\r\n r here1,I2CMDR:0x%04x,I2CSTR:0x%04x",I2caRegs.I2CMDR.all,I2caRegs.I2CSTR.all);
        while(0 == I2caRegs.I2CSTR.bit.XRDY);	//判断这个是否合适??
        // Wait Register-access-ready
        //while(I2caRegs.I2CSTR.bit.ARDY == 0);	//如果不需要先写入的读取,用这个判断也不合适??
        
        I2caRegs.I2CCNT = iRxDataLen; 
        I2caRegs.I2CMDR.all = 0x2C20; 
        if (I2caRegs.I2CSTR.bit.NACK == 1)
        {
            return I2C_BUS_BUSY_ERROR;
        }
        
        for(i=0; i<iRxDataLen; i++)
        {
            printf("\r\n r here2,I2CMDR:0x%04x,I2CSTR:0x%04x",I2caRegs.I2CMDR.all,I2caRegs.I2CSTR.all);
            while(0 == I2caRegs.I2CSTR.bit.RRDY);	//卡在这里
            
            Temp = I2caRegs.I2CDRR;
            if (I2caRegs.I2CSTR.bit.NACK == 1)
            {
                return I2C_BUS_BUSY_ERROR;
            }
            *pRxData = Temp;
            pRxData++;
        }
        return I2C_SUCCESS;
    }

    在while(0 == I2caRegs.I2CSTR.bit.RRDY);卡住,程序停止运行了。在其上一句调试信号为 r here2,I2CMDR:0x0c20,I2CSTR:0x3438

    看sprg03b手册上说,在RSFULL=1或XMST=0时会将SCL拉低,但是在卡住的调试上看,这两个条件都不满足,但是SCL却输出低了。(将SCL断开和外设的连接,测试DSP侧的SCL信号,为低)

  • DSP28335属于C2000系列,请到C2000论坛咨询。
    e2echina.ti.com/.../
  • DSP28335 自带的IIC列程正常吗
  • 目前没有使用外置EEPROM,没有测试过control suite自带的eeprom的例程。
  • 目前的更新情况是,在使用另一个TEF6686的收音机芯片的I2C外设时,上面的程序中读写都没有问题,TEF6686的读取需要先指定要读取的地址的,所以上面关于读取部分的疑问就没有问题。
    但是对于SHT32这个温湿度传感器,写入还是不行,还是和上面描述的情况一致。手上两个这个传感器都是这样的情况。
    还有就是对于无地址写入的读取方式的I2C读取,还是没有调通。
  • 谢谢指点,不说还没有留意。进错地了。已在C2000那边新建帖子后,链接过来。
  • 怎么能不接外部传感器看看时钟波形等不 你的start沿能不能看到
    排查一下是不是电平不匹配等原因 或者上拉电阻不合理