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.

[参考译文] MSP430FR6928:AT24C256与 MSP430FR6928连接

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1299074/msp430fr6928-at24c256-interfacing-with-msp430fr6928

器件型号:MSP430FR6928
主题中讨论的其他器件:MSP430FR6989

您好、在与 at24c256 EEPROM 连接时无法生成 I2C 中断。

我参考以下代码:

//*****
// MSP430FR69xx 演示- eUSCI_B0、I2C 主器件多字节 TX/RX
//
//说明:I2C 主设备与 I2C 从设备进行通信发送和接收
// 3个不同长度的不同消息。 I2C 主器件将进入 LPM0模式
//同时通过 I2C 中断等待消息的发送/接收。
// ACLK = NA、MCLK = SMCLK = DCO 16MHz。
//
///|\/|\
// MSP430FR6989 4.7K |
//------------------------------------------------------- | 4.7K
///|\| P1.7|---------- I2C 时钟(UCB.S.)
//|||||
//--------|RST P1.6|----- +/- I2C 数据(UCB1SDA)
//|
//|
//|
//|
//|
//|
//
/// Nima Eskandari 和 Ryan Meredith
//德州仪器公司
// 2018年1月
//通过 CCS v7.3构建
//*****

#包含
#包含
#包含

//*****
//引脚配置
//*****

#define LED_OUT P1OUT
#define LED_DIR P1DIR
#define LED0_PIN BIT0
#define LED1_PIN 位1

//*****
//命令示例
//*****

#define SLAVE_ADDR 0x05

/* CMD_TYPE_X_SLAVE 是主设备发送到从设备的示例命令。
*从器件将发送示例 SlaveTypeX 缓冲区作为响应。
*
* CMD_TYPE_X_MASTER 是主设备向从设备发送的示例命令。
*从器件将初始化自身以接收 MasterTypeX 示例缓冲区。
***/

#define CMD_TYPE_0_SLAVE 0
#define CMD_TYPE_1_SLAVE 1
#define CMD_TYPE_2_SLAVE 2

#define CMD_TYPE_0_MASTER 3
#define CMD_TYPE_1_MASTER 4
#define CMD_TYPE_2_MASTER 5

#define TYPE_0_LENGTH 1
#define TYPE_1_LENGTH 2
#define TYPE_2_LENGTH 6

#define MAX_BUFFER_SIZE 20

/* MasterTypeX 是在主器件中初始化的示例缓冲区、它们将
*主器件发送到从器件。
* SlaveTypeX 是在从器件中初始化的示例缓冲区,它们将是
*由从机发送到主机。
***/

uint8_t MasterType2 [TYPE_2_LENGTH]={'F'、'4'、'1'、'9'、'2'、 'b'};
uint8_t MasterType1 [TYPE_1_LENGTH]={8、9};
uint8_t MasterType0 [TYPE_0_LENGTH]={11};


uint8_t SlaveType2 [TYPE_2_LENGTH]={0};
uint8_t SlaveType1 [TYPE_1_LENGTH]={0};
uint8_t SlaveType0 [TYPE_0_LENGTH]={0};

//*****
//常规 I2C 状态机
//*****

typedef 枚举 I2C_ModeEnum{
IDLE_MODE、
NACK_MODE、
TX_REG_ADDRESS_MODE、
RX_REG_ADDRESS_MODE、
TX_DATA_MODE、
RX_DATA_MODE、
SWITCH_TO_RX_MODE、
SWITHC_TO_TX_MODE、
超时模式
} I2C_Mode;


/*用于跟踪软件状态机的状态*/
I2C_Mode MasterMode = IDLE_MODE;

/*要使用的寄存器地址/命令*/
uint8_t TransmitRegAddr = 0;

/* ReceiveBuffer:用于在 ISR 中接收数据的缓冲区
* RXByteCtr :接收剩余字节数
ReceiveIndex:应在 ReceiveBuffer 中接收的下一个字节的索引
* TransmitBuffer:用于在 ISR 中传输数据的缓冲区
* TXByteCtr:待传输的剩余字节数
* TransmitIndex:在 TransmitBuffer 中发送的下一个字节的索引
***/
uint8_t ReceiveBuffer[MAX_BUFFER_SIZE]={0};
uint8_t RXByteCtr = 0;
uint8_t ReceiveIndex = 0;
uint8_t TransmitBuffer[MAX_BUFFER_SIZE]={0};
uint8_t TXByteCtr = 0;
uint8_t TransmitIndex = 0;

/* I2C 写入和读取函数*/

/*对于具有 dev_addr 的从器件、写入在* reg_data 中指定的数据
*
* dev_addr:从设备地址。
*示例: SLAVE_ADDR
* reg_addr :发送到从机的寄存器或命令。
*示例: CMD_TYPE_0_MASTER
** reg_data :要写入的缓冲区
*示例: MasterType0
* count :* reg_data 的长度
*示例: TYPE_0_LENGTH
***/
I2C_Mode I2C_REF Master_Write (uint8_t dev_addr、uint8_t reg_addr、uint8_t * reg_data、uint8_t count);

/*对于具有 dev_addr 的从器件、读取在从器件 reg_addr 中指定的数据。
*接收到的数据在 ReceiveBuffer 中可用
*
* dev_addr:从设备地址。
*示例: SLAVE_ADDR
* reg_addr :发送到从机的寄存器或命令。
*示例: CMD_TYPE_0_SLAVE
*计数:要读取的数据长度
*示例: TYPE_0_LENGTH
***/
I2C_Mode I2C_REF Master_Read (uint8_t dev_addr、uint8_t reg_addr、uint8_t count);
void CopyArray (uint8_t *源、uint8_t * dest、uint8_t count);


I2C_Mode I2C_EVM Master_Read (uint8_t dev_addr、uint8_t reg_addr、uint8_t count)
{
/*初始化状态机*/
MasterMode = TX_REG_ADDRESS_MODE;
TransmitRegAddr = reg_addr;
RXByteCtr = count;
TXByteCtr = 0;
ReceiveIndex = 0;
TransmitIndex = 0;

/*初始化从机地址和中断*/
UCB1I2CSA = DEV_addr;
UCB1IFG &&~(UCTXIFG + UCRXIFG);//清除任何挂起的中断
UCB1IE &&~UCRXIE;//禁用 RX 中断
UCB1IE |= UCTXIE;//启用 TX 中断

UCB1CTLW0 |= UCTR + UCTXSTT;// I2C TX、启动条件
//_ bis_SR_register (LPM0_bits + GIE);//随着中断进入 LPM0

返回 MasterMode;


I2C_Mode I2C_REF Master_Write (uint8_t dev_addr、uint8_t reg_addr、uint8_t * reg_data、uint8_t count)
{
/*初始化状态机*/
MasterMode = TX_REG_ADDRESS_MODE;
TransmitRegAddr = reg_addr;

//将寄存器数据复制到 TransmitBuffer
CopyArray (reg_data、TransmitBuffer、count);

TXByteCtr = count;
RXByteCtr = 0;
ReceiveIndex = 0;
TransmitIndex = 0;

/*初始化从机地址和中断*/
UCB1I2CSA = DEV_addr;
UCB1IFG &&~(UCTXIFG + UCRXIFG);//清除任何挂起的中断
UCB1IE &&~UCRXIE;//禁用 RX 中断
UCB1IE |= UCTXIE;//启用 TX 中断

UCB1CTLW0 |= UCTR + UCTXSTT;// I2C TX、启动条件
//_ bis_SR_register (LPM0_bits + GIE);//随着中断进入 LPM0

返回 MasterMode;

void CopyArray (uint8_t *源、uint8_t * dest、uint8_t count)
{
uint8_t copyIndex = 0;
对于(copyIndex = 0;copyIndex < count;copyIndex ++)
{
dest[copyIndex]= source[copyIndex];


//*****
//设备初始化
//*****


void initGPIO()
{
//配置 GPIO
LED_OUT &&~(LED0_PIN | LED1_PIN);//针对 LED 和 RESET 输出的 P1设置
LED_DIR |=(LED0_PIN | LED1_PIN);

// I2C 引脚
P3SEL0 |= BIT1 | BIT2;
P3SEL1 &=~(BIT1 | BIT2);
P3DIR |=BIT0;
P3OUT &=~(BIT0);
//禁用 GPIO 上电默认高阻抗模式以激活
//先前配置的端口设置
PM5CTL0 &=~μ A LOCKLPM5;

void initClock45C() 16MHz
{
//根据 MCLK 的器件数据表需要配置一个 FRAM 等待状态
//在配置时钟系统之前8MHz 之外的操作。
FRCTL0 = FRCTLPW | NWAITS_1;

//时钟系统设置
CSCTL0_H = CSKEY_H;//解锁 CS 寄存器
CSCTL1 = DCOFSEL_0;//将 DCO 设置为1MHz

//设置 SMCLK=MCLK=DCO、ACLK=LFXTCLK (如果不可用、则为 VLOCLK)
CSCTL2 = SELM__LFXTCLK | SELS__DCOCLK | SELM__DCOCLK;

//每器件勘误表将分频器设置为4,然后再将频率更改为
//防止过冲瞬变导致超出规范操作
CSCTL3 = DIVA_4 | DIVS__4 | DIVM__4;//将所有相应的 clk 源设置为4分频、以进行勘误
CSCTL1 = DCOFSEL_4 | DCORSEL;//将 DCO 设置为16MHz

//延迟~10us 以使 DCO 稳定。 60个周期= 20个周期缓冲区+(10us /(4MHz))
__delay_cycles (60);
CSCTL3 = DIVA_1 | DIVS__1 | DIVM_1;//将所有分频器设置为1以进行16MHz 操作
CSCTL0_H = 0;//锁定 CS 寄存器

void initI2C()
{
UCB1CTLW0 = UCSWRST;//启用软件复位
UCB1CTLW0 |= UCMODE_3 | UCMST | UCSSEL__SMCLK | UCSYNC;// I2C 主模式、SMCLK
UCB1BRW = 160;// fSCL = SMCLK/160 =~100kHz
UCB1I2CSA = SLAVE_ADDR;//从器件地址
UCB1CTLW0 &=~μ V UCSWRST;//清除软件复位、恢复操作
UCB1IE |= UCNACKIE;


//*****
//主要文件
//发送和接收三条包含示例命令的消息*****
//*****

int main (void){
WDTCTL = WDTPW | WDTHOLD;//停止看门狗计时器
initClock45C(); 16MHz
initGPIO();
initI2C();

I2C_EVENT(Master_Write SLAVE_ADDR、CMD_TYPE_0_MASTER、MasterType0、TYPE_0_LENGTH);
I2C_EVENT(Master_Write SLAVE_ADDR、CMD_TYPE_1_MASTER、MasterType1、TYPE_1_LENGTH);
I2C_RDCM_ADDR Master_Write (SLAVE_ADDR、CMD_TYPE_2_MASTER、MasterType2、TYPE_2_LENGTH);

I2C_EVENT(Master_Read SLAVE_ADDR、CMD_TYPE_0_SLAVE、TYPE_0_LENGTH);
CopyArray (ReceiveBuffer、SlaveType0、TYPE_0_LENGTH);

I2C_RDCM_ADDR Master_Read (slave_ADDR、CMD_TYPE_1_SLAVE、TYPE_1_LENGTH);
CopyArray (ReceiveBuffer、SlaveType1、TYPE_1_LENGTH);

I2C_RDCM_ADDR Master_Read (slave_ADDR、CMD_TYPE_2_SLAVE、TYPE_2_LENGTH);
CopyArray (ReceiveBuffer、SlaveType2、TYPE_2_LENGTH);

//_ bis_SR_register (LPM0_bits + GIE);
返回0;


//*****
// I2C 中断
//*****

#if defined (__TI_Compiler_version__)|| defined (__IAR_SYSTEMS_ICC__)
#pragma vector = USCI_B1_VECTOR
__interrupt void USCI_B1_ISR (void)
#Elif 已定义(_ GNU _)
void __attribute__((interrupt (USCI_B0_vector)) USCI_B1_ISR (void)
#else
#错误编译器不受支持!
#endif
{
//必须从 UCB1RXBUF 读取
uint8_t rx_val = 0;
switch (__even_in_range (UCB1IV、USCI_I2C_UCBIT9IFG))
{
USCI_NONE:break;// Vector 0:无中断
情况 USCI_I2C_UCALIFG:break;//矢量2:ALIFG
实例 USCI_I2C_UCNACKIFG://矢量4:NACKIFG
中断;
情况 USCI_I2C_UCSTTIFG:break;// Vector 6:STTIFG
情况 USCI_I2C_UCSTPIFG:break;//矢量8:STPIFG
情况 USCI_I2C_UCRXIFG3:中止;//向量10:RXIFG3
case USCI_I2C_UCTXIFG3:break;//矢量12:TXIFG3
情况 USCI_I2C_UCRXIFG2:break;// Vector 14:RXIFG2
case USCI_I2C_UCTXIFG2:break;//矢量16:TXIFG2
USCI_I2C_UCRXIFG1:break;//向量18:RXIFG1
情况 USCI_I2C_UCTXIFG1:break;// Vector 20:TXIFG1
实例 USCI_I2C_UCRXIFG0://矢量22:RXIFG0
RX_val = UCB1RXBUF;
IF (RXByteCtr)
{
ReceiveBuffer[ReceiveIndex++]= Rx_val;
RXByteCtr --;

if (RXByteCtr =1)
{
UCB1CTLW0 |= UCTXSTP;

否则、如果(RXByteCtr =0)
{
UCB1IE &=~UCRXIE;
MasterMode = IDLE_MODE;
__ bic_SR_register_on_exit (CPUOFF);//退出 LPM0

中断;
情况 USCI_I2C_UCTXIFG0://矢量24:TXIFG0
开关(主模式)
{
案例 TX_REG_ADDRESS_MODE:
UCB1TXBUF = TransmitRegAddr;
IF (RXByteCtr)
MasterMode = SWITCH_TO_RX_MODE;//需要立即开始接收
否则
MasterMode = TX_DATA_MODE;//继续传输发送缓冲器中的数据
中断;

案例 SWITCH_TO_RX_MODE:
UCB1IE |= UCRXIE;//启用 RX 中断
UCB1IE &&~μ A UCTXIE;//禁用 TX 中断
UCB1CTLW0 &=~μ A UCTR;//切换到接收器
MasterMode = RX_DATA_MODE;//状态为接收数据
UCB1CTLW0 |= UCTXSTT;//发送重复启动
if (RXByteCtr =1)
{
//因为这是 N-1字节,所以必须发送 STOP
while ((UCB1CTLW0和 UCTXSTT));
UCB1CTLW0 |= UCTXSTP;//发送停止条件

中断;

案例 TX_DATA_MODE:
IF (TXByteCtr)
{
UCB1TXBUF = TransmitBuffer[TransmitIndex++];
TXByteCtr—;

否则
{
//完成传输
UCB1CTLW0 |= UCTXSTP;//发送停止条件
MasterMode = IDLE_MODE;
UCB1IE &&~μ A UCTXIE;//禁用 TX 中断
__ bic_SR_register_on_exit (CPUOFF);//退出 LPM0

中断;

默认值:
___ no_operation();
中断;

中断;
默认值:中断;

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

     >/__ bis_SR_register (LPM0_bits + GIE);//随着中断进入 LPM0

    此行将为 CPU 启用中断、因此删除它(以及另外两行)意味着您永远不会看到任何中断。

    它所做的另一件事是等待事务完成。 如果你不这样做,你将回圈,并(尝试)启动另一个交易,同时第一个仍在运行。

    我建议您取消对这些行的注释。

    ----------------

    > #define SLAVE_ADDR 0x05

    当我阅读数据表(DOC0670版本 T)图7时、这应该是:

    > #define SLAVE_ADDR 0x50

    根据您使用的板、它也可能是0x51/0x52/0x53 [再次参考图7 ]、但请先尝试这个。

    ----------------

    > I2C_Mode I2C_C2 Master_Write (uint8_t dev_addr、uint8_t reg_addr、uint8_t * reg_data、uint8_t count)

    更一般地说,读过数据表第10页--你需要一个 uint16_t reg_addr,并且你需要更改代码来处理这个问题。 这个参与其它讨论的人似乎已经明白了(线程中有几个代码版本):

    https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1172339/msp430fr5994-interfacing-issue/4417244