mbed-os/targets/TARGET_RENESAS/TARGET_RZ_A1XX/rtc_api.c

366 lines
9.1 KiB
C

/* mbed Microcontroller Library
* Copyright (c) 2006-2015 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed_assert.h"
#include "device.h"
#if DEVICE_RTC
#include "rtc_api.h"
#include "iodefine.h"
#include "mbed_drv_cfg.h"
#include "mbed_mktime.h"
#define RCR1_VAL_ON (0x08u) // AIE = 1
#define RCR1_VAL_OFF (0x00u)
#define RCR3_VAL (0x00u)
#define RCR5_VAL (0x00u)
#ifdef USE_RTCX1_CLK
#define RCR2_VAL_ALLSTOP (0x08u)
#define RCR2_VAL_START (0x09u) // START = 1
#define RCR2_VAL_RESET (0x0Au) // RESET = 1
#define RCR5_VAL_RTCX1 (0x00u) // RCKSEL = clock rtc from RTCX1(32.768 kHz)
#elif defined(USE_EXTAL_CLK)
#define RCR2_VAL_ALLSTOP (0x00u)
#define RCR2_VAL_START (0x01u) // START = 1
#define RCR2_VAL_RESET (0x02u) // RESET = 1
#define RCR5_VAL_EXTAL (0x01u) // RCKSEL = clock rtc from EXTAL
#define RFRH_VAL_13333 (0x8003u) // 13.3333MHz (= 64Hz * 0x32DCD)
#define RFRL_VAL_13333 (0x2DCDu) //
#elif defined(USE_RTCX3_CLK)
#define RCR2_VAL_ALLSTOP (0x08u)
#define RCR2_VAL_START (0x09u) // START = 1
#define RCR2_VAL_RESET (0x0Au) // RESET = 1
#define RCR5_VAL_RTCX3 (0x02u) // RCKSEL = clock rtc from RTCX3(4.000 MHz)
#define RFRH_VAL_4000 (0x8000u) // 4.000MHz (= 64Hz * 0xF424)
#define RFRL_VAL_4000 (0xF424u) //
#else
#error Select RTC clock input !
#endif
#define RFRH_VAL_MAX (0x0007u) // MAX value (= 128Hz * 0x7FFFF)
#define RFRL_VAL_MAX (0xFFFFu) //
#define MASK_00_03_POS (0x000Fu)
#define MASK_04_07_POS (0x00F0u)
#define MASK_08_11_POS (0x0F00u)
#define MASK_12_15_POS (0xF000u)
#define MASK_16_20_POS (0x000F0000u)
#define SHIFT_1_HBYTE (4u)
#define SHIFT_2_HBYTE (8u)
#define SHIFT_3_HBYTE (12u)
#define SHIFT_1BYTE (8u)
#define SHIFT_2BYTE (16u)
#define TIME_ERROR_VAL (0u)
static int rtc_dec8_to_hex(uint8_t dec_val, uint8_t offset, int *hex_val);
static int rtc_dec16_to_hex(uint16_t dec_val, uint16_t offset, int *hex_val);
static uint8_t rtc_hex8_to_dec(uint8_t hex_val);
static uint16_t rtc_hex16_to_dec(uint16_t hex_val);
/*
* Setup the RTC based on a time structure.
* The rtc_init function should be executed first.
* [in]
* None.
* [out]
* None.
*/
void rtc_init(void)
{
volatile uint8_t dummy_read;
CPG.STBCR6 &= ~(CPG_STBCR6_BIT_MSTP60);
// Set control register
RTC.RCR2 = RCR2_VAL_ALLSTOP;
RTC.RCR1 = RCR1_VAL_ON;
RTC.RCR3 = RCR3_VAL;
#ifdef USE_RTCX1_CLK
RTC.RCR5 = RCR5_VAL_RTCX1;
RTC.RFRH = 0;
RTC.RFRL = 0;
#elif defined(USE_EXTAL_CLK)
RTC.RCR5 = RCR5_VAL_EXTAL;
RTC.RFRH = RFRH_VAL_13333;
RTC.RFRL = RFRL_VAL_13333;
#else
RTC.RCR5 = RCR5_VAL_RTCX3;
RTC.RFRH = RFRH_VAL_4000;
RTC.RFRL = RFRL_VAL_4000;
#endif
// Dummy read
dummy_read = RTC.RCR2;
dummy_read = RTC.RCR2;
RTC.RCR2 = RCR2_VAL_START; // SRART = 1
// Dummy read
dummy_read = RTC.RCR2;
dummy_read = RTC.RCR2;
(void)dummy_read;
}
/*
* Release the RTC based on a time structure.
* @note This function does not stop the RTC from counting
* [in]
* None.
* [out]
* None.
*/
void rtc_free(void)
{
}
/*
* Check the RTC has been enabled.
* Clock Control Register RTC.RCR1(bit3): 0 = Disabled, 1 = Enabled.
* [in]
* None.
* [out]
* 0:Disabled, 1:Enabled.
*/
int rtc_isenabled(void)
{
int ret_val = 0;
if ((RTC.RCR1 & RCR1_VAL_ON) != 0) { // RTC ON ?
ret_val = 1;
}
return ret_val;
}
/*
* RTC read function.
* [in]
* None.
* [out]
* UNIX timestamp value.
*/
time_t rtc_read(void)
{
struct tm timeinfo;
int err = 0;
uint8_t tmp_regdata;
time_t t;
if (rtc_isenabled() != 0) {
RTC.RCR1 &= ~0x10u; // CIE = 0
do {
// before reading process
tmp_regdata = RTC.RCR1;
tmp_regdata &= ~0x80u; // CF = 0
tmp_regdata |= 0x01u; // AF = 1
RTC.RCR1 = tmp_regdata;
// Read RTC register
err = rtc_dec8_to_hex(RTC.RSECCNT , 0 , &timeinfo.tm_sec);
err += rtc_dec8_to_hex(RTC.RMINCNT , 0 , &timeinfo.tm_min);
err += rtc_dec8_to_hex(RTC.RHRCNT , 0 , &timeinfo.tm_hour);
err += rtc_dec8_to_hex(RTC.RDAYCNT , 0 , &timeinfo.tm_mday);
err += rtc_dec8_to_hex(RTC.RMONCNT , 1 , &timeinfo.tm_mon);
err += rtc_dec16_to_hex(RTC.RYRCNT , 1900 , &timeinfo.tm_year);
} while ((RTC.RCR1 & 0x80u) != 0);
} else {
err = 1;
}
if (err == 0) {
// Convert to timestamp
if (_rtc_maketime(&timeinfo, &t, RTC_FULL_LEAP_YEAR_SUPPORT) == false) {
return TIME_ERROR_VAL;
}
} else {
// Error
t = TIME_ERROR_VAL;
}
return t;
}
/*
* Dec(8bit) to Hex function for RTC.
* [in]
* dec_val:Decimal value (from 0x00 to 0x99).
* offset:Subtract offset from dec_val.
* hex_val:Pointer of output hexadecimal value.
* [out]
* 0:Success
* 1:Error
*/
static int rtc_dec8_to_hex(uint8_t dec_val, uint8_t offset, int *hex_val)
{
int err = 0;
uint8_t ret_val;
if (hex_val != NULL) {
if (((dec_val & MASK_04_07_POS) >= (0x0A << SHIFT_1_HBYTE)) ||
((dec_val & MASK_00_03_POS) >= 0x0A)) {
err = 1;
} else {
ret_val = ((dec_val & MASK_04_07_POS) >> SHIFT_1_HBYTE) * 10 +
(dec_val & MASK_00_03_POS);
if (ret_val < offset) {
err = 1;
} else {
*hex_val = ret_val - offset;
}
}
} else {
err = 1;
}
return err;
}
/*
* Dec(16bit) to Hex function for RTC
* [in]
* dec_val:Decimal value (from 0x0000 to 0x9999).
* offset:Subtract offset from dec_val.
* hex_val:Pointer of output hexadecimal value.
* [out]
* 0:Success
* 1:Error
*/
static int rtc_dec16_to_hex(uint16_t dec_val, uint16_t offset, int *hex_val)
{
int err = 0;
uint16_t ret_val;
if (hex_val != NULL) {
if (((dec_val & MASK_12_15_POS) >= (0x0A << SHIFT_3_HBYTE)) ||
((dec_val & MASK_08_11_POS) >= (0x0A << SHIFT_2_HBYTE)) ||
((dec_val & MASK_04_07_POS) >= (0x0A << SHIFT_1_HBYTE)) ||
((dec_val & MASK_00_03_POS) >= 0x0A)) {
err = 1;
*hex_val = 0;
} else {
ret_val = (((dec_val & MASK_12_15_POS)) >> SHIFT_3_HBYTE) * 1000 +
(((dec_val & MASK_08_11_POS)) >> SHIFT_2_HBYTE) * 100 +
(((dec_val & MASK_04_07_POS)) >> SHIFT_1_HBYTE) * 10 +
(dec_val & MASK_00_03_POS);
if (ret_val < offset) {
err = 1;
} else {
*hex_val = ret_val - offset;
}
}
} else {
err = 1;
}
return err;
}
/*
* RTC write function
* [in]
* t:UNIX timestamp value
* [out]
* None.
*/
void rtc_write(time_t t)
{
struct tm timeinfo;
if (_rtc_localtime(t, &timeinfo, RTC_FULL_LEAP_YEAR_SUPPORT) == false) {
return;
}
volatile uint16_t dummy_read;
if (rtc_isenabled() != 0) {
RTC.RCR2 = RCR2_VAL_ALLSTOP;
dummy_read = (uint16_t)RTC.RCR2;
dummy_read = (uint16_t)RTC.RCR2;
RTC.RCR2 = RCR2_VAL_RESET; // RESET = 1
dummy_read = (uint16_t)RTC.RCR2;
dummy_read = (uint16_t)RTC.RCR2;
RTC.RSECCNT = rtc_hex8_to_dec(timeinfo.tm_sec);
RTC.RMINCNT = rtc_hex8_to_dec(timeinfo.tm_min);
RTC.RHRCNT = rtc_hex8_to_dec(timeinfo.tm_hour);
RTC.RDAYCNT = rtc_hex8_to_dec(timeinfo.tm_mday);
RTC.RMONCNT = rtc_hex8_to_dec(timeinfo.tm_mon + 1);
RTC.RYRCNT = rtc_hex16_to_dec(timeinfo.tm_year + 1900);
dummy_read = (uint16_t)RTC.RYRCNT;
dummy_read = (uint16_t)RTC.RYRCNT;
RTC.RCR2 = RCR2_VAL_START; // START = 1
dummy_read = (uint16_t)RTC.RCR2;
dummy_read = (uint16_t)RTC.RCR2;
(void)dummy_read;
}
}
/*
* HEX to Dec(8bit) function for RTC.
* [in]
* hex_val:Hexadecimal value.
* [out]
* decimal value:From 0x00 to 0x99.
*/
static uint8_t rtc_hex8_to_dec(uint8_t hex_val)
{
uint32_t calc_data;
calc_data = hex_val / 10 * 0x10;
calc_data += hex_val % 10;
if (calc_data > 0x99) {
calc_data = 0;
}
return (uint8_t)calc_data;
}
/*
* HEX to Dec(16bit) function for RTC.
* [in]
* hex_val:Hexadecimal value.
* [out]
* decimal value:From 0x0000 to 0x9999.
*/
static uint16_t rtc_hex16_to_dec(uint16_t hex_val)
{
uint32_t calc_data;
calc_data = hex_val / 1000 * 0x1000;
calc_data += ((hex_val / 100) % 10) * 0x100;
calc_data += ((hex_val / 10) % 10) * 0x10;
calc_data += hex_val % 10;
if (calc_data > 0x9999) {
calc_data = 0;
}
return (uint16_t)calc_data;
}
#endif /* DEVICE_RTC */