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.

[参考译文] MSP430F2618:自定义构建的I2C驱动器在地址后停止

Guru**** 2595805 points
Other Parts Discussed in Thread: MSP430F2618

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/642847/msp430f2618-custom-built-i2c-driver-stalls-after-address

部件号:MSP430F2618

大家好!

我正在尝试为我的MSP430F2618构建自定义I2C驱动程序。  该驱动程序用于在没有ISR的情况下运行,并且具有大量错误检查/处理。  我已经尝试让它运行几个星期了,我成功地捕获了一些错误,但它总是在发送设备地址后挂起,即使接收设备将地址加密。  以下是相关代码。  所有引脚,端口,时钟速率等的初始化都以另一种方法处理。  已根据MSP430系列用户指南和TI的I2C代码示例对这些代码进行了检查,因此我认为问题不存在。  如果需要,我可以提供,但我不想让读者对整个文件的代码感到不知所措。  此外,提及"主要"是指此代码旨在与F2618中内置的两个I2C接口之一配合使用。  下面仅是“主要”(USCIB0)的代码,因为“辅助”的代码只是一个精确的副本。

提前感谢您!

John

void i2cSendMessage(I2CMessage* messageStrut){//errors needed to be handled

//local variables
char nackCount =0;
int i =0;
char singleByteRXFlag =0;

//错误检查
(!messageStrut){//Null指针
OSUnprotect();
return;
}
IF (messageStrut->isInitialized != is_initialized){//message has not been initialized'
messageStruct -> error = I2CERR_struct_NOT_initialized;
OSUnprotect();
return;
}//Lessgo


如果(!Get_primary_is_active){//界面未激活
messageStruct -> error = I2CERR_INTERFACE_NOT_ACTIVE;
返回;//必须手动激活
}

//初始化
UCB0I2CSA =消息结构->地址;//设置地址

如果(messageStruct -> messageLength > 0){//如果没有TX,则我们要直接转到RX部分
start_primary_I2C;//设置启动条件
}

I = 0;
while (I < messageStrut->messageLength ){//仅处理RX的情况:如果消息为空,而循环永远不会运行
如果(!GET_PRIMARY_TX_READY){
如果(primary_Get_nack){//如果从属设备传输了nack,则再次发送同一字节
nackCount++;
如果(nackCount >= MAX_nack){//Slave unreachable,中止以防止操作系统停止
STOP_PRIMARY_I2C;
disable_primary_I2C;//从属设备问题,因此关闭接口以防止未定义的行为(但不确定是什么行为)
messageStruct -> error = I2CERR_nack_limit_reached;
返回;
}
start_primary_I2C;//重复启动
}
继续;
} 否则{
UCB0TXBUF =消息结构->消息[I];
nackCount = 0;//字节已通过,从属设备可访问。
I++;
}
}

//接收
如果(messageStrut->txrxMode == RX_mode){
int j =0;
UCB0CTL1 &=~UCTR;//设置为接收模式
start_primary_I2C;//(重复)启动条件
IFG2 &=~UCB0TXIFG;//清除TX标志(数据表告诉我)
同时(j < messageStrut->respLen){
如果(!GET_PRIMARY_RX_READY){
如果(primary_Get_nack){//未确认地址(仅在输入循环时才可能发生)
start_primary_I2C;//重复启动
继续;
}
如果(messageStrut->respLen ==1)&& primary_Get_STT_CLr){//发送停止条件。如果只接收一个字节(来自数据表),则只要清除STT就会立即停止条件
STOP_PRIMARY_I2C;//根据I2C规范的要求自动发送最终nack。
singleByteRXFlag = 1;
继续;
}
}其他{
messageStrut->Response[j]= UCB0RXBUF;
J++;
}
}
//全部完成(非常确定...)
}

//停止通信
如果(!singleByteRXFlag){//阻止重复停止(不知道这是否是问题)
STOP_PRIMARY_I2C;
}

messageStruct -> error = I2CERR_NO_ERROR;
返回;

} 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好,John:

    首先,我建议阅读 MSP430 MCU上常见eUSCI和USCI串行通信问题解决方案的I2C部分。 此应用报告描述了最常见的I2C问题,并提供了解决方案以及一些有用的提示和技巧。  

    接下来,我建议您浏览 MSP430F2618设备错误表。 MSP430F2618上有几个I2C相关勘误表。 您能否通读并验证是否有任何与您观察到的声音类似的声音?

    我通读了您上面的代码,需要更多信息:

    1. 您能描述一下"悬挂"的含义吗?
      1. 遇到此问题时,您是否能够暂停代码并查看MSP430“卡住”的位置?
    2. 您能否提供I2C和时钟初始化代码?
    3. 是否可以在代码中提供以下宏的实现:
      1. GET_PRIMARY_TX_READY
      2. primary_Get_nack
      3. start_primary_I2C
      4. GET_PRIMARY_RX_READY
      5. PRIMARY_GET_STT_CLR
      6. STOP_PRIMARY_I2C
      7. disable_primary_I2C

    最后,您能否使用逻辑分析仪探测I2C总线并提供您所描述的故障的屏幕截图?

    此致,  
    Caleb Overbay

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢您的快速回复,Caleb!

    我将查看您提供的文档。  我已经看过勘误表,找不到任何相关信息,但重新检查不会有任何影响。  但是,"常见问题解决方案"表看起来很有希望。  回答您的问题:

    1.当我说“挂起”时,我的意思是当我观察逻辑分析器中的I2C总线时,我在时钟线路上看到8个嘀嗒信号,在数据线路上看到从属地址(我可以说是正确的),然后第九个时钟位永远不会出现。  ACK中的数据线保持在低位,时钟线始终保持低位。  很遗憾,我手头没有逻辑分析仪输出的屏幕截图。

    2.以下是时钟初始化代码:

    //IN main()
    WDTCTL = WDTPW + WDTHOLD;
    BCSCTL1 = CALC1_1MHz;
    DCOCTL = CALDCO_1MHz;
    
    //IN I2CInit(),请参见下面
    的UCB0CTL1 ||(时钟结构->
    
    分频源)<< 0x6;//register from SMCLK = Ubconfig/1f-;CB0=8;CB1=0/多路由<0;CB1F=0B1F=8 

    下面是I2C初始化代码:

    void i2cInit(I2CConfig* configStrut){
    disable_primary_I2C;//在我们配置时禁用I2C
    reset_primary_config_0;//清除配置寄存器,以便我们从一个干净的模板开始(全部为零)
    UCB0CTL1 = BIT0;//清除配置寄存器(复位启用除外)
    
    UCB0CTL0 ||(UCMST + UCMODE_3 + UCSYNC);//UCMST -主模式,UCMODE_3 - I2C模式,UCSYNC -同步模式
    UCB0CTL1 ||(configStrut->clockSource)<< Clock_SRC_shift;//请仔细检查此项...
    PRIMARY_I2C_SEL ||(SCL_PIN + SDA_PIN);//设置引脚模式
    UCB0BR0 =((configStrut->BaudDivider)& BAUD_Low_mask);//低8位寄存器
    UCB0BR1 =(configStrut->BaudDivider )>> BAUD_SHIFT;//高8位寄存器
    UCB0CTL1 || UCTR;//始终以TX模式启动
    
    enable_primary_I2C;
    } 

    3.这里是宏

    #define disable_primary_I2C (UCB0CTL1 || UCSWRST)
    #define enable_primary_I2C (UCB0CTL1 &=~UCSWRST)
    #define set_I2C_MODE_PRIMARY (UCB0CTL0 |= UCMODE_3)
    #define set_sync_primary (UCB0CTL0 |= USync)
    #define reset_primary_config_0 (UCB0CTL0 ^= UCB0CTL0)
    #define reset_primary_config_1 (UCB0CTL1 ^= UCB0CTL1)
    #define Get_primary_is_active ~(UCB0CTL1和UCSWRST)//返回重置引脚的反转值,以指示活动(1)或非活动(0)
    #define start_primary_I2C (UCB0CTL1 || UCTXSTT)//通过在配置reg
    #define primary_TXRX_INT_EN中设置起始位来生成启动条件 (IE2 |= UCB0TXIE + UCB0RXIE)
    #define primary_TXRX_INT_DIS (IE2 &=~(UCB0TXIE + UCB0RXIE)
    )#define GET_PRIMARY_TX_READY (IFG2和UCB0TXIFG)//检查标记
    #define GET_PRIMARY_RX_READY (IFG2和UCB0RXIFG)
    #define stop_primary_I2C (UCB0CTL1 |= UCTXSTP)//生成停止条件
    #define primary_Get_nack (UCB0STAT和UCNACKIFG)
    #define primary_Get_STT_CLR ~(UCB0CTL1和UCTXSTT)//获取是否清除了起始位 

    再次感谢!

    John

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好,John:

    我将浏览此代码,如果我发现任何奇怪的地方,请告诉您。

    [引用user="John Walnut]当我说“挂起”时,我是指当我观察逻辑分析器中的I2C总线时,我在时钟线路上看到8个嘀嗒信号,在数据线路上看到从属地址(我可以补充一下),然后第九个时钟位就不会出现。  ACK中的数据线保持在低位,时钟线始终保持低位。[/QUOT]

    这称为时钟拉伸,是由于从属设备需要更多时间来处理数据(通常)。 所以最可能的情况是,salve正在处理某些东西或者被卡住,并且在有时间处理刚收到的数据之前,I2C总线保持在较低的水平。 我会将你们的工作重点放在从属设备上,看看它是否卡在某个位置的代码中,并且不能正确地为I2C服务。  

    此致,  
    Caleb Overbay

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我解决了!

    我不确定是不是只有一件事,但我会列出我修复的各种问题。

    1.我使用的从属设备(10美元的MPU-9250 IMU)被破坏。  就是这样。  现在,我们之前用几个不同的IMU测试过我的驱动程序,但它不起作用,但这是需要解决的第一个问题。

    2.我必须在主传输环路后添加"while (!Get_primary_TX_ready);",以确保在设置停止或重复启动之前,最终字节已完成传输。

    3.我必须在接收循环之前移动此代码,以便正确处理我只想接收一个字节的情况。  如《家庭用户指南》所述,此类案件的时间安排非常特殊。  另外,我必须添加一条线路,等待UCTXSTT位降低(表示成功的启动条件) ,然后再设置停止条件。

    如果(messageStruct->respLen == 1)&& primary_Get_STT_CLr){//发送停止条件。如果在
    	(UCB0CTL1和UCTXSTT)期间仅接收一个字节,则清除STT;
    STOP_PRIMARY_I2C;//根据I2C规范的要求自动发送最终nack。
    singleByteRXFlag = 1;
    }