//this is a single file containing all three drivers in single one . Just edit the diagram and add another peripheral to see the behavior of rtc and mpu6050
//********************************LCD INTERFACING***********************************
#define RCC_base_addr 0x40021000
#define APB1_offset 0x1C
#define APB2_offset 0x18
#define PORTB_base_addr 0x40010C00
#define GPIOB_CRL_offset 0x00
#define I2C_base_addr 0x40005400
#define I2C_CR1 0x00
#define I2C_CR2 0x04
#define I2C_SR1 0x14
#define I2C_SR2 0x18
#define I2C_CCR 0x1C
#define I2C_TRISE 0x20
#define I2C_DR 0x10
// void I2C_START(void);
int I2C_Start(uint8_t address, uint8_t direction) ;
void config_I2C(void);
void I2C_Write(uint8_t data);
void I2C_Stop(void);
void init_lcd(void);
void out_4bit_data(char out_data, uint8_t rs);
void write_data(char wr_data);
void write_string(char *ptr);
void set_cursor_second_row(void);
volatile uint32_t * const apb2_reg = (volatile uint32_t*)(RCC_base_addr + APB2_offset);
volatile uint32_t * const apb1_reg = (volatile uint32_t*)(RCC_base_addr + APB1_offset);
volatile uint32_t * const mode_reg = (volatile uint32_t*)(PORTB_base_addr + GPIOB_CRL_offset);
volatile uint32_t * const i2c_cr1 = (volatile uint32_t*)(I2C_base_addr + I2C_CR1);
volatile uint32_t * const i2c_cr2 = (volatile uint32_t*)(I2C_base_addr + I2C_CR2);
volatile uint32_t * const i2c_ccr = (volatile uint32_t*)(I2C_base_addr + I2C_CCR);
volatile uint32_t * const i2c_trise = (volatile uint32_t*)(I2C_base_addr + I2C_TRISE);
volatile uint32_t * const i2c_dr = (volatile uint32_t*)(I2C_base_addr + I2C_DR);
volatile uint32_t * const i2c_sr1 = (volatile uint32_t*)(I2C_base_addr + I2C_SR1);
volatile uint32_t * const i2c_sr2 = (volatile uint32_t*)(I2C_base_addr + I2C_SR2);
void setup() {
init_lcd();
write_string("yeah 4bit mode worked");
}
void config_I2C(void) {
*apb2_reg |= 1 << 3; //enabling clock for portB
*apb1_reg |= 1 << 21; //enabling clock for i2c1
*mode_reg &= ~(15 << 24); // clear the four config bits of port b6
*mode_reg &= ~(15 << 28); //clear the bits for port b7
*mode_reg |= (15 << 24); //1111 to b6
*mode_reg |= (15 << 28); // 1111 to b7
*i2c_cr2 = (36 << 0); //apb1 operating freq: 36MHZ
*i2c_ccr = 180; //ccr value: how to toggle scl
*i2c_trise = 37;
*i2c_cr1 |= (1 << 0); //peripheral enable
}
// void I2C_START() {
// *i2c_cr1 |= (1 << 8); //set start bit
// while (!(*i2c_sr1 & (1 << 0))); // 2. Wait for SB (EV5)
// *i2c_dr = (0x27 << 1); //address + write bit(0)
// while (!(*i2c_sr1 & (1 << 1))); // 4. Wait for ADDR (EV6)
// uint32_t temp = *i2c_sr1; // Read SR1
// temp = *i2c_sr2; //Read SR2
// (void)temp; //prevent unused variable warning
// }
int I2C_Start(uint8_t address, uint8_t direction) {
*i2c_cr1 |= (1 << 8); //set start bit
while (!(*i2c_sr1 & (1 << 0))); // 2. Wait for SB (EV5)
*i2c_dr = (address << 1) | direction;
while (!(*i2c_sr1 & (1 << 1))); //addr bit set waitn(indicates end of address transmission)
// For 7-bit addressing, the bit is set after the ACK of the byte
// ADDR is not set after a NACK reception
uint32_t temp = *i2c_sr1; // Read SR1
temp = *i2c_sr2; //Read SR2
(void)temp;
return 0; // Success
}
void I2C_Write(uint8_t data) {
while (!(*i2c_sr1 & (1 << 7))); // Wait for TxE (Transmit Empty)
*i2c_dr = data;
while (!(*i2c_sr1 & (1 << 2))); // Wait for BTF (Byte Transfer Finished)
}
void I2C_Stop(void) {
*i2c_cr1 |= (1 << 9); // Generate STOP
}
//********************
void init_lcd(void){
config_I2C();
out_4bit_data(0x02,0); //function set: 4bit ,2line , 5*8
out_4bit_data(0x28,0); //function set: 4bit ,2line , 5*8
out_4bit_data(0x0F,0); //display on ,cursor blinking
out_4bit_data(0x01,0); //clear display
out_4bit_data(0x06,0); //auto increment after writing 1 char; entry mode
}
// rs = 0 for command, rs = 1 for data
void out_4bit_data(char out_data, uint8_t rs){
while (*i2c_sr2 & (1 << 1));
I2C_Start(0x27,0); // Open bus for this specific transaction
uint8_t upper_nibble = (out_data & 0xF0);
uint8_t lower_nibble = ((out_data << 4) & 0xF0);
uint8_t ctrl = (1 << 3) | rs; // Backlight ON, RS bit set
I2C_Write(upper_nibble | ctrl | (1 << 2));;
I2C_Write(upper_nibble | ctrl);
I2C_Write(lower_nibble | ctrl | (1 << 2));
I2C_Write(lower_nibble | ctrl);
I2C_Stop();
// If it was the 'Clear' command (0x01), wait longer
}
void write_string(char *ptr) {
volatile long count=0;
while (*ptr != 0) {
if(count==16){
set_cursor_second_row();
}
write_data(*ptr); // Write character to the LCD
ptr++;
count++;
}
}
void write_data(char wr_data){
//last 4 bits
out_4bit_data(wr_data,1);
}
void set_cursor_second_row(void) {
out_4bit_data(0xC0,0); // Address of the second row in 16x2 LCD(DDRAM)
}
void loop(){}
//********************************MPU6050 INTERFACING********************
// #include<serialPort.h>
// #define RCC_base_addr 0x40021000
// #define APB1_offset 0x1C
// #define APB2_offset 0x18
// #define PORTB_base_addr 0x40010C00
// #define GPIOB_CRL_offset 0x00
// #define I2C_base_addr 0x40005400
// #define I2C_CR1 0x00
// #define I2C_CR2 0x04
// #define I2C_SR1 0x14
// #define I2C_SR2 0x18
// #define I2C_CCR 0x1C
// #define I2C_TRISE 0x20
// #define I2C_DR 0x10
// typedef struct{
// int16_t Accel_X, Accel_Y, Accel_Z;
// int16_t Temperature;
// int16_t Gyro_X, Gyro_Y,Gyro_Z;
// }mpu6050;
// void config_I2C();
// void I2C_START();
// void I2C_STOP();
// void I2C_Write(uint8_t data);
// void I2C_receive(int16_t bytes[]);
// mpu6050 process_mpu_data();
// volatile uint32_t *const abp1 =(volatile uint32_t*) (RCC_base_addr + APB1_offset);
// volatile uint32_t *const portB = (volatile uint32_t*) (PORTB_base_addr + GPIOB_CRL_offset);
// volatile uint32_t * const i2c_cr1 = (volatile uint32_t*)(I2C_base_addr + I2C_CR1);
// volatile uint32_t * const i2c_cr2 = (volatile uint32_t*)(I2C_base_addr + I2C_CR2);
// volatile uint32_t * const i2c_ccr = (volatile uint32_t*)(I2C_base_addr + I2C_CCR);
// volatile uint32_t * const i2c_trise = (volatile uint32_t*)(I2C_base_addr + I2C_TRISE);
// volatile uint32_t * const i2c_dr = (volatile uint32_t*)(I2C_base_addr + I2C_DR);
// volatile uint32_t * const i2c_sr1 = (volatile uint32_t*)(I2C_base_addr + I2C_SR1);
// volatile uint32_t * const i2c_sr2 = (volatile uint32_t*)(I2C_base_addr + I2C_SR2);
// mpu6050 data;
// void setup() {
// config_UART();
// config_I2C();
// // // Wake up MPU6050
// printUART("HII lets read data from mpu6050");
// UART_SendNewLine();
// I2C_START(0x68, 0);
// I2C_Write(0x6B); // PWR_MGMT_1 register
// I2C_Write(0x00); // Set to 0 to wake it up
// I2C_Stop();
// // for(volatile int i=0; i<50000; i++);
// // After I2C_Stop() or before I2C_Start()
// while (*i2c_sr2 & (1 << 1)); // Wait until the BUSY bit is cleared by hardware
// }
// void config_I2C() {
// *abp1 |= (1 << 21); //enabling clk for i2c1
// *abp2 |= (1 << 3); //port B enable
// *portB &= ~(15 << 24);
// *portB &= ~(15 << 28);
// *portB |= (15 << 24); //alternate function open drain
// *portB |= (15 << 28);
// *i2c_cr2 = (36 << 0); //apb1 operating freq: 36MHZ
// *i2c_ccr = 180; //ccr value: how to toggle scl
// *i2c_trise = 37;
// *i2c_cr1 |= (1 << 0); //peripheral enable
// }
// void I2C_START(volatile uint8_t address, int r_w) {
// *i2c_cr1 |= (1 << 8); //set start bit
// int timeout=0;
// while (!(*i2c_sr1 & (1 << 0))); // 2. Wait for SB (EV5)
// *i2c_dr = (address << 1) | r_w; // //Shifting 0x68(mpu6050 addr) left and adding 1 gives you 0xD1.
// while (!(*i2c_sr1 & (1 << 1))); //addr bit wait
// uint32_t temp = *i2c_sr1; // Read SR1
// temp = *i2c_sr2; //Read SR2
// }
// mpu6050 process_mpu_data(){
// int16_t raw[14] ;
// I2C_receive(raw);
// mpu6050 sensor;
// // Accelerometer (0x3B to 0x40)
// sensor.Accel_X = (int16_t)(raw[0] << 8 | raw[1]);
// sensor.Accel_Y = (int16_t)(raw[2] << 8 | raw[3]);
// sensor.Accel_Z = (int16_t)(raw[4] << 8 | raw[5]);
// // Temperature (0x41 to 0x42)
// sensor.Temperature = (int16_t)(raw[6] << 8 | raw[7]);
// // Gyroscope (0x43 to 0x48)
// sensor.Gyro_X = (int16_t)(raw[8] << 8 | raw[9]);
// sensor.Gyro_Y = (int16_t)(raw[10] << 8 | raw[11]);
// sensor.Gyro_Z = (int16_t)(raw[12] << 8 | raw[13]);
// return sensor;
// }
//data in millis (to avoid float)
// typedef struct {
// int32_t Accel_X_mG, Accel_Y_mG, Accel_Z_mG;
// int32_t Temp_mC;
// int32_t Gyro_X_mDPS, Gyro_Y_mDPS, Gyro_Z_mDPS;
// } mpu6050_processed_t;
// mpu6050_processed_t process_mpu_data(uint8_t *raw_bytes) {
// mpu6050_processed_t sensor;
// int16_t raw_temp;
// // --- Accelerometer Conversion (mG) ---
// // Combine bytes into signed 16-bit, then scale to milli-G
// raw_temp = (int16_t)(raw_bytes[0] << 8 | raw_bytes[1]);
// sensor.Accel_X_mG = ((int32_t)raw_temp * 1000) / 16384;
// raw_temp = (int16_t)(raw_bytes[2] << 8 | raw_bytes[3]);
// sensor.Accel_Y_mG = ((int32_t)raw_temp * 1000) / 16384;
// raw_temp = (int16_t)(raw_bytes[4] << 8 | raw_bytes[5]);
// sensor.Accel_Z_mG = ((int32_t)raw_temp * 1000) / 16384;
// // --- Temperature Conversion (milli-Celsius) ---
// // Formula: (Raw / 340 + 36.53) * 1000 => (Raw * 100 / 34) + 36530
// raw_temp = (int16_t)(raw_bytes[6] << 8 | raw_bytes[7]);
// sensor.Temp_mC = (((int32_t)raw_temp * 1000) / 340) + 36530;
// // --- Gyroscope Conversion (milli-DPS) ---
// raw_temp = (int16_t)(raw_bytes[8] << 8 | raw_bytes[9]);
// sensor.Gyro_X_mDPS = ((int32_t)raw_temp * 1000) / 131;
// raw_temp = (int16_t)(raw_bytes[10] << 8 | raw_bytes[11]);
// sensor.Gyro_Y_mDPS = ((int32_t)raw_temp * 1000) / 131;
// raw_temp = (int16_t)(raw_bytes[12] << 8 | raw_bytes[13]);
// sensor.Gyro_Z_mDPS = ((int32_t)raw_temp * 1000) / 131;
// return sensor;
// }
// void I2C_receive(int16_t bytes[]) {
// // 1. Point to the first register (Accel X High)
// I2C_START(0x68, 0);
// I2C_Write(0x3B);
// while (!(*i2c_sr1 & (1 << 2))); // Wait for BTF
// I2C_Stop();
// // After I2C_Stop() or before I2C_Start()
// while (*i2c_sr2 & (1 << 1)); // Wait until the BUSY bit is cleared by hardware
// // --- CRITICAL FIX: ENABLE ACK BEFORE START ---
// I2C_START(0x68, 1); // Start in Read Mode
// *i2c_cr1 |= (1 << 10);
// // printUART(" Restart Done, Waiting for Data... ");
// for(int i = 0; i < 14; i++) {
// // Prepare NACK for the last byte
// if (i == 13) {
// *i2c_cr1 &= ~(1 << 10); // Clear ACK (NACK)
// *i2c_cr1 |= (1 << 9); // Set STOP
// }
// // Wait for RxNE
// int timeout = 0;
// while (!(*i2c_sr1 & (1 << 6))) {
// if(++timeout > 100000) {
// printUART("!Data Timeout at byte "); //only used for debugging
// UART_SendInt(i);
// return;
// }
// }
// bytes[i] = *i2c_dr; // Read clears RxNE
// // // Re-enable ACK for all bytes except the last one
// // if (i < 12) {
// // *i2c_cr1 |= (1 << 10);
// // } //Technically, you don't need to re-enable it every time.
// //Once the ACK bit is set to 1, it stays 1 until you manually clear it.
// //Most developers set it once right after clearing the ADDR flag and only clear it when they reach the N-1 byte.
// }
// }
// void I2C_Stop(void) {
// *i2c_cr1 |= (1 << 9); // Generate STOP
// }
// //f
// void I2C_Write(uint8_t data) {
// while (!(*i2c_sr1 & (1 << 7))); // Wait for TxE (Transmit Empty) (set by hardware of receiving acknowledgement)
// *i2c_dr = data;
// while (!(*i2c_sr1 & (1 << 2))){
// if (*i2c_sr1 & (1 << 10)) { // Check AF (Acknowledge Failure)
// *i2c_sr1 &= ~(1 << 10); // Clear AF bit
// printUART("write I2C NACK Error!\n");
// } // Wait for BTF (Byte Transfer Finished)
// }
// }
// void loop(){
// data = process_mpu_data();
// printUART(" temperature : ");
// UART_SendInt((data.Temperature)/340 + 36.53);
// printUART(" accelX : ");
// UART_SendInt(data.Accel_X);
// printUART(" gyroX : ");
// UART_SendInt(data.Gyro_X);
// UART_SendNewLine();
// delay(2000);
// }
//*************** RTC programming*************************************
//remember mpu6050 also has same address as of rtc, you have stuck for day just because of this mistake u sucka
// #include <serialPort.h>
// #define RCC_base_addr 0x40021000
// #define PORTB_base_addr 0x40010C00
// #define APB1_offset 0x1C
// #define APB2_offset 0x18
// #define GPIOB_CRL_offset 0x00
// #define I2C_base_addr 0x40005400
// #define I2C_CR1 0x00
// #define I2C_CR2 0x04
// #define I2C_SR1 0x14
// #define I2C_SR2 0x18
// #define I2C_CCR 0x1C
// #define I2C_TRISE 0x20
// #define I2C_DR 0x10
// #define rtc_base_addr 0x68
// typedef struct{
// uint8_t seconds ;
// uint8_t minutes;
// uint8_t hours;
// char *meridiem;
// char *day;
// uint8_t date; // as year would greater than 255
// uint8_t month;
// uint16_t year;
// }RTC_time;
// void config_I2C();
// void I2C_START();
// void I2C_Stop(void);
// void RTC_SetTime(uint8_t sec, uint8_t minutes, uint8_t hour,uint8_t day,uint8_t date,uint8_t month,uint8_t year) ;
// uint8_t bcdToDec(uint8_t val);
// void RTC_ReadTime(uint8_t data[]);
// uint8_t decToBcd(int val) ;
// void I2C_Write(int data);
// RTC_time process_rtc_data();
// volatile uint32_t *const abp1 =(volatile uint32_t*) (RCC_base_addr + APB1_offset);
// // volatile uint32_t *const abp2 =(volatile uint32_t*) (RCC_base_addr + APB2_offset);
// volatile uint32_t *const portB = (volatile uint32_t*) (PORTB_base_addr + GPIOB_CRL_offset);
// volatile uint32_t * const i2c_cr1 = (volatile uint32_t*)(I2C_base_addr + I2C_CR1);
// volatile uint32_t * const i2c_cr2 = (volatile uint32_t*)(I2C_base_addr + I2C_CR2);
// volatile uint32_t * const i2c_ccr = (volatile uint32_t*)(I2C_base_addr + I2C_CCR);
// volatile uint32_t * const i2c_trise = (volatile uint32_t*)(I2C_base_addr + I2C_TRISE);
// volatile uint32_t * const i2c_dr = (volatile uint32_t*)(I2C_base_addr + I2C_DR);
// volatile uint32_t * const i2c_sr1 = (volatile uint32_t*)(I2C_base_addr + I2C_SR1);
// volatile uint32_t * const i2c_sr2 = (volatile uint32_t*)(I2C_base_addr + I2C_SR2);
// enum Day {
// MONDAY = 1,
// TUESDAY,
// WEDNESDAY,
// THURSDAY,
// FRIDAY,
// SATURDAY,
// SUNDAY
// };
// RTC_time sensor_data;
// void setup() {
// config_UART();
// config_I2C();
// printUART("hello rtc driver ");
// UART_SendNewLine();
// // config_I2C();
// RTC_SetTime(0,30,02,6,13,2,26);
// for(volatile int i=0; i<50000; i++); //delay required
// // sensor_data=process_rtc_data();
// // UART_SendInt(sensor_data.date);
// // UART_SendInt(sensor_data.month);
// }
// void config_I2C(){
// *abp1 |= (1 << 21); //enabling clk for i2c1
// *abp2 |= (1 << 3); //port B enable
// *portB &= ~(15 << 24);
// *portB &= ~(15 << 28);
// *portB |= (15 << 24);
// *portB |= (15 << 28);
// *i2c_cr2 = (36 << 0); //apb1 operating freq: 36MHZ
// *i2c_ccr = 180; //ccr value: how to toggle scl
// *i2c_trise = 37;
// *i2c_cr1 |= (1 << 0); //peripheral enable
// }
// void I2C_START(volatile uint8_t address, int r_w){
// *i2c_cr1 |= (1 << 8); //set start bit
// while (!(*i2c_sr1 & (1 << 0))); // 2. Wait for SB (EV5)
// *i2c_dr = (address << 1) | r_w;
// while (!(*i2c_sr1 & (1 << 1))); //addr bit set waitn(indicates end of address transmission)
// // For 7-bit addressing, the bit is set after the ACK of the byte
// // ADDR is not set after a NACK reception
// uint32_t temp = *i2c_sr1; // Read SR1
// temp = *i2c_sr2; //Read SR2
// }
// void I2C_Write(int data){
// while (!(*i2c_sr1 & (1 << 7))); // Wait for TxE (Transmit Empty) (set by hardware on receiving acknowledgement)
// *i2c_dr = data;
// while (!(*i2c_sr1 & (1 << 2))); //check for BTF flag
// // printUART("in write func");
// }
// void I2C_Stop(void) {
// *i2c_cr1 |= (1 << 9); // Generate STOP
// }
// void RTC_SetTime(uint8_t sec, uint8_t minutes, uint8_t hour,uint8_t day,uint8_t date,uint8_t month,uint8_t year) {
// I2C_START(0x68, 0);
// I2C_Write(0x00); // Start at Seconds register
// I2C_Write(decToBcd(sec)); // Bit 7 is 0, so clock starts!
// I2C_Write(decToBcd(minutes));
// I2C_Write(decToBcd(hour)); //12 hr mode selected
// I2C_Write(decToBcd(day));
// I2C_Write(decToBcd(date));
// I2C_Write(decToBcd(month));
// I2C_Write(decToBcd(year));
// I2C_Stop();
// }
// void RTC_ReadTime(uint8_t data[]){
// I2C_START(0x68, 0);
// I2C_Write(0x00); //point of first register
// I2C_Stop();
// while (*i2c_sr2 & (1 << 1)); // Wait until the BUSY bit is cleared by hardware
// *i2c_cr1 |= (1 << 10); //ENABLE ACK BEFORE ReSTART to start reading ---
// I2C_START(0x68, 1); // Start in Read Mode
// // for(int i = 0; i <7; i++){
// // // Prepare NACK for the last byte
// // if (i == 6) {
// // *i2c_cr1 &= ~(1 << 10); // Clear ACK (NACK)
// // *i2c_cr1 |= (1 << 9); // Set STOP
// // }
// // while (!(*i2c_sr1 & (1 << 6))); //wait for RxNE bit
// // data[i] = *i2c_dr; // Read clears RxNE
// // }
// for(int i = 0; i < 6; i++) {
// while (!(*i2c_sr1 & (1 << 6))); // Wait for RxNE
// data[i] = *i2c_dr;
// *i2c_cr1 |= (1 << 10); // Ensure ACK is still set
// }
// // 6. The "AVR NACK" equivalent for the 7th byte
// *i2c_cr1 &= ~(1 << 10); // Set NACK (Match: TWCR = (1 << TWINT) | (1 << TWEN))
// *i2c_cr1 |= (1 << 9); // Set STOP
// while (!(*i2c_sr1 & (1 << 6))); // Wait for last byte
// data[6] = *i2c_dr;
// }
// RTC_time process_rtc_data(){
// uint8_t raw[7];
// RTC_ReadTime(raw);
// RTC_time sensor;
// sensor.seconds = bcdToDec(raw[0]);
// sensor.minutes = bcdToDec(raw[1]);
// uint8_t hourData = (raw[2]);
// sensor.hours = bcdToDec(hourData & 0x1F);
// if(hourData & (1<<5)){
// sensor.meridiem = "PM";
// }
// else{
// sensor.meridiem = "AM";
// }
// // UART_SendInt(sensor.hours);
// int dayNumber = bcdToDec(raw[3]);
// switch(dayNumber){
// case MONDAY: sensor.day = "Monday"; break;
// case TUESDAY: sensor.day = "Tuesday"; break;
// case WEDNESDAY: sensor.day = "Wednesday"; break;
// case THURSDAY: sensor.day = "Thursday"; break;
// case FRIDAY: sensor.day = "Friday"; break;
// case SATURDAY: sensor.day = "Saturday"; break;
// case SUNDAY: sensor.day = "Sunday"; break;
// default: sensor.day = "Invalid day"; break; // Handle invalid input (not 1-7)
// }
// sensor.date = bcdToDec(raw[4]);
// sensor.month = bcdToDec(raw[5]);
// uint8_t year = bcdToDec(raw[6]);
// sensor.year= (uint16_t) (year+2000);
// return sensor;
// }
// uint8_t decToBcd(int val) {
// return (uint8_t)( (val/10 << 4) | (val % 10) );
// }
// uint8_t bcdToDec(uint8_t val) {
// return (uint8_t)( (val/16*10) + (val%16) );
// }
// // void Test_RTC_RAM() {
// // // 1. WRITE PHASE
// // printUART("Writing 0xAA to RAM...");
// // I2C_START(0x68, 0);
// // I2C_Write(0x08); // Target DS1307 RAM address 0x08
// // I2C_Write(0xAA); // Write the test pattern
// // I2C_Stop();
// // // Tiny delay to let the RTC internalize the write
// // for(volatile int i=0; i<10000; i++);
// // // 2. READ PHASE
// // I2C_START(0x68, 1);
// // I2C_Write(0x08); // Set pointer back to 0x08
// // while (!(*i2c_sr1 & (1 << 2))); // Wait for Byte Transfer Finished
// // // Toggling PE bit to clear the Master State (The fix that worked for you)
// // *i2c_cr1 &= ~(1 << 0);
// // for(volatile int i=0; i<100; i++);
// // *i2c_cr1 |= (1 << 0);
// // *i2c_cr1 |= (1 << 10); // Re-enable ACK
// // // Start Read
// // *i2c_cr1 |= (1 << 8);
// // while (!(*i2c_sr1 & (1 << 0))); // Wait for SB
// // *i2c_dr = (0x68 << 1) | 1; // SLA+R
// // while (!(*i2c_sr1 & (1 << 1))); // Wait for ADDR
// // // Clear ADDR sequence
// // uint32_t temp = *i2c_sr1;
// // temp = *i2c_sr2;
// // (void)temp;
// // // We only want 1 byte, so NACK it immediately
// // *i2c_cr1 &= ~(1 << 10); // NACK
// // *i2c_cr1 |= (1 << 9); // STOP
// // while (!(*i2c_sr1 & (1 << 6))); // Wait for RxNE
// // uint8_t result = *i2c_dr;
// // printUART(" Read Result: 0x");
// // UART_SendInt(result);
// // UART_SendNewLine();
// // if(result == 0xAA) {
// // printUART("SUCCESS: I2C Write/Read is perfect!\n");
// // } else {
// // printUART("FAIL: Still getting 0 or junk.\n");
// // }
// // }
// void loop(){
// sensor_data=process_rtc_data();
// printUART(" Time : ");
// UART_SendInt(sensor_data.hours);
// printUART(":");
// UART_SendInt(sensor_data.minutes);
// printUART(":");
// UART_SendInt(sensor_data.seconds);
// printUART(" ");
// printUART(sensor_data.day);
// printUART(" Date: ");
// UART_SendInt(sensor_data.date);
// printUART(":");
// UART_SendInt(sensor_data.month);
// printUART(":");
// UART_SendInt(sensor_data.year);
// UART_SendNewLine();
// delay(2000);
// }