Working with STM32 and I2C: Reading Multiple Bytes

In the pervious guid (here), we took a look how to write/read single byte using I2C and the slave device is DS3231

In this guide, we shall see how to read multiple byte of DS3231 which they are seconds, minutes and hours and display them on the serial monitor.

In this guide, we will cover the following:

  • I2C read multiple byte
  • I2C read multiple byte code
  • Code Download
  • Demo

1. I2C Read Multiple Byte:

In order to read multiple byte, first we send the start condition, then followed by the slave address with write bit then the memory location in our case ( seconds memory location 0x00). After that a repeat start must be generated and send slave address with read bit after that we enable acknowledge(ACK). We keep reading (in out case 3) until one byte remains then we disable acknowledge (NAK). The figure below shows the reading sequence.

2. I2C Read Multiple Byte Code:

We start of by declaring the function name as following:

void i2c_ReadMulti(char saddr,char maddr, int n, char* data){

it takes three arguments

  • slave address
  • starting address to read from
  • number of byte to be read
  • buffer to store the data

Inside the function we declare temp to clear flags

volatile int temp;

we wait until the bus is free

while (I2C1->SR2 & I2C_SR2_BUSY){;}

Send start condition and wait until start condition is generated

	I2C1->CR1|=I2C_CR1_START;
	while(!(I2C1->SR1 & I2C_SR1_SB)){;}

Send the slave address with write operation and wait until address is set

I2C1->DR=saddr<<1;
	while(!(I2C1->SR1 & I2C_SR1_ADDR)){;}

Then clear the status register

temp=I2C1->SR2;

Then wait until transmit bit is set

while(!(I2C1->SR1&I2C_SR1_TXE)){;}

Now we send memory location

I2C1->DR = maddr;

Then we wait until transmit bit is set

while(!(I2C1->SR1&I2C_SR1_TXE)){;}

After that we regenerate start condition and wait until the start condition is generated

I2C1->CR1|=I2C_CR1_START;
while(!(I2C1->SR1 & I2C_SR1_SB)){;}

Now, we send slave address with read bit and wait until the address is set

I2C1->DR=saddr<<1|1;
while(!(I2C1->SR1 & I2C_SR1_ADDR)){;}

we clear the status register

temp=I2C1->SR2;

Then we enable acknowledge

I2C1->CR1|=I2C_CR1_ACK;

After that we start reading

we start of with while loop

while(n>0U)
		{

Now we have a little bit of machine state

In case we have only one byte left, we must do the following:

  • Disable acknowledge
  • Generate stop
  • Wait until receive bit is set
  • Store the last received byte to the buffer
  • Break the while loop

In case more than one byte left

  • Wait for receive bit to be set
  • store the data in the buffer
  • increment the buffer counter
  • decrement the counter
if(n==1U)
				{
				I2C1->CR1&=~I2C_CR1_ACK;
					I2C1->CR1|=I2C_CR1_STOP;
					while(!(I2C1->SR1&I2C_SR1_RXNE)){;}
					*data++=I2C1->DR;
						break;
				}
			else
					{
					
					while(!(I2C1->SR1&I2C_SR1_RXNE)){;}
						(*data++)=I2C1->DR;
							n--;
					
					}	
}//for the while loop

Hence the code shall be like this:

void i2c_ReadMulti(char saddr,char maddr, int n, char* data)
{
	volatile int temp;
	while (I2C1->SR2 & I2C_SR2_BUSY){;}
	I2C1->CR1|=I2C_CR1_START;
	while(!(I2C1->SR1 & I2C_SR1_SB)){;}
	I2C1->DR=saddr<<1;
	while(!(I2C1->SR1 & I2C_SR1_ADDR)){;}
	temp=I2C1->SR2;
	while(!(I2C1->SR1&I2C_SR1_TXE)){;}
	I2C1->DR = maddr;
	while(!(I2C1->SR1&I2C_SR1_TXE)){;}
	I2C1->CR1|=I2C_CR1_START;
	while(!(I2C1->SR1 & I2C_SR1_SB)){;}
	I2C1->DR=saddr<<1|1;
	while(!(I2C1->SR1 & I2C_SR1_ADDR)){;}
	temp=I2C1->SR2;
	I2C1->CR1|=I2C_CR1_ACK;
	while(n>0U)
		{
		if(n==1U)
				{
				I2C1->CR1&=~I2C_CR1_ACK;
					I2C1->CR1|=I2C_CR1_STOP;
					while(!(I2C1->SR1&I2C_SR1_RXNE)){;}
					*data++=I2C1->DR;
						break;
				}
			else
					{
					
					while(!(I2C1->SR1&I2C_SR1_RXNE)){;}
						(*data++)=I2C1->DR;
							n--;
					
					}	
				
			
		}	
		
}

3. Code Download

You can download the code from here

4. Demo

After you compile and upload the code, open serial monitor program and set the baudrate at 115200 and you should see the serial is printing the time

Happy coding 🙂

Add Comment

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