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