打印
[STM32F4]

M3/M4精确定时问题

[复制链接]
2065|16
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
magic_yuan|  楼主 | 2014-3-5 17:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
各位大侠,
    近来设计一个系统要求比较精准的实时性。
    以M4为例,168MHZ主频,那么每周期时钟大致是6nS。
    我想实现以下动作,请大侠分析看是否可行。
   1, PB0=1,输出高----设CPU内部开始执行这条指令为零时刻,则CPU执行完PB0=1需要消耗时钟周期(大致是一周期吧?),然后系统模拟管脚单元动作,需要消耗一定的延时(大概uS级别?和IO口设置的输出速率有关,假设输出最高速率。)待PB0引脚输出为高时,假设耗时T1.
  2,系统延时24nS----问题:这24nS如何实现呢?只能以最基本的系统时钟6nS为基本单位来计算,执行三个单周期指令?。但由于STM-CORE M4的流水线指令,似乎无法确定每个指令到底消耗多少周期?且我想做成子函数的形式,也就是说40nS,50nS,这样的延时可以直接设置。。。。有没有这样的指令固定执行一周期的?
   请大侠指教!十分感谢!
沙发
wyjben| | 2014-3-5 18:30 | 只看该作者
你这个6NS是大致时间,为什么不用168/8作为时钟源呢?以168/8作为时钟源,每nS需要的周期刚好是21个时钟周期,这样才叫精准吧?
如果你要写成子函数,40nS需要的时钟周期就是40*21=840个周期,向SYSTICK的LOAD寄存器写840就行了。

使用特权

评论回复
板凳
aozima| | 2014-3-5 18:43 | 只看该作者
还是从的你的应用方面考虑别的招吧。

使用特权

评论回复
评论
magic_yuan 2014-3-5 19:40 回复TA
__disable_irq();大侠看这条指令怎么样 
magic_yuan 2014-3-5 18:45 回复TA
目前为止估计只有这个招了。nS级的延时,没其他招啊 
地板
magic_yuan|  楼主 | 2014-3-5 18:44 | 只看该作者
wyjben 发表于 2014-3-5 18:30
你这个6NS是大致时间,为什么不用168/8作为时钟源呢?以168/8作为时钟源,每nS需要的周期刚好是21个时钟周 ...

多谢大侠,
   水平有限。168/8?您指的是168M再8分频?

使用特权

评论回复
5
wyjben| | 2014-3-5 18:52 | 只看该作者
magic_yuan 发表于 2014-3-5 18:44
多谢大侠,
   水平有限。168/8?您指的是168M再8分频?

在设置SYSTICK时,有个时钟源选择,可以选择内部时钟和外部时钟,内部时钟如果你设为168,那么外部时钟就是168/8,例子:
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//选择外部时钟HCLK/8
SysTick_CLKSource_HCLK_Div8为外部时钟
SysTick_CLKSource_HCLK为内部时钟

#define SysTick_CLKSource_HCLK_Div8    ((uint32_t)0xFFFFFFFB)
#define SysTick_CLKSource_HCLK         ((uint32_t)0x00000004)

使用特权

评论回复
6
magic_yuan|  楼主 | 2014-3-5 18:55 | 只看该作者
wyjben 发表于 2014-3-5 18:52
在设置SYSTICK时,有个时钟源选择,可以选择内部时钟和外部时钟,内部时钟如果你设为168,那么外部时钟就 ...

168MHZ是M4经过外部时钟倍频以后得到的吧。。。。。

使用特权

评论回复
7
magic_yuan|  楼主 | 2014-3-5 19:40 | 只看该作者
刚在网上搜了下,
__disable_irq()
这条指令貌似可以实现双周期固定定时。

使用特权

评论回复
8
wyjben| | 2014-3-5 20:17 | 只看该作者
本帖最后由 wyjben 于 2014-3-5 20:19 编辑

#include "systick.h"
#include "stm32f4xx_systick.h"
#include "stm32f4xx.h"
#include "misc.h"

void SysTick_Init(void)
{
   SysTick_CounterCmd(DISABLE);
         SysTick_ITConfig(DISABLE);
   SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
}

void delay_ms(uint32_t msnum)
{
         delay_time=msnum;        
         SysTick_SetReload(22500);
         SysTick_ITConfig(ENABLE);
         SysTick_CounterCmd(ENABLE);
   while(delay_time!=0);
         SysTick_CounterCmd(DISABLE);
         SysTick_ITConfig(DISABLE);        
}

void SysTick_Handler(void)
{
        delay_time--;
}

这个给你参考一下

使用特权

评论回复
9
magic_yuan|  楼主 | 2014-3-5 20:25 | 只看该作者
wyjben 发表于 2014-3-5 20:17
#include "systick.h"
#include "stm32f4xx_systick.h"
#include "stm32f4xx.h"

感谢大侠啊,
  我刚学STM,看不怎么懂啊。能否加点注释。。。。。

使用特权

评论回复
10
wyjben| | 2014-3-6 09:00 | 只看该作者
SysTick定时器

NVIC中,捆绑着一个SysTick定时器,它是一个24位的倒数计数定时器,当计到0时,将从RELOAD寄存器中自动重装载定时初值并继续计数,同时内部的 COUNTFLAG 标志会置位,触发中断 (如果中断使能情况下)。只要不把它在SysTick控制及状态寄存器中的使能位清除,就用不停息。Cortex-M3允许为SysTick提供2个时钟源以供选择,第一个是内核的“自由运行时钟”FCLK,“自由”表现在它不是来自系统时钟HCLK,因此在系统时钟停止时,FCLK也能继续运行。第2个是一个外部的参考时钟,但是使用外部时钟时,因为它在内部是通过FCLK来采样的,因此其周期必须至少是FCLK的两倍(采样定理)。

下面介绍一下STM32中的SysTick,它属于NVIC控制部分,一共有4个寄存器:

STK_CSR,          0xE000E010:             控制寄存器

STK_LOAD,       0xE000E014:             重载寄存器

STK_VAL,          0xE000E018:             当前值寄存器

STK_CALRB,     0xE000E01C:             校准值寄存器


首先看STK_CSR控制寄存器,有4个bit具有意义:

第0位:ENABLE,SysTick使能位(0:关闭SysTick功能,1:开启SysTick功能);

第1位:TICKINT,SysTick中断使能位(0:关闭SysTick中断,1:开启SysTick中断);

第2位:CLKSOURCE,SysTick时钟选择(0:使用HCLK/8作为时钟源,1:使用HCLK);

第3为:COUNTFLAG,SysTick计数比较标志,如果在上次读取本寄存器后,SysTick已经数到0了,则该位为1,如果读取该位,该位自动清零。

STK_LOAD重载寄存器:

Systick是一个递减的定时器,当定时器递减至0时,重载寄存器中的值就会被重装载,继续开始递减。STK_LOAD  重载寄存器是个24位的寄存器最大计数0xFFFFFF。

STK_VAL当前值寄存器:

也是个24位的寄存器,读取时返回当前倒计数的值,写它则使之清零,同时还会清除在SysTick 控制及状态寄存器中的COUNTFLAG 标志。

STK_CALRB校准值寄存器:

其中包含着一个TENMS位段,具体信息不详。暂时用不到。

在MDK开发环境中,我们不必要非得去操作每一个寄存器,可以通过调用ST函数库中的函数来进行相关的操作,其步骤如下:

(1)       调用SysTick_CounterCmd()                 失能SysTick计数器

(2)       调用SysTick_ITConfig()                      失能SysTick中断

(3)       调用SysTick_CLKSourceConfig()        设置SysTick时钟源

(4)       调用SysTick_SetReload()                    设置SysTick重装载值

(5)       调用NVIC_SystemHandlerPriorityConfig()         设置SysTick定时器中断优先级

(6)       调用SysTick_ITConfig()                      使能SysTick中断

(7)       在stm32f10x_it.c中SysTickHandler()下写中断服务函数。

(8)       在需要的时候调用SysTick_CounterCmd()          开启SysTick计数器

使用特权

评论回复
11
IJK| | 2014-3-6 09:41 | 只看该作者
精确的10ns量级的定时一般靠定时器控制IO或者ADC之类完成某些事情,靠堆指令不大靠谱。us量级或者更长时间的延时用SysTick才比较靠谱。

使用特权

评论回复
12
h295472204| | 2014-3-6 10:45 | 只看该作者
用systick啊 准确些

使用特权

评论回复
13
magic_yuan|  楼主 | 2014-3-6 12:10 | 只看该作者
IJK 发表于 2014-3-6 09:41
精确的10ns量级的定时一般靠定时器控制IO或者ADC之类完成某些事情,靠堆指令不大靠谱。us量级或者更长时间 ...

定时器也需要写入寄存器,然后启动,这个本身就消耗一定的时间了。貌似也不精确呢?
谢谢啊!

使用特权

评论回复
14
huzi2099| | 2014-3-6 12:42 | 只看该作者
nop可以
不整的问题无解,必须整
这么短的时间程序是没法做的,逻辑门的延时都接近这个数值了,想别的办法吧

使用特权

评论回复
15
nj21ic| | 2014-3-6 13:47 | 只看该作者
想别的办法吧

使用特权

评论回复
16
magic_yuan|  楼主 | 2014-3-6 14:06 | 只看该作者
huzi2099 发表于 2014-3-6 12:42
nop可以
不整的问题无解,必须整
这么短的时间程序是没法做的,逻辑门的延时都接近这个数值了,想别的办法吧 ...

也考虑到逻辑门延时,但只要逻辑门延时固定变化不大也可以。我要的是一个延时差。

使用特权

评论回复
17
wyjben| | 2014-3-6 16:08 | 只看该作者
magic_yuan 发表于 2014-3-6 12:10
定时器也需要写入寄存器,然后启动,这个本身就消耗一定的时间了。貌似也不精确呢?
谢谢啊! ...

这个也是相对来说比较精准的,如果要更准一点,你可以再这个函数里减掉1个周期
SysTick_SetReload(22500-1);

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:发到3000帖时,生活大概完成了一种转折。

359

主题

2770

帖子

7

粉丝