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.

[参考译文] MSP430FR5994:具有 MSP430FR5994的 I2C EEPROM

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1199746/msp430fr5994-i2c-eeprom-with-msp430fr5994

器件型号:MSP430FR5994
主题中讨论的其他器件: MSP430F5529

你好。

我正在使用 MSP430FR5994和 I2C EEPROM。 我在迁移部分工作的 I2Croutines.c 时遇到一些困难。

写入 EEPROM 后、电池消耗过多、读取 EEPROM 时不会发生这种情况。

使用另一个 MSP430F5529、写入和读取工作正常、而不会改变电池消耗。

是否有人可以指导我、或者他们是否知道 MSP430FR5994寄存器以更正所附的代码?

我感谢每个人的冷气!

MSP430FR5994 I2C Pin Configuration
////////////////////////////////////////////////////////////////////////////////
//         Definição da Porta P5 como Serial I2C das Memórias EEPROMS         //
////////////////////////////////////////////////////////////////////////////////
P5OUT = 0;                                                                   // Reseta Todos os Pinos da Porta P5
P5DIR = 0xFF;                                                                // Define Todos os Pinos da Porta P5 como Saídas
P5OUT &=~ 0xFF;                                                              // Inicializa Todos os Pinos da Porta P5 com Nível Lógico "0" Baixo
P5SEL0 |= BIT0 | BIT1;                                                       // Seleciona o Pino da Porta P5.0 UCB1SDA e P5.1 UCB1SCL como Barramento I2C                                                   
P5SEL1 &= ~(BIT0 | BIT1);                                                    // Seleciona Módulo Primário Conforme Tabela I/O Function Selection
// Configuração do Barramento I2C das Memórias EEPROMs
UCB1CTLW0 = UCSWRST;                                                         // Enable SW reset
UCB1CTLW0 |= UCMODE_3 | UCMST | UCSSEL__SMCLK;                               // I2C Master, synchronous mode
UCB1BRW = 160;                                                               // fSCL = SMCLK/160 = 100 kHz
UCB1CTLW1 |= 0x40;                                                           // Use SMCLK, TX mode, keep SW reset
UCB1CTLW1 |= UCASTP_2;
UCB1CTLW0 &= ~UCSWRST;                                                       // Clear SW reset, resume operation
//UCB1IE |= UCNACKIE + UCALIE + UCSTPIE + UCSTTIE + UCTXIE0 + UCRXIE0 | UCBCNTIE | USCI_I2C_UCCLTOIFG; // Interrupts Enable
UCB1IE |= UCNACKIE + UCTXIE0 + UCRXIE0; // Interrupts Enable
  
   
I2Croutines.h

void InitI2C(char eeprom_i2c_address);
void EEPROM_ByteWrite(unsigned int Address , char Data);
void EEPROM_PageWrite(unsigned int StartAddress , char * Data , unsigned int Size);
char EEPROM_RandomRead(unsigned int Address);
char EEPROM_CurrentAddressRead(void);
void EEPROM_SequentialRead(unsigned int Address , char * Data , unsigned int Size);
void EEPROM_AckPolling(void);   
   
   
I2CRoutines.c

#include "I2Croutines.h"
#include "delay.h"

#define     MAXPAGEWRITE   33

int PtrTransmit;
char I2CBufferArray[66];
char I2CBuffer;

/*----------------------------------------------------------------------------*/
// Description:
//   Initialization of the I2C Module
/*----------------------------------------------------------------------------*/
void InitI2C(char eeprom_i2c_address)
{
  while (UCB1STAT & UCBUSY);                                                    // wait until I2C module has
                                                                                // finished all operations.
  // Direciona para o Endereço de Memória EEPROM Correto para o Uso
  UCB1I2CSA  = eeprom_i2c_address;                                              // define Slave Address
                                                                                // In this case the Slave Address
                                                                                // defines the control byte that is
                                                                                // sent to the EEPROM.
}

/*---------------------------------------------------------------------------*/
// Description:
//   Initialization of the I2C Module for Write operation.
/*---------------------------------------------------------------------------*/
void I2CWriteInit(void)
{
  UCB1CTL1 |= UCTR;                                                             // UCTR=1 => Transmit Mode (R/W bit = 0)
  UCB1IFG &= ~UCTXIFG;
  UCB1IE &= ~UCRXIE;                                                            // disable Receive ready interrupt
  UCB1IE |= UCTXIE;                                                             // enable Transmit ready interrupt
}

/*----------------------------------------------------------------------------*/
// Description:
//   Initialization of the I2C Module for Read operation.
/*----------------------------------------------------------------------------*/
void I2CReadInit(void)
{
  UCB1CTL1 &= ~UCTR;                                                            // UCTR=0 => Receive Mode (R/W bit = 1)
  UCB1IFG &= ~UCRXIFG;
  UCB1IE &= ~UCTXIE;                                                            // disable Transmit ready interrupt
  UCB1IE |= UCRXIE;                                                             // enable Receive ready interrupt
}

/*----------------------------------------------------------------------------*/
// Description:
//   Byte Write Operation. The communication via the I2C bus with an EEPROM
//   (2465) is realized. A data byte is written into a user defined address.
/*----------------------------------------------------------------------------*/
void EEPROM_ByteWrite(unsigned int Address, char Data)
{
  char adr_hi;
  char adr_lo;

  while (UCB1STAT & UCBUSY);                                                    // wait until I2C module has
                                                                                // finished all operations.

  adr_hi = Address >> 8;                                                        // calculate high byte
  adr_lo = Address & 0xFF;                                                      // and low byte of address

  I2CBufferArray[2] = adr_hi;                                                   // Low byte address.
  I2CBufferArray[1] = adr_lo;                                                   // High byte address.
  I2CBufferArray[0] = Data;
  PtrTransmit = 2;                                                              // set I2CBufferArray Pointer

  I2CWriteInit();
  UCB1CTL1 |= UCTXSTT;                                                          // start condition generation
                                                                                // => I2C communication is started
  __bis_SR_register(LPM3_bits + GIE);                                           // Enter LPM0 w/ interrupts
  UCB1CTL1 |= UCTXSTP;                                                          // I2C stop condition
  while(UCB1CTL1 & UCTXSTP);                                                    // Ensure stop condition got sent
}

/*----------------------------------------------------------------------------*/
// Description:
//   Page Write Operation. The communication via the I2C bus with an EEPROM
//   (24xx65) is realized. A data byte is written into a user defined address.
/*----------------------------------------------------------------------------*/
void EEPROM_PageWrite(unsigned int StartAddress, char * Data, unsigned int Size)
{
  volatile unsigned int i = 0;
  volatile char counterI2cBuffer;
  char adr_hi;
  char adr_lo;
  unsigned int currentAddress = StartAddress;
  unsigned int currentSize = Size;
  unsigned int bufferPtr = 0;
  char moreDataToRead = 1;

  while (UCB1STAT & UCBUSY);                                                    // wait until I2C module has
                                                                                // finished all operations.

  // Execute until no more data in Data buffer
  while(moreDataToRead)
  {
    adr_hi = currentAddress >> 8;                                               // calculate high byte
    adr_lo = currentAddress & 0xFF;                                             // and low byte of address

    // Chop data down to 64-byte packets to be transmitted at a time
    // Maintain pointer of current startaddress
    if(currentSize > MAXPAGEWRITE)
    {
      bufferPtr = bufferPtr + MAXPAGEWRITE;
      counterI2cBuffer = MAXPAGEWRITE - 1;
      PtrTransmit = MAXPAGEWRITE + 1;                                           // set I2CBufferArray Pointer
      currentSize = currentSize - MAXPAGEWRITE;
      currentAddress = currentAddress + MAXPAGEWRITE;

      // Get start address
      I2CBufferArray[MAXPAGEWRITE + 1] = adr_hi;                                // High byte address.
      I2CBufferArray[MAXPAGEWRITE] = adr_lo;                                    // Low byte address.
    }
    else
    {
      bufferPtr = bufferPtr + currentSize;
      counterI2cBuffer = currentSize - 1;
      PtrTransmit = currentSize + 1;                                            // set I2CBufferArray Pointer.
      moreDataToRead = 0;
      currentAddress = currentAddress + currentSize;

      // Get start address
      I2CBufferArray[currentSize + 1] = adr_hi;                                 // High byte address.
      I2CBufferArray[currentSize] = adr_lo;                                     // Low byte address.
    }

    // Copy data to I2CBufferArray
    char temp;
    for(i ; i < bufferPtr ; i++)
    {
      temp = Data[i];                                                           // Required or else IAR throws a
                                                                                // warning [Pa082]
      I2CBufferArray[counterI2cBuffer] = temp;
      counterI2cBuffer--;
    }

    I2CWriteInit();
    UCB1CTL1 |= UCTXSTT;                                                        // start condition generation
                                                                                // => I2C communication is started
    __bis_SR_register(LPM3_bits + GIE);                                         // Enter LPM0 w/ interrupts
    UCB1CTL1 |= UCTXSTP;                                                        // I2C stop condition
    while(UCB1CTL1 & UCTXSTP);                                                  // Ensure stop condition got sent

    EEPROM_AckPolling();                                                        // Ensure data is written in EEPROM
  }
}

/*----------------------------------------------------------------------------*/
// Description:
//   Current Address Read Operation. Data is read from the EEPROM. The current
//   address from the EEPROM is used.
/*----------------------------------------------------------------------------*/
char EEPROM_CurrentAddressRead(void)
{
  while(UCB1STAT & UCBUSY);                                                     // wait until I2C module has
                                                                                // finished all operations
  I2CReadInit();

  UCB1CTL1 |= UCTXSTT;                                                          // I2C start condition
  while(UCB1CTL1 & UCTXSTT);                                                    // Start condition sent?
  UCB1CTL1 |= UCTXSTP;                                                          // I2C stop condition
  __bis_SR_register(LPM3_bits + GIE);                                           // Enter LPM0 w/ interrupts
  while(UCB1CTL1 & UCTXSTP);                                                    // Ensure stop condition got sent
  return I2CBuffer;
}

/*----------------------------------------------------------------------------*/
// Description:
//   Random Read Operation. Data is read from the EEPROM. The EEPROM
//   address is defined with the parameter Address.
/*----------------------------------------------------------------------------*/
char EEPROM_RandomRead(unsigned int Address)
{
  char adr_hi;
  char adr_lo;

  while (UCB1STAT & UCBUSY);                                                    // wait until I2C module has
                                                                                // finished all operations

  adr_hi = Address >> 8;                                                        // calculate high byte
  adr_lo = Address & 0xFF;                                                      // and low byte of address

  I2CBufferArray[1] = adr_hi;                                                   // store single bytes that have to
  I2CBufferArray[0] = adr_lo;                                                   // be sent in the I2CBuffer.
  PtrTransmit = 1;                                                              // set I2CBufferArray Pointer

  // Write Address first
  I2CWriteInit();
  UCB1CTL1 |= UCTXSTT;                                                          // start condition generation
                                                                                // => I2C communication is started
  __bis_SR_register(LPM3_bits + GIE);                                           // Enter LPM0 w/ interrupts

  // Read Data byte
  I2CReadInit();

  UCB1CTL1 |= UCTXSTT;                                                          // I2C start condition
  while(UCB1CTL1 & UCTXSTT);                                                    // Start condition sent?
  UCB1CTL1 |= UCTXSTP;                                                          // I2C stop condition
  __bis_SR_register(LPM3_bits + GIE);                                           // Enter LPM0 w/ interrupts
  while(UCB1CTL1 & UCTXSTP);                                                    // Ensure stop condition got sent
  return I2CBuffer;
}

/*----------------------------------------------------------------------------*/
// Description:
//   Sequential Read Operation. Data is read from the EEPROM in a sequential
//   form from the parameter address as a starting point. Specify the size to
//   be read and populate to a Data buffer.
/*----------------------------------------------------------------------------*/
void EEPROM_SequentialRead(unsigned int Address , char * Data , unsigned int Size)
{
  char adr_hi;
  char adr_lo;
  unsigned int counterSize;

  while (UCB1STAT & UCBUSY);                                                    // wait until I2C module has
                                                                                // finished all operations

  adr_hi = Address >> 8;                                                        // calculate high byte
  adr_lo = Address & 0xFF;                                                      // and low byte of address

  I2CBufferArray[1] = adr_hi;                                                   // store single bytes that have to
  I2CBufferArray[0] = adr_lo;                                                   // be sent in the I2CBuffer.
  PtrTransmit = 1;                                                              // set I2CBufferArray Pointer

  // Write Address first
  I2CWriteInit();
  UCB1CTL1 |= UCTXSTT;                                                          // start condition generation
                                                                                // => I2C communication is started
  __bis_SR_register(LPM3_bits + GIE);                                           // Enter LPM0 w/ interrupts

  // Read Data byte
  I2CReadInit();

  UCB1CTL1 |= UCTXSTT;                                                          // I2C start condition
  while(UCB1CTL1 & UCTXSTT);                                                    // Start condition sent?

  for(counterSize = 0 ; counterSize < Size ; counterSize++)
  {
    __bis_SR_register(LPM3_bits + GIE);                                         // Enter LPM0 w/ interrupts
    Data[counterSize] = I2CBuffer;
  }
  UCB1CTL1 |= UCTXSTP;                                                          // I2C stop condition
  __bis_SR_register(LPM3_bits + GIE);                                           // Enter LPM0 w/ interrupts
  while(UCB1CTL1 & UCTXSTP);                                                    // Ensure stop condition got sent
}

/*----------------------------------------------------------------------------*/
// Description:
//   Acknowledge Polling. The EEPROM will not acknowledge if a write cycle is
//   in progress. It can be used to determine when a write cycle is completed.
/*----------------------------------------------------------------------------*/
void EEPROM_AckPolling(void)
{
  while (UCB1STAT & UCBUSY);                                                    // wait until I2C module has
                                                                                // finished all operations
  do
  {
    UCB1STAT = 0x00;                                                            // clear I2C interrupt flags
    UCB1CTL1 |= UCTR;                                                           // I2CTRX=1 => Transmit Mode (R/W bit = 0)
    UCB1CTL1 &= ~UCTXSTT;
    UCB1CTL1 |= UCTXSTT;                                                        // start condition is generated
    while(UCB1CTL1 & UCTXSTT)                                                   // wait till I2CSTT bit was cleared
    {
      if(!(UCNACKIFG & UCB1STAT))                                               // Break out if ACK received
        break;
    }
    UCB1CTL1 |= UCTXSTP;                                                        // stop condition is generated after
                                                                                // slave address was sent => I2C communication is started
    while (UCB1CTL1 & UCTXSTP);                                                 // wait till stop bit is reset
    delay_ms(5);                                                                // Aguarda 5 milisegundos
  }while(UCNACKIFG & UCB1STAT);
}

/*----------------------------------------------------------------------------*/
//  Interrupt Service Routines                                               
//     Note that the Compiler version is checked in the following code and   
//     depending of the Compiler Version the correct Interrupt Service       
//     Routine definition is used.                                           
/*----------------------------------------------------------------------------*/
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = EUSCI_B1_VECTOR
__interrupt void USCI_B1_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(EUSCI_B1_VECTOR))) USCI_B1_ISR (void)
#else
#error Compiler not supported!
#endif
{
   switch(__even_in_range(UCB1IV, USCI_I2C_UCBIT9IFG))
     {
        case USCI_NONE:          break;                                         // Vector 0: No interrupts
        case USCI_I2C_UCALIFG:   break;                                         // Vector 2: ALIFG
        case USCI_I2C_UCNACKIFG: break;                                         // Vector 4: NACKIFG
        case USCI_I2C_UCSTTIFG:  break;                                         // Vector 6: STTIFG
        case USCI_I2C_UCSTPIFG:  break;                                         // Vector 8: STPIFG
        case USCI_I2C_UCRXIFG3:  break;                                         // Vector 10: RXIFG3
        case USCI_I2C_UCTXIFG3:  break;                                         // Vector 12: TXIFG3
        case USCI_I2C_UCRXIFG2:  break;                                         // Vector 14: RXIFG2
        case USCI_I2C_UCTXIFG2:  break;                                         // Vector 16: TXIFG2
        case USCI_I2C_UCRXIFG1:  break;                                         // Vector 18: RXIFG1
        case USCI_I2C_UCTXIFG1:  break;                                         // Vector 20: TXIFG1
        case USCI_I2C_UCRXIFG0:                                                 // Vector 22: RXIFG0
                I2CBuffer = UCB1RXBUF;                                          // store received data in buffer
                __bic_SR_register_on_exit(LPM3_bits);                           // Exit LPM0
        break;
        case USCI_I2C_UCTXIFG0:  	                                        // Vector 24: TXIFG0
                UCB1TXBUF = I2CBufferArray[PtrTransmit];                        // Load TX buffer
                PtrTransmit--;                                                  // Decrement TX byte counter
                if(PtrTransmit < 0)
                 {
                    while (!(UCB1IFG & UCTXIFG));                               // USCI_B1 TX buffer ready?
                    UCB1IE &= ~UCTXIE;                                          // disable interrupts.
                    UCB1IFG &= ~UCTXIFG;                                        // Clear USCI_B1 TX int flag
                    __bic_SR_register_on_exit(LPM3_bits);                       // Exit LPM3
                }
        break;
        case USCI_I2C_UCBCNTIFG: break;                                         // Vector 26: BCNTIFG
        case USCI_I2C_UCCLTOIFG: break;                                         // Vector 28: clock low timeout
        case USCI_I2C_UCBIT9IFG: break;                                         // Vector 30: 9th bit
        default: break;
     }
}

Anderson Portela。

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

    > if (!(UCNACKIFG & UCB1STAT))//如果收到 ACK 则中断

    这看起来有点奇怪、因为 UCNACKIFG 位于 UCB1IFG 中。 UCB1STAT (USCI 和 EUSCI)中的位5是 UCGC、(我想)一直为0。 (对于应答轮询、该测试看起来也是向后的。)

    由于延迟为5ms (EEPROM 的标准 Twrite)、这可能会意外发生。

    此代码是否与您用于 F5529 (USCI)的代码相同?

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

    你好 Bruce。

    是的、此代码与我在 F5529中使用的代码相同。

    奇怪的是、它的写入和读取正常、但在 FR5994中、写入后会产生大约600uA 的电池过多电流消耗。 如果我不写入、我消耗大约10uA。

    在 F5529中、写入和读取大约14uA 后的功耗。

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

    高电流条件是否在第一次写入后一直持续、还是暂时的?  

    > UCB1CTLW1 |= UCASTP_2;

    您正在设置 UCASTP=2、但 TBCNT 始终为0。 我从未尝试过这种组合、可能会有一些与之相关的异常(UG 模糊)。 由于您不使用此功能、我建议您不要申请它。 (这与 F5529不同。)

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

    我想我在这里找到了您代码的早期版本:

    /cfs-file/__key/communityserver-discussions-components-files/166/I2Croutines.c
    从注释中可以看到、这适用于 F2系列器件、其中 UCNACKIFG 位于 UCBxSTAT [参考 F2用户指南(SLAU144K)表17-7]。 F5 NOR FR5系列则不是这样。
    该测试看起来仍然不正确、因为它假定 NACK 在开始后立即出现、此时它不能早于(1+8+1) I2C 时钟(100kHz 时为100us)。
    [编辑:这似乎是原始版本:
    该代码通过 PDF 中的链接提供。]
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好 Bruce。

    回答您之前的问题:

    写入后功耗仍然过大、仅在 F5994复位后才会恢复正常。

    是的、我将此代码用于 F5529、效果很好。

    我对 F5994进行了一些修改、在写入内存后发现问题。

    P.S. 我可能不知道如何配置正确的 F5994寄存器。 这可能是个问题!

    有趣的是、在调试时、我没有发现任何代码崩溃、尤其是在 NACK 部分。

    以下是一些修改、我注意到改进、不确定配置是否正确:

    ////////////////////////////////////////////////////////////////////////////////
    //         Definição da Porta P5 como Serial I2C das Memórias EEPROMS         //
    ////////////////////////////////////////////////////////////////////////////////
    P5OUT = 0;                                                                   // Reseta Todos os Pinos da Porta P5
    P5DIR = 0xFF;                                                                // Define Todos os Pinos da Porta P5 como Saídas
    P5OUT &=~ 0xFF;                                                              // Inicializa Todos os Pinos da Porta P5 com Nível Lógico "0" Baixo
    P5SEL0 |= BIT0 | BIT1;                                                       // Seleciona o Pino da Porta P5.0 UCB1SDA e P5.1 UCB1SCL como Barramento I2C                                                   
    P5SEL1 &= ~(BIT0 | BIT1);                                                    // Seleciona Módulo Primário Conforme Tabela I/O Function Selection
    // Configuração do Barramento I2C das Memórias EEPROMs
    UCB1CTLW0 = UCSWRST;                                                         // Enable SW reset
    UCB1CTLW0 |= UCMODE_3 | UCMST | UCSSEL__SMCLK;                               // I2C Master, synchronous mode
    UCB1BRW = 160;                                                               // fSCL = SMCLK/160 = 100 kHz
    //UCB1CTLW1 |= 0x40;                                                           // Use SMCLK, TX mode, keep SW reset
    //UCB1CTLW1 |= UCASTP_2;
    UCB1CTLW0 &= ~UCSWRST;                                                       // Clear SW reset, resume operation
    //UCB1IE |= UCNACKIE + UCALIE + UCSTPIE + UCSTTIE + UCTXIE0 + UCRXIE0 | UCBCNTIE | USCI_I2C_UCCLTOIFG; // Interrupts Enable
    UCB1IE |= UCNACKIE + UCTXIE0 + UCRXIE0; // Interrupts Enable
    
    
    
    #include "I2Croutines.h"
    #include "delay.h"
    
    #define     MAXPAGEWRITE   33
    
    int PtrTransmit;
    char I2CBufferArray[66];
    char I2CBuffer;
    
    /*----------------------------------------------------------------------------*/
    // Description:
    //   Initialization of the I2C Module
    /*----------------------------------------------------------------------------*/
    void InitI2C(char eeprom_i2c_address)
    {
      while (UCB1STATW & UCBUSY);                                                    // wait until I2C module has
                                                                                    // finished all operations.
      // Direciona para o Endereço de Memória EEPROM Correto para o Uso
      UCB1I2CSA  = eeprom_i2c_address;                                              // define Slave Address
                                                                                    // In this case the Slave Address
                                                                                    // defines the control byte that is
                                                                                    // sent to the EEPROM.
    }
    
    /*---------------------------------------------------------------------------*/
    // Description:
    //   Initialization of the I2C Module for Write operation.
    /*---------------------------------------------------------------------------*/
    void I2CWriteInit(void)
    {
      UCB1CTLW0 |= UCTR;                                                             // UCTR=1 => Transmit Mode (R/W bit = 0)
      UCB1IFG &= ~UCTXIFG;
      UCB1IE &= ~UCRXIE;                                                            // disable Receive ready interrupt
      UCB1IE |= UCTXIE;                                                             // enable Transmit ready interrupt
    }
    
    /*----------------------------------------------------------------------------*/
    // Description:
    //   Initialization of the I2C Module for Read operation.
    /*----------------------------------------------------------------------------*/
    void I2CReadInit(void)
    {
      UCB1CTLW0 &= ~UCTR;                                                            // UCTR=0 => Receive Mode (R/W bit = 1)
      UCB1IFG &= ~UCRXIFG;
      UCB1IE &= ~UCTXIE;                                                            // disable Transmit ready interrupt
      UCB1IE |= UCRXIE;                                                             // enable Receive ready interrupt
    }
    
    /*----------------------------------------------------------------------------*/
    // Description:
    //   Byte Write Operation. The communication via the I2C bus with an EEPROM
    //   (2465) is realized. A data byte is written into a user defined address.
    /*----------------------------------------------------------------------------*/
    void EEPROM_ByteWrite(unsigned int Address, char Data)
    {
      char adr_hi;
      char adr_lo;
    
      while (UCB1STATW & UCBUSY);                                                    // wait until I2C module has
                                                                                    // finished all operations.
    
      adr_hi = Address >> 8;                                                        // calculate high byte
      adr_lo = Address & 0xFF;                                                      // and low byte of address
    
      I2CBufferArray[2] = adr_hi;                                                   // Low byte address.
      I2CBufferArray[1] = adr_lo;                                                   // High byte address.
      I2CBufferArray[0] = Data;
      PtrTransmit = 2;                                                              // set I2CBufferArray Pointer
    
      I2CWriteInit();
      UCB1CTLW0 |= UCTXSTT;                                                          // start condition generation
                                                                                    // => I2C communication is started
      __bis_SR_register(LPM3_bits + GIE);                                           // Enter LPM0 w/ interrupts
      UCB1CTLW0 |= UCTXSTP;                                                          // I2C stop condition
      while(UCB1CTLW0 & UCTXSTP);                                                    // Ensure stop condition got sent
    }
    
    /*----------------------------------------------------------------------------*/
    // Description:
    //   Page Write Operation. The communication via the I2C bus with an EEPROM
    //   (24xx65) is realized. A data byte is written into a user defined address.
    /*----------------------------------------------------------------------------*/
    void EEPROM_PageWrite(unsigned int StartAddress, char * Data, unsigned int Size)
    {
      volatile unsigned int i = 0;
      volatile char counterI2cBuffer;
      char adr_hi;
      char adr_lo;
      unsigned int currentAddress = StartAddress;
      unsigned int currentSize = Size;
      unsigned int bufferPtr = 0;
      char moreDataToRead = 1;
    
      while (UCB1STATW & UCBUSY);                                                    // wait until I2C module has
                                                                                    // finished all operations.
    
      // Execute until no more data in Data buffer
      while(moreDataToRead)
      {
        adr_hi = currentAddress >> 8;                                               // calculate high byte
        adr_lo = currentAddress & 0xFF;                                             // and low byte of address
    
        // Chop data down to 64-byte packets to be transmitted at a time
        // Maintain pointer of current startaddress
        if(currentSize > MAXPAGEWRITE)
        {
          bufferPtr = bufferPtr + MAXPAGEWRITE;
          counterI2cBuffer = MAXPAGEWRITE - 1;
          PtrTransmit = MAXPAGEWRITE + 1;                                           // set I2CBufferArray Pointer
          currentSize = currentSize - MAXPAGEWRITE;
          currentAddress = currentAddress + MAXPAGEWRITE;
    
          // Get start address
          I2CBufferArray[MAXPAGEWRITE + 1] = adr_hi;                                // High byte address.
          I2CBufferArray[MAXPAGEWRITE] = adr_lo;                                    // Low byte address.
        }
        else
        {
          bufferPtr = bufferPtr + currentSize;
          counterI2cBuffer = currentSize - 1;
          PtrTransmit = currentSize + 1;                                            // set I2CBufferArray Pointer.
          moreDataToRead = 0;
          currentAddress = currentAddress + currentSize;
    
          // Get start address
          I2CBufferArray[currentSize + 1] = adr_hi;                                 // High byte address.
          I2CBufferArray[currentSize] = adr_lo;                                     // Low byte address.
        }
    
        // Copy data to I2CBufferArray
        char temp;
        for(i ; i < bufferPtr ; i++)
        {
          temp = Data[i];                                                           // Required or else IAR throws a
                                                                                    // warning [Pa082]
          I2CBufferArray[counterI2cBuffer] = temp;
          counterI2cBuffer--;
        }
    
        I2CWriteInit();
        UCB1CTLW0 |= UCTXSTT;                                                        // start condition generation
                                                                                    // => I2C communication is started
        __bis_SR_register(LPM3_bits + GIE);                                         // Enter LPM0 w/ interrupts
        UCB1CTLW0 |= UCTXSTP;                                                        // I2C stop condition
        while(UCB1CTLW0 & UCTXSTP);                                                  // Ensure stop condition got sent
    
        EEPROM_AckPolling();                                                        // Ensure data is written in EEPROM
      }
    }
    
    /*----------------------------------------------------------------------------*/
    // Description:
    //   Current Address Read Operation. Data is read from the EEPROM. The current
    //   address from the EEPROM is used.
    /*----------------------------------------------------------------------------*/
    char EEPROM_CurrentAddressRead(void)
    {
      while(UCB1STATW & UCBUSY);                                                     // wait until I2C module has
                                                                                    // finished all operations
      I2CReadInit();
    
      UCB1CTLW0 |= UCTXSTT;                                                          // I2C start condition
      while(UCB1CTLW0 & UCTXSTT);                                                    // Start condition sent?
      UCB1CTLW0 |= UCTXSTP;                                                          // I2C stop condition
      __bis_SR_register(LPM3_bits + GIE);                                           // Enter LPM0 w/ interrupts
      while(UCB1CTLW0 & UCTXSTP);                                                    // Ensure stop condition got sent
      return I2CBuffer;
    }
    
    /*----------------------------------------------------------------------------*/
    // Description:
    //   Random Read Operation. Data is read from the EEPROM. The EEPROM
    //   address is defined with the parameter Address.
    /*----------------------------------------------------------------------------*/
    char EEPROM_RandomRead(unsigned int Address)
    {
      char adr_hi;
      char adr_lo;
    
      while (UCB1STATW & UCBUSY);                                                    // wait until I2C module has
                                                                                    // finished all operations
    
      adr_hi = Address >> 8;                                                        // calculate high byte
      adr_lo = Address & 0xFF;                                                      // and low byte of address
    
      I2CBufferArray[1] = adr_hi;                                                   // store single bytes that have to
      I2CBufferArray[0] = adr_lo;                                                   // be sent in the I2CBuffer.
      PtrTransmit = 1;                                                              // set I2CBufferArray Pointer
    
      // Write Address first
      I2CWriteInit();
      UCB1CTLW0 |= UCTXSTT;                                                          // start condition generation
                                                                                    // => I2C communication is started
      __bis_SR_register(LPM3_bits + GIE);                                           // Enter LPM0 w/ interrupts
    
      // Read Data byte
      I2CReadInit();
    
      UCB1CTLW0 |= UCTXSTT;                                                          // I2C start condition
      while(UCB1CTLW0 & UCTXSTT);                                                    // Start condition sent?
      UCB1CTLW0 |= UCTXSTP;                                                          // I2C stop condition
      __bis_SR_register(LPM3_bits + GIE);                                           // Enter LPM0 w/ interrupts
      while(UCB1CTLW0 & UCTXSTP);                                                    // Ensure stop condition got sent
      return I2CBuffer;
    }
    
    /*----------------------------------------------------------------------------*/
    // Description:
    //   Sequential Read Operation. Data is read from the EEPROM in a sequential
    //   form from the parameter address as a starting point. Specify the size to
    //   be read and populate to a Data buffer.
    /*----------------------------------------------------------------------------*/
    void EEPROM_SequentialRead(unsigned int Address , char * Data , unsigned int Size)
    {
      char adr_hi;
      char adr_lo;
      unsigned int counterSize;
    
      while (UCB1STATW & UCBUSY);                                                    // wait until I2C module has
                                                                                    // finished all operations
    
      adr_hi = Address >> 8;                                                        // calculate high byte
      adr_lo = Address & 0xFF;                                                      // and low byte of address
    
      I2CBufferArray[1] = adr_hi;                                                   // store single bytes that have to
      I2CBufferArray[0] = adr_lo;                                                   // be sent in the I2CBuffer.
      PtrTransmit = 1;                                                              // set I2CBufferArray Pointer
    
      // Write Address first
      I2CWriteInit();
      UCB1CTLW0 |= UCTXSTT;                                                          // start condition generation
                                                                                    // => I2C communication is started
      __bis_SR_register(LPM3_bits + GIE);                                           // Enter LPM0 w/ interrupts
    
      // Read Data byte
      I2CReadInit();
    
      UCB1CTLW0 |= UCTXSTT;                                                          // I2C start condition
      while(UCB1CTLW0 & UCTXSTT);                                                    // Start condition sent?
    
      for(counterSize = 0 ; counterSize < Size ; counterSize++)
      {
        __bis_SR_register(LPM3_bits + GIE);                                         // Enter LPM0 w/ interrupts
        Data[counterSize] = I2CBuffer;
      }
      UCB1CTLW0 |= UCTXSTP;                                                          // I2C stop condition
      __bis_SR_register(LPM3_bits + GIE);                                           // Enter LPM0 w/ interrupts
      while(UCB1CTLW0 & UCTXSTP);                                                    // Ensure stop condition got sent
    }
    
    /*----------------------------------------------------------------------------*/
    // Description:
    //   Acknowledge Polling. The EEPROM will not acknowledge if a write cycle is
    //   in progress. It can be used to determine when a write cycle is completed.
    /*----------------------------------------------------------------------------*/
    void EEPROM_AckPolling(void)
    {
      while (UCB1STATW & UCBUSY);                                                    // wait until I2C module has
                                                                                    // finished all operations
      do
      {
        UCB1STATW = 0x00;                                                            // clear I2C interrupt flags
        UCB1CTLW0 |= UCTR;                                                           // I2CTRX=1 => Transmit Mode (R/W bit = 0)
        UCB1CTLW0 &= ~UCTXSTT;
        UCB1CTLW0 |= UCTXSTT;                                                        // start condition is generated
        while(UCB1CTLW0 & UCTXSTT)                                                   // wait till I2CSTT bit was cleared
        {
          if(!(UCNACKIFG & UCB1STATW))                                               // Break out if ACK received
            break;
        }
        UCB1CTLW0 |= UCTXSTP;                                                        // stop condition is generated after
                                                                                    // slave address was sent => I2C communication is started
        while (UCB1CTLW1 & UCTXSTP);                                                 // wait till stop bit is reset
        delay_ms(5);                                                                // Aguarda 5 milisegundos
      }while(UCNACKIFG & UCB1STATW);
    }
    
    /*----------------------------------------------------------------------------*/
    //  Interrupt Service Routines                                               
    //     Note that the Compiler version is checked in the following code and   
    //     depending of the Compiler Version the correct Interrupt Service       
    //     Routine definition is used.                                           
    /*----------------------------------------------------------------------------*/
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector = EUSCI_B1_VECTOR
    __interrupt void USCI_B1_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(EUSCI_B1_VECTOR))) USCI_B1_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
       switch(__even_in_range(UCB1IV, USCI_I2C_UCBIT9IFG))
         {
            case USCI_NONE:          break;                                         // Vector 0: No interrupts
            case USCI_I2C_UCALIFG:   break;                                         // Vector 2: ALIFG
            case USCI_I2C_UCNACKIFG: break;                                         // Vector 4: NACKIFG
            case USCI_I2C_UCSTTIFG:  break;                                         // Vector 6: STTIFG
            case USCI_I2C_UCSTPIFG:  break;                                         // Vector 8: STPIFG
            case USCI_I2C_UCRXIFG3:  break;                                         // Vector 10: RXIFG3
            case USCI_I2C_UCTXIFG3:  break;                                         // Vector 12: TXIFG3
            case USCI_I2C_UCRXIFG2:  break;                                         // Vector 14: RXIFG2
            case USCI_I2C_UCTXIFG2:  break;                                         // Vector 16: TXIFG2
            case USCI_I2C_UCRXIFG1:  break;                                         // Vector 18: RXIFG1
            case USCI_I2C_UCTXIFG1:  break;                                         // Vector 20: TXIFG1
            case USCI_I2C_UCRXIFG0:                                                 // Vector 22: RXIFG0
                    I2CBuffer = UCB1RXBUF;                                          // store received data in buffer
                    __bic_SR_register_on_exit(LPM3_bits);                           // Exit LPM0
            break;
            case USCI_I2C_UCTXIFG0:  	                                        // Vector 24: TXIFG0
                    UCB1TXBUF = I2CBufferArray[PtrTransmit];                        // Load TX buffer
                    PtrTransmit--;                                                  // Decrement TX byte counter
                    if(PtrTransmit < 0)
                     {
                        while (!(UCB1IFG & UCTXIFG));                               // USCI_B1 TX buffer ready?
                        UCB1IE &= ~UCTXIE;                                          // disable interrupts.
                        UCB1IFG &= ~UCTXIFG;                                        // Clear USCI_B1 TX int flag
                        __bic_SR_register_on_exit(LPM3_bits);                       // Exit LPM3
                    }
            break;
            case USCI_I2C_UCBCNTIFG: break;                                         // Vector 26: BCNTIFG
            case USCI_I2C_UCCLTOIFG: break;                                         // Vector 28: clock low timeout
            case USCI_I2C_UCBIT9IFG: break;                                         // Vector 30: 9th bit
            default: break;
         }
    }

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

    我看到您关闭了 UCASTP 和 UCCLTO。 您看到了多少改进?

    1) 1) EUSCI 和 USCI 的工作原理大致相同、但它们是不同的实现方式、因此如果"插入"未记录的条件、它们的行为可能会有所不同。 因为(除了我提到的内容)我没有看到任何与你所做的事情完全不符的地方,这是我正在寻找的事情。

    2)我一直回到反向轮询函数、因为(a)它仅在写入之后使用、而不是在读取之后使用(b)它不执行它声称的操作(c)它可能会因意外工作而发生、因为它始终会延迟5ms [TWR]。 下面是一个实验:用一个裸"delay_ms (5)"替换对该函数的每次调用。

    此外,delay_ms()是如何工作的? 是否有可能留下不应该运行的东西? (在最初的版本中、它是一个自包含的__delay_cycles (500)。)

    3) 3) 3)您能否为 EEPROM 器件提供器件型号? 我找到了(MCHP) 24LC65 [DS21073K]的数据表、[表1-2注(4)]指出、每8个字节的 TWR 为5ms、因此对于32个字节、它将为4*5=20ms。 您的器件可能不是这样。 (我曾使用过类似的器件、但我在这里没有任何器件。)

    4) 4)另一件事对我来说是:在许多地方、会检查 UCBUSY、而 UCBUSY 实际上不 是在 I2C 模式中定义的。 相反、I2C 模式定义了一个单独的 UCBBUSY。 F2系列也是如此、高建先生显然取得了成功、但 UCBUSY 似乎可以做(未记录的)事情、但对 EUSCI 与 USCI 的行为不同。  

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

    Bruce、

    来自 EEPROM 24LC1025和 delay_ms()函数代码的信息如下;

    您能否按照您了解的方式编写 I2Croutines.c 代码、以便我在此使用 F5994进行测试?

    delay.h
    
    // Example for 16MHz
    #define F_CPU 16000000UL
    
    #define F_CPU_NS (F_CPU/1000000000.0)
    #define F_CPU_US (F_CPU/1000000.0)
    #define F_CPU_MS (F_CPU/1000.0)
    #define F_CPU_S  (F_CPU/1.0)
    
    // Delay Macros (more accurate -- static delay required)
    /*
    #define delay_ns(__ns) \
      if((uint32_t) (F_CPU_NS * __ns) != F_CPU_NS * __ns)\
            __delay_cycles((uint32_t) ( F_CPU_NS * __ns)+1);\
      else __delay_cycles((uint32_t) ( F_CPU_NS * __ns))
    */
    #define delay_us(__us) \
      if((uint32_t) (F_CPU_US * __us) != F_CPU_US * __us)\
            __delay_cycles((uint32_t) ( F_CPU_US * __us)+1);\
      else __delay_cycles((uint32_t) ( F_CPU_US * __us))
    #define delay_ms(__ms) \
      if((uint32_t) (F_CPU_MS * __ms) != F_CPU_MS * __ms)\
            __delay_cycles((uint32_t) ( F_CPU_MS * __ms)+1);\
      else __delay_cycles((uint32_t) ( F_CPU_MS * __ms))
    /*
    #define delay_s(__s) \
      if((uint32_t) (F_CPU_S * __s) != F_CPU_S * __s)\
            __delay_cycles((uint32_t) ( F_CPU_S * __s)+1);\
      else __delay_cycles((uint32_t) ( F_CPU_S * __s))
    */

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

    24LC1025数据表(DS20001941L)表1-2显示了 TWC = 5ms (最大值)、因此上述(3)不是问题。

    delay_ms 定义看起来不错。

    从删除 UCASTP 和 UCCLTO 中可以看出有多大的改进?

    如果没有测试用例、我将编码为"盲"、但我将从以下内容开始:

    1) 1)将所有出现的 UCBUSY 替换为 UCBBUSY

    2)使用 delay_ms (5)替换对 EEPROM_AckPolling 的调用(我只看到一个)。 如果这显示(积极)效果、那么我会考虑是否/如何重新实施。

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

    祝贺布鲁斯!!!!

    从删除 UCASTP 和 UCCLTO 中可以看出有多大的改进?

    回答:
    电池电流消耗在8.9uA 时变得更加稳定。 在20uA 和10uA 之间振荡之前。

    1) 1)将所有出现的 UCBUSY 替换为 UCBBUSY

    回答:
    通过使用 UCBBUSY、消耗仅增加一倍、达到1.650uA。 我返回使用 UCBUSY、消耗为8.9uA。

    2)使用 delay_ms (5)替换对 EEPROM_AckPolling 的调用(我只看到一个)。 如果这显示(积极)效果、那么我会考虑是否/如何重新实施。

    回答:
    该问题的解决方案是使用简单的 DELAY_ms (5)替换 EEPROM_AckPolling 函数。 解决了写入内存后电流消耗过大的问题。

    我承认、我在理解使用 EEPROM_AckPolling 函数时出现的问题时遇到了一些困难。 但是、无论出于什么目的、它都能发挥出色的作用!

    非常感谢 Bruce 的关注、尤其是他的解决方案!

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

    我很高兴你成功。 我也不知道 ACK 轮询功能到底有什么问题;也许有一天如果我有测试用例、我可以进行实验。

    至于 UCBBUSY:我的第一个想法是、检查会消耗更多的电流(我假设您的意思是16.5uA 而不是1.65uA)、因为它实际上是在测试某个东西、即有时 I2C 在此时确实很忙、UCBUSY 测试不会检测到它。 我不会争辩说成功、也许测试并不重要、但如果将来出现异常行为、可能需要将其放入您的实验室笔记本中。