Working with STM32 and I2C: Writing Multiple Bytes

In the pervious guide, we took a look how to read multiple bytes using I2C (here). In this guide, we shall cover how to use I2C to write multiple bytes to I2C slave which in our case is DS3231. (for connect diagram from here and I2C initialize from here).

In this guide, we will cover the following:

  • I2C write multiple byte
  • I2C write multiple byte code
  • Code download
  • Demo

1. I2C write multiple byte:

To write multiple byte for a slave device, we start off by sending start condition then wait to start to be generated then send the slave address and wait for the address to set then sending the memory location (0x00 in our case) then the reset of the data as shown in figure below

With each byte transfer, we need to wait for Byte Transfer Finished (BTF in SR1 register).

2. I2C write multiple byte code:

We start off by declaring the function as following:

void i2c_WriteMulti(char saddr,char maddr,char *buffer, uint8_t length)

The function takes four arguments:

  • Slave address
  • Memory address
  • Pointer to the buffer that holds the data
  • Number of bytes to be transmitted

Inside the function, we start by waiting for the bus to be free as following:

while (I2C1->SR2 & I2C_SR2_BUSY);           //wait until bus not busy

Once it is free, a start condition generated and wait until start condition is generated

I2C1->CR1 |= I2C_CR1_START;                   //generate start
while (!(I2C1->SR1 & I2C_SR1_SB)){;}					//wait until start is generated

Then we declare a variable to clear the SR2

volatile int Temp;		

Then we send the slave address shifted to left by 1 bit and wait until the address is set

I2C1->DR = saddr<< 1;                 	 			// Send slave address
while (!(I2C1->SR1 & I2C_SR1_ADDR)){;}        //wait until address flag is set

After that we need to clear the SR2 register

Temp = I2C1->SR2; 						      //Clear SR2

Then we wait until the TX buffer is empty

while (!(I2C1->SR1 & I2C_SR1_TXE));           //Wait until Data register empty

Now, the memory address can be sent as following:

I2C1->DR = maddr;                      				// send memory address

Wait until TX buffer is empty

while (!(I2C1->SR1 & I2C_SR1_TXE));           //wait until data register empty

For sending n byte, a for loop is used for the purpose

for (uint8_t i=0;i<length;i++)

The loop shall loop for the number bytes

inside the loop we send data[i] and wait until the byte transfer is set.

I2C1->DR=buffer[i]; 													//filling buffer with command or data
while (!(I2C1->SR1 & I2C_SR1_BTF));

After that we close the communication by generating a stop condition

I2C1->CR1 |= I2C_CR1_STOP;										//wait until transfer finished

Hence the code shall be like this

void i2c_WriteMulti(char saddr,char maddr,char *buffer, uint8_t length)
{	
while (I2C1->SR2 & I2C_SR2_BUSY);           //wait until bus not busy
I2C1->CR1 |= I2C_CR1_START;                   //generate start
while (!(I2C1->SR1 & I2C_SR1_SB)){;}					//wait until start is generated
volatile int Temp;														
I2C1->DR = saddr<< 1;                 	 			// Send slave address
while (!(I2C1->SR1 & I2C_SR1_ADDR)){;}        //wait until address flag is set
Temp = I2C1->SR2; 						      //Clear SR2
while (!(I2C1->SR1 & I2C_SR1_TXE));           //Wait until Data register empty
I2C1->DR = maddr;                      				// send memory address
while (!(I2C1->SR1 & I2C_SR1_TXE));           //wait until data register empty
//sending the data
for (uint8_t i=0;i<length;i++)
 { 
 I2C1->DR=buffer[i]; 													//filling buffer with command or data
	while (!(I2C1->SR1 & I2C_SR1_BTF));
 }	
                             
I2C1->CR1 |= I2C_CR1_STOP;										//wait until transfer finished

}

In main function, we shall randomize the minutes and hours each 5 seconds as following:

uint8_t data_s[3]={0,rand()%20,rand()%10}; //seconds,minutes,hours
i2c_WriteMulti(0x68,0x00,(char *)data_s,3);

3. Code Download

You may download the entire code from here

4. Demo:

After you compile the code, burn it to your mcu and open serial terminal with baud rate of 115200, you should get this

Each 5 seconds, the minutes and hours is randomized using our function

Happy coding 🙂

Add Comment

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