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