Files
kunlun/dtest/dtest3/kl3_rtc_test/rtc_test.c
2024-09-28 14:24:04 +08:00

516 lines
17 KiB
C

/****************************************************************************
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
be copied by any method or incorporated into another program without
the express written consent of Aerospace C.Power. This Information or any portion
thereof remains the property of Aerospace C.Power. The Information contained herein
is believed to be accurate and Aerospace C.Power assumes no responsibility or
liability for its use in any way and conveys no license or title under
any patent or copyright and makes no representation or warranty that this
Information is free from patent or copyright infringement.
****************************************************************************/
#include "chip_reg_base.h"
#include "hw_reg_api.h"
#include "ahb.h"
#include "gp_timer.h"
#include "rtc_hw.h"
#include "uart.h"
#include "wdt_hw.h"
#include "cpu.h"
#include "iot_clock.h"
#include "dbg_io.h"
#include "iot_rtc.h"
#include "iot_irq.h"
#include "iot_wdg.h"
#include "iot_errno_api.h"
#include "iot_rtc_api.h"
#include "dtest_printf.h"
#define DTEST_RTC_MS_TO_RTC_TICK(x) (((x) << 12) / 125)
#define DTEST_RTC_S_TO_RTC_TICK(x) ((x) << 15)
#define DTEST_RTC_TICK_TO_MS(x) (((x) >> 12) * 125)
#define DTEST_RTC_TICK_TO_S(x) ((x) >> 15)
#define DTEST_RTC_SCRATCH_INDEX 0
/* Several counting cycles may be lost due to cross clock domain problems */
#define DTEST_RTC_OPT_CNT_COMPENSATION 4
#define DTEST_RTC_CASE_TIMER_CNT_GET_SET (1 << 0)
#define DTEST_RTC_CASE_TIMER_PAUSE_REGAIN (1 << 1)
#define DTEST_RTC_CASE_TIMER_START_STOP (1 << 2)
#define DTEST_RTC_CASE_TIMER_INTERRUPT (1 << 3)
#define DTEST_RTC_CASE_TIMER_CASCADE (1 << 4)
#define DTEST_RTC_CASE_TIMER_ACCURACY (1 << 5)
#define DTEST_RTC_CASE_WDG_RESET (1 << 6)
static uint32_t dtest_rtc_cnt_get_set_test()
{
uint32_t cnt_tmr0_0, cnt_tmr1_0, cnt_tmr0_1, cnt_tmr1_1, cnt_d0, cnt_d1;
uint32_t delay_us = 1000000;
uint32_t rtc_tick_us = DTEST_RTC_MS_TO_RTC_TICK(delay_us / 1000);
dcase_start("rtc timer cnt value get and set\n");
/* get rtc timer counter value */
cnt_tmr0_0 = rtc_timer_cnt_value_get(RTC_TIMER_ID_0);
cnt_tmr1_0 = rtc_timer_cnt_value_get(RTC_TIMER_ID_1);
dprintf("first time get cnt value, timer0:%d, timer1:%d\n", cnt_tmr0_0, cnt_tmr1_0);
dprintf("gptimer delay %dus, rtc tick:%d\n", delay_us, rtc_tick_us);
iot_delay_us(delay_us);
cnt_tmr0_1 = rtc_timer_cnt_value_get(RTC_TIMER_ID_0);
cnt_tmr1_1 = rtc_timer_cnt_value_get(RTC_TIMER_ID_1);
dprintf("after delay get cnt value, timer0:%d, timer1:%d\n", cnt_tmr0_1, cnt_tmr1_1);
cnt_d0 = cnt_tmr0_1 - cnt_tmr0_0;
cnt_d1 = cnt_tmr1_1 - cnt_tmr1_0;
dprintf("get cnt diff, timer0:%d, timer1:%d\n", cnt_d0, cnt_d1);
if (cnt_d0 < rtc_tick_us || cnt_d1 < rtc_tick_us) {
dprintf("rtc count value is less than the delay time\n");
goto fail;
}
/* set rtc timer cuonter value */
dprintf("set rtc timer0/1 counter value to 0\n");
rtc_timer_cnt_value_set(RTC_TIMER_ID_0, 0x00);
rtc_timer_cnt_value_set(RTC_TIMER_ID_1, 0x00);
dprintf("gptimer delay %dus, rtc tick:%d\n", delay_us, rtc_tick_us);
iot_delay_us(delay_us);
cnt_tmr0_1 = rtc_timer_cnt_value_get(RTC_TIMER_ID_0);
cnt_tmr1_1 = rtc_timer_cnt_value_get(RTC_TIMER_ID_1);
dprintf("after delay get cnt value, timer0:%d, timer1:%d\n", cnt_tmr0_1, cnt_tmr1_1);
if ((cnt_tmr0_1 < rtc_tick_us || cnt_tmr1_1 < rtc_tick_us)
|| (cnt_tmr0_1 >= 2 * rtc_tick_us || cnt_tmr1_1 >= 2 * rtc_tick_us)) {
dprintf("rtc count value deviates from the expected value\n");
goto fail;
}
dcase_success();
return ERR_OK;
fail:
dcase_failed();
return ERR_FAIL;
}
static uint32_t dtest_rtc_pause_regain_test()
{
uint32_t cnt_tmr0_0, cnt_tmr1_0, cnt_tmr0_1, cnt_tmr1_1, cnt_d0, cnt_d1;
uint32_t delay_us = 1000000;
uint32_t rtc_tick_us = DTEST_RTC_MS_TO_RTC_TICK(delay_us / 1000);
dcase_start("rtc timer pause and regain\n");
/* pause and regain test */
cnt_tmr0_0 = rtc_timer_cnt_value_get(RTC_TIMER_ID_0);
cnt_tmr1_0 = rtc_timer_cnt_value_get(RTC_TIMER_ID_1);
dprintf("beform pause get cnt value, timer0:%d, timer1:%d\n", cnt_tmr0_0, cnt_tmr1_0);
dprintf("pause rtc timer0/1 and delay %dus\n", delay_us);
rtc_timer_cnt_pause(RTC_TIMER_ID_0, 1);
rtc_timer_cnt_pause(RTC_TIMER_ID_1, 1);
dprintf("timer delay %dus, rtc tick:%d\n", delay_us, rtc_tick_us);
iot_delay_us(delay_us);
cnt_tmr0_1 = rtc_timer_cnt_value_get(RTC_TIMER_ID_0);
cnt_tmr1_1 = rtc_timer_cnt_value_get(RTC_TIMER_ID_1);
dprintf("after pause get cnt value, timer0:%d, timer1:%d\n", cnt_tmr0_1, cnt_tmr1_1);
cnt_d0 = cnt_tmr0_1 - cnt_tmr0_0;
cnt_d1 = cnt_tmr1_1 - cnt_tmr1_0;
dprintf("get cnt diff, timer0:%d, timer1:%d\n", cnt_d0, cnt_d1);
if (cnt_d0 >= rtc_tick_us || cnt_d1 >= rtc_tick_us) {
dprintf("pause rtc timer failed\n");
goto fail;
}
dprintf("regain rtc timer0/1 and delay %dus\n", delay_us);
rtc_timer_cnt_pause(RTC_TIMER_ID_0, 0);
rtc_timer_cnt_pause(RTC_TIMER_ID_1, 0);
dprintf("timer delay %dus, rtc tick:%d\n", delay_us, rtc_tick_us);
iot_delay_us(delay_us);
cnt_tmr0_0 = rtc_timer_cnt_value_get(RTC_TIMER_ID_0);
cnt_tmr1_0 = rtc_timer_cnt_value_get(RTC_TIMER_ID_1);
dprintf("after regain get cnt value, timer0:%d, timer1:%d\n", cnt_tmr0_0, cnt_tmr1_0);
cnt_d0 = cnt_tmr0_0 - cnt_tmr0_1;
cnt_d1 = cnt_tmr1_0 - cnt_tmr1_1;
dprintf("get cnt diff, timer0:%d, timer1:%d\n", cnt_d0, cnt_d1);
if (cnt_d0 + DTEST_RTC_OPT_CNT_COMPENSATION < rtc_tick_us ||
cnt_d1 + DTEST_RTC_OPT_CNT_COMPENSATION< rtc_tick_us) {
dprintf("regain rtc timer failed\n");
goto fail;
}
dcase_success();
return ERR_OK;
fail:
dcase_failed();
return ERR_FAIL;
}
static uint32_t dtest_rtc_start_stop_test()
{
uint32_t cnt_tmr0_0, cnt_tmr1_0, cnt_tmr0_1, cnt_tmr1_1, cnt_d0, cnt_d1;
uint32_t delay_us = 1000000;
uint32_t rtc_tick_us = DTEST_RTC_MS_TO_RTC_TICK(delay_us / 1000);
dcase_start("rtc timer start and stop\n");
/* start and stop test */
cnt_tmr0_0 = rtc_timer_cnt_value_get(RTC_TIMER_ID_0);
cnt_tmr1_0 = rtc_timer_cnt_value_get(RTC_TIMER_ID_1);
dprintf("beform stop get cnt value, timer0:%d, timer1:%d\n", cnt_tmr0_0, cnt_tmr1_0);
dprintf("stop rtc timer0/1 and delay %dus\n", delay_us);
rtc_timer_cnt_disable(RTC_TIMER_ID_0);
rtc_timer_cnt_disable(RTC_TIMER_ID_1);
dprintf("timer delay %dus, rtc tick:%d\n", delay_us, rtc_tick_us);
iot_delay_us(delay_us);
cnt_tmr0_1 = rtc_timer_cnt_value_get(RTC_TIMER_ID_0);
cnt_tmr1_1 = rtc_timer_cnt_value_get(RTC_TIMER_ID_1);
dprintf("after stop get cnt value, timer0:%d, timer1:%d\n", cnt_tmr0_1, cnt_tmr1_1);
cnt_d0 = cnt_tmr0_1 - cnt_tmr0_0;
cnt_d1 = cnt_tmr1_1 - cnt_tmr1_0;
dprintf("get cnt diff, timer0:%d, timer1:%d\n", cnt_d0, cnt_d1);
if (cnt_d0 >= rtc_tick_us || cnt_d1 >= rtc_tick_us) {
dprintf("stop rtc timer failed\n");
goto fail;
}
dprintf("restart rtc timer0/1 and delay %dus, rtc tick:%d\n", delay_us, rtc_tick_us);
rtc_timer_cnt_enable(RTC_TIMER_ID_0);
rtc_timer_cnt_enable(RTC_TIMER_ID_1);
iot_delay_us(delay_us);
cnt_tmr0_0 = rtc_timer_cnt_value_get(RTC_TIMER_ID_0);
cnt_tmr1_0 = rtc_timer_cnt_value_get(RTC_TIMER_ID_1);
dprintf("after restart get cnt value, timer0:%d, timer1:%d\n", cnt_tmr0_0, cnt_tmr1_0);
if (cnt_tmr0_0 < cnt_tmr0_1 && cnt_tmr1_0 < cnt_tmr1_1) {
dprintf("cnt enable will start form 0!!!\n");
}
cnt_d0 = cnt_tmr0_0 - cnt_tmr0_1;
cnt_d1 = cnt_tmr1_0 - cnt_tmr1_1;
dprintf("get cnt diff, timer0:%d, timer1:%d\n", cnt_d0, cnt_d1);
if (cnt_d0 + DTEST_RTC_OPT_CNT_COMPENSATION < rtc_tick_us ||
cnt_d1 + DTEST_RTC_OPT_CNT_COMPENSATION < rtc_tick_us) {
dprintf("restart rtc timer failed\n");
goto fail;
}
dcase_success();
return ERR_OK;
fail:
dcase_failed();
return ERR_FAIL;
}
static uint32_t dtest_rtc_interrupt_handle(uint32_t vector, iot_addrword_t data)
{
uint32_t scratch_val = ahb_scratch_reg_get(DTEST_RTC_SCRATCH_INDEX);;
dprintf("interrupt trigger, vector:%d, data:%d\n", vector, data);
if (vector == HAL_VECTOR_RTC_TMR_0 && data == RTC_TIMER_ID_0) {
dprintf("timer 0 interrupt\n");
} else if (vector == HAL_VECTOR_RTC_TMR_1 && data == RTC_TIMER_ID_1) {
dprintf("timer 1 interrupt\n");
} else {
dprintf("interrupt source or data error\n");
IOT_ASSERT(0);
}
rtc_timer_int_clear(data);
ahb_scratch_reg_set(DTEST_RTC_SCRATCH_INDEX, scratch_val | (1 << data));
return 0;
}
static uint32_t dtest_rtc_interrupt_test()
{
uint8_t i;
uint32_t vector, temp;
uint32_t wait_delay_us = 100000, wait_cnt_max = 70; //7s
iot_irq_t rtc_irq[RTC_TIMER_ID_MAX];
uint32_t delay_us = 3 * 1000 * 1000; //3s
uint32_t rtc_tick_us = DTEST_RTC_MS_TO_RTC_TICK(delay_us / 1000);
dcase_start("rtc interrupt test\n");
/* init scratch register */
ahb_scratch_reg_set(DTEST_RTC_SCRATCH_INDEX, 0);
/* rtc interrupt trigger condition set */
rtc_timer_cnt_disable(RTC_TIMER_ID_0);
rtc_timer_cnt_disable(RTC_TIMER_ID_1);
/* timer0 sets the count value by the compensation value */
temp = rtc_timer_cnt_value_get(RTC_TIMER_ID_0);
temp = 0xffffffff - temp - rtc_tick_us;
rtc_timer_cnt_compensate_set(RTC_TIMER_ID_0, 1, temp);
/* timer1 sets the interrupt by modifying the threshold */
rtc_timer_cnt_value_max_set(RTC_TIMER_ID_1, rtc_tick_us);
rtc_timer_cnt_value_set(RTC_TIMER_ID_1, 0x00);
/* enable cnt */
rtc_timer_cnt_enable(RTC_TIMER_ID_0);
rtc_timer_cnt_enable(RTC_TIMER_ID_1);
/* rtc interrupt enable */
rtc_timer_int_clear(RTC_TIMER_ID_0);
rtc_timer_int_clear(RTC_TIMER_ID_1);
rtc_timer_int_enable(RTC_TIMER_ID_0);
rtc_timer_int_enable(RTC_TIMER_ID_1);
/* interrupt handle create */
for (i = RTC_TIMER_ID_0; i < RTC_TIMER_ID_MAX; i++) {
vector = rtc_timer_get_vector(i);
rtc_irq[i] = iot_interrupt_create(vector, HAL_INTR_PRI_6,
(iot_addrword_t)i, dtest_rtc_interrupt_handle);
iot_interrupt_attach(rtc_irq[i]);
iot_interrupt_unmask(rtc_irq[i]);
}
/* waiting interrupt function exit */
i = 0;
while (ahb_scratch_reg_get(DTEST_RTC_SCRATCH_INDEX) != 0x3) {
iot_delay_us(wait_delay_us);
i++;
if (i >= wait_cnt_max) {
break;
}
}
rtc_timer_int_disable(RTC_TIMER_ID_0);
rtc_timer_int_disable(RTC_TIMER_ID_1);
if (i >= wait_cnt_max) {
dcase_failed();
return ERR_FAIL;
}
dcase_success();
return ERR_OK;
}
static uint32_t dtest_rtc_cascade_test()
{
uint64_t cnt = 0, cnt_expect;
uint32_t delay_us = 1 * 1000 * 1000; //1s
uint32_t rtc_tick_us = DTEST_RTC_MS_TO_RTC_TICK(delay_us / 1000);
uint32_t cnt_h, cnt_l;
dcase_start("rtc cascade test\n");
rtc_deinit();
rtc_init(RTC_INIT_MODE_CASCADE);
/* reconfigure to ensure that the count value exceeding MAX_UINT32 */
dprintf("reconfigure to ensure that the count value exceeding MAX_UINT32\n");
rtc_timer_cnt_disable(RTC_TIMER_ID_0);
// rtc_timer_cnt_disable(RTC_TIMER_ID_1);
rtc_timer_cnt_value_set(RTC_TIMER_ID_0, 0xffffffff);
rtc_timer_cnt_value_set(RTC_TIMER_ID_1, 0);
rtc_timer_cnt_enable(RTC_TIMER_ID_0);
// rtc_timer_cnt_enable(RTC_TIMER_ID_1);
/* delay sometime */
dprintf("gptimer delay %dus, rtc tick:%d\n", delay_us, rtc_tick_us);
iot_delay_us(delay_us);
cnt = rtc_cascade_cnt_get();
cnt_h = (cnt >> 32) & 0xffffffff;
cnt_l = cnt & 0xffffffff;
dprintf("get rtc cascade cnt:%d(H), %d(L)\n", cnt_h, cnt_l);
dprintf("get rtc cascade cnt:%llu\n", cnt);
cnt_expect = (uint64_t)0xffffffff + (uint64_t)rtc_tick_us;
cnt_h = (cnt_expect >> 32) & 0xffffffff;
cnt_l = cnt_expect & 0xffffffff;
dprintf("get rtc cascade cnt expect:%d(H), %d(L)\n", cnt_h, cnt_l);
dprintf("get rtc cascade cnt expect:%llu\n", cnt_expect);
if (cnt + DTEST_RTC_OPT_CNT_COMPENSATION <= cnt_expect ||
cnt_h != 1) {
dprintf("timer cnt less than expected\n");
goto fail;
}
dcase_success();
return ERR_OK;
fail:
dcase_failed();
return ERR_FAIL;
}
extern struct uart_ctrl uart_e_ctrl;
static uint32_t dtest_rtc_accuracy_test()
{
uint32_t cnt_old, cnt_new, cnt_d;
uint32_t ms_old, ms_new, ms_d;
uint32_t sec_old, sec_new, sec_d;
uint32_t delay_us = 3600000000; // 1*60*60*1000*1000 = 1th
uint32_t rtc_tick_us = DTEST_RTC_MS_TO_RTC_TICK(delay_us / 1000), tick_diff;
dcase_start("rtc accuracy test\n");
for (uint8_t i = 0; i < 3; i++) {
wdg_deinit(i);
}
rtc_timer_cnt_value_set(RTC_TIMER_ID_0, 0);
uart_e_ctrl.putc(0, 'a');
uart_e_ctrl.putc(0, 'a');
uart_e_ctrl.putc(0, 'a');
uart_e_ctrl.putc(0, '\n');
cnt_old = rtc_timer_cnt_value_get(RTC_TIMER_ID_0);
uart_e_ctrl.putc(0, 'b');
uart_e_ctrl.putc(0, '\n');
for (uint8_t i = 0; i < 24; i++) {
iot_delay_us(delay_us);
}
cnt_new = rtc_timer_cnt_value_get(RTC_TIMER_ID_0);
uart_e_ctrl.putc(0, 'c');
uart_e_ctrl.putc(0, '\n');
ms_old = DTEST_RTC_TICK_TO_MS(cnt_old);
sec_old = DTEST_RTC_TICK_TO_S(cnt_old);
dprintf("get first second:%lu, ms:%lu, cnt:%lu\n", sec_old, ms_old, cnt_old);
dprintf("gptimer delay %ds(%dms)\n", delay_us / 1000 / 1000, delay_us / 1000);
ms_new = DTEST_RTC_TICK_TO_MS(cnt_new);
sec_new = DTEST_RTC_TICK_TO_S(cnt_new);
dprintf("get last second:%lu, ms:%lu, cnt:%lu\n", sec_new, ms_new, cnt_new);
sec_d = sec_new - sec_old;
ms_d = ms_new - ms_old;
cnt_d = cnt_new - cnt_old;
dprintf("second diff:%lu, ms diff:%lu, cnt diff:%lu\n", sec_d, ms_d, cnt_d);
tick_diff = ((rtc_tick_us > cnt_d) ? (rtc_tick_us - cnt_d) : (cnt_d - rtc_tick_us));
dprintf("cnt diff:%lu, expect:%lu, diff:%lu\n", cnt_d, rtc_tick_us, tick_diff);
dcase_success();
return ERR_OK;
}
extern void wdg_eb_enable(uint8_t cpu);
static uint32_t dtest_rtc_wdg_rst_test()
{
uint8_t core = cpu_get_mhartid();
uint32_t rst_delay = 3;
volatile uint32_t *rtc_reg_ptr = (volatile uint32_t *)(RTC_TMR0_BASEADDR);
dcase_start("rtc watchdog reset test\n");
dprintf("rtc register dump:\n");
for (uint8_t i = 0; i < 28 / 4; i++) {
iot_printf("\t%p:\t0x%08x\t0x%08x\t0x%08x\t0x%08x\n", rtc_reg_ptr,
*rtc_reg_ptr, *(rtc_reg_ptr + 1), *(rtc_reg_ptr + 2), *(rtc_reg_ptr + 3));
rtc_reg_ptr += 4;
}
dprintf("module will be reset by wdg after %ds\n", rst_delay);
wdg_eb_enable(core);
wdg_set_cmp(core, SYS_CLK_VAL);
wdg_set_timeout_cmp(core, rst_delay * 10);
wdg_set_cpurst_cmp(core, rst_delay * 10);
wdg_set_fullrst_cmp(core, rst_delay);
wdg_cnt_enable(core);
wdg_enable(core);
while(1) {
iot_delay_us(500 * 1000);
iot_printf(".");
}
dcase_success();
return ERR_OK;
}
static void dtest_rtc_main()
{
uint32_t case_group = 0, failed_cnt = 0;
dbg_uart_init();
dconfig();
dstart();
dversion();
if (dtest_get_case_group(&case_group) < 0) {
case_group = 0xffffffff;
}
dprintf("get case group:0x%08X\n", case_group);
gp_timer_init();
gp_timer_set(0, 0xffffffff, 0);
gp_timer_start(0);
rtc_init(RTC_INIT_MODE_TIMER);
if (case_group & DTEST_RTC_CASE_TIMER_CNT_GET_SET) {
if (dtest_rtc_cnt_get_set_test()) {
failed_cnt++;
}
}
if (case_group & DTEST_RTC_CASE_TIMER_PAUSE_REGAIN) {
if (dtest_rtc_pause_regain_test()) {
failed_cnt++;
}
}
if (case_group & DTEST_RTC_CASE_TIMER_START_STOP) {
if (dtest_rtc_start_stop_test()) {
failed_cnt++;
}
}
if (case_group & DTEST_RTC_CASE_TIMER_INTERRUPT) {
if (dtest_rtc_interrupt_test()) {
failed_cnt++;
}
}
if (case_group & DTEST_RTC_CASE_TIMER_CASCADE) {
if (dtest_rtc_cascade_test()) {
failed_cnt++;
}
}
/* manual test */
// if (case_group & DTEST_RTC_CASE_TIMER_ACCURACY) {
if (0) {
if (dtest_rtc_accuracy_test()) {
failed_cnt++;
}
}
/* manual test, use gdb dump register after wdg reset */
// if (case_group & DTEST_RTC_CASE_WDG_RESET) {
if (0) {
if (dtest_rtc_wdg_rst_test()) {
failed_cnt++;
}
}
if (failed_cnt) {
dprintf("rtc dtest failed\n");
} else {
dprintf("rtc dtest succeed\n");
}
dend();
return;
}
int main(void)
{
dtest_rtc_main();
return 0;
}