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.

MSP430FR2355: Configuring MSP430 as slave for a register read or write

Part Number: MSP430FR2355
Other Parts Discussed in Thread: HDC2010

I have been looking through the documentation and forums and haven't been able to clear up the following programming issue:

I would like to configure an FR2355 as a slave. The master (also an MSP430 Launchpad for development) should be able to read from and write to individual data registers on the slave. It appears the slave interrupt vector must be agile enough to understand if the master is addressing it with UCTR set or unset, ie. writing or reading data from the register. The first byte of received data is always the register address. If the master is reading the register, the code should point to it and load its value into UCB0TXBUF. This is sometimes handled with repeated start. If, however, the master is over-writing the register and perhaps the registers following it, the code has to collect this data and parse it with UCB0RXBUF. It sure looks like there has to be a branching capability.

I believe this can be handled by firmware in the MSPWare driver library, but I would like to implement it on the registry level so I can understand what is going on. Is there documentation or code examples available that show how to do this?

Would it be better to setup independent registers in RAM for writing and reading?

  • Hi Mike,

    You can check out the I2C code examples in the TI Resource Explorer either inside Code Composer Studio (CCS) or at dev.ti.com/tirex. Here's a direct link to the I2C register-level examples. Also, the MSP430FR2355 user's guide will be a vital reference for your development. Another good resource is the Solutions to Common eUSCI and USCI Serial Communication Issues on MSP430 MCUs app note. The I2C introduction in MSP Academy may also help you.

    I hope this gets you started.

  • A specific point of confusion that prompted my initial post is TI's documentation of the I2C protocol as described in slva704; link is here: https://www.ti.com/lit/an/slva704/slva704.pdf

    Section 3.2 shows how a data byte is read from a slave. The master sends a start with the slave address and the R/W bit cleared, followed by a start with the desired register address and R/W set. The slave responds with the appropriate data byte(s). TI's popular temperature-humidity sensor HDC2010 is accessed this way, but other I2C peripherals may not be. Since the MSP430 uses data buffers and interrupts to implement data transfer on I2C, it would appear that a non-trivial amount of coding is needed to configure it as a slave for the protocol depicted in slva704, i.e. where the slave is pointed to a register address that is then read. I could not find anything useful in MSPWare, but was able to write some slave code myself that works OK with the MSP430FR2355 Launchpad.

  • I think they function the same way, and I think the diagram in SLVA704 is a little better than what's shown in the MSP430FR2355 user's guide.

    SLVA704 shows that the most significant bit in the address is actually bit 6, not bit 7 (assuming the least significant bit is 0 in an 8-bit address). The MSP430FR2355 user's guide mentions this in the description for the UCBxI2CSA register.

    The code examples should also function this way, and if you capture the I2C communication with a logic analyzer, you should see that the slave address is basically shifted to the left by 1 bit.

  • [For some reason I can't open that PDF, either using your link or by searching at ti.com ("Failed - Server problem") so I don't know what it says.]

    I once wrote a very simple I2C slave as part of a larger experiment. It had 3 pieces of state: Counter, Index, and Array[32].

    It responded to 3 interrupts:

    STTIFG: Set Counter=0

    RXIFG: if (Counter == 0) Index = RXBUF; else Array[Index++] = RXBUF; ++Counter;

    TXIFG: TXBUF = Array[Index++];

    The EUSCI did all the other work.

    It accomplished my goal but was pretty boring since there were no semantics associated with Array[]. Given the intrinsic flow control in I2C, I could imagine extending it to do something interesting.

  • That's essentially what I did, placing the byte counters inside the RX and TX interrupts. I need to read and write bytes from/to the MSP430 slave so I use a receive buffer, examine it, then decide what to do. I also load data designated for the master into a second array that the master can retrieve at any time by sending the slave address with the R/W bit set.

    I'm developing a low power application, so it was important that I got interrupts on both sides of the bus to behave well with LPM*. That's why I'm working with the various I2C registers instead of the opaque macro commands that are available for this purpose.

    My issue with slva704 is not configuring the 7-bit slave address. It's use of data register addresses as shown in Section 3.2 of that document. I found it far more transparent to place bytes in arrays and access them with pointers, but maybe I'm missing something.

  • Since the MSP430 uses data buffers and interrupts to implement data transfer on I2C, it would appear that a non-trivial amount of coding is needed to configure it as a slave for the protocol depicted in slva704, i.e. where the slave is pointed to a register address that is then read.
    My issue with slva704 is not configuring the 7-bit slave address. It's use of data register addresses as shown in Section 3.2 of that document. I found it far more transparent to place bytes in arrays and access them with pointers, but maybe I'm missing something.

    I did want to point out that Figure 9 in Section 3.2 in SLVA704 is demonstrated by the read operation scope shot in the Logic Probe Captures section in the I2C Academy (linked above). This example uses the I2C standard master and slave code examples. For the read operation by the master, the master sends the slave address to the slave. After the slave acknowledges that, an example command (used to demonstrate the register address) is sent to the slave. Next, the master will send the slave address to the slave device again followed by data byte(s) associated with the previously-received example command. Notice that the eUSCI module handles the slave address and R/W bit automatically (not checked manually in the code like your approach), and the slave's state machine determines how to respond based on the received command. While these examples do use several functions, the code inside those functions are at the register level.

    Your approach makes sense, and it sounds like you're on the right track. Configuring a MSP430 as a slave device can be advantageous since you can write code that does exactly what you want it to do. However, that flexibility can also be more challenging because it's more open ended compared to fixed function devices like the HDC2010 with defined registers.

  • I took a look at the example linked in the I2C academy. The macros call other functions and it took some unpacking to see what was going on. My MSP430 slave application can't use these macros as-is because it's gathering data in a timed loop and I need to keep the UCRXIE0 and UCTXIE0 interrupts constantly enabled. In particular, I want the master to be able to retrieve data from the slave at any time, ie. asynchronous with the timed slave operations. All the signal processing happens on the slave, but I have status bytes always loaded in an array that the master can retrieve and read as needed. I also need to move the slave in and out of either LPM3 or LPM4 depending on the conditions. The ability of the master to wake an MSP430 slave from LPM4 is a very nice feature.

    Anyway, I believe I have the MSP430 slave properly configured for my needs. I appreciate the help.

**Attention** This is a public forum