Getting started with STM32L053: I2C Read Mode with DMA

In the previous guide (here), we saw how to configure the I2C in STM32L053 to write to slave address using DMA. Now, we shall read from a slave device using DMA.

In this guide, we shall cover the following:

  • DMA initializing.
  • I2C Read using DMA function.
  • Code.
  • Demo.

5. DMA Initializing:

We shall continue from the previous topic and we start from the i2c_init function.

Since the DMA1_Channel6 is used for I2C1_TX, we need to find another channel for the RX part.

From the reference manual of STM32L053, we can find that DMA1_Channel7 is for I2C1_RX:

Since the clock is already enabled, we shall configure the DMA.

The DMA has the following configuration:

  • Memory increment mode.
  • Read from peripheral (DIR=0).
  • Transfer complete interrupt.

DMA1_Channel7->CCR |=DMA_CCR_MINC|DMA_CCR_TCIE;

Set the peripheral address to be RXDR of the I2C1:

DMA1_Channel7->CPAR= (uint32_t)&I2C1->RXDR;

Set CxS of Channel7 to 6 which is I2C1.

DMA_CSELR|=(0x06<<24);

Thats all for the initializing for the DMA mode.

6. I2C Read Function:

void i2_read_dma(uint8_t slav_add, uint8_t memadd, uint8_t *data, uint8_t length )
	{
		(slav_add=slav_add<<1);
		/*Enable I2C*/
		I2C1->CR1 |=I2C_CR1_PE;
		/*Set slave address*/
		I2C1->CR2=(slav_add<<I2C_CR2_SADD_Pos);
		/*7-bit addressing*/
		I2C1->CR2&=~I2C_CR2_ADD10;
		/*Set number to transfer to 1 for write operation*/
		I2C1->CR2|=(1<<I2C_CR2_NBYTES_Pos);
		/*Set the mode to write mode*/
		I2C1->CR2&=~I2C_CR2_RD_WRN;
		/*Software end*/
		I2C1->CR2&=~I2C_CR2_AUTOEND;
		/*Generate start*/
		I2C1->CR2|=I2C_CR2_START;
		/*Wait until transfer is completed*/
		while(!(I2C1->ISR & I2C_ISR_TC)){
			/*Check if TX buffer is empty*/
			if(I2C1->ISR & I2C_ISR_TXE)
			{
				/*send memory address*/
				I2C1->TXDR = (memadd);
			}
		}
		/*Reset I2C*/
		I2C1->CR1 &=~I2C_CR1_PE;
		I2C1->CR1 |=I2C_CR1_PE;
		/*Enable DMA RX*/
		I2C1->CR1|=I2C_CR1_RXDMAEN;
		/*Set slave address*/
		I2C1->CR2=(slav_add<<I2C_CR2_SADD_Pos);
		/*Set mode to read operation*/
		I2C1->CR2|=I2C_CR2_RD_WRN;
		/*Set length to the required length*/
		I2C1->CR2|=((length)<<I2C_CR2_NBYTES_Pos);
		/*auto generate stop after transfer completed*/
		I2C1->CR2|=I2C_CR2_AUTOEND;

		DMA1_Channel7->CCR&=~DMA_CCR_EN;
		while(DMA1_Channel7->CCR &DMA_CCR_EN);

		DMA1_Channel7->CNDTR=length;
		DMA1_Channel7->CMAR=data;
		DMA1_Channel7->CCR|=DMA_CCR_EN;
		I2C1->CR2|=I2C_CR2_START;
		while(rx_done==0);
		rx_done=0;
	}

7. Code:

You may download the code from here:

8. Demo:

After uploading the code to the STM32L053, open serial terminal and set the baud to 9600 and you should get something similar to this:

Happy coding 🙂

Add Comment

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