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.

[参考译文] MSP-EXP430FR5739:I2C @ M24C02-FMN6TP

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1004801/msp-exp430fr5739-i2c-m24c02-fmn6tp

器件型号:MSP-EXP430FR5739

您好!

我正在尝试使用以下代码与 EEPROM (M24C02-FMN6TP)通信。 如果我执行此代码并使用示波器观察 SDA 和 SCL、我只会看到一个"序列":

开始条件- EEPROM 地址(0x50)-#WRITE_FLAG -来自 EEPROM 的 ACK - 1字节(0x66)-来自 EEPROM 的 ACK -停止条件

现在、问题不是为什么我只能看到一个序列、也不是我想知道为什么它只包含一个单字节。 问题是为什么序列中的那个字节是数据字节(0x66)而不是地址(0x05)?

感谢您的回复。

Christian

#include <msp430.h>
#include <stdint.h>

void init_16_MHz_clock(void)
{
  //Unlock CS registers with CSKEY password.
  CSCTL0 = CSKEY;
  //Set DCOCLK = 16 MHz.
  CSCTL1 &= ~(DCOFSEL1 + DCOFSEL0);
  CSCTL1 |= DCORSEL + DCOFSEL_2;
  //Set ACLK = SMCLK = MCLK = DCOCLK.
  CSCTL2 = SELA_3 + SELS_3 + SELM_3;
  //Set all dividers to 0.
  CSCTL3 = DIVA_0 + DIVS_0 + DIVM_0;

  //Lock CS registers again.
  CSCTL0_H = 0;
}

void hold_watchdog_timer(void) {
  WDTCTL = WDTPW + WDTHOLD;
}

void init_i2c(const uint8_t eeprom_address) {
  P1SEL0 &= ~(0xC0u);
  P1SEL1 |= 0xC0u;

  UCB0CTLW0 |= UCSWRST;
  UCB0CTLW0 &= ~(UCA10 + UCSLA10 + UCMM + UCTXACK + UCTXNACK + UCTXSTP +
    UCTXSTT);
  UCB0CTLW0 |= UCMST + UCMODE_3 + UCSYNC + UCSSEL__SMCLK + UCTR;
  UCB0CTLW1 &= ~(UCETXINT + UCCLTO1 + UCCLTO0 + UCSTPNACK + UCSWACK + UCASTP1 +
    UCASTP0 + UCGLIT1 + UCGLIT0);
  UCB0CTLW1 |= UCASTP_2;
  UCB0BRW = 160;
  UCB0TBCNT = 1;
  UCB0I2COA0 &= ~(UCGCEN + UCOAEN);
  UCB0I2COA1 &= ~(UCOAEN);
  UCB0I2COA2 &= ~(UCOAEN);
  UCB0I2COA3 &= ~(UCOAEN);
  UCB0ADDMASK |= 0x3FFu;
  UCB0CTLW0 &= ~UCSWRST;
  UCB0I2CSA = eeprom_address;

  //Test if the bus is free, otherwise a manual clock on is generated.
  if(UCB0STATW & UCBBUSY) {
    P1SEL1 &= ~0x80;
    P1OUT &= ~0x80;
    P1DIR |= 0x80;
    P1SEL1 |= 0x80;
  }

  UCB0IE = 0; UCB0IFG = 0; UCB0IV |= 0xFFFFu;
}

void eeprom_write(const uint8_t address, const uint8_t data) {
  unsigned short i;

  const uint8_t buffer[2] = {data, address};

  UCB0CTLW0 |= UCTR;
  UCB0IE |= UCTXIE0;
  while(UCB0STATW & UCBBUSY);
  UCB0CTLW0 |= UCTXSTT;
  for(i = 2; i > 0; --i) {
    UCB0TXBUF = buffer[i - 1];
    while(!(UCB0IFG & UCTXIFG0));
  }
  UCB0IE &= ~UCTXIE0;
  UCB0IFG = 0; UCB0IV |= 0xFFFFu;
  while(UCB0STATW & UCTXSTP);
}

uint8_t eeprom_read(const uint16_t address) {
  return 0;
}

int main(void) {
  unsigned short i;

  const uint8_t EEPROM_ADDRESS = 0x50u;

  const uint8_t write_values[6] = {0x11u, 0x22u, 0x33u, 0x44u, 0x55u, 0x66u};
  volatile uint8_t read_values[6] = {0};

  hold_watchdog_timer();

  init_16_MHz_clock();

  init_i2c(EEPROM_ADDRESS);

  //Write values to addresses 0x05..0x00 in the EEPROM.
  for(i = 6; i > 0; --i) {
    eeprom_write(0x00u + i - 1, write_values[i - 1]);
  }

  //Read values from addresses 0x05..0x00 in the EEPROM.
  for(i = 6; i > 0; --i)
    read_values[i - 1] = eeprom_read(0x00u + i - 1);

  return 0;
}

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

    >UCB0TXBUF =缓冲器[I - 1];
    > while (!(UCB0IFG & UCTXIFG0));
    尽管有用户指南(SLAU272D)图20-12、但我很确定我已经观察到 CPU 设置 TXSTT=1和 I2C 单元设置 UCTXIFG=1之间存在一个可检测延迟。 这将导致第一个字节(地址)丢失。 在任何情况下、你应该坚持一个通用规则、除非 TXIFG=1、否则你不应该写入 TXBUF。

    具体地说:我建议你颠倒这两个发言的顺序。

    未经请求:如果您没有使用中断(即您没有 ISR)、我建议您不要设置 UCTXIE。 您似乎没有在此程序中全局启用中断(GIE)、因此它会意外工作、但它没有作用、当您决定启用 GIE 时会导致问题。