Msp430 I2c Slave Example

0 views
Skip to first unread message

Lynne Pruskowski

unread,
Aug 3, 2024, 5:27:48 PM8/3/24
to parwegentleb

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?

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.

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.

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.

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.

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.

I'm more of a high level software guy but have been working on some embedded projects lately so I'm sure there's something obvious I'm missing here, though I have spent over a week trying to debug this and every 'MSP' related link in google is purple at this point...

I currently have an MSP430F5529 set up as an I2C slave device whose only responsibility currently is to receive packets from a master device. The master uses industry grade I2C and has been heavily tested and ruled out as the source of my problem here. I'm using Code composer as my IDE using the TI v15.12.3.LTS compiler.

What is currently happening is the master queries how many packets (of size 62 bytes) the slave can hold, then sends over a few packets which the MSP is just currently discarding. This is happening every 100ms on the master side and for the minimal example below the MSP will always just send back 63 when asked how many packets it can hold. I have tested the master with a Total Phase Aardvark and everything is working fine with that so I'm sure it's a problem on the MSP side. The problem is as follows:

The program will work for 15-20 minutes, sending over tens of thousands of packets. At some point the slave starts to hold the clock line low and when paused in debug mode, is shown to be stuck in the start interrupt. The same sequence of events is happening every single time to cause this.

1) Master queries how many packets the MSP can hold.
2) A packet is sent successfully
3) Another packet is attempted but < 62 bytes are received by the MSP (counted by logging how many Rx interrupts I receive). No stop condition is sent so master times out.
4) Another packet is attempted. A single byte is sent before the stop condition is sent.
5) Another packet is attempted to be sent. A start interrupt, then a Tx interrupt happens and the device hangs.

Below is the minimal working example which is reproducing the problem. My particular concern is with the SetUpRx and SetUpTx functions. The examples that the Code Composer Resource Explorer gives only has examples of Rx or Tx, I'm not sure if I'm combining them in the right way. I also tried removing the SetUpRx completely, putting the device into transmit mode and replacing all calls to SetUpTx/Rx with mode = TX_MODE/RX_MODE, which did work but still eventually holds the clock line low. Ultimately I'm not 100% sure on how to set this up to receive both Rx and Tx requests.

I am new to controller programming. I have been programming in Windows for 20 years, but the low level controller programming is just one huge paradigm shift for me. If somebody could point me to a good example of the above 3 operations that will work in Code Composer Studio 7.x, I'd be very grateful.

I can't make any sense of it. It's all abbreviated. Setting values is acting like calling a function. It's nice and compact, but for a guy used to calling a function with a meaningful name, it's incomprehensible... Looks like jibberish. I cannot read that code and make out what parts of it are doing what.. I'm thinking I might just need some 'Intro to Controller Programming' class to put me in the mode to decipher the above code.

It appears to me that the world of controller programming uses 'short-hand' instead of calling functions. I'm sure there's good reasons for this, but it's really hard to follow when first starting out. Any useful help with some explanations that would be useful to somebody like me who doesn't already know the answer would be greatly appreciated.

Anybody can say that they know how to do something. A truly gifted person can actually teach it to somebody that doesn't already know. That's what I'm asking for here. Or at least guide me to some source where the examples ARE spoon fed to start with. I just don't get the whole paradigm at this point, so it's hard for me to decipher...

SetPinMode(14, OUTPUT) likely as well only sets a value in the register that controls the pin (in pseudocode: pin[14].output=true) . In C that's often done with binary arithmetic (bit manipulation). The registers in the MSP are memory mapped, so writing to these predefined memory regions is writing directly to the machine registers, to which the machine reacts accordingly, as explained in the set of reference manuals (search by chip family and part number). To get an intro on the hardware, any book on MSP or 8-bit microcontrolers in general should be enough.

I'm sure open source implementations for I2C exist, already, e.g. in msp430ware from TI, or other open source libraries, so you wouldn't have to roll your own. If you do try to, though, experimenting is expected, as the official documentation only goes so far.

c80f0f1006
Reply all
Reply to author
Forward
0 new messages