Working with STM32 and I2C: Writing a single Byte

In the pervious guide (from here), we took a look at DS3231 hardware and we read the second register and display the seconds on the terminal through UART. In this guide, we shall see how to write a single byte to a specific register.

In this guide, we shall cover the following:

  • Write byte implementation
  • Demo

1. Write byte implementation:

Before we start, for more information about DS3231 and how to connect it and initialize the i2c please refer to this topic Working with STM32 and I2C: Reading single Byte

We start of by declaring the function name as following:

void i2c_write_byte(char saddr,char maddr, char *data)

The function takes three arguments. Which the are:

  • Slave address
  • memory address
  • data to be writing to the address

Then we declare a volatile variable which will help us to clear the status register 2 (SR2)

volatile int Temp;

Then we wait until the bus is free as following:

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

After the bus is free, we generate a start condition as following:

I2C1->CR1|=I2C_CR1_START;                 /*generate start*/

Then we wait until the start bit is set as following

while(!(I2C1->SR1&I2C_SR1_SB)){;}         /*wait until start bit is set*/

Then we send the slave address as following

I2C1->DR = saddr<< 1;                 	 /* Send slave address*/

Then we shall wait until the address bit as following:

while(!(I2C1->SR1&I2C_SR1_ADDR)){;}      /*wait until address flag is set*/

Now, we clear the status register as following:

Temp = I2C1->SR2; 											 /*clear SR2 by reading it */

After that, we wait until the data register is empty as following:

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

Then we send the memory address as following:

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

Then we wait again until the data register is empty

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

After that, we send the data as following:

I2C1->DR = *data; 	

And we wait until the byte transfer finished as following:

while (!(I2C1->SR1 & I2C_SR1_BTF));      /*wait until transfer finished*/

And finally, we generate stop condition

I2C1->CR1 |=I2C_CR1_STOP;								 /*Generate Stop*/

Hence, the full write byte is as following:

void i2c_write_byte(char saddr,char maddr, char *data)
	{
volatile int Temp;
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 bit is set*/
I2C1->DR = saddr<< 1;                 	 /* Send slave address*/
while(!(I2C1->SR1&I2C_SR1_ADDR)){;}      /*wait until address flag is set*/
Temp = I2C1->SR2; 											 /*clear SR2 by reading it */
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*/
I2C1->DR = *data; 	
while (!(I2C1->SR1 & I2C_SR1_BTF));      /*wait until transfer finished*/
I2C1->CR1 |=I2C_CR1_STOP;								 /*Generate Stop*/
}

In main function, we shall reset the value of seconds when reaches 5 as following:

if(seconds>5){UART_Write_String("reseting 0x0 register to 0\r\n");
			i2c_write_byte(0x68,0x00,0);
			UART_Write_String("Register 0x00 has been set to 0\r\n");

To download the code from here:

2. Demo

Happy coding 🙂

Add Comment

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