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和 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不同。)
我想我在这里找到了您代码的早期版本:
你好 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 测试不会检测到它。 我不会争辩说成功、也许测试并不重要、但如果将来出现异常行为、可能需要将其放入您的实验室笔记本中。