打印
[ZLG-MCU]

请问周工:lm3s6xx 读写IO的速度

[复制链接]
1866|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lidawei1|  楼主 | 2008-3-2 16:43 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
lm3s6xx,软件读或写io脚需几个时钟周期?
如假设运行于50M的频率,连续读或写io脚能达到什么频率?
STM32F10x据说运行于72M时只能输出18M的方波。
望拿出实际数据以便比较,最好有个类似“LPC214x_user_cn.pdf”P101、P102页的输出15.38M方波的图表例子。

相关帖子

沙发
zlgmcu| | 2008-3-3 11:43 | 只看该作者

LM3S运行于50MHz时GPIO管脚可以输出25MHz的方波

我以前测试过,但忘记程序放在那里了,下午贴一个新的。

(zlgmcu_wdx)

使用特权

评论回复
板凳
zlgmcu| | 2008-3-3 14:17 | 只看该作者

刚才写了个测试程序,GPIO管脚确实可以产生高达25MHz的方波


下面的例程在EasyARM615开发板上测试通过,用示波器观察PC6或PD5管脚,会看到25MHz的方波。此时内核速度为50MHz。


#include  "hw_types.h"
#include  "hw_memmap.h"
#include  "hw_ints.h"
#include  "hw_sysctl.h"
#include  "hw_gpio.h"
#include  "hw_timer.h"
#include  "interrupt.h"
#include  "sysctl.h"
#include  "gpio.h"
#include  "timer.h"

#define  SysCtlPeriEn                SysCtlPeripheralEnable
#define  GPIOPinTypeIn                GPIOPinTypeGPIOInput
#define  GPIOPinTypeOut                GPIOPinTypeGPIOOutput

#define  KEY_JTAG                    GPIO_PORTA_BASE , GPIO_PIN_2
#define  CCP2_PORT                    SYSCTL_PERIPH_GPIOD
#define  CCP2_PIN                    GPIO_PORTD_BASE , GPIO_PIN_5
#define  CCP3_PORT                    SYSCTL_PERIPH_GPIOC
#define  CCP3_PIN                    GPIO_PORTC_BASE , GPIO_PIN_6
#define  T1_A                        TIMER1_BASE , TIMER_A
#define  T1_B                        TIMER1_BASE , TIMER_B
#define  T1_BOTH                    TIMER1_BASE , TIMER_BOTH
#define  T1_BOTH_CFG_16_PWM            TIMER1_BASE , ( TIMER_CFG_16_BIT_PAIR  |  
                                                    TIMER_CFG_A_PWM  |  
                                                    TIMER_CFG_B_PWM )

void  waitJTAG ( void )
{
    SysCtlPeriEn ( SYSCTL_PERIPH_GPIOA ) ;                /* 使能GPIOA端口                */
    GPIOPinTypeIn ( KEY_JTAG ) ;                        /* 设置按键所在的PA2管脚为输入    */
    if ( GPIOPinRead ( KEY_JTAG )  ==  0x00 ) {            /* 如果有键按下,则进入            */
        for ( ; ; ) ;                                    /* 死循环,以等待JTAG连接        */
    }
}

void  Timer1Init ( void )
{
    SysCtlPeriEn ( CCP2_PORT ) ;                         /* 使能CCP2所在的GPIO端口        */
    SysCtlPeriEn ( CCP3_PORT ) ;                         /* 使能CCP3所在的GPIO端口        */
    GPIOPinTypeTimer ( CCP2_PIN ) ;                        /* 配置CCP2管脚为PWM输出        */
    GPIOPinTypeTimer ( CCP3_PIN ) ;                     /* 配置CCP3管脚为PWM输出        */

    SysCtlPeriEn ( SYSCTL_PERIPH_TIMER1 ) ;                /* 使能定时器模块                */
    TimerConfigure ( T1_BOTH_CFG_16_PWM ) ;                /* 配置定时器为双16位PWM        */
    TimerControlLevel ( T1_BOTH , true ) ;                /* 控制PWM输出反相                */
    TimerLoadSet ( T1_BOTH , 1 ) ;                        /* 设置定时器初值                */
    TimerMatchSet ( T1_A , 0 ) ;                        /* 设置TimerA的PWM匹配值        */
    TimerMatchSet ( T1_B , 0 ) ;                        /* 设置TimerB的PWM匹配值        */
    TimerEnable ( T1_BOTH ) ;                            /* 使能定时器计数,PWM开始输出    */
}

int  main ( void )
{
    waitJTAG ( ) ;                                        /* 防止JTAG失效                    */
    SysCtlLDOSet(SYSCTL_LDO_2_75V);                     // 内核电压设置为最高的2.75V
    SysCtlClockSet(SYSCTL_USE_PLL  |                    // 配置系统时钟,采用PLL,50MHz
                   SYSCTL_OSC_MAIN  |
                   SYSCTL_XTAL_6MHZ  |
                   SYSCTL_SYSDIV_4);
    Timer1Init ( ) ;                                    /* 定时器初始化                    */
    for ( ; ; ) {
    }
}

(zlgmcu_wdx)

使用特权

评论回复
地板
lidawei1|  楼主 | 2008-3-3 15:39 | 只看该作者

非常感谢周工的测试!

非常感谢周工的测试!
但可能我没说清楚,是任意一个IO管脚的输入或输出,不是PWM的输出,如“LPC214x_user_cn.pdf”第101页的例子:
ldr r0, =0xe01fc1a0 /*寄存器地址-使能高速端口*/
mov r1, #0x1
str r1, [r0] /*使能高速端口0*/
ldr r1, =0xffffffff
ldr r0, =0x3fffc000 /*高速端口0 的方向*/
str r1, [r0]
ldr r0, =0xe0028018 /*低速端口1 的方向*/
str r1, [r0]
ldr r0, =0x3fffc018 /*FIO0SET – 高速端口0 寄存器*/
ldr r1, =0x3fffc01c /*FIO0CLR0 – 高速端口0 寄存器*/
ldr r2, =0xC0010000 /*选择高速端口0.16 用于触发*/
ldr r3, =0xE0028014 /*IO1SET – 低速端口1 寄存器*/
ldr r4, =0xE002801C /*IO1CLR – 低速端口1 寄存器*/
ldr r5, =0x00100000 /*选择低速端口1.20 用于触发*/
/*在高速端口上生成2 个脉冲
str r2, [r0]
str r2, [r1]
str r2, [r0]
str r2, [r1]

按此例子,在50M的LM3s6xx上能输出多大频率的方波?

使用特权

评论回复
5
zlgmcu| | 2008-3-3 17:17 | 只看该作者

换个用库函数(效率低)写的GPIO翻转例程,2.271MHz

现在再贴一个利用Luminary官方提供的驱动库写的例程,测试结果是2.271MHz
不过库函数的效率低,不能完全说明问题。改天再贴个汇编的例子。


#include  "hw_types.h"
#include  "hw_memmap.h"
#include  "hw_sysctl.h"
#include  "hw_gpio.h"
#include  "sysctl.h"
#include  "gpio.h"


#define  SysCtlPeriEn           SysCtlPeripheralEnable
#define  SysCtlPeriDis          SysCtlPeripheralDisable
#define  GPIOPinTypeIn          GPIOPinTypeGPIOInput
#define  GPIOPinTypeOut         GPIOPinTypeGPIOOutput
#define  KEY_PORT               SYSCTL_PERIPH_GPIOA
#define  KEY_PIN                GPIO_PORTA_BASE,GPIO_PIN_2
#define  PB0                    GPIO_PORTB_BASE,GPIO_PIN_0


// 防止JTAG失效
void  WaitJTAG(void)
{
    SysCtlPeriEn(KEY_PORT);                             // 使能按键所在的GPIO端口
    GPIOPinTypeIn(KEY_PIN);                             // 设置按键所在的管脚为输入
    if ( GPIOPinRead(KEY_PIN) == 0x00 )                 // 如果有键按下,则进入
    {
        for (;;);                                       // 死循环,以等待JTAG连接
    }
    SysCtlPeriDis(KEY_PORT);                            // 禁止按键所在的GPIO端口
}


// 延时
void  timeDelay(unsigned long  ulVal)
{
    while ( --ulVal  !=  0 );
}


int  main(void)
{
    WaitJTAG();                                         // 防止JTAG失效
    SysCtlLDOSet(SYSCTL_LDO_2_75V);                     // 内核电压设置为最高的2.75V
    SysCtlClockSet(SYSCTL_USE_PLL  |                    // 配置系统时钟,采用PLL,50MHz
                   SYSCTL_OSC_MAIN  |
                   SYSCTL_XTAL_6MHZ  |
                   SYSCTL_SYSDIV_4);
    SysCtlPeriEn(SYSCTL_PERIPH_GPIOB);                  // 使能GPIOB端口
    GPIOPinTypeOut(PB0);                                // 设置PB0为输出
    for (;;) {
        GPIOPinWrite(PB0,0x00);                         // 清除PB0
        GPIOPinWrite(PB0,0x01);                         // 置位PB0
    }
}


(zlgmcu_wdx)

使用特权

评论回复
6
lidawei1|  楼主 | 2008-3-3 18:10 | 只看该作者

等待中...

使用特权

评论回复
7
zlgmcu| | 2008-3-4 10:02 | 只看该作者

C语言、寄存器,可以到4.55MHz

以下是用C语言写的,没用库函数,而是直接操作寄存器
CPU内核为50MHz,得到的GPIO翻转速度是4.55MHz


#include  "hw_types.h"
#include  "hw_memmap.h"
#include  "hw_sysctl.h"
#include  "hw_gpio.h"
#include  "sysctl.h"
#include  "gpio.h"

int  main(void)
{
    SysCtlLDOSet(SYSCTL_LDO_2_75V);                                             // 内核电压设置为最高的2.75V
    SysCtlClockSet(SYSCTL_USE_PLL  |                                            // 配置系统时钟,采用PLL,50MHz
                   SYSCTL_OSC_MAIN  |
                   SYSCTL_XTAL_6MHZ  |
                   SYSCTL_SYSDIV_4);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);                                // 使能GPIOB端口
    GPIODirModeSet(GPIO_PORTB_BASE,GPIO_PIN_0,GPIO_DIR_MODE_OUT);               // 设置PB0为输出
    GPIOPadConfigSet(GPIO_PORTB_BASE,GPIO_PIN_0,                                // 设置PB0为8mA推挽
                     GPIO_STRENGTH_8MA,
                     GPIO_PIN_TYPE_STD);
Loop:
        HWREG(GPIO_PORTB_BASE + (GPIO_O_DATA + (GPIO_PIN_0 << 2))) = 0x00;      // 清除PB0
        HWREG(GPIO_PORTB_BASE + (GPIO_O_DATA + (GPIO_PIN_0 << 2))) = 0x01;      // 置位PB0
    goto  Loop;
}


(zlgmcu_wdx)

使用特权

评论回复
8
AIRWILL| | 2008-3-4 10:15 | 只看该作者

楼上的测试跑题了

虽然做了很大的努力,但是,和抱歉

人家要求 读或写io脚需几个时钟周期?

其实是想知道,操作 IO 寄存器是否单周期完成,还是要插入等待周期

使用特权

评论回复
9
zlgmcu| | 2008-3-4 10:17 | 只看该作者

如果用汇编则GPIO翻转速度最快可以到10MHz

在7楼程序里的循环是:

Loop:
        HWREG(GPIO_PORTB_BASE + (GPIO_O_DATA + (GPIO_PIN_0 << 2))) = 0x00;      // 清除PB0
        HWREG(GPIO_PORTB_BASE + (GPIO_O_DATA + (GPIO_PIN_0 << 2))) = 0x01;      // 置位PB0
    goto  Loop;


用IAR编译器看到的汇编代码是:

;Loop:
;   HWREG(GPIO_PORTB_BASE + (GPIO_O_DATA + (GPIO_PIN_0 << 2))) = 0x00;      // 清除PB0
        LDR          R0, [PC,#0x018]          ; [0x440] =0x40005004
        MOVS         R1#0x0
        STR          R1, [R0, #0]
;   HWREG(GPIO_PORTB_BASE + (GPIO_O_DATA + (GPIO_PIN_0 << 2))) = 0x01;      // 置位PB0
        LDR          R0, [PC,#0x010]          ; [0x440] =0x40005004
        MOVS         R1#0x1
        STR          R1, [R0, #0]
;   goto  Loop;
        B            0x000426

总共7条指令,按照4.55MHz的GPIO翻转率推算,花了11个时钟周期。
如果用汇编来写程序,LDR和MOVS指令完成的动作都可以事先设定好,而循环里只有两条STR指令。照此推算,仅需要5个时钟周期,即GPIO翻转率可达10MHz。


(zlgmcu_wdx)

使用特权

评论回复
10
zlgmcu| | 2008-3-4 10:20 | 只看该作者

8楼:如果单说写或者读,最快只需要2个周期!

因为一条STR存储器操作指令只需要2个周期。

使用特权

评论回复
11
lidawei1|  楼主 | 2008-3-4 11:27 | 只看该作者

Luminary Micro Forums 相关:

使用特权

评论回复
12
zlgmcu| | 2008-3-4 11:47 | 只看该作者

谢谢11楼提供的官方解释!

while(1)循环相当于goto语句,变成汇编是一条B指令,执行B指令仅需1个周期。STR指令是2个周期,因此输出方波高电平40ns、低电平60ns的现象。

要说输出方波频率还可以更高,极限是12.5MHz,方法是:

while(1) {
    asm("str    r3, [r2]");
    asm("str    r4, [r2]");

    asm("str    r3, [r2]");
    asm("str    r4, [r2]");

    asm("str    r3, [r2]");
    asm("str    r4, [r2]");

    asm("str    r3, [r2]");
    asm("str    r4, [r2]");

    ... 
}


(zlgmcu_wdx)

使用特权

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

本版积分规则

1

主题

16

帖子

0

粉丝