STM32-Peripheral’s- I2C DMA mode

STM32-Peripheral’s- I2C DMA mode

https://www.i2cbus.org/

Introduction


The I2C (inter-integrated circuit) bus interface handles communications between the
microcontroller and the serial I2C bus. It provides multimaster capability, and controls all I2C
bus-specific sequencing, protocol, arbitration and timing.
DMA can be used to reduce CPU overload

I2C main features


• I2C bus specification rev03 compatibility:
– Slave and master modes
– Multimaster capability
– Standard-mode (up to 100 kHz)
– Fast-mode (up to 400 kHz)
– Fast-mode Plus (up to 1 MHz) (Controller Specific)
– 7-bit and 10-bit addressing mode
– Multiple 7-bit slave addresses (2 addresses, 1 with configurable mask)
– All 7-bit addresses acknowledge mode
– General call
– Programmable setup and hold times
– Easy to use event management
– Optional clock stretching
– Software reset
• 1-byte buffer with DMA capability
• Programmable analog and digital noise filters

In addition to receiving and transmitting data, this interface converts it from serial to parallel
format and vice versa. The interrupts are enabled or disabled by software. The interface is
connected to the I2C bus by a data pin (SDA) and by a clock pin (SCL). It can be connected
with a standard (up to 100 kHz), Fast-mode (up to 400 kHz) or Fast-mode Plus (up to
1 MHz) I2C bus.

Pin nameSignal typeDescription
I2C_SDABidirectionalI2C data
I2C_SCLBidirectionalI2C clock
Table 1: I2C Pin Details

How to use this driver

The I2C HAL driver can be used as follows:
1. Declare a I2C_HandleTypeDef handle structure, for example: I2C_HandleTypeDef hi2c;
2. Initialize the I2C low level resources by implementing the @ref HAL_I2C_MspInit() API:
a. Enable the I2Cx interface clock
b. I2C pins configuration
◦ Enable the clock for the I2C GPIOs
◦ Configure I2C pins as alternate function open-drain
c. NVIC configuration if you need to use interrupt process
◦ Configure the I2Cx interrupt priority
◦ Enable the NVIC I2C IRQ Channel
d. DMA Configuration if you need to use DMA process
◦ Declare a DMA_HandleTypeDef handle structure for the transmit or receive channel
◦ Enable the DMAx interface clock using
◦ Configure the DMA handle parameters
◦ Configure the DMA Tx or Rx channel
◦ Associate the initialized DMA handle to the hi2c DMA Tx or Rx handle
◦ Configure the priority and enable the NVIC for the transfer complete interrupt on the DMA Tx or
Rx channel
3. Configure the Communication Clock Timing, Own Address1, Master Addressing mode, Dual Addressing
mode, Own Address2, Own Address2 Mask, General call and Nostretch mode in the hi2c Init structure.
4. Initialize the I2C registers by calling the @ref HAL_I2C_Init(), configures also the low level Hardware (GPIO,
CLOCK, NVIC…etc) by calling the customized @ref HAL_I2C_MspInit(&hi2c) API.
5. To check if target device is ready for communication, use the function @ref HAL_I2C_IsDeviceReady()
6. For I2C IO and IO MEM operations, three operation modes are available within this driver :

DMA mode IO operation
• Transmit in master mode an amount of data in non-blocking mode (DMA) using @ref
HAL_I2C_Master_Transmit_DMA()
• At transmission end of transfer, @ref HAL_I2C_MasterTxCpltCallback() is executed and user can add his
own code by customization of function pointer @ref HAL_I2C_MasterTxCpltCallback()

• Receive in master mode an amount of data in non-blocking mode (DMA) using @ref
HAL_I2C_Master_Receive_DMA()
• At reception end of transfer, @ref HAL_I2C_MasterRxCpltCallback() is executed and user can add his own
code by customization of function pointer @ref HAL_I2C_MasterRxCpltCallback()

DMA mode IO MEM operation
• Write an amount of data in non-blocking mode with DMA to a specific memory address using @ref
HAL_I2C_Mem_Write_DMA()
• At Memory end of write transfer, @ref HAL_I2C_MemTxCpltCallback() is executed and user can add his
own code by customization of function pointer @ref HAL_I2C_MemTxCpltCallback()
• Read an amount of data in non-blocking mode with DMA from a specific memory address using @ref
HAL_I2C_Mem_Read_DMA()
• At Memory end of read transfer, @ref HAL_I2C_MemRxCpltCallback() is executed and user can add his
own code by customization of function pointer @ref HAL_I2C_MemRxCpltCallback()
• In case of transfer Error, @ref HAL_I2C_ErrorCallback() function is executed and user can add his own
code by customization of function pointer @ref HAL_I2C_ErrorCallback()

For this blog we are going to use I2C in DMA mode(master), we are going to used all above functions for demonstration, PA9 & PA10 Pin used for debugging purpose as UART Tx & UART Rx respectively. this blog is specially for I2C configuration in DMA mode, below 10 steps represents STM32 project creation from scratch, only difference will be board selection or controller selection part, user can select according to there requirements but below steps will remain same for all the projects.

for I2C implementation in poling mode refer

Creating a new STM32 executable project

  1. The easiest way to create a new STM32 C/C++ project is to use the STM32 project wizard. It is selected through the menu [File]>[New STM32 Project].
  2. The MCU/MPU selector and Board Selector tabs can be selected at the top of the window. Use the first tab to create project for a specific device and the second if a project for a specific board is needed. today we will select specific device.
Figure 1

3. Select SMT32F429ZI in MCU Selector tab

4. According to the settings in Figure 3, the project is meant to be stored in the default location with the following

options set:

• C project

• Executable binary type

STM32CubeIDE targeted project type

Press [Next] to open the Firmware Library Package Setup page.

Figure 3 Project Name

5. In this page, it is possible to select the STM32Cube firmware package to use when creating the project. In this case, the default settings are used. Press [Finish] to create the project. (Fig 4)

Figure 4 Select Firmware Package

6. wait for project creation process

Figure 5 Project Creation process

7. Initial view of STM32CUBE ide after project generation

Figure 6

8. Go to System core > SYS > Enable Serial wire debug

Figure 8 Enable Serial Wire Debug

9. If require enable external clock

Figure 9 Enable external clock

10. System clock setting at 180MHz

Figure 10 clock settings

11. Enable Peripheral Configuration

Go to System mode > Connectivity > I2C > Enable I2C > keep all other settings as its

Figure 11: Enable I2C

12. Enable the DMA settings for Tx & Rx depending upon your application requirement

I2C Tx DMA Settings

I2C Rx DMA Settings

12. Pin configuration

Figure 12: Pin configuration

13. Press below icon for code generation

Figure 13 Cube IDE Code Generation

15. Sample Code:

/*
Below is general pupose code for I2C communication user pass address accodinf to I2C device,
simiparly he/she can pass config paramters
USER_DEFINED_DATA_COUNT value can be vary from device to device 
*/
HAL_StatusTypeDef I2C_Master_Functions_Handler(uint8_t address, uint8_t *config)
{
	HAL_StatusTypeDef ret;
	uint8_t rxData[USER_DEFINED_DATA_COUNT];

	ret = HAL_I2C_Master_Transmit_DMA(&hi2c1, (uint16_t)(address<<0x01u), config, sizeof(config));
	if(ret != HAL_OK)
	{
		return ret;
	}

	HAL_Delay(10);	//10ms delay 

	ret = HAL_I2C_Master_Receive_DMA(&hi2c1, (uint16_t)((address<<0x01u)|0x01u), rxData, USER_DEFINED_DATA_COUNT);
	if(ret != HAL_OK)
	{
		return ret;
	}
	// Assemble reading data from rxData bytes 
  	//Todo Write user defined code
	return HAL_OK;
}
#define MEMADD_Tx 0x00 //Dummy value
#define MEMADD_Rx 0x00 //Dummy value
#define MEM_CONFIG_COUNT 0x01	//Dummy value
#define MEM_Rx_COUNT 	0x01	//Dummy value
/*
Below is general pupose code for I2C communication user pass address accodinf to I2C device,
simiparly he/she can pass config paramters
USER_DEFINED_DATA_COUNT value can be vary from device to device 
*/
HAL_StatusTypeDef I2C_Mem_Functions_Handler(uint8_t address, uint8_t *config)
{
	HAL_StatusTypeDef ret;
	uint8_t rxData[USER_DEFINED_DATA_COUNT];


	ret = HAL_I2C_Mem_Write_DMA(&hi2c1, (uint16_t)(address), (uint16_t)MEMADD, MEM_CONFIG_COUNT, 
                            config, sizeof(config));
	if(ret != HAL_OK)
	{
		return ret;
	}

	HAL_Delay(10);	//10ms delay 

	ret = HAL_I2C_Mem_Read_DMA(&hi2c1, (uint16_t)(address) |0x01u, (uint16_t)MEMADD_Rx, MEM_Rx_COUNT, 								rxData, USER_DEFINED_DATA_COUNT);
	if(ret != HAL_OK)
	{
		return ret;
	}

	// Assemble reading data from rxData bytes 
  	//Todo Write user defined code

	return HAL_OK;
}
Software Tools:
  1. STM32CubeIDE
  2. STM32CubeMx
  3. Teraterm
Hardware Setup:
  1. STM32F429IDISCOVERY board
  2. Mini USB Cable
  3. Jumper wire
Conclusion:

Successfully demonstrated I2C DMA mode functionality implementation. If you enjoyed this article, share your feedback.

References:
  1. STM32 HAL Library
Similar topics:
  1. STM32 code generation using STM32CubeIDE
  2. STM32 Peripherals: GPIO
  3. STM32 Peripherals: DAC
  4. STM32 Peripherals: ADC using Polling Mode
  5. STM32 Peripherals: UART Interrupt Mode
  6. STM32-Peripheral’s-SPI: Polling Mode
  7. STM32-Peripheral’s I2C Polling Mode

Leave a Reply

Your email address will not be published. Required fields are marked *