Part Number: MSP430F5329
I have been writing a SMBus slave for Read Word, Write Word, and Block Read protocol with and without PEC, using the MSP430F5329.I have been using the Python SMBUS libraries on the Raspberry Pi to test the code. I have gotten the Read word with PEC and Without PEC. I can not get the Read Block to work, and I know the bytes I am sending are right. Documentation is nonexistant. So I am looking for something else. In the process of looking at the SMBus protocol more closely in both the read word and block read, the last data byte sent by the slave is NAKed by the master, then the master sends a Stop. I had not noticed it before.
My code lets me know every time an I2C interrupt is generated and logs the type of interrupt. I have never seen a NAK interrupt come through. So now I am very suspicious of the Raspberry Pi code. I figured I might as well use another MSP430 chip as my I2C Master and picked up the MSP-EXP430FR2433. I was looking at the library functions in the MSPDRIVERLIB: DriverLib for MSP430 devices and can not figure out a way to send a NAK after a the last byte is received, as the SMBus specification requires. For example Figure 31 in System Management Bus (SMBus) Specification Version 3.0 <Master Start> <Master Address> <Master Wr> <Slave ACK> <Master Command Code> <Slave ACK> <Master Restart> <Master Address> <Master R> <Slave ACK> <Slave Data byte Low> <Master Ack> <Slave Data byte High> <Master NAK> <Master Stop>What am I missing? How do I send the Master NAK in response to the Slave sending the Data byte High? It seems to be ACKed automatically. Kip
In reply to Walter Schnoor:
I have to think about this a bit. On the block transfer the first byte read is the length of the data to follow, not counting the PEC. So for the master, I have to read one byte, than use that input for the number of bytes to read (and if there is a PEC add one more to the number of bytes to read) and when it gets to the last byte it will send the NAK and then the Stop.
O.K. so next step is to implement it. :) Something for Monday.
In reply to Kipton Moravec:
I think I am close to understanding this. I am confused about a couple of things.
MP.selectClockSource = EUSCI_B_CLOCKSOURCE_SMCLK;
MP.i2cClk = 16000000;
MP.dataRate = EUSCI_B_I2C_SET_DATA_RATE_100KBPS;
MP.byteCounterThreshold = 255;
MP.autoSTOPGeneration = EUSCI_B_I2C_NO_AUTO_STOP;
// The values passed are defined in the I2C_master_for_host.h file
EUSCI_B_I2C_setMode(I2C_HOST_BASE_ADDRESS, USCI_B_I2C_TRANSMIT_MODE); // Is this right?
EUSCI_B_I2C_enableInterrupt(I2C_HOST_BASE_ADDRESS,0xFF); // All interrupts
First question: I do not understand setMode.Here is what the documentation says MSP430FR2xx_4xx_DriverLib_Users_Guide:void EUSCI B I2C setMode ( uint16 t baseAddress, uint8 t mode )Sets the mode of the I2C device.When the receive parameter is set to EUSCI B I2C TRANSMIT MODE, the address will indicatethat the I2C module is in receive mode; otherwise, the I2C module is in send mode.Parameters
Modified bits are UCTR of UCBxCTLW0 register.ReturnsNone Is that a typo? When the receive is Transmit mode it is in Receive Mode? What???Moving on... So now it is initialized:I want to send a command: normally I would want a <Start><Slave Address Write> <Command> <Start> <Slave Address Read> <Number Bytes (3)> <Byte 1> ... <Byte 3><NAK><Stop>Bold is the host sending, not bold is the slave sendinguint8_t data;// I need to make sure the setMode is Transmit to start?EUSCI_B_I2C_masterSendMultiByteStart(EUSCI_ADDRESS,Command);// Do I change the setMode to Receive here before the start? // I understand this part mostly have a couple of questions:EUSCI_B_I2C_masterReceiveStart(EUSCI_ADDRESS); // This generates the second start or restartwhile(!(EUSCI_B_I2C_getInterruptStatus(EUSCI_ADDRESS, EUSCI_B_I2C_RECEIVE_INTERRUPT0)));data = EUSCI_B_I2C_masterReceiveMultiByteNext(EUSCI_ADDRESS); // Number of bytes = 3while(!(EUSCI_B_I2C_getInterruptStatus(EUSCI_ADDRESS, EUSCI_B_I2C_RECEIVE_INTERRUPT0)));data = EUSCI_B_I2C_masterReceiveMultiByteNext(EUSCI_ADDRESS); // Byte 1while(!(EUSCI_B_I2C_getInterruptStatus(EUSCI_ADDRESS, EUSCI_B_I2C_RECEIVE_INTERRUPT0)));data = EUSCI_B_I2C_masterReceiveMultiByteNext(EUSCI_ADDRESS); // Byte 2data = EUSCI_B_I2C_masterReceiveMultiByteFinish(EUSCI_ADDRESS); // Byte 3 I am doing this all interrupt driven and I have a state machine.Does the last command poll until the data Byte 3 is received? I cannot poll in a ISR. I can see all interrupts. Is there a better way to do this?Maybe when the receive interrupt for Byte 2 fires, I should set the UCTXSTP? Then wait for the Receive interrupt to get data?I do not think there are any other interrupts that should fire except the two Start interrupts, and one or two transmit Interrupts right?
One more question on the other side. When this ends the Slave will get a NAK interrupt and a Stop interrupt? or just one of them? (If one, which one?)Thanks,Kip
Kipton MoravecIs that a typo? When the receive is Transmit mode it is in Receive Mode? What???
Yes, this is a misprint. I have notified the developer and this will be fixed in the next DriverLib / MSP430Ware release. The correct comment should read: "When the mode parameter is set to EUSCI_B_I2C_TRANSMIT_MODE, the address will indicate that the I2C module is in send mode; otherwise, the I2C module is in receive mode."
With regard to the rest of your questions:
- Before calling EUSCI_B_I2C_masterSendMultiByteStart() you do want to set the mode to transmitter using EUSCI_B_I2C_setMode(I2C_0_BASE, EUSCI_B_I2C_TRANSMIT_MODE).
- Interestingly enough, you do not need to change the mode to receiver when sending out the repeated start; this is done from within EUSCI_B_I2C_masterReceiveStart(I2C_0_BASE).
- You are correct, you don't want to be polling in an ISR. For the ISR approach, you can use EUSCI_B_I2C_masterReceiveMultiByteStop() instead of EUSCI_B_I2C_masterReceiveMultiByteFinish(). This sets the stop condition generation bit. The tricky part with this is getting the timing to work out. That bit needs to be set before the last byte is clocked in for the nack to get generated correctly by the master. This is the area of critical timing. The byte counter feature is handy if you know the # of bytes to receive, because it will generate the stop and nack automatically.
- In master receiver mode, you WILL get a stop interrupt when the stop condition goes through. You will not get the NACK interrupt from the master-generated NACK. You only get this if the slave NACK's.
Here is a code snipped I implemented on an MSP-EXP430FR2433 LaunchPad with a dummy host to mimic your use-case with a 1-byte read-out from the slave.
#define DCOFREQ 8000000
#define I2C_0_BASE (EUSCI_B0_BASE)
#define I2C_RECEIVE_BUFFER_SIZE (32)
int8_t I2C_0_rxBytesRemaining = 0;
int8_t I2C_0_rxCnt = 0;
// SMCLK = MCLK = DCO = 4MHz
// ACL = 32kHz
CS_initClockSignal(CS_FLLREF, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1);
CS_initClockSignal(CS_ACLK, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1);
CS_initClockSignal(CS_MCLK, CS_DCOCLKDIV_SELECT, CS_CLOCK_DIVIDER_1);
CS_initClockSignal(CS_SMCLK, CS_DCOCLKDIV_SELECT, CS_CLOCK_DIVIDER_1);
// I2C port mux selection
P1OUT = 0;
P1DIR |= BIT0 | BIT1 | BIT4 | BIT5 | BIT6;
P1SEL0 |= BIT2 | BIT3;
PM5CTL0 &= ~LOCKLPM5;
// I2C Setup
I2C_0.selectClockSource = EUSCI_B_I2C_CLOCKSOURCE_SMCLK;
I2C_0.i2cClk = DCOFREQ;
I2C_0.dataRate = EUSCI_B_I2C_SET_DATA_RATE_400KBPS;
I2C_0.byteCounterThreshold = 0;
I2C_0.autoSTOPGeneration = EUSCI_B_I2C_NO_AUTO_STOP;
uint8_t I2C_0_readCmd(uint8_t slave, uint8_t cmd)
P1OUT |= BIT0 | BIT4 | BIT5 | BIT6;
// Set slave address and wait for bus
I2C_0_rxBytesRemaining = 0;
// Write command to slave
if (EUSCI_B_I2C_getInterruptStatus(I2C_0_BASE, EUSCI_B_I2C_NAK_INTERRUPT))
// Read response from slave
P1OUT &= ~BIT0;
WDTCTL = WDTPW | WDTHOLD;
__interrupt void I2C_0_ISR(void)
P1OUT |= BIT1;
case 0x00: break; // Vector 0: No interrupts break;
case 0x02: break; // Vector 2: ALIFG break;
case 0x04: break; // Vector 4: NACKIFG break;
case 0x06: break; // Vector 6: STT IFG break;
P1OUT &= ~BIT5;
break; // Vector 8: STPIFG break;
case 0x0a: break; // Vector 10: RXIFG3 break;
case 0x0c: break; // Vector 14: TXIFG3 break;
case 0x0e: break; // Vector 16: RXIFG2 break;
case 0x10: break; // Vector 18: TXIFG2 break;
case 0x12: break; // Vector 20: RXIFG1 break;
case 0x14: break; // Vector 22: TXIFG1 break;
case 0x16: // Vector 24: RXIFG0 break;
// Receive byte
data = EUSCI_B_I2C_masterReceiveMultiByteNext(I2C_0_BASE);
// If this is the first byte (RX Length Invalid), then save the length to read
// and reset the receive counter to 0
if (I2C_0_rxBytesRemaining == 0x00)
I2C_0_rxBytesRemaining = data;
if (I2C_0_rxBytesRemaining > I2C_RECEIVE_BUFFER_SIZE)
I2C_0_rxBytesRemaining = I2C_RECEIVE_BUFFER_SIZE;
I2C_0_rxCnt = 0;
// If this is not the first byte, append the response to the RX
I2C_0_rxBuffer[I2C_0_rxCnt++] = data;
// Send NACK and STOP on last byte coming in
if (I2C_0_rxBytesRemaining == 1)
P1OUT &= ~BIT4;
case 0x18: break; // Vector 26: TXIFG0 break;
case 0x1a: break; // Vector 28: BCNTIFG break;
case 0x1c: break; // Vector 30: clock low timeout break;
case 0x1e: break; // Vector 32: 9th bit break;
P1OUT &= ~BIT1;
This gives the following logic trace:
All content and materials on this site are provided "as is". TI and its respective suppliers and providers of content make no representations about the suitability of these materials for any purpose and disclaim all warranties and conditions with regard to these materials, including but not limited to all implied warranties and conditions of merchantability, fitness for a particular purpose, title and non-infringement of any third party intellectual property right. TI and its respective suppliers and providers of content make no representations about the suitability of these materials for any purpose and disclaim all warranties and conditions with respect to these materials. No license, either express or implied, by estoppel or otherwise, is granted by TI. Use of the information on this site may require a license from a third party, or a license from TI.
TI is a global semiconductor design and manufacturing company. Innovate with 100,000+ analog ICs andembedded processors, along with software, tools and the industry’s largest sales/support staff.