I2C
Description
The MSPM0G3507 has dedicated modules to support I2C communication; specifically, two: I2C0 and I2C1. Both UART and SPI communication support is also provided via different and independent modules. Each instances of the I2C module is capable having its signals, SCL and SDA, routed to several different GPIO pins for additional flexibility; see Peripheral Functions.
The I2C configuration is capable of operating in both Controller Mode and Peripheral Mode. These modes are more widely known as the Master and Slave mode, respectively; however, these terms are being slowly replaced with alternative namings. For instance, the manufacturer documentation and DriverLib functions are written with the terms Controller and Target (Target=Peripheral; however, the register naming within CCS is uses the archaic Master and Slave terms. This documentation (the ENGR-2350 website) is written using the Controller and Peripheral names and it should be understood that these terms are interchangeable.
For the purposes of this class, only the Controller Mode is discussed and implemented.
As there are two instances of the I2C type modules, the functions listed below require that the specific instance be specified. The first argument for all I2C HAL functions is the I2c module to use: I2C_Regs *i2c; with value being either I2C0 or I2C1.
Note
A rigorous implementation of I2C would likely involve employing the I2C module in interrupt mode. As this course does not require this type of implementation, the interrupt modes of the I2C are omitted from this discussion.
Controller Mode Configuration
The configuration requires the creation of a I2C_ControllerConfig type struct. The table below shows the fields for this configuration struct.
Field |
type |
Possible Values |
|---|---|---|
|
|
|
|
|
|
|
|
|
Field Descriptions:
.busclkRate: Specifies the frequency, in Hz, of the current and/or expected BUSCLK during I2C module operation.
.bitRate: Specifies the desired bit rate, in bits-per-second, for the I2C bus. This value is equivalent to the serial clock, SCL, frequency.
.addrMode: Selects between 7-bit,I2C_ADDR_MODE_7BIT, and 10-bit,I2C_ADDR_MODE_10BIT,
With the configuration struct filled in, the I2C may be initialized with the function:
void I2C_initController( I2C_Regs * i2c , I2C_ControllerConfig * cfg )
The first argument to this function, I2C_Regs * i2c, is the I2C module to use (see above). The second argument is the configuration struct as described above.
Important
The I2C module’s input clock is configured by the above function to be BUSCLK/8. Actual valid values for the I2C bit rate are limited to an integer division of BUSCLK/8 between 1 and 128. The requested value by the field .bitRate, if not an allowed value, will be coerced to the next highest valid bit rate. The .bitRate field will be updated by I2C_initController with this coerced value.
Operation of the I2C module requires that the associated SCL and SDA signals on the corresponding GPIO pins <gpio_af> be enabled and the pins are also set to Open-Drain mode: Basic I/O.
Controller Mode: Read/Write
Implementation of the I2C read and write functionality with the MSPM0 serving as the controller requires a consistent series of steps. The implementation is moderately complex, with errors being probable and very difficult to detect. To this end, high level functions are provided towards ease of implementation. The two functions are:
void I2C_writeData( I2C_Regs * i2c , uint8_t PeriphAddress, uint8_t StartReg , uint8_t * data , uint8_t len )
void I2C_readData( I2C_Regs * i2c , uint8_t PeriphAddress, uint8_t StartReg , uint8_t * data , uint8_t len )
As shown, both functions require the same arguments. These are:
I2C_Regs * i2cspecifies the I2C instance to use for the communication.
uint8_t PeriphAddressspecifies the 7-bit address of the peripheral device to communication with. This is was known historically as the slave address.
uint8_t StartRegis the peripheral device register to begin communication with. This is the register that is written-to or read-from first.
uint8_t * datais and must be an array that either stores the data to be written to the peripheral device (I2C_writeData) or is used to save the data that is read from the device (I2C_readData). Note that there is no return value for theI2C_readData()function. This array is always accessed starting from the 0th index, independent of the StartReg value.
uint8_t lenis the number of data bytes to be written-to or read-from the peripheral device. This number does not include the pheripheral address or start register.
Examples
Below is an example for reading and writing to a peripheral device using the functions provided above.
Write Example: It is desired to write configuration values of 0x3A (register 1), 0xFF (register 2), and 0x12 (register 10) for a peripheral with a 7-bit address of 0x52 using I2C instance 0:
uint8_t arry[2]; // Array must be *at least* as long as longest write used arry[0] = 0x3A; // Set values to send, starting at index 0 arry[1] = 0xFF; I2C_writeData(I2C0,0x52,1,arry,2); // send values to registers 1 and 2 arry[0] = 0x12; // Set value to send for second transmission I2C_writeData(I2C0,0x52,10,arry,1); // send single value to register 10
Read Example: Registers 4 through 6 must be read from the same peripheral.
uint8_t arry[3]; // Array must be *at least* 3 long for 3 register read. I2C_readData(I2C0,0x52,4,arry,3); // read values from register 4-6 printf("4: %u\t5: %u\t6: %u\r\n",arry[0],arry[1],arry[2]); // print out values