"Sequential burst operation up to 96M"
经测试,顺序执行时确实能达到96M的速度。
但是跳转指令的执行速度很慢。一个跳转指令大约需要5个指令周期。
谁有办法让跳转指令的执行效率更高点呀?
加 branch queue 的选项,否则改改程序吧
arm 9 的跳转成功一定要有至少3个延迟,跳转不成功到时没有延迟,所以你只有修改程序将if语句的内容 变为主程序的一部分。
指令速度
我的测试程序如下:
u16 * addr1=(u16 *)(0x2C000000),* addr2=(u16 *)(0x2C000000)+ 0xFFFF;
u16 data1=0x0,data2=0xFFFF;
while(1)
{
*addr1 = data1; //往EMI总线上写0
*addr2 = data2; //往EMI总线上写1
}
它们的汇编代码:
0X0025CC STRH R9 [R7, #0]
0X0025D0 STRH R9 [R8, #0]
0X0025D4 B 0X0025CC
结果发现高电平比低电平多出50ns(96M时钟),也就是说指令"B 0X0025CC"用了5个指令周期。
不知道你说的 branch queue 选项是什么意思,是在哪加呢?
branch queue
首先说说 arm的特性,您只有到exe阶段之后才能的到目的地址(但是这也是个了不起的方法),同时由于要重新刷新pipe line 然后去取目的地址,以及flash的滞后性,所以会造成较大延迟。
为了平衡这个弱项,cpu 会在取跳转指令的时候会同时检查branch queue, 如果这个地址存在,那么对应的项中就包含着跳转的目的地址,cpu 在下一次就会去取目的地址而不是 brach 后面的指令。到底跳转成功与否要到id 之后才可以知道。这样如果成功几乎没有延迟。对于上面代码的结果,我想你应该没有打开这个选项。
我确信st 的arm 9有这个功能因为我曾经问过浪淘沙,是要设置一个寄存器具体哪一个我忘记了。
你找找你的datasheet吧。
祝你顺利。
Branch Queue是STR9在ARM核心之外的一个非常重要的扩充
5楼说的是对的。
明天我们会有人回答如何使用Branch Queue的问题。谢谢!
branch queue
我想你指的branch queue就是Pre-Fetch Queue and branch cache.
我在程序中已经将它打开了,要不然顺序执行的指令速度都达不到96M.
我用的打开Pre-Fetch Queue and branch cache的代码如下:
SCU_PFQBCCmd(ENABLE);
目前没有板子,只有猜测
1)确定程序是在内部flash(它是哈佛结构).
2)如果1成立验证如下前3句代码中的高低之差
0X0025CC STRH R9 [R7, #0]
0X0025D0 STRH R9 [R8, #0]
0X0025C4 STRH R9 [R7, #0]
0X0025D8 STRH R9 [R8, #0]
0X0025DC B 0X0025CC
3)如果2的结果是高低相等,而且也确定打开了branch queue,如果是我就只有怀疑st了 :-)。
RE telnet
我原本的程序就是:
while(1)
{
*addr1 = data1; //往EMI总线上写0
*addr2 = data2; //往EMI总线上写1
*addr1 = data1; //往EMI总线上写0
*addr2 = data2; //往EMI总线上写1
*addr1 = data1; //往EMI总线上写0
*addr2 = data2; //往EMI总线上写1
}
和你现在的一样。
有一个问题!
我的疏忽,回头看到你往奇地址写双字节(*addr2 = data2; //往EMI总线上写1 )难道不会产生异常么?!,换成偶地址去测上面的代码。
RE telnet
addr2=(u16 *)(0x2C000000)+ 0xFFFF;
addr2就是一个偶地址,因为以上语句相当于:
addr2=(u16 *)(0x2C000000+ 2*0xFFFF);
关于“STR9指令速度”的问题:请楼主把所有代码发上来
包括你的初始化部分,我们帮你看看。
另你这样测试指令速度不一定合适,等我们看了你的代码再来讨论。
流水线被打断会增加额外的时间,但预测准确的话可以不增
LZ还是先检查下自己的设置和程序写法吧
真要这么计较速度的话就该考虑用DSP了,都能0耗时循环
而且速度的测试也不是这样测的,很多IC的内部时钟和外部总线速度相差极大,IO速度更慢,怎么测的对?
代码
#define DELAY5 asm("nop");asm("nop");asm("nop");asm("nop");asm("nop")
#define DELAY10 DELAY5;DELAY5
void SCU_Configuration(void);
void GPIO_Configuration(void);
void EMI_Configuration(void);
int main()
{
#ifdef DEBUG
debug();
#endif
/* Configure the system clocks */
SCU_Configuration();
/* Configure the GPIO ports */
GPIO_Configuration();
EMI_Configuration();
u16 * addr1=(u16 *)0x2C000000,* addr2=(u16 *)0x2C000000+ 0xFFFF;
u16 data1=0x0,data2=0xFFFF;
while(data1<data2)
{
*addr1 = data1; //往EMI总线上写0
*addr2 = data2; //往EMI总线上写1
*addr1 = data1; //往EMI总线上写0
*addr2 = data2; //往EMI总线上写1
*addr1 = data1; //往EMI总线上写0
*addr2 = data2; //往EMI总线上写1
}
}
void SCU_Configuration(void)
{
SCU_PFQBCCmd(ENABLE);
FMI_Config(FMI_READ_WAIT_STATE_2, FMI_WRITE_WAIT_STATE_1, FMI_PWD_ENABLE,
FMI_LVD_ENABLE, FMI_FREQ_HIGH);
SCU_MCLKSourceConfig(SCU_MCLK_OSC);
DELAY10;DELAY10;DELAY10;DELAY10;DELAY10;DELAY10;
SCU_PLLCmd(DISABLE);
SCU_RCLKDivisorConfig(SCU_RCLK_Div1);
SCU_PCLKDivisorConfig(SCU_PCLK_Div2);
SCU_HCLKDivisorConfig(SCU_HCLK_Div1);
SCU_FMICLKDivisorConfig(SCU_FMICLK_Div1);
SCU_EMIBCLKDivisorConfig(SCU_EMIBCLK_Div1);
SCU_PLLFactorsConfig(125, 12, 2);//96M
SCU_PLLCmd(ENABLE);
SCU_MCLKSourceConfig(SCU_MCLK_PLL);
SCU->SCR0 |=0x10;//96K SRAM
SCU->SCR0 &=0xF7;
/* Enable the GPIO Clock */
SCU_APBPeriphClockConfig(__GPIO0, ENABLE);
SCU_APBPeriphClockConfig(__GPIO1, ENABLE);
SCU_APBPeriphClockConfig(__GPIO2, ENABLE);
SCU_APBPeriphClockConfig(__GPIO3, ENABLE);
SCU_APBPeriphClockConfig(__GPIO4, ENABLE);
SCU_APBPeriphClockConfig(__GPIO5, ENABLE);
SCU_APBPeriphClockConfig(__GPIO6, ENABLE);
SCU_APBPeriphClockConfig(__GPIO7, ENABLE);
SCU_APBPeriphClockConfig(__GPIO8, ENABLE);
SCU_APBPeriphClockConfig(__GPIO9, ENABLE);
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_DeInit(GPIO0);
GPIO_DeInit(GPIO1);
GPIO_DeInit(GPIO2);
GPIO_DeInit(GPIO3);
GPIO_DeInit(GPIO4);
GPIO_DeInit(GPIO5);
GPIO_DeInit(GPIO6);
GPIO_DeInit(GPIO7);
GPIO_DeInit(GPIO8);
GPIO_DeInit(GPIO9);
/* Gonfigure EMI */
GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull ;
GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Disable;
GPIO_InitStructure.GPIO_Alternate = GPIO_OutputAlt2;
GPIO_Init (GPIO7, &GPIO_InitStructure);
GPIO_Init (GPIO8, &GPIO_InitStructure);
GPIO_Init (GPIO9, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull ;
GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Disable;
GPIO_InitStructure.GPIO_Alternate = GPIO_OutputAlt3;
GPIO_Init (GPIO7, &GPIO_InitStructure);
}
/* 16位复用模式 */
void EMI_Configuration(void)
{
EMI_InitTypeDef EMI_InitStruct;
/* Enable EMI clock */
SCU_AHBPeriphClockConfig( __EMI, ENABLE );
SCU_EMIModeConfig( SCU_EMI_MUX );
SCU_EMIALEConfig( SCU_EMIALE_LEN1,SCU_EMIALE_POLLow );
GPIO_EMIConfig( ENABLE );
EMI_DeInit();
EMI_StructInit( &EMI_InitStruct );
EMI_InitStruct.EMI_Bank_MemWidth=EMI_Width_HalfWord;
EMI_InitStruct.EMI_PageModeRead_Selection=EMI_NormalMode;
EMI_InitStruct.EMI_Bank_IDCY =0xf;
EMI_InitStruct.EMI_Bank_WSTRD =0xf;
EMI_InitStruct.EMI_Bank_WSTWR =0xf;
EMI_InitStruct.EMI_Bank_WSTROEN=0xf;
EMI_InitStruct.EMI_Bank_WSTWEN=0x0f;
EMI_InitStruct.EMI_Bank_WSTRD =0x04;
EMI_InitStruct.EMI_Bank_WSTROEN=0x03;
EMI_InitStruct.EMI_Bank_WSTWR =0x04;
EMI_InitStruct.EMI_Bank_WSTWEN=0x03;
EMI_Init( EMI_Bank0, &EMI_InitStruct );
}
P8口上的波形
------- ---- ---- -------
___| |_____| |_____| |_____| |__
较宽的高脉冲为160ns,较窄的高脉冲为50ns,低脉冲为60ns。
如果将程序中的while(data1<data2)改成while(1),则结果如下:
较宽的高脉冲为100ns,较窄的高脉冲为50ns,低脉冲为60ns。
测量仪器是采样周期为10ns的逻辑分析仪。
结论
一条“B 0X0025CC”的执行时间是100-50=50ns。
两条“B 0X00xxxx”的执行时间是160-50=110ns。
谢谢你的结果!
能否将时钟频率降为10M,想看看同样程序的P8口上的波形!仅仅单从指令上看,低脉冲也应该是一个时钟(10n),所以我的建议是忽略对外部操作的延迟,延长指令时间能够更清楚地看到P8口上的波形执行指令的个数,同时使用while(1)。
telnet的主意不错
我们在测试检查楼主提供的程序,看看配置是否正确。
香水城,测试结果有否改进?
怎么没人回答我的问题了呢?
我现在的项目对速度要求很高,如果每个while语句都得多费110ns-60ns=50ns的时间,很心疼呀。
配置的问题
不知道楼主最终是想要看CPU跑在最快的速度(96MHz)还是EMI跑在最快的速度(66MHz)时候的情况。
在这个配置里,EMI已经被配置在了96MHz,已经超出了datasheet的上限值
另外,楼主用的oscillator用的是多少?