482 lines
14 KiB
C
482 lines
14 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 "iot_bitops.h"
|
||
#include "os_lock.h"
|
||
#include "iot_config.h"
|
||
#include "dtest_printf.h"
|
||
#include "cpu.h"
|
||
#include "ahb.h"
|
||
#include "iot_gptmr_api.h"
|
||
#include "iot_spinlock.h"
|
||
#include "gp_timer.h"
|
||
#if HW_PLATFORM > HW_PLATFORM_SIMU
|
||
#include "dbg_io.h"
|
||
#endif
|
||
#include "iot_io.h"
|
||
#include "gpio_hw.h"
|
||
#include "hw_reg_api.h"
|
||
#include "iot_gpio.h"
|
||
#include "gtmr_reg.h"
|
||
|
||
uint32_t gp_timer_reg_read(uint32_t reg);
|
||
void gp_timer_reg_write(uint32_t reg, uint32_t data);
|
||
|
||
#define GPTMR_TEST_SPINLOCK 5
|
||
|
||
uint32_t g_tmr_count = 0;
|
||
|
||
extern void _core_start(void);
|
||
uint32_t gp_timer_get_current_val(uint8_t);
|
||
|
||
uint8_t gptmr_isr(iot_addrword_t data)
|
||
{
|
||
g_tmr_count++;
|
||
|
||
return 0;
|
||
}
|
||
|
||
void gptmr_core2_loop(void)
|
||
{
|
||
uint32_t cur_cpu = cpu_get_mhartid(), next_cnt = 0, loop, spinlock = GPTMR_TEST_SPINLOCK;
|
||
|
||
iot_spinlock_lock(spinlock, cur_cpu);
|
||
dprintf("CPU %d : Start!!!\n", cur_cpu);
|
||
iot_spinlock_unlock(spinlock, cur_cpu);
|
||
|
||
iot_gp_timer_set(0, 0xFFFFFFFF, 1);
|
||
|
||
iot_gp_timer_start(0);
|
||
|
||
for(;;) {
|
||
if (next_cnt < gp_timer_get_current_val(0)) {
|
||
iot_spinlock_lock(spinlock, cur_cpu);
|
||
dprintf("I'm CPU %d : tmr 0 count %d\n", cur_cpu, next_cnt);
|
||
iot_spinlock_unlock(spinlock, cur_cpu);
|
||
next_cnt += 2000000;
|
||
}
|
||
|
||
loop = 0;
|
||
|
||
while(loop++ < 100000) __asm volatile ("nop\n");
|
||
}
|
||
}
|
||
|
||
#define COUNTER_TIMER_ID 0
|
||
void gptmr_div_freq_test()
|
||
{
|
||
uint32_t tmp;
|
||
uint32_t timer0_val, timer1_val, timer2_val;
|
||
dcase_start("gp_timer div freq test\n");
|
||
/* 时钟1M,分频系数1 */
|
||
tmp = gp_timer_reg_read(CFG_GTMR0_CTRL_CFG_ADDR);
|
||
REG_FIELD_SET(TMR0_TICK_SEL, tmp, 1); //1m tick sel
|
||
gp_timer_reg_write(CFG_GTMR0_CTRL_CFG_ADDR, tmp);
|
||
/* 分频 1 */
|
||
gp_timer_reg_write(CFG_GTMR0_DIV_ADDR, 1);
|
||
gp_timer_set(0, 1000000, 0);
|
||
|
||
/* 时钟25M,分频系数1 */
|
||
tmp = gp_timer_reg_read(CFG_GTMR1_CTRL_CFG_ADDR);
|
||
REG_FIELD_SET(TMR0_TICK_SEL, tmp, 0); //25m tick sel
|
||
gp_timer_reg_write(CFG_GTMR1_CTRL_CFG_ADDR, tmp);
|
||
/* 分频 1 */
|
||
gp_timer_reg_write(CFG_GTMR1_DIV_ADDR, 1);
|
||
gp_timer_set(1, 100000000, 0);
|
||
|
||
/* 时钟25M,分频系数5 */
|
||
tmp = gp_timer_reg_read(CFG_GTMR2_CTRL_CFG_ADDR);
|
||
REG_FIELD_SET(TMR0_TICK_SEL, tmp, 0); //25m tick sel
|
||
gp_timer_reg_write(CFG_GTMR2_CTRL_CFG_ADDR, tmp);
|
||
/* 分频 5 */
|
||
gp_timer_reg_write(CFG_GTMR2_DIV_ADDR, 5);
|
||
gp_timer_set(2, 100000000, 0);
|
||
/* 启动 */
|
||
gp_timer_start(0);
|
||
gp_timer_start(1);
|
||
gp_timer_start(2);
|
||
|
||
while(!(gp_timer_get_int_status(0) & TMR0_INT_RAW_MASK));
|
||
gp_timer_stop(0);
|
||
gp_timer_stop(1);
|
||
gp_timer_stop(2);
|
||
/* timer0_val 1000000 */
|
||
timer0_val = gp_timer_get_current_val(0);
|
||
/* timer1_val 25000000 左右 */
|
||
timer1_val = gp_timer_get_current_val(1);
|
||
/* timer2_val 5000000 左右 */
|
||
timer2_val = gp_timer_get_current_val(2);
|
||
dprintf("timer0 val:%u timer1 val:%u timer2 val:%u\n",
|
||
timer0_val, timer1_val, timer2_val);
|
||
gp_timer_clear_int_status(0);
|
||
|
||
/* 时钟切回1m */
|
||
tmp = gp_timer_reg_read(CFG_GTMR1_CTRL_CFG_ADDR);
|
||
REG_FIELD_SET(TMR0_TICK_SEL, tmp, 1); //1m tick sel
|
||
gp_timer_reg_write(CFG_GTMR1_CTRL_CFG_ADDR, tmp);
|
||
tmp = gp_timer_reg_read(CFG_GTMR2_CTRL_CFG_ADDR);
|
||
REG_FIELD_SET(TMR0_TICK_SEL, tmp, 1); //1m tick sel
|
||
gp_timer_reg_write(CFG_GTMR2_CTRL_CFG_ADDR, tmp);
|
||
}
|
||
|
||
void gptmr_repeat_test()
|
||
{
|
||
uint32_t repeat_cnt = 0;
|
||
dcase_start("gp_timer repeat test\n");
|
||
|
||
gp_timer_init();
|
||
gp_timer_set(0, 1000000, 1);
|
||
gp_timer_set(1, 5000000, 0);
|
||
gp_timer_start(0);
|
||
gp_timer_start(1);
|
||
while(repeat_cnt < 3) {
|
||
if (gp_timer_get_int_status(0) & TMR0_INT_RAW_MASK) {
|
||
gp_timer_clear_int_status(0);
|
||
repeat_cnt++;
|
||
}
|
||
|
||
if (gp_timer_get_int_status(1) & TMR1_INT_RAW_MASK) {
|
||
gp_timer_clear_int_status(1);
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (repeat_cnt != 3) {
|
||
dcase_failed();
|
||
} else {
|
||
dcase_success();
|
||
}
|
||
gp_timer_stop(0);
|
||
}
|
||
|
||
void gptmr_start_pause_stop_test()
|
||
{
|
||
/* 使用timer0作为计时,timer1用作测试 */
|
||
uint32_t timer1_val1, timer1_val2, tmp;
|
||
|
||
dcase_start("gp_timer start pause stop test\n");
|
||
gp_timer_init();
|
||
/* 启动timer1 100s */
|
||
gp_timer_set(1, 100000000, 1);
|
||
gp_timer_start(1);
|
||
|
||
/* 获取当前timer1的计数值 */
|
||
timer1_val1 = gp_timer_get_current_val(1);
|
||
dprintf("start timer1 start: val:%u\n", timer1_val1);
|
||
/* 计时1s钟 */
|
||
gp_timer_set(COUNTER_TIMER_ID, 1000000, 1);
|
||
gp_timer_start(COUNTER_TIMER_ID);
|
||
while(!(gp_timer_get_int_status(COUNTER_TIMER_ID) & TMR0_INT_RAW_MASK));
|
||
gp_timer_clear_int_status(COUNTER_TIMER_ID);
|
||
timer1_val2 = gp_timer_get_current_val(1);
|
||
dprintf("start timer1 end: val:%u\n", timer1_val2);
|
||
/* 数值没有变,则timer没有启动 */
|
||
if (timer1_val1 == timer1_val2) {
|
||
dcase_failed();
|
||
return;
|
||
}
|
||
/* 停止timer1 */
|
||
gp_timer_stop(1);
|
||
/* 获取当前timer1的计数值 */
|
||
timer1_val1 = gp_timer_get_current_val(1);
|
||
dprintf("stop timer1 start: val:%u\n", timer1_val1);
|
||
/* 计时1s */
|
||
while(!(gp_timer_get_int_status(COUNTER_TIMER_ID) & TMR0_INT_RAW_MASK));
|
||
gp_timer_clear_int_status(COUNTER_TIMER_ID);
|
||
timer1_val2 = gp_timer_get_current_val(1);
|
||
dprintf("stop timer1 end: val:%u\n", timer1_val2);
|
||
/* 数值变化了,则timer没有停止 */
|
||
if (timer1_val1 != timer1_val2) {
|
||
dcase_failed();
|
||
return;
|
||
}
|
||
|
||
/* 启动timer1 */
|
||
gp_timer_set(1, 100000000, 1);
|
||
gp_timer_start(1);
|
||
/* 获取当前timer1的计数值 */
|
||
timer1_val1 = gp_timer_get_current_val(1);
|
||
dprintf("pause timer1 val:%u\n", timer1_val1);
|
||
/* 计时1s钟 */
|
||
while(!(gp_timer_get_int_status(COUNTER_TIMER_ID) & TMR0_INT_RAW_MASK));
|
||
gp_timer_clear_int_status(COUNTER_TIMER_ID);
|
||
timer1_val2 = gp_timer_get_current_val(1);
|
||
dprintf("pause timer1 start: val:%u\n", timer1_val2);
|
||
/* 数值没有变,则timer没有启动 */
|
||
if (timer1_val1 == timer1_val2) {
|
||
dcase_failed();
|
||
return;
|
||
}
|
||
/* 暂停timer1 */
|
||
tmp = gp_timer_reg_read(CFG_GTMR1_CTRL_CFG_ADDR);
|
||
REG_FIELD_SET(TMR1_PAUSE_CFG, tmp, 1);
|
||
gp_timer_reg_write(CFG_GTMR1_CTRL_CFG_ADDR, tmp);
|
||
/* 获取当前timer1的计数值 */
|
||
timer1_val1 = gp_timer_get_current_val(1);
|
||
dprintf("pause timer1 val:%u\n", timer1_val1);
|
||
/* 计时1s */
|
||
while(!(gp_timer_get_int_status(COUNTER_TIMER_ID) & TMR0_INT_RAW_MASK));
|
||
gp_timer_clear_int_status(COUNTER_TIMER_ID);
|
||
timer1_val2 = gp_timer_get_current_val(1);
|
||
dprintf("pause timer1 end: val:%u\n", timer1_val2);
|
||
|
||
/* 数值变化了,则timer没有暂停 */
|
||
if (timer1_val1 != timer1_val2) {
|
||
dcase_failed();
|
||
return;
|
||
}
|
||
/* 取消暂停 */
|
||
tmp = gp_timer_reg_read(CFG_GTMR1_CTRL_CFG_ADDR);
|
||
REG_FIELD_SET(TMR1_PAUSE_CFG, tmp, 0);
|
||
gp_timer_reg_write(CFG_GTMR1_CTRL_CFG_ADDR, tmp);
|
||
|
||
gp_timer_stop(COUNTER_TIMER_ID);
|
||
gp_timer_stop(1);
|
||
dcase_success();
|
||
}
|
||
|
||
void gptmr_interrupt_test()
|
||
{
|
||
uint32_t cur_cpu = cpu_get_mhartid();
|
||
uint32_t timer_id1, timer_id2;
|
||
dcase_start("gp_timer interrupt test\n");
|
||
iot_gp_timer_init();
|
||
|
||
timer_id1 = iot_gp_timer_create(cur_cpu, NULL, gptmr_isr, 0);
|
||
iot_gp_timer_set(timer_id1, 1000000, 0);
|
||
iot_gp_timer_start(timer_id1);
|
||
|
||
timer_id2 = iot_gp_timer_create(cur_cpu, NULL, gptmr_isr, 0);
|
||
iot_gp_timer_set(timer_id2, 2000000, 0);
|
||
iot_gp_timer_start(timer_id2);
|
||
|
||
while(gp_timer_get_current_val(timer_id2) < 1500000) {
|
||
if (g_tmr_count > 0) {
|
||
dcase_success();
|
||
iot_gp_timer_stop(timer_id1);
|
||
iot_gp_timer_stop(timer_id2);
|
||
return;
|
||
}
|
||
}
|
||
dcase_failed();
|
||
}
|
||
|
||
void gptmr_precision_test()
|
||
{
|
||
uint32_t cpu_cycle1, cpu_cycle2;
|
||
dcase_start("gp_timer precision test\n");
|
||
/* 计时1s钟 */
|
||
gp_timer_set(COUNTER_TIMER_ID, 1000000, 0);
|
||
gp_timer_start(COUNTER_TIMER_ID);
|
||
cpu_cycle1 = cpu_get_mcycle();
|
||
while(!(gp_timer_get_int_status(COUNTER_TIMER_ID) & TMR0_INT_RAW_MASK));
|
||
gp_timer_clear_int_status(COUNTER_TIMER_ID);
|
||
cpu_cycle2 = cpu_get_mcycle();
|
||
dprintf("gp_timer delta: 1000000 cpu_cycle delta:%u\n",
|
||
cpu_cycle2 - cpu_cycle1);
|
||
}
|
||
|
||
void gptmr_gpio_latch_test()
|
||
{
|
||
#define TEST_TIMER_ID 3
|
||
#define INPUT_GPIO 28
|
||
|
||
uint32_t value1, value2;
|
||
dcase_start("gp_timer gpio_latch test\n");
|
||
/* 开始计时 */
|
||
gp_timer_set(TEST_TIMER_ID, 0xffffffff, 0);
|
||
gp_timer_set_gpio_latch(TEST_TIMER_ID, INPUT_GPIO);
|
||
gp_timer_start(TEST_TIMER_ID);
|
||
hw_gpio_api_table.gpio_init();
|
||
hw_gpio_api_table.set_gpio_mode(INPUT_GPIO, GPIO_OUTPUT);
|
||
/* 输入管脚拉低,开始计数 */
|
||
hw_gpio_api_table.set_value(INPUT_GPIO, 0);
|
||
|
||
gp_timer_set(COUNTER_TIMER_ID, 1000000, 0);
|
||
gp_timer_start(COUNTER_TIMER_ID);
|
||
while(!(gp_timer_get_int_status(COUNTER_TIMER_ID) & TMR0_INT_RAW_MASK));
|
||
gp_timer_clear_int_status(COUNTER_TIMER_ID);
|
||
/* 输入管脚拉高,停止计数 */
|
||
hw_gpio_api_table.set_value(INPUT_GPIO, 1);
|
||
value1 = gp_timer_get_current_val(TEST_TIMER_ID);
|
||
dprintf("gp_timer value1: %d\n", value1);
|
||
gp_timer_set(COUNTER_TIMER_ID, 1000000, 0);
|
||
gp_timer_start(COUNTER_TIMER_ID);
|
||
while(!(gp_timer_get_int_status(COUNTER_TIMER_ID) & TMR0_INT_RAW_MASK));
|
||
gp_timer_clear_int_status(COUNTER_TIMER_ID);
|
||
value2 = gp_timer_get_current_val(TEST_TIMER_ID);
|
||
dprintf("gp_timer value2:%u\n", value2);
|
||
|
||
gp_timer_stop(COUNTER_TIMER_ID);
|
||
gp_timer_stop(TEST_TIMER_ID);
|
||
|
||
if (value1 == value2) {
|
||
dcase_success();
|
||
} else {
|
||
dcase_failed();
|
||
}
|
||
#undef TEST_TIMER_ID
|
||
#undef INPUT_GPIO
|
||
}
|
||
void gp_timer_reg_write(uint32_t reg, uint32_t data);
|
||
uint32_t gp_timer_reg_read(uint32_t reg);
|
||
|
||
void gptmr_64bit_timer(void)
|
||
{
|
||
#define DELAY_TIMER_ID 2
|
||
#define TIMER_64BIT_ID0 0
|
||
#define TIMER_64BIT_ID1 1
|
||
uint32_t tmp;
|
||
dcase_start("gp_timer 64bit timer test\n");
|
||
gp_timer_reg_write(CFG_TMR64_SEL_ADDR, 0x1);
|
||
/* timer 0 low 32bit timer 1 high 32bit */
|
||
gp_timer_set(TIMER_64BIT_ID0, 1098, 0);
|
||
gp_timer_set(TIMER_64BIT_ID1, 1, 0);
|
||
/* 切换时钟为25m */
|
||
tmp = gp_timer_reg_read(CFG_GTMR0_CTRL_CFG_ADDR);
|
||
REG_FIELD_SET(TMR0_TICK_SEL, tmp, 0); //25m tick sel
|
||
gp_timer_reg_write(CFG_GTMR0_CTRL_CFG_ADDR, tmp);
|
||
gp_timer_start(TIMER_64BIT_ID0);
|
||
/* 打印间隔 1s */
|
||
gp_timer_set(DELAY_TIMER_ID, 1000000, 1);
|
||
gp_timer_start(DELAY_TIMER_ID);
|
||
while(1) {
|
||
while(!(gp_timer_get_int_status(DELAY_TIMER_ID) & TMR2_INT_RAW_MASK));
|
||
gp_timer_clear_int_status(DELAY_TIMER_ID);
|
||
dprintf("64bit timer value high: [%u] low:[%u]\n",
|
||
gp_timer_get_current_val(TIMER_64BIT_ID1), gp_timer_get_current_val(TIMER_64BIT_ID0));
|
||
if (gp_timer_get_int_status(TIMER_64BIT_ID0) & TMR0_INT_STS_MASK) {
|
||
dprintf("64bit timer interrupt status OK\n");
|
||
dcase_success();
|
||
gp_timer_clear_int_status(TIMER_64BIT_ID0);
|
||
break;
|
||
}
|
||
}
|
||
|
||
gp_timer_stop(DELAY_TIMER_ID);
|
||
/* 切换为32bit timer */
|
||
gp_timer_reg_write(CFG_TMR64_SEL_ADDR, 0x0);
|
||
}
|
||
|
||
void gptmr_core0_loop(void)
|
||
{
|
||
uint32_t cur_cpu = cpu_get_mhartid(), next_cnt = 0, loop, spinlock = GPTMR_TEST_SPINLOCK;
|
||
|
||
iot_spinlock_lock(spinlock, cur_cpu);
|
||
dprintf("CPU %d : Start!!!\n", cur_cpu);
|
||
iot_spinlock_unlock(spinlock, cur_cpu);
|
||
dstart();
|
||
dversion();
|
||
gp_timer_init();
|
||
gptmr_div_freq_test();
|
||
gptmr_repeat_test();
|
||
gptmr_start_pause_stop_test();
|
||
gptmr_precision_test();
|
||
gptmr_gpio_latch_test();
|
||
gptmr_64bit_timer();
|
||
gptmr_interrupt_test();
|
||
dend();
|
||
iot_gp_timer_set(0, 0xFFFFFFFF, 1);
|
||
|
||
iot_gp_timer_start(0);
|
||
|
||
for(;;) {
|
||
|
||
if (next_cnt < gp_timer_get_current_val(0)) {
|
||
iot_spinlock_lock(spinlock, cur_cpu);
|
||
dprintf("I'm CPU %d : tmr 0 count %d\n", cur_cpu, next_cnt);
|
||
iot_spinlock_unlock(spinlock, cur_cpu);
|
||
next_cnt += 1100000;
|
||
}
|
||
|
||
loop = 0;
|
||
|
||
while(loop++ < 100000) __asm volatile ("nop\n");
|
||
}
|
||
}
|
||
|
||
void gptmr_core1_loop()
|
||
{
|
||
uint32_t cur_cpu = cpu_get_mhartid(), id, loop, last_cnt = 0, spinlock = GPTMR_TEST_SPINLOCK;
|
||
|
||
iot_gp_timer_init();
|
||
|
||
id = iot_gp_timer_create(cur_cpu, NULL, gptmr_isr, 0);
|
||
|
||
iot_gp_timer_set(id, 1000000, 1);
|
||
|
||
iot_gp_timer_start(id);
|
||
|
||
iot_spinlock_lock(spinlock, cur_cpu);
|
||
dprintf("Test tmr%d @ cpu%d\n", id, cur_cpu);
|
||
iot_spinlock_unlock(spinlock, cur_cpu);
|
||
|
||
for(;;) {
|
||
|
||
if (last_cnt != g_tmr_count) {
|
||
|
||
iot_spinlock_lock(spinlock, cur_cpu);
|
||
dprintf("I'm CPU %d : tmr %d interrupts %d times.\n", cur_cpu, id, g_tmr_count);
|
||
iot_spinlock_unlock(spinlock, cur_cpu);
|
||
|
||
last_cnt = g_tmr_count;
|
||
}
|
||
|
||
loop = 0;
|
||
|
||
while(loop++ < 100000) __asm volatile ("nop\n");
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
#include "clk.h"
|
||
int main(void)
|
||
{
|
||
gp_timer_set(COUNTER_TIMER_ID, 1000000, 0);
|
||
gp_timer_start(COUNTER_TIMER_ID);
|
||
while(!(gp_timer_get_int_status(COUNTER_TIMER_ID) & TMR0_INT_RAW_MASK));
|
||
gp_timer_clear_int_status(COUNTER_TIMER_ID);
|
||
|
||
uint32_t cur_cpu = cpu_get_mhartid();
|
||
|
||
if(cur_cpu == 0) {
|
||
clk_system_clock_tree_config(CLK_FRQ_GP_IDX_FAST);
|
||
dbg_uart_init();
|
||
|
||
// ahb_core2_set_start((uint32_t)_core_start);
|
||
//
|
||
// ahb_core2_enable();
|
||
//
|
||
// ahb_core2_reset();
|
||
|
||
gptmr_core0_loop();
|
||
|
||
} else if (cur_cpu == 2) {
|
||
|
||
ahb_core1_set_start((uint32_t)_core_start);
|
||
|
||
ahb_core1_enable();
|
||
|
||
ahb_core1_reset();
|
||
|
||
gptmr_core2_loop();
|
||
} else {
|
||
gptmr_core1_loop();
|
||
}
|
||
|
||
|
||
return 0;
|
||
}
|