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.

[参考译文] MSP430FR6989:两个 MSP#39;s 之间的时序问题

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/931471/msp430fr6989-timing-problems-between-two-msp-s

器件型号:MSP430FR6989

尊敬的:  

对于一个项目、我将连接两个 MSP、一个作为主器件、另一个作为从器件。 从属方将仅充当主控方的内存(主控方将向从属方写入地址和数据)。 有许多方法可以"解决"这一问题、但我的手被迫去做。  

主器件将向从器件写入一个地址、并且还将一个引脚拉高(在从器件上不执行任何操作)、并将另一个引脚拉低(将在从器件上引起中断)。 这些引脚分别为3.0和3.1。  根据被拉至低电平的引脚、从器件将从主器件读取数据并将其存储在主器件提供的地址中、或者查看地址并将存储在该地址的数据写入主器件。  

正如您可以想象的那样、当您执行此操作时、会出现很多时序问题(数据在引脚上停留的时间不够长等)。 我尝试使用引脚3.2来解决这个问题。 主器件仅在该引脚被拉至高电平时才会读取(它基本上会轮询整个时间、因为主器件此时不需要执行任何其他操作)。 写入时会发生相同的情况(大约 ISH)。 主器件将再次将该引脚推至低电平

主器件代码的段为:  

 

空写入(uint16_t 地址、uint8_t 数据){
splitAndWriteAddress (address);//将端口中可用引脚上的地址拆分并写入。
P2DIR |= 0xFF; //将 dataIO 设置为写入模式
P3OUT |= BIT1; //禁用读取模式
P3OUT &=~BIT0; //激活写入模式
P2OUT =数据; //写入数据
while (!(P3IN & BIT2)){
__no_operation();
}
P3OUT |= BIT0; //禁用写入模式
P3DIR |= BIT2;
P3OUT &=~BIT2;
P3DIR &=~BIT2;
//P2DIR |= 0x00; //将 dataIO 设置为读取模式

} 
uint8_t 读取(uint16_t 地址){
uint8_t data = 0x00;
splitAndWriteAddress (地址);
P2DIR &= 0x00; //将 dataIO 设置为读取模式
P3OUT |= BIT0; //禁用写入模式
P3OUT &=~BIT1; //激活读取模式
while (!(P3IN & BIT2)){
__no_operation();
}
数据= P2IN;
P3OUT |= BIT1; //禁用读取模式
P3DIR |= BIT2;
P3OUT &=~BIT2;
P3DIR &=~BIT2;
返回数据;
} 

对于从器件、中断为:  

#if defined (__TI_Compiler_version__)|| defined (__IAR_systems_icc_)
#pragma vector=PORT3_vector
__interrupt void Port_3 (void)
#elif defined (__GNU__)
void __attribute__((interrupt (PORT3_vector)))) Port_3 (void

编译器#else 不支持!
#endif
{
/*
* 4个可用 RAM 段:
* 1. D --> 1800h '到187Fh
* 2. C -> 1880h '到18FFh
* 3. b --> 1900h '直至187Fh
* 4. a --> 1980h '直到19FFh
*
uint16_t volatile * address =(uint16_t *) getAddress ();//从端口获取地址
P3DIR |= BIT2;


if (P3IFG & BIT0){
P2DIR &= 0x00;//置于读取模式
*地址= P2IN;
P3OUT |= BIT2;
}
//写入
if (P3IFG & BIT1){//可以是其他类型
P2DIR |= 0xFF;//置于写入模式
P2OUT =*地址;
P3OUT |= BIT2;
}

P3DIR &=~BIT2;

P3IFG=0;//将所有标志设置为0

} 

调试时,一切都正常(我使用 UART 连接进行测试),但当正常运行(在释放模式下)时,它不再运行(数据和地址都是通过正确给出的)。 这让我认为这仍然是一个计时错误、但我不知道如何以及为什么。  

我还想在不使用该端口3.2的情况下就能做到这一点、但我还没有尝试过、因为我认为那里也会出现一些主要的时序问题、我现在不知道如何解决。  

如果需要更多的代码、请咨询、但这些只是我认为最重要的代码。

此致。  

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

    您好、Yannick、

    您能给我更详细地说明代码运行时如何进行测试吗? 这是通过连接 CCS 的 UART 接口实现的吗? (您是否还通过 CCS 调试代码?)  您是否检查了 MSP-ware 中是否有类似的示例?

    BR、
    Leo

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

    两个 MCU 是否使用相同的时钟频率?

    当数据就绪时、发送器将选通脉冲设置为高电平、并等待接收器发送一个应答信号、然后释放选通脉冲和引脚。

    另一个选项是在 SPI 模式下使用 USCI。

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

    这两个器件实际上位于同一个 CLK 频率上。 (8MHz)。  

    所有这些选项的问题在于、我被"赋予"了主器件代码、我只能更改小部分内容(例如、我现在在引脚3.2上执行的轮询)、我不能使用任何其他端口、或者对代码进行重大更改。  

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

    您好、Leonardo、  

    对于 UART 连接、我只需使用 Putty 与其进行连接。 这一切都很好、因为我通过它发送的不仅仅是这个、一切似乎都很完美。 我所做的非常简单、我用一些不同的数据将4次写入 MCU 中的不同地址(有效的可写地址)、然后再次读取这些数据(尽管顺序不同)。 此代码非常简单、每当我在 Putty 终端中写入"1"时、就会启动:  

    int testing(){
    int tests_succeeded = 0;
    uint16_t 地址 s1 = 0x1820;
    uint8_t data1 = 0b10101010;
    uint16_t 地址 s2 = 0x1860;
    uint8_t data2 = 0b01010101;
    uint16_t Address3 = 0x1920;
    uint8_t data3 = 0b11110000;-
    uint16_t 地址4 = 0x1960;
    uint8_t data4 = 0b00001111;
    
    写入(地址1、数据1);
    __no_operation();
    写入(address 2、data2);
    __no_operation();
    WRITE (Address3、data3);
    __no_operation();
    写入(address 4、data4);
    __no_operation();
    
    uint8_t new_data =读取(地址1);
    if (new_data == data1){
    SEND_DATA (0x4B4F);//通过 UART 发送'OK'
    tests_succeeded ++;
    } 否则{
    SEND_DATA (0x4F4E);//通过 UART
    发送'no'}
    
    
    new_data =读取(address 4);
    if (new_data = data4){
    SEND_DATA (0x4B4F);//通过 UART 发送'OK'
    tests_succeeded ++;
    } 否则{
    SEND_DATA (0x4F4E);//通过 UART
    发送'no'}
    
    new_data =读取(Address3);
    if (new_data = data3){
    SEND_DATA (0x4B4F);//通过 UART 发送'OK'
    tests_succeeded ++;
    } 否则{
    SEND_DATA (0x4F4E);//通过 UART
    发送'no'}
    
    new_data =读取(address 2);
    if (new_data == data2){
    SEND_DATA (0x4B4F);//通过 UART 发送'OK'
    tests_succeeded ++;
    } 否则{
    SEND_DATA (0x4F4E);//通过 UART
    发送'no'}
    
    返回 tests_succeeded;
    } 

    这将通过 UART 提供"确定"或"否"。 在 Putty 终端中、我只读回了 no、但有时会读出"正常"、但我不知道我对这"正常"有多大的信任、因为它可能只是数据卡在意外读取的线路上。 $

    调试是在 CCS 环境中完成的、我在这两个 MCU 上分步执行、它们随后完美地工作、这就是我现在怀疑时序错误的原因。  

    我没有检查任何类似的例子,谢谢您的建议。 我要看一下。 但是、由于我被赋予了这个"主"代码、并且不允许进行太多的更改(除了我现在使用的引脚之外、不能使用任何额外的引脚、也不会发生重大的代码更改(因此没有中断、但是我正在进行的轮询是可以的)。  

    此致。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
     >   P3OUT |= BIT1;      // deactivate read mode
     >   P3OUT &= ~BIT0;     // activate write mode
     >   P2OUT = data;       // write data

     

    From your description, one of the first two lines causes an interrupt on the slave, but the data lines haven't been set up yet. This sets up a race. The master will usually win, but if e.g. a stray interrupt happens it will lose.

    根据您的描述、只有一个 P3.0/1触发一个从中断、但我不确定它是如何工作的、因为 P2IES 只能在一个方向上被设定。 如何配置这些引脚?

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

    我已经可以设置数据线、但我认为这不起作用。 有一个竞争、是的、但是从器件需要在实际读取数据之前做很多事情(进入中断、获取地址、检查标志...)。 因此,我认为奴隶永远不会赢。 不过,最好不要让比赛发生,所以我会解决这个问题。  

    P3.0/1可以在其中一个中断发生时触发从机中断。 这是写入数据之前(由从器件)正在执行的操作。 数据引脚上没有中断。 数据引脚在从器件中按如下方式进行设置:  

    _bis_SR_register (GIE); //启用中断
    
    //声明所有引脚
    //控制端口
    P3IFG &=~0x03;//清除标志
    P3DIR |= 0b00000100;//第三个端口是 CSn 端口,使用该端口可以说准备好了,进行写操作
    P3OUT &=~BIT2;
    P3IE |= 0b00000011;
    P3IES |= 0x03;//前两个引脚从高电平到低电平
    P3IFG &=~0x03;//清除标志
    
    //地址端口(端口1:5、端口8:4、端口9:7),只读
    P1DIR |= 0b00000000;
    P8DIR |= 0b00000000;
    P9DIR |= 0b00000000;
    __no_operation();
    
    //数据端口
    P2DIR |= 0x00; 

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

    我列举了一个奴隶获胜的例子。 更一般而言、我建议您不要从这些角度思考。 如果有比赛、任何一方都可以获胜。

    您认为以哪种方式设置数据总线不起作用?

    您的导线有多长? 您的 CPU 时钟(MCLK)的速度有多快?

    您可能会发现在"否"结果上显示故障数据很有用。 更好的方法是查看从设备。 了解写入还是读取失败通常很有用。

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

    我首先设置数据库的"问题"是、如果从写入(为主控方读取)到读取(为主控方写入)、它在线路上仍然有自己的数据、并且仍在写入、而主控方也开始写入。 这意味着两个 MCU 同时在相同的线路上写入、这只是在询问问题。  

    不过、我要解决它、只需让从器件写入、然后直接将其 DIR 更改为读取(0x00)、这意味着可能会在这些行上"写入"某个内容(发生这种情况的可能性相当小、但仍然如此)。  

    MCU 均为8MHz、但没有连接 CLK 线。 使用的导线是常规跳线(母对母)、长度为10cm、但由于太多、它们有点混乱、可能存在一些电感问题、我没有想到、 但我现在不知道如何解决这个问题(太多导线而不是扭线)。  

    但是、在从设备中打印是一个很好的主意。 正如我说过的、可以在调试模式下执行此操作、因此我预计会出现时序错误、但添加一些代码来检查从器件时没有故障、这可能提供了更好的线索。  

    同时、我还连接了一个逻辑分析仪、但这提供了一些我不确定的数据(例如、数据线在不应该这样做时会经常上下移动、 或者、当我读取6次时、逻辑分析仪仅在线路中提供4次"突降"、而 Putty 清楚地显示全部6次"突降")。 我认为这是因为连接、我必须用一些较长的跳线(25cm)将它们连接到分析仪的母连接器和电路板的母连接器。  

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

    通常情况下、我希望数据总线线路在事务之间浮动(两侧的输入)、这意味着任一端都可以抓取它。  

    8MHz 时的10cm 导线应该正常。 我在8MHz 时看到了传播偏斜、但这可能超过了30cm 的导线。 [尽管 ADM Hopper 有"纳秒线"

    我可以想象、接线是一项挑战。 和(越来越好或更糟) Launchpad 不会按端口号订购接头引脚。

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

    我找到了一些解决方案、这些解决方案只改变了 CTRL 线路(端口3)的使用、其中我将使用1根线作为 R/W 线、1根线作为触发线(都只能由主器件写入)、1根线作为从器件的 ACK。 明天我将测试这个、如果它可以的话、我将对它进行写操作。 但是、它确实对主代码进行了一些比我希望的更大的更改、但目前这似乎也不起作用、所以为什么不尝试它。  

    导线确实应该可以、但由于连接器不完全理想、他们仍然让我担心。 launchpad 上的端口确实是一场噩梦、无法四处走动(要进入16位地址、我必须将3个不同的端口与其不同的引脚连接起来)。 但我成功了!

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

    也许您已经考虑过这一点、但是:现在您已经将 R/W 和请求分开、我认为您可以采纳该请求作为双向解决方案的第二部分:

    0)最初:请求= 1 (主器件的输出)、从器件-确认= 1 (从器件的输出)、数据悬空

    1)主器件设置 R/W 和(可能)数据、然后设置 Request=0并等待 Slave-Ack 变为低电平

    2)从机处理请求(可能设置数据)、然后将 Slave-Ack 设置为低电平并等待请求变为高电平

    3)主器件设置 request=1 (事务结束)并且(也许)释放数据为浮点

    4)从机(可能)将数据释放为浮点、并将从机 Ack 设置为高电平(事务结束)

    5)最后:请求= 1 (主器件的输出)、从器件-确认= 1 (从器件的输出)、数据悬空[与初始值相同]

    这样、所有(非数据)引脚都是单向的、并且事务结束的时刻是明确的。 双向 Ack 可确保在整个过程中锁步。

    我可能已经使它听起来很复杂、但我认为它不是比你现在更多的代码。

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

    这正是我所想到的、但 Ack 和 Request 变为低电平而不是高电平。

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

    我有表决权。

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

    您所描述的内容对我来说似乎很困惑。

    作为入门、我建议:

    地址行:主设备->从设备。

    2.数据线:双向。 因此、它应该在两端充当输入。

    R/W 线路:指示读取或写入的电平。 主设备->从设备。

    4、选通:转换表示传输。 主设备->从设备。 您可以稍后添加从站信令。 我认为、低-高转换更有意义、因为它允许从器件将线路下拉为信号。

    因此、写入例程类似于:

    1.现地址;

    2.提供数据;

    3.清除 R/W 线;

    4.频闪灯;

    5.等待一点时间(或从机架)。

    6.浮点数据线。

    一个读取例程就是这样的

    1.现地址;

    2.设置 R/W 线;

    3.频闪灯;

    4.等待一会儿(或从机架);

    5.读取数据线。

    从器件将由选通信号线激活:

    读取地址行

    2.如果 R/W 行设置->这是主器件读取、从器件写入

     2.1在数据线上提供数据;

     2.2等待一段时间

     2.3浮点数据线

     2.4.退出/发送 ACK

     else ->这是用于主设备写入、而从设备读取

     2.5读取数据

     2.6退出/发送 ACK

    最初、您可以从固定的延迟长度开始、稍后再添加 ACK。

    由于涉及的线路太多、某种串行协议实际上非常有用。而且编码容易得多。

      

    2.  

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

    我已经解决了、但我遇到了另一个问题。  

    首先、让我展示一下新代码。  

    在主器件中、写入和读取被更改为:  

    空写入(uint16_t 地址、uint8_t 数据){
    splitAndWriteAddress (address);//将端口中可用引脚上的地址拆分并写入。
    P2DIR |= 0xFF; //将 dataIO 设置为写入模式
    P2OUT =数据; //写入数据
    
    P3OUT &=~BIT0; //取消激活读取模式设置写入模式--> R/~W = 0
    P3OUT &=~BIT1; //激活触发--> T = 0 (高到低)
    
    while (!(P3IN & BIT2)){//如果 P3.2 (ACK)变为1、则继续
    __no_operation();
    }
    P3OUT |= BIT1; //停用触发器--> T = 1
    P2DIR |= 0x00; //将 dataIO 设置为读取模式
    
    while (((P3IN & BIT2)){//如果 P3.2 (ACK)变为1、请继续->可能会卡在此处
    __no_operation();
    }
    
    }
    
    
    uint8_t 读取(uint16_t 地址){
    uint8_t data = 0x00;
    splitAndWriteAddress (地址);
    P2DIR &= 0x00; //将 dataIO 设置为读取模式
    P3OUT |= BIT0; //取消激活写入模式设置读取模式--> R/~W = 1
    P3OUT &=~BIT1; //激活触发--> T = 0 (高到低)
    while (!(P3IN & BIT2)){//如果 P3.2 (ACK)变为1、则继续
    __no_operation();
    }
    数据= P2IN;
    P3OUT |= BIT1; //停用触发器--> T = 1
    
    while (P3IN & BIT2){//如果 P3.2变为0,则继续
    __no_operation();
    }
    返回数据;
    } 

    它基本上遵循上述给定的逻辑。  

    并且从器件中断更改为:  

    #if defined (__TI_Compiler_version__)|| defined (__IAR_systems_icc_)
    #pragma vector=PORT3_vector
    __interrupt void Port_3 (void)
    #elif defined (__GNU__)
    void __attribute__((interrupt (PORT3_vector)))) Port_3 (void
    
    编译器#else 不支持!
    #endif
    {
    /*
    * 4个可用 RAM 段:
    * 1. D --> 1800h '到187Fh
    * 2. C -> 1880h '到18FFh
    * 3. b --> 1900h '直至187Fh
    * 4. a --> 1980h '直到19FFh
    *
    uint16_t volatile * address =(uint16_t *) getAddress ();
    
    if (!(P3IN & BIT0)){//读取
    P2DIR &= 0x00;//置于读取模式
    *地址= P2IN;
    P3OUT |= BIT2;
    }
    //写入
    否则{
    P2DIR |= 0xFF;//置于写入模式
    P2OUT &= 0x00;
    P2OUT |=*地址;
    P3OUT |= BIT2;//将 ACK 设置为1
    P4DIR |= BIT0;
    P4OUT |= BIT0;
    }
    //}
    while (!(P3IN & BIT1)){//在 Trigger (3.1)仍然为高电平时不执行任何操作
    __no_operation();
    }
    
    P2DIR &= 0x00;
    P3OUT =~BIT2;
    
    P3IFG=0;//将所有标志设置为0
    
    } 

    这再次遵循上述逻辑。  

    但是、现在存在一些错误。  

    我主要无法写入从器件中的存储器。 我进入 if 语句进行读取(作为从器件、因此在中断中、在该语句中、使用不同端口上亮起的 LED 对其进行了测试)、但不会将任何内容放入存储器中。 我知道这一点是因为如果我尝试向存储器地址写入新的内容、我只会得到"no"。 但是、主器件的读操作非常好、因为我之前已经在从器件中放置了一些数据(以及其他调试器等)、现在当我将这些数据读回主器件时、"正确"的数据(因此旧数据)就会发出。  

    我尝试通过将新数据写入同一地址来测试这一点、然后发现、主器件可以读取第一个数据(仍然与旧数据相同)、但之后他一直提供相同的数据。  

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

    >          if(!(P3IN & BIT0)){  // READ

    该测试向后看。 主器件似乎认为读取的是 P3.0=1 (R/~W)、但这表明它是 P3.0=0 (~R/W)。

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

    非 这里的语义很奇怪。  

    从机的读操作是主机的写操作、因为当主机向从机写入数据(R/W = 0)时、从机必须读操作。  

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

    初始设置如何? 我希望 P3.0=1 (主器件的输出)、P3.2=0 (从器件的输出)、P2.ALL 悬空。

    您是否有可能丢失 MPU 设置、而信息 FRAM 突然无法写入?

    我只是注意到:"地址"是一个(uint16_t *)、但你实际上只读/写8位。 至少、写入会额外放置一个0x00字节。 可能还有一些对齐方式。 (即使如此、如果您使用的地址完全相同、我也希望获得合理的结果。)

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

    主设备的初始设置为:  

    PM5CTL0 &=~LOCKLPM5;
    WDTCTL = WDTPW | WDTHOLD;//停止看门狗计时器
    
    //声明所有引脚
    //控制端口
    P3DIR |= 0b00000011;//第三个端口是 ACK 端口,这是只读的
    P3OUT |= 0b00000011;
    
    //地址端口(端口1:5、端口8:4、端口9:7)
    P1DIR |= 0b11111000;
    P8DIR |= 0b11110000;
    P9DIR |= 0b01111111;
    
    //数据端口
    P2SEL0 &= 0x00;
    P2DIR |= 0x00;
    
    //初始化计时器和 UART 的 GPIO 和时钟
    init_gpio();
    init_clocks();
    init_communication();
    init_timer(); 

    上述方法为:  

    void init_gpio (void){
    //WDTCTL = WDTPW | WDTHOLD; //停止看门狗
    
    //配置 GPIO
    P3SEL0 |= BIT4 + BIT5; // eUSCI_A1 UART
    P3SEL1 &=~(BIT4 + BIT5); // eUSCI_A1 UART
    PJSEL0 |= BIT4 | BIT5; //为 ACLK 配置 XT1引脚
    
    //禁用 GPIO 上电默认高阻抗模式以激活
    //先前配置的端口设置
    PM5CTL0 &=~LOCKLPM5;
    }
    
    void init_clocks (void){
    //时钟系统设置
    CSCTL0_H = CSKEY >> 8; //解锁 CS 寄存器
    CSCTL1 = DCOFSEL_6; //将 DCO 设置为8MHz
    CSCTL2 = SELA_LFXTCLK | SELESS__DCOCLK | SELM_DCOCLK;//设置 SMCLK = MCLK = DCO
    // ACLK = VLOCLK
    CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1; //将所有分频器设置为1
    
    CSCTL4 &=~LFXTOFF;
    操作
    {
    CSCTL5 &=~LFXTOFFG; //清除 XT1故障标志
    SFRIFG1 &=~OFIFG;
    } while (SFRIFG1&OFIFG); //测试振荡器故障标志
    
    CSCTL0_H = 0; //锁定 CS 寄存
    器}
    
    void init_communication (void)
    {
    //为 UART 模式配置 USCI_A1
    UCA1CTLW0 = UCSWRST; //将 eUSCI 置于复位
    UCA1CTLW0 |= UCSSEL_ACLK; // CLK = ACLK
    UCA1BR0 = 3; // 9600波特
    UCA1MCTLW |= 0x5300; // 32768/9600 - INT (32768/9600)=0.41
    // UCBRSx 值= 0x53 (请参阅 UG)
    UCA1BR1 = 0;
    UCA1CTL1 &=~UCSWRST; //初始化 eUSCI
    UCA1IE |= UCRXIE; //启用 USCI_A1 RX 中断
    
    __bis_SR_register (GIE); //输入 LPM3,启用中断-->写入状态寄存器
    __no_operation();
    }
    
    void init_timer (void){
    TA0CTL = tassel_SMCLK | MC__Continous;// SMCLK,连续模式
    } 

    对于从器件、我们具有:  

    void main (void)
    {
    PM5CTL0 &=~LOCKLPM5;
    WDTCTL = WDTPW | WDTHOLD;//停止看门狗计时器
    init_gpio ();
    init_clocks ();
    while (1){
    __no_operation();
    }
    

    使用这些方法可以:  

    void init_gpio (void){
    _bis_SR_register (GIE); //启用中断
    
    P4DIR |= BIT0;
    P4OUT &=~BIT0;
    
    //声明所有引脚
    //控制端口
    P3IFG &=~0x02;//清除标志
    P3DIR |= 0b00000100;//第三个端口是 CSn 端口,这是只读的-->使用该端口说准备就绪时进行写入
    P3OUT &=~BIT2;
    P3IE |= BIT1;
    P3IES |= BIT1;//从 L 到 H 在第二个
    P3IFG &=~0x02;//清除标志
    
    //地址端口(端口1:5、端口8:4、端口9:7),只读
    P1DIR |= 0b00000000;
    P8DIR |= 0b00000000;
    P9DIR |= 0b00000000;
    __no_operation();
    
    //数据端口
    P2DIR &= 0x00;
    }
    
    void init_clocks (void){
    //时钟系统设置
    CSCTL0_H = CSKEY >> 8; //解锁 CS 寄存器
    CSCTL1 = DCOFSEL_6; //将 DCO 设置为8MHz
    CSCTL2 = SELA_VLOCLK | SELESS__DCOCLK | SELM_DCOCLK;//设置 SMCLK = MCLK = DCO
    // ACLK = VLOCLK
    CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1; //将所有分频器设置为1
    CSCTL0_H = 0;
    } 

    我认为这里不会发生任何怪异的事情吗?  

    由于我用作从器件的 MSP430是全新的、我不知道如何更改其中的 MPU 设置。 我查看了其中一个编码示例、如果需要、我可以实现它、但我看不到这是如何以及为什么会起作用的、因为我正在写入一个"打开的"RAM 部分(我使用的地址始终在0x1800和0x19FF 之间)。 在调试模式下、我能够对它进行写入。

    我还将指针更改为 uint8_t*,但这尚未解决。  

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

    根据数据表(SLAS789D)表6-46、这些地址位于由 MPU 控制的信息 FRAM 中。 每当我想对其进行写操作时(我不记得我是否尝试过 FR6989)、我都需要使用"Build Settings->CCS General"选项卡将其设为可写、  

    奇怪的是、显然您以前已经成功了。 另一方面、您描述的症状是、您将看到这些区域是否受写保护。  

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

    执行此操作后(在选项卡中执行"手动指定存储器..."、段1的下边界为0x4400、顶部为0x4800)、并使该段为读取和写入、每当我写入地址(例如0x4410)时、我仍然没有任何结果。 但我认为这是因为边界<4向右移动。 如0x4400实际上是0x440000 (请参阅 第315 - 316页的《MSP430FR58xx、MSP430FR59xx 和 MSP430FR6xx 系列用户指南》(修订版 P))。 是这样吗?  

    因为我能够写入。 我认为我已经能够在调试模式下执行此操作、在调试模式下、MPU 可能没有那么严格、更宽容。 然后它就停留在那里。

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

    当我这么做时、它似乎是有效的。 地址实际上是0x4400/0x4800、这是 FRAM 的开头[参考数据表表6-45]

    除了实验之外、我建议您重点关注信息 FRAM (位于 MPU 选项卡的底部)、因为在那里工作不会与链接器的任何操作发生冲突。

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

    您好、Bruce、  

    我也在这样做(写入0x1810等)。 这似乎仍然不适合我。 我从未使用过 MPU、因此这对我来说有点陌生(我通常不使用特定的存储器)。  

    但是、由于我们对这个线程的主题非常不熟悉、我在这里创建了一个关于这个确切问题(写入存储器、尽管我可以向您保证我也在查看数据表并尝试找到解决方案)的新问题: https://e2e.ti.com/support/microcontrollers/msp430/f/166/t/932016 

    在这个(时序错误)线程中、我将确保您上面的一条评论是"这已解决我的问题"评论(其中包含协议建议的评论)。  

    感谢您的帮助、非常感谢您在下一个主题上提供的帮助。

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

    您是否能够观察(例如在调试器中)从器件无法写入? 这将作为主要证据。 此锁步协议的一个优点是、您应该能够随时停止它(断点)、并且它仍将执行正确的操作。

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

    这就是调试器中写入操作失败的原因。 我可以清楚地看到该地址上的数据被覆盖。 更好的是、如果我再次读取(无论是在调试器中、还是正常情况下)、主器件会为我提供"确定"(它返回了他预期的数据的符号)、但是如果我更改地址的数据、则它会返回到"no"。  

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

    getAddress()是否与此处另一个线程中的相同?

    https://e2e.ti.com/support/microcontrollers/msp430/f/166/p/903258/3338850

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

    是的。  

    地址本身通常是正确的(多次使用调试器欺骗它)

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

    您在另一个线程中报告说、某个东西"已解决"。 这是否意味着这些方案现在可以按预期工作?

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

    我仍在彻底测试它,但一切似乎都很完美。

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

    我很担心代码中会出现这种情况。 一段时间后、您不知道要在那里执行什么操作。

    我会放置一个宏来描述那里的活动、并根据目标/引脚分配映射宏。 本质上、使代码尽可能"独立于硬件"。 因此、下次您可以将相同的代码转至不同的平台并重新映射宏、这样就完成了。