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.
Tool/software: Code Composer Studio
Hello friend, thank you for replying. This problem:
In this code I do the read / write on the RTC via I2C. Each state of the state machine represents the reading of a byte from the RTC. This can be seen in the I2C interrupt service (within if (IFG2 & UCB0RXIFG)).
After I receive the byte from the RTC to the UCB0RXBUF, I convert the BCD format data and store it in the "relogio" variable.
Then I get this variable and send it through UART, by UCA0TXBUF.
And so the operation of the state machine would be: it writes the current date in the RTC (I2C_STATE = 0 to I2C_STATE = 18); and then read the RTC (I2C_STATE = 19 to I2C_STATE = 37); when it arrives in the last state, the state machine returns to I2C_STATE = 19 and stays forever just reading.
However the write / read routine in the RTC via I2C does not work when I try to send the data through the UART.
For example:
If I comment the UART_Config () function on the main function, the write / read routine on the RTC works normally, as shown in the figure below:
However if I uncomment the UART_Congif () function in the main function, the RTC stops working, and the I2C and UART stops working. The figure below shows the bus:
Can you understand how I expect the code to work and what's happening?
Section 17.3.7.4 of the User's Guide says:
USCI_Ax and USCI_Bx share the same interrupt vectors. In I²C mode the state change interrupt flags UCSTTIFG, UCSTPIFG, UCNACKIFG, UCALIFG from USCI_Bx and UCAxRXIFG from USCI_Ax are routed to one interrupt vector. The I²C transmit and receive interrupt flags UCBxTXIFG and UCBxRXIFG from USCI_Bx and UCAxTXIFG from USCI_Ax share another interrupt vector.
So you have to use two interrupt handlers, and check and clear the correct interrupt flags in each one:
#pragma vector = USCIAB0TX_VECTOR __interrupt void USCIAB0TX_ISR(void) { if (IFG2 & UCA0TXIFG) ... if (IFG2 & UCB0RXIFG) ... if (IFG2 & UCB0TXIFG) ... } #pragma vector = USCIAB0RX_VECTOR __interrupt void USCIAB0RX_ISR(void) { if (IFG2 & UCA0RXIFG) ... else // check I²C state changes }
Hi Luiz,
as Clemens showed above, there are two interrupt handler and for that you need to provide the functions:
This one is called with the UART TX and the I2C RX and TX interrupt and needs to handle this functions
#pragma vector = USCIAB0TX_VECTOR __interrupt void USCIAB0TX_ISR(void) { if (IFG2 & UCA0TXIFG) ... if (IFG2 & UCB0RXIFG) ... if (IFG2 & UCB0TXIFG) ... }
This one is called with the UART RX and the I2C State interrupt and needs to handle this functions
#pragma vector = USCIAB0RX_VECTOR __interrupt void USCIAB0RX_ISR(void) { if (IFG2 & UCA0RXIFG) ... else // check I²C state changes e.g. START and STOP bits }
The reason why your code stuck currently is that you have enabled the UART RX interrupt but not handler for that provided. So the CPU jumps to an undefined location as soon as this interrupt happens.
Regards,
Stefan
Hello guys,
I was able to run the RTC via I2C with the UART. I changed the code completely.
Based on an example IT code for I2C communication. I changed the code for my case and added it to my UART interrupt routine.
I do not read the RTC full time, only after sending the data to the UART.
This is my new job code:
#include <msp430g2553.h> #include <stdint.h> #include <stdbool.h> #define SLAVE_ADDR 0x68 #define CMD_TYPE_2_MASTER 5 #define TYPE_1_LENGTH 6 #define TYPE_2_LENGTH 8 #define MAX_BUFFER_SIZE 20 uint8_t MasterType2 [TYPE_2_LENGTH] = {0x30, 0x32, 0x21, 0x07, 0x17, 0x10, 0x18, 0x10}; uint8_t SlaveType2 [TYPE_1_LENGTH] = {0}; typedef enum 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, TIMEOUT_MODE } I2C_Mode; I2C_Mode MasterMode = IDLE_MODE; uint8_t TransmitRegAddr = 0; 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_Mode I2C_Master_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count); I2C_Mode I2C_Master_ReadReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t count); void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count); void initClockTo16MHz(void); void GPIO_Config(void); void I2C_Config(void); void UART_Config(void); long int cont = 0; int FLAG = 0; int main(void) { WDTCTL = WDTPW | WDTHOLD; initClockTo16MHz(); GPIO_Config(); UART_Config(); I2C_Config(); IFG2 &= ~UCA0TXIFG; I2C_Master_WriteReg(SLAVE_ADDR, 0x00, MasterType2, TYPE_2_LENGTH); while(1) { if ((MasterMode == IDLE_MODE) & (FLAG == 0)) { I2C_Master_ReadReg(SLAVE_ADDR, 0x00, TYPE_2_LENGTH); CopyArray(ReceiveBuffer, SlaveType2, TYPE_1_LENGTH); FLAG = 1; } if ((MasterMode == IDLE_MODE) & (cont >= 65530) & (FLAG == 1)) { FLAG = 2; RXByteCtr = 0; IFG2 |= UCA0TXIFG; IE2 |= UCA0TXIE; } if ((MasterMode == IDLE_MODE) & (FLAG == 3)) { I2C_Master_ReadReg(SLAVE_ADDR, 0x00, TYPE_2_LENGTH); CopyArray(ReceiveBuffer, SlaveType2, TYPE_1_LENGTH); FLAG = 1; cont = 0; } if (cont < 65530) cont++; } } #pragma vector = USCIAB0TX_VECTOR __interrupt void USCIAB0TX_ISR(void) { if (IFG2 & UCA0TXIFG) { if (RXByteCtr < 7 ) UCA0TXBUF = ReceiveBuffer[RXByteCtr]; else { FLAG = 3; IFG2 &= ~UCA0TXIFG; IE2 &= ~UCA0TXIE; } RXByteCtr++; } if (IFG2 & UCB0RXIFG) // Receive Data Interrupt { uint8_t rx_val = UCB0RXBUF; if (RXByteCtr) { ReceiveBuffer[ReceiveIndex++] = rx_val; RXByteCtr--; } if (RXByteCtr == 1) { UCB0CTL1 |= UCTXSTP; } else if (RXByteCtr == 0) { IE2 &= ~UCB0RXIE; MasterMode = IDLE_MODE; __bic_SR_register_on_exit(CPUOFF); // Exit LPM0 } } else if (IFG2 & UCB0TXIFG) // Transmit Data Interrupt { switch (MasterMode) { case TX_REG_ADDRESS_MODE: UCB0TXBUF = TransmitRegAddr; if (RXByteCtr) MasterMode = SWITCH_TO_RX_MODE; // Need to start receiving now else MasterMode = TX_DATA_MODE; // Continue to transmision with the data in Transmit Buffer break; case SWITCH_TO_RX_MODE: IE2 |= UCB0RXIE; // Enable RX interrupt IE2 &= ~UCB0TXIE; // Disable TX interrupt UCB0CTL1 &= ~UCTR; // Switch to receiver MasterMode = RX_DATA_MODE; // State state is to receive data UCB0CTL1 |= UCTXSTT; // Send repeated start if (RXByteCtr == 1) { //Must send stop since this is the N-1 byte if ((UCB0CTL1 & UCTXSTT) == 0) UCB0CTL1 |= UCTXSTP; // Send stop condition } break; case TX_DATA_MODE: if (TXByteCtr) { UCB0TXBUF = TransmitBuffer[TransmitIndex++]; TXByteCtr--; } else { //Done with transmission UCB0CTL1 |= UCTXSTP; // Send stop condition MasterMode = IDLE_MODE; IE2 &= ~UCB0TXIE; // disable TX interrupt __bic_SR_register_on_exit(CPUOFF); // Exit LPM0 } break; default: __no_operation(); break; } } } #pragma vector = USCIAB0RX_VECTOR __interrupt void USCIAB0RX_ISR(void) { if (IFG2 & UCA0RXIFG) { IFG2 &= ~UCA0RXIFG; char A = UCA0RXBUF; if (A == 'A') P1OUT ^= BIT0; } if (UCB0STAT & UCNACKIFG) { UCB0STAT &= ~UCNACKIFG; // Clear NACK Flags } if (UCB0STAT & UCSTPIFG) //Stop or NACK Interrupt { UCB0STAT &= ~(UCSTTIFG + UCSTPIFG + UCNACKIFG); //Clear START/STOP/NACK Flags } if (UCB0STAT & UCSTTIFG) { UCB0STAT &= ~(UCSTTIFG); //Clear START Flags } } I2C_Mode I2C_Master_ReadReg(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; UCB0I2CSA = dev_addr; IFG2 &= ~(UCB0TXIFG + UCB0RXIFG); // Clear any pending interrupts IE2 &= ~UCB0RXIE; // Disable RX interrupt IE2 |= UCB0TXIE; // Enable TX interrupt UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition __bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts return MasterMode; } I2C_Mode I2C_Master_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count) { MasterMode = TX_REG_ADDRESS_MODE; TransmitRegAddr = reg_addr; CopyArray(reg_data, TransmitBuffer, count); TXByteCtr = count; RXByteCtr = 0; ReceiveIndex = 0; TransmitIndex = 0; UCB0I2CSA = dev_addr; IFG2 &= ~(UCB0TXIFG + UCB0RXIFG); // Clear any pending interrupts IE2 &= ~UCB0RXIE; // Disable RX interrupt IE2 |= UCB0TXIE; // Enable TX interrupt UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition __bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts return MasterMode; } void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count) { uint8_t copyIndex = 0; for (copyIndex = 0; copyIndex < count; copyIndex++) { dest[copyIndex] = source[copyIndex]; } } void initClockTo16MHz() { if (CALBC1_16MHZ==0xFF) // If calibration constant erased { while(1); // do not load, trap CPU!! } DCOCTL = 0; // Select lowest DCOx and MODx settings BCSCTL1 = CALBC1_16MHZ; // Set DCO DCOCTL = CALDCO_16MHZ; } void GPIO_Config() { P1DIR |= BIT0 + BIT1 + BIT2 + BIT3 + BIT4; P1OUT &= ~(BIT0 + BIT1 + BIT2 + BIT3 + BIT4); P1SEL |= BIT6 + BIT7; // Assign I2C pins to USCI_B0 P1SEL2|= BIT6 + BIT7; // Assign I2C pins to USCI_B0 } void I2C_Config() { UCB0CTL1 |= UCSWRST; // Enable SW reset UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset UCB0BR0 = 160; // fSCL = SMCLK/160 = ~100kHz UCB0BR1 = 0; UCB0I2CSA = SLAVE_ADDR; // Slave Address UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation UCB0I2CIE |= UCNACKIE; } void UART_Config(void) { P1SEL |= BIT1 + BIT2; // P1.1 = RXD, P1.2=TXD P1SEL2 |= BIT1 + BIT2; // P1.1 = RXD, P1.2=TXD UCA0CTL1 |= UCSWRST; UCA0CTL0 |= UCMODE_0; UCA0CTL1 = UCSSEL_2 + UCSWRST; // UCSSEL_2 = SMCLK; UCSWRST = Reset UCA0BR0 = 104; // 16MHz 9600 UCA0BR1 = 0; // 16MHz 9600 UCA0MCTL |= UCBRF2 + UCBRF1 + UCOS16; // Modulation UCBRSx = 0, UCBRFx = 3, UCOS16 = 1 UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine** IE2 |= UCA0RXIE; }
These are the I2C bus signals:
And these are the signs read on the PC (the print screen was not taken at the same time):
Thank you very much for your support!
**Attention** This is a public forum