/****************************************************************************** 版权所有: @copyright (C) 2024-2034 HaiYang Technology Corp. All rights reserved. 文件名称: ustimer.c 文件版本: 01.01 创建作者: zhaoyang 创建日期: 2025-07-28 功能说明: us定时器模块驱动程序。目前使用了TIM2定时器,作为延时函数的参考定时器用。 TIM2的时钟周期为1/3us。延时函数的最大时间长度为1431.6557653秒。 其它说明: 修改记录: */ #include "bsp_ustimer.h" #include #include #include #include #include #include #include "bsp_ccu.h" #include "rt_types.h" #define MAP_SIZE 4096UL #define MAP_MASK (MAP_SIZE - 1) #define BSP_USTIMER_DELAY_MAX_US (10UL*60*BSP_USTIMER_SEC) //10分钟 int g_ustimer_fd = -1; unsigned g_ustimer_mapped_size; void *g_ustimer_map_base, *g_ustimer_virt_addr; /****************************************************************************** 函数名称: bsp_ustimer_init 函数版本: 01.01 创建作者: zhaoyang 创建日期: 2025-07-28 函数说明: 使用timer2做为延时函数参考定时器并注册 参数说明: 无 返回值: 无 修改记录: */ int bsp_ustimer_init(void) { void *temp_ccu_base, *temp_virt_l_base, *temp_virt_h_base, *temp_virt_ctl_base; unsigned long read_result; off_t target; unsigned page_size, offset_in_page; unsigned width = 8 * sizeof(int); target = TIMER_BASE; // 获取页面大小 g_ustimer_mapped_size = page_size = sysconf(_SC_PAGESIZE); offset_in_page = (unsigned)target & (page_size - 1); if (offset_in_page + width > page_size) { /* This access spans pages. * Must map two pages to make it possible: */ g_ustimer_mapped_size *= 2; } g_ustimer_fd = open("/dev/mem", O_RDWR | O_SYNC); if (g_ustimer_fd < 0) { printf("open(/dev/mem) failed.\n"); return -1; } fflush(stdout); g_ustimer_map_base = mmap (NULL, g_ustimer_mapped_size, PROT_READ | PROT_WRITE, MAP_SHARED, g_ustimer_fd, target & ~(off_t)(page_size - 1)); if (g_ustimer_map_base == (void *)-1) { printf ("NULL pointer!\n"); } else { printf ("BSP ustimer map Successfull!\n"); } fflush(stdout); g_ustimer_virt_addr = (char*)g_ustimer_map_base + offset_in_page; // printf("g_ustimer_virt_addr: %p %p %x\n", g_ustimer_virt_addr, g_ustimer_map_base, offset_in_page); // Init timer ccu clock /* set TMR2 clock source to HOSC, 8 pre-division */ temp_ccu_base = g_ccu_map_base + 0x0808; read_result = *(volatile u_int32_t*)(temp_ccu_base); read_result &= ~((0x01 << 24) | 7); read_result |= (1 << 31) | 3; *(volatile u_int32_t*)(temp_ccu_base) = read_result; // Enable timer2 /* set timer intervalue */ temp_virt_l_base = (char*)g_ustimer_map_base + 0x64; temp_virt_h_base = (char*)g_ustimer_map_base + 0x6C; *(volatile u_int32_t*)(temp_virt_l_base) = 0xFFFFFFFF; *(volatile u_int32_t*)(temp_virt_h_base) = 0xFFFFFF; /* set mode to auto reload */ temp_virt_ctl_base = (char*)g_ustimer_map_base + 0x60; read_result = *(volatile u_int32_t*)(temp_virt_ctl_base); read_result &= TIMER_CTL_PERIODIC; *(volatile u_int32_t*)(temp_virt_ctl_base) = (read_result | TIMER_CTL_AUTORELOAD | TIMER_CTL_ENABLE); // read_result = *(volatile u_int32_t*)g_ustimer_virt_addr; // printf("ustimer_init res: 0x%08lx\n", read_result); return 0; } /****************************************************************************** 函数名称: bsp_ustimer_exit 函数版本: 01.01 创建作者: zhaoyang 创建日期: 2025-07-28 函数说明: 用户定时器注销 参数说明: 无 返回值: 无 修改记录: */ int bsp_ustimer_exit(void) { if (g_ustimer_fd >= 0) { close(g_ustimer_fd); g_ustimer_fd = -1; } if (munmap(g_ustimer_map_base, g_ustimer_mapped_size) == -1) { printf("munmap failed!"); return -1; } return 0; } /****************************************************************************** 函数名称: bsp_ustimer_get_origin 函数版本: 01.01 创建作者: zhaoyang 创建日期: 2025-07-28 函数说明: 得到当前时刻定时器的值,用作ustimer_get_duration、 ustimer_delay_origin函数的origin参数。 参数说明: 无 返回值: 当前时刻定时器的值。 修改记录: */ unsigned long bsp_ustimer_get_origin(void) { void *temp_virt_l_base, *temp_virt_h_base; u_int64_t val_low, val_high; if (!g_ustimer_map_base) { return 0; } temp_virt_l_base = (char*)g_ustimer_map_base + 0x68; temp_virt_h_base = (char*)g_ustimer_map_base + 0x70; val_low = (~*(volatile u_int32_t*)temp_virt_l_base) & TIMER_VL_MASK; val_high = (~*(volatile u_int32_t*)temp_virt_h_base) & TIMER_VH_MASK; return ((val_high << TIMER_VH_OFFSET) | val_low)/3; } /****************************************************************************** 函数名称: bsp_ustimer_get_duration 函数版本: 01.01 创建作者: zhaoyang 创建日期: 2025-07-28 函数说明: 得到当前时刻相对于指定时间原点的时间间隔,以us为单位。 参数说明: origin: 时间原点,以us为单位。 返回值: 当前时刻相对于原点的的时间间隔。 修改记录: */ unsigned long bsp_ustimer_get_duration(unsigned long origin) { if(!g_ustimer_map_base) return 0; // 返回差值(根据C语言算法,会自动处理回绕问题) return bsp_ustimer_get_origin() - origin; } /****************************************************************************** 函数名称: bsp_ustimer_delay_origin 函数版本: 01.01 创建作者: zhaoyang 创建日期: 2025-07-28 函数说明: 以us为单位的延时函数。最大延时值为1小时(3600000000us)和 ustimer_delay函数不同的是bsp_ustimer_delay_origin函数的延时计算的时间 原点为origin,而不是函数被调用的时刻。当这个函数退出时,会确保延时 大于等于设定值。如果需要高精度的延时,调用这个函数时应先屏蔽中断。 参数说明: origin: 延时计算的时间原点,以us为单位,通常通过ustimer_get_origin函数获得。 us: 延时us数。 返回值: 0: 成功 其它: 失败 修改记录: */ unsigned long bsp_ustimer_delay_origin(unsigned long origin,unsigned long us) { if(!g_ustimer_map_base) return 0; //检查参数 if(us > BSP_USTIMER_DELAY_MAX_US) return -1; // 循环等待 while (us > (bsp_ustimer_get_origin() - origin)) ; return 0; } /****************************************************************************** 函数名称: ustimer_delay 函数版本: 01.01 创建作者: zhaoyang 创建日期: 2025-07-28 函数说明: 以us为单位的延时函数。最大延时值为1小时(3600000000us)。 当这个函数退出时,会确保延时大于等于设定值。如果需要高精度的延时, 调用这个函数时应先屏蔽中断。 参数说明: us: 延时us数。 返回值: 0: 成功 其它: 失败 修改记录: */ unsigned long bsp_ustimer_delay(unsigned long us) { u64 origin; if(!g_ustimer_map_base) return 0; //检查参数 if(us > BSP_USTIMER_DELAY_MAX_US) return -1; origin = bsp_ustimer_get_origin(); bsp_ustimer_delay_origin(origin, us); return 0; }