doubao_chat/apps/common/example/peripheral/timer/test2.c

305 lines
7.6 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "includes.h"
#include "os/os_api.h"
#include "asm/clock.h"
#include "asm/irq.h"
//#include "jiffies.h"
#include "system/timer.h"
#include "system/init.h"
#include "gpio.h"
//#include "asm/power_interface.h"
#include "generic/atomic.h"
#include "asm/cpu.h"
#include "demo_config.h"
#ifdef USE_TIMER_TEST2_DEMO
//用户只能选择:JL_TIMER2、JL_TIMER3、JL_TIMER4、JL_TIMER5
//PWM使用定时器2或者3映射PWM时候,不能用于定时
static JL_TIMER_TypeDef *TMR = JL_TIMER4;//选择定时器4
static u8 timer_irq = IRQ_TIMER4_IDX;//选择定时器4
//#define JL_TIMER_B JL_TIMER5
//u32 timer_b_cnt;
static const u8 timer_index[16] = {0, 4, 1, 5, 2, 6, 3, 7, 8, 12, 9, 13, 10, 14, 11, 15};
static const u32 timer_table[16] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768};
static u32 timer_clk = 0;
void timer4_stop(void);
void timer4_run(u32 precesion);
// timer_b_test(void);
void test(void);
#define AWINLINE __attribute__((always_inline))
//#define TSEC SEC_USED(.volatile_ram_code) //当中断1ms一下,建议使用函数放在内部ram
#define TSEC
#define TIMER_CON JL_TIMER4->CON //定时器4的控制寄存器
#define TIMER_CNT JL_TIMER4->CNT //定时器4的计数寄存器
#define TIMER_PRD JL_TIMER4->PRD //定时器4的周期寄存器
//#define TIMER_VETOR IRQ_TIMER4_IDX
struct timer_hdl {
u32 ticks;
int index;
int prd;
u32 fine_cnt;
u8 run;
u32 precesion;
void *power_ctrl;
struct list_head head;
};
static struct timer_hdl hdl;
#define __this (&hdl)
static const u32 timer_div[] = {
/*0000*/ 1,
/*0001*/ 4,
/*0010*/ 16,
/*0011*/ 64,
/*0100*/ 2,
/*0101*/ 8,
/*0110*/ 32,
/*0111*/ 128,
/*1000*/ 256,
/*1001*/ 4 * 256,
/*1010*/ 16 * 256,
/*1011*/ 64 * 256,
/*1100*/ 2 * 256,
/*1101*/ 8 * 256,
/*1110*/ 32 * 256,
/*1111*/ 128 * 256,
};
#define APP_TIMER_CLK clk_get("osc") //获得时钟源
#define MAX_TIME_CNT 0x7fff //最大计数值
#define MIN_TIME_CNT 0x100 //最小计数值
static AWINLINE TSEC void timer_cfg(u32 freq, u32 us) //定时中断配置
{
u32 clock = timer_clk;
u8 psc = 0;
u8 tmp = 0;
u32 prd = 0;
u32 ts = us / (1000 * 1000);//计算秒
u32 tu = us % (1000 * 1000);//计算秒剩余us
u8 i;
float tp = 0;
if (freq >= clock) {
freq = clock;
} else if (freq <= 1) {
freq = 1;
if (ts) {
tp = (float)tu / (1000 * 1000);
}
}
/*求prd值*/
prd = clock / freq;
if (prd > 65535) {
for (psc = 0; psc < 16; psc++) {
prd = (u32)(clock / (timer_table[psc]) / freq);
if (prd <= 65535) {
break;
} else if (psc == 15) {
prd = 65535;
break;
}
}
}
prd = ts ? (prd * ts + tp * prd) : prd;
psc = timer_index[psc];
TMR->CON = 0;
TMR->CNT = 0;
TMR->CON |= BIT(14);
TMR->PRD = prd;
TMR->CON |= psc << 4; //lsb_clk分频
TMR->CON |= BIT(0);
}
static void TSEC timer_set(u32 us)//设置时间,该函数可以在中断调用重新设置定时器值
{
u32 freq = 1000000 / us;
timer_cfg(freq, us);
}
static void TSEC timer_freq_set(u32 freq)//设置频率,该函数可以在中断调用重新设置定时器值
{
timer_cfg(freq, 0);
}
static ___interrupt TSEC void timer_isr(void)//中断
{
if (TMR->CON & BIT(15)) {
TMR->CON |= BIT(14);
putchar('@');
//todo,中断函数执行程序...
}
}
//example test
static int c_main(void)
{
timer_clk = clk_get("timer");//先获取定时器的时钟源
request_irq(timer_irq, 3, timer_isr, 0);//注册中断函数定和中断优先级
#if 1
timer_set(50 * 1000); //初始化50ms进一次中断
os_time_dly(500);
timer4_stop(); //定时器停止
os_time_dly(500);
timer4_run(2); //定时器开始
os_time_dly(500);
test(); //输入捕获功能测试
#else
//timer_freq_set(10000);//设置10K频率进中断
#endif
return 0;
}
static void timer4_suspend(void) //定时器暂停
{
if (__this->run) {
__this->ticks = JL_TIMER4->CNT;
JL_TIMER4->CON = 0;
}
}
static void timer4_resume(void) //定时器继续
{
if (__this->run == 0) {
return;
}
u32 prd_cnt;
u8 index;
//precesion = PRD * index / CLK
for (index = 0; index < (sizeof(timer_div) / sizeof(timer_div[0])); index++) {
prd_cnt = __this->precesion * (APP_TIMER_CLK / 1000) / timer_div[index];
if (prd_cnt > MIN_TIME_CNT && prd_cnt < MAX_TIME_CNT) {
break;
}
}
__this->index = index;
__this->prd = prd_cnt;
JL_TIMER4->CNT = __this->ticks;
JL_TIMER4->PRD = prd_cnt; //2ms
JL_TIMER4->CON = (index << 4) | BIT(0) | BIT(3);
}
void timer4_stop(void) //定时器停止
{
printf("--->Stop");
JL_TIMER4->CON = BIT(14);
__this->run = 0;
__this->precesion = 0;
}
void timer4_run(u32 precesion) //定时器开始
{
precesion = 2;//br23 br25 周期不变化 为减少占用cpu资源,固定收集2ms内的计数值 可去掉
if (__this->precesion == precesion) {
return;
}
printf("-->Run %d", precesion);
JL_TIMER4->CON = BIT(14);
__this->precesion = precesion;
__this->run = 1;
__this->ticks = 0;
timer4_resume();
}
//////输入捕获
static bool isr_flag = false; //设立中断标志位
enum edge_mode {
RISE_EDGE = 0,
FALL_EDGE,
};
bool timer5_interrupt(void)
{
return isr_flag;
}
void timer5_start(void) //定时器5开始,清空计数器和标志位
{
JL_TIMER5->CNT = 0;
isr_flag = false;
}
___interrupt
static void timer5_isr(void)
{
JL_TIMER5->CON |= BIT(14);
isr_flag = true;
}
int timer5_get_cnt(void) //10us
{
u32 a = JL_TIMER5->PRD;
u32 b = a * 96 / 100; //53Mhz/512k 再转化为10us
return b ;
}
void timer5_init(int mode) //定时器5初始化
{
JL_TIMER5->CNT = 0;
#if CPU_CORE_NUM > 1
request_irq(IRQ_TIMER5_IDX, 1, timer5_isr, 1);
#else
request_irq(IRQ_TIMER5_IDX, 1, timer5_isr, 0);
#endif
JL_TIMER5->CON = BIT(7) | BIT(6);//lsb_clk的512分频
if (mode == FALL_EDGE) {
JL_TIMER5->CON |= BIT(0) | BIT(1);//下降沿捕获
gpio_direction_input(IO_PORTC_08);//输入引脚为PC8
gpio_set_pull_up(IO_PORTC_08, 1);
} else {
JL_TIMER5->CON |= BIT(1);//上升沿捕获
gpio_direction_input(IO_PORTC_08);
gpio_set_pull_down(IO_PORTC_08, 1);
}
}
void timer5_uninit(void)
{
JL_TIMER5->CON = 0;
}
void test(void)
{
extern bool timer5_interrupt(void);
extern void timer5_start(void);
extern void timer5_init(int mode); //mode: 0 上升沿 1 下降沿
extern void timer5_uninit(void);
extern int timer5_get_cnt(void);
timer5_init(1);
printf("-------%s-------%d\r\n", __func__, __LINE__);
while (1) {
timer5_start(); //先清空下数据
printf("-------%s-------%d\r\n", __func__, __LINE__);
while (!timer5_interrupt()) { //检测到有下降沿则为true,采用轮询方式每200ms检测一次
os_time_dly(20);
}
printf("-------%s-------%d get cnt = %d\r\n", __func__, __LINE__, timer5_get_cnt()); //返回出来的是单位是10us 的cnt 就是 cnt* 100 000就是秒
/* timer5_get_cnt(); */
}
timer5_uninit(); //用完就释放
}
late_initcall(c_main);
#endif