2016-03-22 09:54:25 +01:00
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*
*/
2016-05-05 23:47:50 +02:00
/** library to communicate with the Maxim DS1307 I2C RTC IC (code)
2016-03-24 10:37:42 +01:00
* @ file rtc_ds1307 . c
2016-03-22 11:16:47 +01:00
* @ author King Kévin < kingkevin @ cuvoodoo . info >
* @ date 2016
2016-04-04 19:15:44 +02:00
* @ note user RAM is not handled
2016-04-30 12:03:34 +02:00
* @ note peripherals used : I2C @ ref rtc_ds1307_i2c , GPIO & timer @ ref rtc_ds1307_square_wave_timer
2016-03-22 11:16:47 +01:00
*/
2016-03-22 09:54:25 +01:00
/* standard libraries */
# include <stdint.h> // standard integer types
# include <stdio.h> // standard I/O facilities
# include <stdlib.h> // general utilities
/* STM32 (including CM3) libraries */
# include <libopencm3/stm32/rcc.h> // real-time control clock library
# include <libopencm3/stm32/gpio.h> // general purpose input output library
# include <libopencm3/stm32/i2c.h> // I2C library
# include <libopencm3/cm3/nvic.h> // interrupt handler
# include <libopencmsis/core_cm3.h> // Cortex M3 utilities
2016-04-30 12:03:34 +02:00
# include <libopencm3/stm32/timer.h> // timer utilities
2016-03-22 09:54:25 +01:00
2016-03-22 11:16:47 +01:00
# include "global.h" // global utilities
2016-03-22 09:54:25 +01:00
# include "rtc_ds1307.h" // RTC header and definitions
2016-05-01 20:29:03 +02:00
# if defined(RTC_DS1307_SQUARE_WAVE_TICKS)
volatile uint32_t rtc_ds1307_ticks = 0 ;
volatile bool rtc_ds1307_tick_flag = false ;
2016-03-25 18:00:44 +01:00
# endif
2016-05-01 20:29:03 +02:00
void rtc_ds1307_setup ( void )
2016-03-22 09:54:25 +01:00
{
2016-04-30 12:03:34 +02:00
// configure I2C peripheral (see RM008 26.3.3, I2C master)
2016-05-01 20:29:03 +02:00
rcc_periph_clock_enable ( RTC_DS1307_I2C_PORT_RCC ) ; // enable clock for I2C I/O peripheral
gpio_set_mode ( RTC_DS1307_I2C_PORT , GPIO_MODE_OUTPUT_10_MHZ , GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN , RTC_DS1307_I2C_PIN_SDA | RTC_DS1307_I2C_PIN_SCL ) ; // setup I2C I/O pins
rcc_periph_clock_enable ( RCC_AFIO ) ; // enable clock for alternate function
rcc_periph_clock_enable ( RTC_DS1307_I2C_RCC ) ; // enable clock for I2C peripheral
i2c_reset ( RTC_DS1307_I2C ) ; // reset configuration
i2c_peripheral_disable ( RTC_DS1307_I2C ) ; // I2C needs to be disable to be configured
i2c_set_clock_frequency ( RTC_DS1307_I2C , rcc_apb1_frequency / 1E6 ) ; // configure the peripheral clock to the APB1 freq (where it is connected to)
i2c_set_standard_mode ( RTC_DS1307_I2C ) ; // the DS1307 has a maximum I2C SCL freq if 100 kHz (corresponding to the standard mode)
i2c_set_ccr ( RTC_DS1307_I2C , rcc_apb1_frequency / ( 100E3 * 2 ) ) ; // set Thigh/Tlow to generate frequency of 100 kHz
i2c_set_trise ( RTC_DS1307_I2C , rcc_apb1_frequency / 1E6 ) ; // max rise time for 100 kHz is 1000 ns (~1 MHz)
i2c_peripheral_enable ( RTC_DS1307_I2C ) ; // enable I2C after configuration completed
# if defined(RTC_DS1307_SQUARE_WAVE_TICKS)
2016-04-30 12:03:34 +02:00
// setup timer to generate tick from square wave output
2016-05-01 20:29:03 +02:00
rcc_periph_clock_enable ( RTC_DS1307_SQUARE_WAVE_GPIO_RCC ) ; // enable clock for GPIO peripheral
gpio_set_mode ( RTC_DS1307_SQUARE_WAVE_GPIO_PORT , GPIO_MODE_INPUT , GPIO_CNF_INPUT_PULL_UPDOWN , RTC_DS1307_SQUARE_WAVE_GPIO_PIN ) ; // set pin as input
gpio_set ( RTC_DS1307_SQUARE_WAVE_GPIO_PORT , RTC_DS1307_SQUARE_WAVE_GPIO_PIN ) ; // enable pull-up
rcc_periph_clock_enable ( RTC_DS1307_SQUARE_WAVE_TIMER_RCC ) ; // enable clock for timer peripheral
timer_reset ( RTC_DS1307_SQUARE_WAVE_TIMER ) ; // reset timer state
timer_ic_set_input ( RTC_DS1307_SQUARE_WAVE_TIMER , RTC_DS1307_SQUARE_WAVE_TIMER_IC , RTC_DS1307_SQUARE_WAVE_TIMER_IN ) ; // configure channel as input capture
timer_ic_set_filter ( RTC_DS1307_SQUARE_WAVE_TIMER , RTC_DS1307_SQUARE_WAVE_TIMER_IC , TIM_IC_OFF ) ; // use no input capture filter
timer_ic_set_polarity ( RTC_DS1307_SQUARE_WAVE_TIMER , RTC_DS1307_SQUARE_WAVE_TIMER_IC , TIM_IC_FALLING ) ; //capture on falling edge
timer_slave_set_trigger ( RTC_DS1307_SQUARE_WAVE_TIMER , RTC_DS1307_SQUARE_WAVE_TIMER_TS ) ; // select trigger
timer_slave_set_mode ( RTC_DS1307_SQUARE_WAVE_TIMER , TIM_SMCR_SMS_ECM1 ) ; // select external clock more 1 as input
timer_ic_enable ( RTC_DS1307_SQUARE_WAVE_TIMER , RTC_DS1307_SQUARE_WAVE_TIMER_IC ) ; // enable input capture
timer_set_mode ( RTC_DS1307_SQUARE_WAVE_TIMER , TIM_CR1_CKD_CK_INT , TIM_CR1_CMS_EDGE , TIM_CR1_DIR_UP ) ; // set timer mode, use undivided timer clock, edge alignment (simple count), and count up
timer_set_prescaler ( RTC_DS1307_SQUARE_WAVE_TIMER , 0 ) ; // no need to prescale
timer_set_period ( RTC_DS1307_SQUARE_WAVE_TIMER , RTC_DS1307_SQUARE_WAVE_TICKS - 1 ) ; // set the tick period
timer_enable_irq ( RTC_DS1307_SQUARE_WAVE_TIMER , TIM_DIER_UIE ) ; // enable interrupt for timer
nvic_enable_irq ( RTC_DS1307_SQUARE_WAVE_TIMER_IRQ ) ; // allow interrupt for timer
rtc_ds1307_tick_flag = false ; // reset RTC tick flag
timer_enable_counter ( RTC_DS1307_SQUARE_WAVE_TIMER ) ; // enable timer to count ticks
rtc_ds1307_write_square_wave ( RTC_DS1307_SQUARE_WAVE_FREQUENCY ) ; // set square wave output frequency
2016-03-25 22:52:36 +01:00
# endif
2016-03-22 09:54:25 +01:00
}
2016-05-05 23:47:50 +02:00
/** read memory from RTC IC
2016-03-22 11:16:47 +01:00
* @ param [ in ] addr start address for memory to read
* @ param [ out ] data buffer to store read memory
* @ param [ in ] len number of byte to read from the memory
* @ return if read succeeded
*/
2016-05-01 20:29:03 +02:00
static bool rtc_ds1307_read_memory ( uint8_t addr , uint8_t * data , size_t len )
2016-03-22 09:54:25 +01:00
{
bool to_return = false ; // return if read succeeded
if ( data = = NULL | | len = = 0 ) { // verify there it data to be read
goto error ;
}
2016-05-01 20:29:03 +02:00
i2c_send_start ( RTC_DS1307_I2C ) ; // send start condition to start transaction
while ( ! ( I2C_SR1 ( RTC_DS1307_I2C ) & I2C_SR1_SB ) ) ; // wait until start condition is transmitted
if ( ! ( I2C_SR2 ( RTC_DS1307_I2C ) & I2C_SR2_MSL ) ) { // verify if in master mode
2016-03-22 09:54:25 +01:00
goto error ;
}
2016-05-01 20:29:03 +02:00
i2c_send_7bit_address ( RTC_DS1307_I2C , RTC_DS1307_I2C_ADDR , I2C_WRITE ) ; // select slave
while ( ! ( I2C_SR1 ( RTC_DS1307_I2C ) & I2C_SR1_ADDR ) ) ; // wait until address is transmitted
if ( ! ( ( I2C_SR2 ( RTC_DS1307_I2C ) & I2C_SR2_TRA ) ) ) { // verify we are in transmit mode (and read SR2 to clear ADDR)
2016-03-22 11:16:47 +01:00
goto error ;
}
2016-05-01 20:29:03 +02:00
i2c_send_data ( RTC_DS1307_I2C , addr ) ; // send memory address we want to read
while ( ! ( I2C_SR1 ( RTC_DS1307_I2C ) & I2C_SR1_TxE ) ) ; // wait until byte has been transmitted
i2c_send_start ( RTC_DS1307_I2C ) ; // send restart condition to switch from write to read mode
while ( ! ( I2C_SR1 ( RTC_DS1307_I2C ) & I2C_SR1_SB ) ) ; // wait until start condition is transmitted
i2c_send_7bit_address ( RTC_DS1307_I2C , RTC_DS1307_I2C_ADDR , I2C_READ ) ; // select slave
while ( ! ( I2C_SR1 ( RTC_DS1307_I2C ) & I2C_SR1_ADDR ) ) ; // wait until address is transmitted
if ( ( I2C_SR2 ( RTC_DS1307_I2C ) & I2C_SR2_TRA ) ) { // verify we are in read mode (and read SR2 to clear ADDR)
2016-03-22 09:54:25 +01:00
goto error ;
}
for ( size_t i = 0 ; i < len ; i + + ) { // read bytes
if ( i = = len - 1 ) { // prepare to sent NACK for last byte
2016-05-01 20:29:03 +02:00
i2c_disable_ack ( RTC_DS1307_I2C ) ; // NACK received to stop slave transmission
i2c_send_stop ( RTC_DS1307_I2C ) ; // send STOP after receiving byte
2016-03-22 09:54:25 +01:00
} else {
2016-05-01 20:29:03 +02:00
i2c_enable_ack ( RTC_DS1307_I2C ) ; // ACK received byte to continue slave transmission
2016-03-22 09:54:25 +01:00
}
2016-05-01 20:29:03 +02:00
while ( ! ( I2C_SR1 ( RTC_DS1307_I2C ) & I2C_SR1_RxNE ) ) ; // wait until byte has been received
data [ i ] = i2c_get_data ( RTC_DS1307_I2C ) ; // read received byte
2016-03-22 09:54:25 +01:00
}
to_return = true ;
error :
2016-05-01 20:29:03 +02:00
if ( I2C_SR2 ( RTC_DS1307_I2C ) & I2C_SR2_BUSY ) { // release bus if busy
i2c_send_stop ( RTC_DS1307_I2C ) ; // send stop to release bus
2016-03-22 09:54:25 +01:00
}
2016-05-01 20:29:03 +02:00
while ( I2C_SR2 ( RTC_DS1307_I2C ) & I2C_SR2_MSL ) ; // wait until bus released (non master mode)
2016-03-22 09:54:25 +01:00
return to_return ;
}
2016-05-01 20:29:03 +02:00
bool rtc_ds1307_oscillator_disabled ( void )
2016-03-23 09:17:43 +01:00
{
2016-03-25 18:00:44 +01:00
uint8_t data [ 1 ] = { 0 } ; // to read data over I2C
2016-05-01 20:29:03 +02:00
rtc_ds1307_read_memory ( 0 , data , LENGTH ( data ) ) ; // read a single byte containing CH value
2016-03-23 09:17:43 +01:00
return data [ 0 ] & 0x80 ; // return CH bit value to indicate if oscillator is disabled
}
2016-05-01 20:29:03 +02:00
uint16_t rtc_ds1307_read_square_wave ( void )
2016-03-25 18:00:44 +01:00
{
uint16_t to_return = 0 ; // square wave frequency to return (in Hz)
uint8_t data [ 1 ] = { 0 } ; // to read data over I2C
2016-05-01 20:29:03 +02:00
const uint16_t rtc_ds1307_rs [ ] = { 1 , 4096 , 8192 , 32768 } ; // RS1/RS0 values
rtc_ds1307_read_memory ( 7 , data , LENGTH ( data ) ) ; // read a single byte containing control register
2016-03-25 18:00:44 +01:00
if ( data [ 0 ] & 0x10 ) { // verify if the square wave is enabled (SQWE)
2016-05-01 20:29:03 +02:00
to_return = rtc_ds1307_rs [ data [ 0 ] & 0x03 ] ; // read RS1/RS0 and get value
2016-03-25 18:00:44 +01:00
} else {
to_return = 0 ; // square wave output is disabled
}
return to_return ;
}
2016-05-01 20:29:03 +02:00
uint8_t rtc_ds1307_read_seconds ( void )
2016-03-22 09:54:25 +01:00
{
uint8_t to_return = 0 ; // seconds to return
2016-03-25 18:00:44 +01:00
uint8_t data [ 1 ] = { 0 } ; // to read data over I2C
2016-05-01 20:29:03 +02:00
rtc_ds1307_read_memory ( 0 , data , LENGTH ( data ) ) ; // read a single byte containing seconds value
2016-03-22 11:16:47 +01:00
to_return = ( ( data [ 0 ] & 0x70 ) > > 4 ) * 10 + ( data [ 0 ] & 0x0f ) ; // convert BCD coding into seconds
2016-03-22 09:54:25 +01:00
return to_return ;
}
2016-03-22 22:07:36 +01:00
2016-05-01 20:29:03 +02:00
uint8_t rtc_ds1307_read_minutes ( void )
2016-03-22 22:07:36 +01:00
{
uint8_t to_return = 0 ; // minutes to return
2016-03-25 18:00:44 +01:00
uint8_t data [ 1 ] = { 0 } ; // to read data over I2C
2016-05-01 20:29:03 +02:00
rtc_ds1307_read_memory ( 1 , data , LENGTH ( data ) ) ; // read a single byte containing minutes value
2016-03-22 22:07:36 +01:00
to_return = ( data [ 0 ] > > 4 ) * 10 + ( data [ 0 ] & 0x0f ) ; // convert BCD coding into minutes
return to_return ;
}
2016-05-01 20:29:03 +02:00
uint8_t rtc_ds1307_read_hours ( void )
2016-03-22 22:07:36 +01:00
{
uint8_t to_return = 0 ; // hours to return
2016-03-25 18:00:44 +01:00
uint8_t data [ 1 ] = { 0 } ; // to read data over I2C
2016-05-01 20:29:03 +02:00
rtc_ds1307_read_memory ( 2 , data , LENGTH ( data ) ) ; // read a single byte containing hours value
2016-03-22 22:07:36 +01:00
if ( data [ 0 ] & 0x40 ) { // 12 hour mode
if ( data [ 0 ] & 0x02 ) { // PM
to_return + = 12 ; // add the 12 hours
}
to_return + = ( ( data [ 0 ] & 0x10 ) > > 4 ) * 10 ; // convert BCD coding into hours (first digit)
} else {
to_return = ( ( data [ 0 ] & 0x30 ) > > 4 ) * 10 ; // convert BCD coding into hours (first digit)
}
to_return + = ( data [ 0 ] & 0x0f ) ; // convert BCD coding into hours (second digit)
return to_return ;
}
2016-05-01 20:29:03 +02:00
uint8_t rtc_ds1307_read_day ( void )
2016-03-22 22:07:36 +01:00
{
uint8_t to_return = 0 ; // day to return
2016-03-25 18:00:44 +01:00
uint8_t data [ 1 ] = { 0 } ; // to read data over I2C
2016-05-01 20:29:03 +02:00
rtc_ds1307_read_memory ( 3 , data , LENGTH ( data ) ) ; // read a single byte containing day value
2016-03-22 22:07:36 +01:00
to_return = ( data [ 0 ] & 0x07 ) ; // convert BCD coding into days
return to_return ;
}
2016-05-01 20:29:03 +02:00
uint8_t rtc_ds1307_read_date ( void )
2016-03-22 22:07:36 +01:00
{
uint8_t to_return = 0 ; // date to return
2016-03-25 18:00:44 +01:00
uint8_t data [ 1 ] = { 0 } ; // to read data over I2C
2016-05-01 20:29:03 +02:00
rtc_ds1307_read_memory ( 4 , data , LENGTH ( data ) ) ; // read a single byte containing date value
2016-03-22 22:07:36 +01:00
to_return = ( ( data [ 0 ] & 0x30 ) > > 4 ) * 10 + ( data [ 0 ] & 0x0f ) ; // convert BCD coding into date
return to_return ;
}
2016-05-01 20:29:03 +02:00
uint8_t rtc_ds1307_read_month ( void )
2016-03-22 22:07:36 +01:00
{
uint8_t to_return = 0 ; // month to return
2016-03-25 18:00:44 +01:00
uint8_t data [ 1 ] = { 0 } ; // to read data over I2C
2016-05-01 20:29:03 +02:00
rtc_ds1307_read_memory ( 5 , data , LENGTH ( data ) ) ; // read a single byte containing month value
2016-03-22 22:07:36 +01:00
to_return = ( ( data [ 0 ] & 0x10 ) > > 4 ) * 10 + ( data [ 0 ] & 0x0f ) ; // convert BCD coding into month
return to_return ;
}
2016-05-05 23:25:55 +02:00
uint8_t rtc_ds1307_read_year ( void )
2016-03-22 22:07:36 +01:00
{
2016-03-25 18:00:44 +01:00
uint8_t data [ 1 ] = { 0 } ; // to read data over I2C
2016-05-01 20:29:03 +02:00
rtc_ds1307_read_memory ( 6 , data , LENGTH ( data ) ) ; // read a single byte containing year value
2016-05-05 23:25:55 +02:00
uint8_t to_return = ( ( data [ 0 ] & 0xf0 ) > > 4 ) * 10 + ( data [ 0 ] & 0x0f ) ; // convert BCD coding into year
2016-03-22 22:07:36 +01:00
return to_return ;
}
2016-03-23 08:09:52 +01:00
2016-05-05 23:25:55 +02:00
uint8_t * rtc_ds1307_read_time ( void )
2016-03-23 08:09:52 +01:00
{
2016-05-05 23:25:55 +02:00
static uint8_t time [ 7 ] = { 0 } ; // store time {seconds, minutes, hours, day, date, month, year}
2016-03-25 18:00:44 +01:00
uint8_t data [ 7 ] = { 0 } ; // to read data over I2C
2016-05-01 20:29:03 +02:00
rtc_ds1307_read_memory ( 0 , data , LENGTH ( data ) ) ; // read all time bytes
2016-03-23 08:09:52 +01:00
time [ 0 ] = ( ( data [ 0 ] & 0x70 ) > > 4 ) * 10 + ( data [ 0 ] & 0x0f ) ; // convert seconds from BCD
time [ 1 ] = ( data [ 1 ] > > 4 ) * 10 + ( data [ 1 ] & 0x0f ) ; // convert minutes from BCD
time [ 2 ] = 0 ; // re-initialize hours
if ( data [ 2 ] & 0x40 ) { // 12 hour mode
if ( data [ 2 ] & 0x02 ) { // PM
time [ 2 ] + = 12 ; // add the 12 hours
}
time [ 2 ] + = ( ( data [ 2 ] & 0x10 ) > > 4 ) * 10 ; // convert BCD coding into hours (first digit)
} else {
time [ 2 ] = ( ( data [ 2 ] & 0x30 ) > > 4 ) * 10 ; // convert BCD coding into hours (first digit)
}
time [ 2 ] + = ( data [ 2 ] & 0x0f ) ; // convert BCD coding into hours (second digit)
time [ 3 ] = ( data [ 3 ] & 0x07 ) ; // convert BCD coding into days
time [ 4 ] = ( ( data [ 4 ] & 0x30 ) > > 4 ) * 10 + ( data [ 4 ] & 0x0f ) ; // convert BCD coding into date
time [ 5 ] = ( ( data [ 5 ] & 0x10 ) > > 4 ) * 10 + ( data [ 5 ] & 0x0f ) ; // convert BCD coding into month
2016-05-05 23:25:55 +02:00
time [ 6 ] = ( ( data [ 6 ] & 0xf0 ) > > 4 ) * 10 + ( data [ 6 ] & 0x0f ) ; // convert BCD coding into year
2016-03-23 08:09:52 +01:00
return time ;
}
2016-05-05 23:47:50 +02:00
/** write memory into RTC IC
2016-03-23 09:17:43 +01:00
* @ param [ in ] addr start address for memory to be written
* @ param [ in ] data buffer to for memory to be written
* @ param [ in ] len number of byte to write into the memory
* @ return if write succeeded
*/
2016-05-01 20:29:03 +02:00
static bool rtc_ds1307_write_memory ( uint8_t addr , uint8_t * data , size_t len )
2016-03-23 09:17:43 +01:00
{
bool to_return = false ; // return if read succeeded
if ( data = = NULL | | len = = 0 ) { // verify there it data to be read
goto error ;
}
2016-05-01 20:29:03 +02:00
i2c_send_start ( RTC_DS1307_I2C ) ; // send start condition to start transaction
while ( ! ( I2C_SR1 ( RTC_DS1307_I2C ) & I2C_SR1_SB ) ) ; // wait until start condition is transmitted
if ( ! ( I2C_SR2 ( RTC_DS1307_I2C ) & I2C_SR2_MSL ) ) { // verify if in master mode
2016-03-23 09:17:43 +01:00
goto error ;
}
2016-05-01 20:29:03 +02:00
i2c_send_7bit_address ( RTC_DS1307_I2C , RTC_DS1307_I2C_ADDR , I2C_WRITE ) ; // select slave
while ( ! ( I2C_SR1 ( RTC_DS1307_I2C ) & I2C_SR1_ADDR ) ) ; // wait until address is transmitted
if ( ! ( ( I2C_SR2 ( RTC_DS1307_I2C ) & I2C_SR2_TRA ) ) ) { // verify we are in transmit mode (and read SR2 to clear ADDR)
2016-03-23 09:17:43 +01:00
goto error ;
}
2016-05-01 20:29:03 +02:00
i2c_send_data ( RTC_DS1307_I2C , addr ) ; // send memory address we want to read
while ( ! ( I2C_SR1 ( RTC_DS1307_I2C ) & I2C_SR1_TxE ) ) ; // wait until byte has been transmitted
2016-03-23 09:17:43 +01:00
for ( size_t i = 0 ; i < len ; i + + ) { // write bytes
2016-05-01 20:29:03 +02:00
i2c_send_data ( RTC_DS1307_I2C , data [ i ] ) ; // send byte to be written in memory
while ( ! ( I2C_SR1 ( RTC_DS1307_I2C ) & I2C_SR1_TxE ) ) ; // wait until byte has been transmitted
2016-03-23 09:17:43 +01:00
}
to_return = true ;
error :
2016-05-01 20:29:03 +02:00
if ( I2C_SR2 ( RTC_DS1307_I2C ) & I2C_SR2_BUSY ) { // release bus if busy
i2c_send_stop ( RTC_DS1307_I2C ) ; // send stop to release bus
2016-03-23 09:17:43 +01:00
}
2016-05-01 20:29:03 +02:00
while ( I2C_SR2 ( RTC_DS1307_I2C ) & I2C_SR2_MSL ) ; // wait until bus released (non master mode)
2016-03-23 09:17:43 +01:00
return to_return ;
}
2016-05-01 20:29:03 +02:00
bool rtc_ds1307_oscillator_disable ( void )
2016-03-23 09:17:43 +01:00
{
2016-03-25 18:00:44 +01:00
uint8_t data [ 1 ] = { 0 } ; // to write CH value data over I2C
2016-05-01 20:29:03 +02:00
rtc_ds1307_read_memory ( 0 , data , LENGTH ( data ) ) ; // read seconds with CH value
2016-03-23 09:17:43 +01:00
data [ 0 ] | = 0x80 ; // set CH to disable oscillator
2016-05-01 20:29:03 +02:00
return rtc_ds1307_write_memory ( 0 , data , LENGTH ( data ) ) ; // write current seconds with CH value
2016-03-23 09:17:43 +01:00
}
2016-05-01 20:29:03 +02:00
bool rtc_ds1307_oscillator_enable ( void )
2016-03-23 09:17:43 +01:00
{
2016-03-25 18:00:44 +01:00
uint8_t data [ 1 ] = { 0 } ; // to write CH value data over I2C
2016-05-01 20:29:03 +02:00
rtc_ds1307_read_memory ( 0 , data , LENGTH ( data ) ) ; // read seconds with CH value
2016-03-23 09:17:43 +01:00
data [ 0 ] & = 0x7f ; // clear CH to enable oscillator
2016-05-01 20:29:03 +02:00
return rtc_ds1307_write_memory ( 0 , data , LENGTH ( data ) ) ; // write current seconds with CH value
2016-03-23 09:17:43 +01:00
}
2016-05-01 20:29:03 +02:00
bool rtc_ds1307_write_square_wave ( uint16_t frequency )
2016-03-25 18:00:44 +01:00
{
uint8_t data [ 1 ] = { 0 } ; // to write control register value data over I2C
switch ( frequency ) { // set RS1/RS0 based on frequency
case 0 :
data [ 0 ] = 0 ;
break ;
case 1 :
data [ 0 ] = 0 | ( 1 < < 4 ) ;
break ;
case 4096 :
data [ 0 ] = 1 | ( 1 < < 4 ) ;
break ;
case 8192 :
data [ 0 ] = 2 | ( 1 < < 4 ) ;
break ;
case 32768 :
data [ 0 ] = 3 | ( 1 < < 4 ) ;
break ;
default : // unspecified frequency
return false ;
}
2016-05-01 20:29:03 +02:00
return rtc_ds1307_write_memory ( 7 , data , LENGTH ( data ) ) ; // write current seconds with CH value
2016-03-25 18:00:44 +01:00
}
2016-05-01 20:29:03 +02:00
bool rtc_ds1307_write_seconds ( uint8_t seconds )
2016-03-23 09:17:43 +01:00
{
2016-03-23 09:52:53 +01:00
if ( seconds > 59 ) {
return false ;
}
2016-03-25 18:00:44 +01:00
uint8_t data [ 1 ] = { 0 } ; // to read CH value data and write seconds value over I2C
2016-05-01 20:29:03 +02:00
if ( ! rtc_ds1307_read_memory ( 0 , data , LENGTH ( data ) ) ) { // read seconds with CH value
2016-03-23 09:52:53 +01:00
return false ;
}
2016-03-23 09:17:43 +01:00
data [ 0 ] & = 0x80 ; // only keep CH flag
2016-03-23 09:52:53 +01:00
data [ 0 ] | = ( ( ( seconds / 10 ) % 6 ) < < 4 ) + ( seconds % 10 ) ; // encode seconds in BCD format
2016-05-01 20:29:03 +02:00
return rtc_ds1307_write_memory ( 0 , data , LENGTH ( data ) ) ; // write current seconds with previous CH value
2016-03-23 09:52:53 +01:00
}
2016-05-01 20:29:03 +02:00
bool rtc_ds1307_write_minutes ( uint8_t minutes )
2016-03-23 09:52:53 +01:00
{
if ( minutes > 59 ) {
return false ;
}
uint8_t data [ 1 ] = { 0 } ; // to write time value
data [ 0 ] = ( ( ( minutes / 10 ) % 6 ) < < 4 ) + ( minutes % 10 ) ; // encode minutes in BCD format
2016-05-01 20:29:03 +02:00
return rtc_ds1307_write_memory ( 1 , data , LENGTH ( data ) ) ; // write time value on RTC
2016-03-23 09:52:53 +01:00
}
2016-05-01 20:29:03 +02:00
bool rtc_ds1307_write_hours ( uint8_t hours )
2016-03-23 09:52:53 +01:00
{
if ( hours > 24 ) {
return false ;
}
uint8_t data [ 1 ] = { 0 } ; // to write time value
data [ 0 ] = ( ( ( hours / 10 ) % 3 ) < < 4 ) + ( hours % 10 ) ; // encode hours in BCD 24h format
2016-05-01 20:29:03 +02:00
return rtc_ds1307_write_memory ( 2 , data , LENGTH ( data ) ) ; // write time value on RTC
2016-03-23 09:17:43 +01:00
}
2016-03-23 09:52:53 +01:00
2016-05-01 20:29:03 +02:00
bool rtc_ds1307_write_day ( uint8_t day )
2016-03-23 09:52:53 +01:00
{
if ( day < 1 | | day > 7 ) {
return false ;
}
uint8_t data [ 1 ] = { 0 } ; // to write time value
data [ 0 ] = ( day % 8 ) ; // encode day in BCD format
2016-05-01 20:29:03 +02:00
return rtc_ds1307_write_memory ( 3 , data , LENGTH ( data ) ) ; // write time value on RTC
2016-03-23 09:52:53 +01:00
}
2016-05-01 20:29:03 +02:00
bool rtc_ds1307_write_date ( uint8_t date )
2016-03-23 09:52:53 +01:00
{
if ( date < 1 | | date > 31 ) {
return false ;
}
uint8_t data [ 1 ] = { 0 } ; // to write time value
data [ 0 ] = ( ( ( date / 10 ) % 4 ) < < 4 ) + ( date % 10 ) ; // encode date in BCD format
2016-05-01 20:29:03 +02:00
return rtc_ds1307_write_memory ( 4 , data , LENGTH ( data ) ) ; // write time value on RTC
2016-03-23 09:52:53 +01:00
}
2016-05-01 20:29:03 +02:00
bool rtc_ds1307_write_month ( uint8_t month )
2016-03-23 09:52:53 +01:00
{
if ( month < 1 | | month > 12 ) {
return false ;
}
uint8_t data [ 1 ] = { 0 } ; // to write time value
data [ 0 ] = ( ( ( month / 10 ) % 2 ) < < 4 ) + ( month % 10 ) ; // encode month in BCD format
2016-05-01 20:29:03 +02:00
return rtc_ds1307_write_memory ( 5 , data , LENGTH ( data ) ) ; // write time value on RTC
2016-03-23 09:52:53 +01:00
}
2016-05-05 23:25:55 +02:00
bool rtc_ds1307_write_year ( uint8_t year )
2016-03-23 09:52:53 +01:00
{
2016-05-05 23:25:55 +02:00
if ( year > 99 ) {
2016-03-23 09:52:53 +01:00
return false ;
}
uint8_t data [ 1 ] = { 0 } ; // to write time value
data [ 0 ] = ( ( ( year / 10 ) % 10 ) < < 4 ) + ( year % 10 ) ; // encode year in BCD format
2016-05-01 20:29:03 +02:00
return rtc_ds1307_write_memory ( 6 , data , LENGTH ( data ) ) ; // write time value on RTC
2016-03-23 09:52:53 +01:00
}
2016-05-05 23:25:55 +02:00
bool rtc_ds1307_write_time ( uint8_t seconds , uint8_t minutes , uint8_t hours , uint8_t day , uint8_t date , uint8_t month , uint8_t year )
2016-03-23 09:52:53 +01:00
{
uint8_t data [ 7 ] = { 0 } ; // to write all time values
// seconds
if ( seconds > 59 ) {
return false ;
}
2016-05-01 20:29:03 +02:00
if ( ! rtc_ds1307_read_memory ( 0 , data , 1 ) ) { // read seconds with CH value
2016-03-23 09:52:53 +01:00
return false ;
}
data [ 0 ] & = 0x80 ; // only keep CH flag
data [ 0 ] | = ( ( ( seconds / 10 ) % 6 ) < < 4 ) + ( seconds % 10 ) ; // encode seconds in BCD format
// minutes
if ( minutes > 59 ) {
return false ;
}
data [ 1 ] = ( ( ( minutes / 10 ) % 6 ) < < 4 ) + ( minutes % 10 ) ; // encode minutes in BCD format
// hours
if ( hours > 24 ) {
return false ;
}
data [ 2 ] = ( ( ( hours / 10 ) % 3 ) < < 4 ) + ( hours % 10 ) ; // encode hours in BCD 24h format
// day
if ( day < 1 | | day > 7 ) {
return false ;
}
data [ 3 ] = ( day % 8 ) ; // encode day in BCD format
// date
if ( date < 1 | | date > 31 ) {
return false ;
}
data [ 4 ] = ( ( ( date / 10 ) % 4 ) < < 4 ) + ( date % 10 ) ; // encode date in BCD format
// month
if ( month < 1 | | month > 12 ) {
return false ;
}
data [ 5 ] = ( ( ( month / 10 ) % 2 ) < < 4 ) + ( month % 10 ) ; // encode month in BCD format
// year
2016-05-05 23:25:55 +02:00
if ( year > 99 ) {
2016-03-23 09:52:53 +01:00
return false ;
}
data [ 6 ] = ( ( ( year / 10 ) % 10 ) < < 4 ) + ( year % 10 ) ; // encode year in BCD format
2016-05-01 20:29:03 +02:00
return rtc_ds1307_write_memory ( 0 , data , LENGTH ( data ) ) ; // write time values on RTC
2016-03-23 09:52:53 +01:00
}
2016-03-25 18:00:44 +01:00
2016-05-01 20:29:03 +02:00
# if defined(RTC_DS1307_SQUARE_WAVE_TICKS)
2016-05-05 23:47:50 +02:00
/** timer interrupt service routine called when number of ticks have been received */
2016-05-01 20:29:03 +02:00
void RTC_DS1307_SQUARE_WAVE_TIMER_ISR ( void )
2016-03-25 18:00:44 +01:00
{
2016-05-01 20:29:03 +02:00
if ( timer_get_flag ( RTC_DS1307_SQUARE_WAVE_TIMER , TIM_SR_UIF ) ) { // overflow even happened
timer_clear_flag ( RTC_DS1307_SQUARE_WAVE_TIMER , TIM_SR_UIF ) ; // clear flag
rtc_ds1307_ticks + + ; // increment count
rtc_ds1307_tick_flag = true ; // update flag
2016-04-30 12:03:34 +02:00
}
2016-03-25 18:00:44 +01:00
}
# endif