打印

GPIO翻转的精华帖子不存在了,谁知道IO翻转达到10M的方法。

[复制链接]
28488|35
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
GPIO, rc, ip, PLL, ST
最近我一直在搜索STM32,IO翻转18M速度的资料和帖子。
香城主提供了以前关于这方面的精华帖链接,但是都被删除不存在了。
我在编译的时候,IO翻转最多才7M。
为了方便大家讨论,现将我编写的程序贴出来。由于我是初学者,花了我不少时间,从最初的150多us,速度提高到了130ns左右,还有就是软件仿真和实际硬件测试是非常不同的。以上速度都是我用示波器测试得到的。所以什么东西还是要看结果能让我们得到什么。
#include <stm32f10x.h>
#include "stm32f10x_conf.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_flash.h"
#include "stm32f10x_usart.h"



#define FLASH_Latency_2                ((uint32_t)0x00000002)  /* FLASH Two Latency cycles */
#define FLASH_PrefetchBuffer_Enable    ((uint32_t)0x00000010)  /* FLASH Prefetch Buffer Enable */
#define RCC_PLLSource_HSE_Div1         ((uint32_t)0x00010000)
//#define RCC_PLLMul_2                    ((uint32_t)0x00000000)
//#define RCC_PLLMul_3                    ((uint32_t)0x00040000)
//#define RCC_PLLMul_4                    ((uint32_t)0x00080000)
//#define RCC_PLLMul_5                    ((uint32_t)0x000C0000)
//#define RCC_PLLMul_6                    ((uint32_t)0x00100000)
//#define RCC_PLLMul_7                    ((uint32_t)0x00140000)
//#define RCC_PLLMul_8                    ((uint32_t)0x00180000)
#define RCC_PLLMul_9                    ((uint32_t)0x001C0000)
//#define RCC_PLLMul_10                   ((uint32_t)0x00200000)
//#define RCC_PLLMul_11                   ((uint32_t)0x00240000)
//#define RCC_PLLMul_12                   ((uint32_t)0x00280000)
//#define RCC_PLLMul_13                   ((uint32_t)0x002C0000)
//#define RCC_PLLMul_14                   ((uint32_t)0x00300000)
//#define RCC_PLLMul_15                   ((uint32_t)0x00340000)
//#define RCC_PLLMul_16                   ((uint32_t)0x00380000)


//时钟初始化
void RCC_Configuration(void)                     //时钟初始化
{
    ErrorStatus HSEStartUpStatus;                 //等待时钟的稳定
    RCC_DeInit();                                 //时钟管理重置
    RCC_HSEConfig(RCC_HSE_ON);                //打开外部晶振
    HSEStartUpStatus = RCC_WaitForHSEStartUp();   //等待外部晶振就绪
         if (HSEStartUpStatus == SUCCESS)
         {
            FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);  //flash缓冲读取加速
            FLASH_SetLatency(FLASH_Latency_2);        // flash操作的延时
            RCC_HCLKConfig(RCC_SYSCLK_Div1);          //AHB使用系统时钟(只有目标时钟源就绪时时钟切换才会发生 )
            RCC_PCLK2Config(RCC_HCLK_Div1);           //APB2(高速)为HCLK的一半
            RCC_PCLK1Config(RCC_HCLK_Div1);           //APB1(低速)为HCLK的一半
              //注:AHB主要负责外部存储器时钟。PB2负责AD,I/O,高级TIM,串口1,EXTI。
              // APB1负责DA,USB,SPI,I2C,CAN,串口2345,普通TIM,IWDG,WWDG。
            RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9); //9为时钟倍频系数,PLLCLK = 8MHz * 9 = 72 MHz
              //HSI时钟信号由内部的8MHz的RC振荡器产生,可直接作为系统时钟,或在2分频后作为PLL输入
            RCC_PLLCmd(ENABLE);                       //启动PLL
             while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY==RESET)) {}    //等待PLL启动
            RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);              //将PLL设置为系统时钟源
             while(RCC_GetSYSCLKSource()!=0x08){}                                                      
         }  
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA
                           |RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC
                           |RCC_APB2Periph_GPIOD | RCC_APB2Periph_ADC1
                           | RCC_APB2Periph_AFIO |
                           RCC_APB2Periph_SPI1, ENABLE );
  // RCC_APB2PeriphClockCmd(RCC_APB2Periph_ALL ,ENABLE );
     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4
                           |RCC_APB1Periph_USART3|RCC_APB1Periph_TIM2                                   
                           , ENABLE );
         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

}
/*
//配置系统时钟,使能各外设时钟
void RCC_Configuration(void)
{
        SystemInit();        
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA
                           |RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC
                           |RCC_APB2Periph_GPIOD | RCC_APB2Periph_ADC1
                           | RCC_APB2Periph_AFIO |
                           RCC_APB2Periph_SPI1, ENABLE );
  // RCC_APB2PeriphClockCmd(RCC_APB2Periph_ALL ,ENABLE );
     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4
                           |RCC_APB1Periph_USART3|RCC_APB1Periph_TIM2                                   
                           , ENABLE );
         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
}

*/

void GPIO_config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}

int main(void)
{  
        RCC_Configuration();
        GPIO_config();

        while (1)
        {
//      GPIOB->BRR=GPIO_Pin_11;
//      GPIOB->BSRR=GPIO_Pin_11;
    GPIOA->BRR=0x00000001;
    GPIOA->BSRR=0x00000001;
        }
}
来自 2楼
lllaaa| | 2012-4-21 09:01 | 只看该作者
要得到最快速度lz方法显然是有问题的

        while (1)
        {
    GPIOA->BRR=0x00000001;
    GPIOA->BSRR=0x00000001;
        }

在while里会涉及到将GPIOA->BRR地址赋给寄存器,然后以cpu寄存器寻址去写外设。这样就有几个周期。
lz应该这样:

      while (1)
        {
    GPIOA->BRR=0x00000001;
    GPIOA->BSRR=0x00000001;
     GPIOA->BRR=0x00000001;
    GPIOA->BSRR=0x00000001;
     GPIOA->BRR=0x00000001;
    GPIOA->BSRR=0x00000001;
     GPIOA->BRR=0x00000001;
    GPIOA->BSRR=0x00000001;
     GPIOA->BRR=0x00000001;
    GPIOA->BSRR=0x00000001;
     GPIOA->BRR=0x00000001;
    GPIOA->BSRR=0x00000001;
     GPIOA->BRR=0x00000001;
    GPIOA->BSRR=0x00000001;
     GPIOA->BRR=0x00000001;
    GPIOA->BSRR=0x00000001;
     GPIOA->BRR=0x00000001;
    GPIOA->BSRR=0x00000001;
     GPIOA->BRR=0x00000001;
    GPIOA->BSRR=0x00000001;
        }

然后把优化开到最大。这样一来,地址就会在最开始存入寄存器并一直保存在寄存器里不用再重新赋值

使用特权

评论回复
板凳
mcuisp| | 2012-4-20 23:19 | 只看该作者
用BitBand要快一些

使用特权

评论回复
地板
acgean| | 2012-4-21 08:52 | 只看该作者
#define RUNLED  (*(u32*)(PERIPH_BB_BASE+((GPIOA_BASE+12)*32)+7*4))

RUNLED  =1;

BitBand要快一些,  按理是的, 但经我测试, 发现并非如此。
为什么呢,是不是 CPU 有地址变换操作,延迟了时间?

使用特权

评论回复
5
seawwh| | 2012-4-21 10:17 | 只看该作者
可以使用DMA的方法试一试:

  Mem->BSSR  的DMA 传输;
  DMA的采用循环模式;
  Mem中存放2个32bits 字,分别为0x00010000,0x00000001
(假定在端口的第一位)
  据说F4的DMA会比F1 快很多

使用特权

评论回复
6
香水城| | 2012-4-21 11:22 | 只看该作者
以前的精华帖子不存在了,俺在送一条裤子给4楼吧。

使用特权

评论回复
7
wang1991| | 2012-4-21 17:06 | 只看该作者
不太懂,我来学习学习!

使用特权

评论回复
8
ucuser| | 2012-4-21 17:11 | 只看该作者
写的好详细啊

使用特权

评论回复
9
logokfu| | 2012-4-22 17:21 | 只看该作者
其实很简单,打开ST固件库中自带的example,里面自带的那个IOtoggle程序,
你在主函数开始第一句开头加上  SystemInit();这句话就好了。

我的轻松都到18Mhz了;P







/**
  ******************************************************************************
  * @file    GPIO/IOToggle/main.c
  * @author  MCD Application Team
  * @version V3.5.0
  * @date    08-April-2011
  * @brief   Main program body.
  ******************************************************************************
  * @attention
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
//#include "stm32_eval.h"
/** @addtogroup STM32F10x_StdPeriph_Examples
  * @{
  */
/** @addtogroup GPIO_IOToggle
  * @{
  */
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
GPIO_InitTypeDef GPIO_InitStructure;
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
  * @brief  Main program.
  * @param  None
  * @retval None
  */
int main(void)
{
  /*!< At this stage the microcontroller clock setting is already configured,
       this is done through SystemInit() function which is called from startup
       file (startup_stm32f10x_xx.s) before to branch to application main.
       To reconfigure the default setting of SystemInit() function, refer to
       system_stm32f10x.c file
     */     
      
  
  
  SystemInit();//重点加上这一句就好了,其他原封不动
  /* GPIOD Periph clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
  /* Configure PD0 and PD2 in output pushpull mode */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOD, &GPIO_InitStructure);
  /* To achieve GPIO toggling maximum frequency, the following  sequence is mandatory.
     You can monitor PD0 or PD2 on the scope to measure the output signal.
     If you need to fine tune this frequency, you can add more GPIO set/reset
     cycles to minimize more the infinite loop timing.
     This code needs to be compiled with high speed optimization option.  */
  while (1)
  {
    /* Set PD0 and PD2 */
    GPIOD->BSRR = 0x00000005;
    /* Reset PD0 and PD2 */
    GPIOD->BRR  = 0x00000005;
    /* Set PD0 and PD2 */
    GPIOD->BSRR = 0x00000005;
    /* Reset PD0 and PD2 */
    GPIOD->BRR  = 0x00000005;
    /* Set PD0 and PD2 */
    GPIOD->BSRR = 0x00000005;
    /* Reset PD0 and PD2 */
    GPIOD->BRR  = 0x00000005;
    /* Set PD0 and PD2 */
    GPIOD->BSRR = 0x00000005;
    /* Reset PD0 and PD2 */
    GPIOD->BRR  = 0x00000005;
    /* Set PD0 and PD2 */
    GPIOD->BSRR = 0x00000005;
    /* Reset PD0 and PD2 */
    GPIOD->BRR  = 0x00000005;
    /* Set PD0 and PD2 */
    GPIOD->BSRR = 0x00000005;
    /* Reset PD0 and PD2 */
    GPIOD->BRR  = 0x00000005;
    /* Set PD0 and PD2 */
    GPIOD->BSRR = 0x00000005;
    /* Reset PD0 and PD2 */
    GPIOD->BRR  = 0x00000005;
    /* Set PD0 and PD2 */
    GPIOD->BSRR = 0x00000005;
    /* Reset PD0 and PD2 */
    GPIOD->BRR  = 0x00000005;
    /* Set PD0 and PD2 */
    GPIOD->BSRR = 0x00000005;
    /* Reset PD0 and PD2 */
    GPIOD->BRR  = 0x00000005;
    /* Set PD0 and PD2 */
    GPIOD->BSRR = 0x00000005;
    /* Reset PD0 and PD2 */
    GPIOD->BRR  = 0x00000005;
  }
}
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* Infinite loop */
  while (1)
  {
  }
}
#endif
/**
  * @}
  */
/**
  * @}
  */
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/




使用特权

评论回复
10
logokfu| | 2012-4-22 17:48 | 只看该作者
正如4楼所说的,如果你只写成这样
while (1)
        {
    GPIOA->BRR=0x00000001;
    GPIOA->BSRR=0x00000001;
        }


速度我测试了下也是可以到12Mhz左右的。

使用特权

评论回复
11
lgxlgxlgxzxj| | 2012-4-22 22:46 | 只看该作者

使用特权

评论回复
12
lut1lut| | 2012-4-23 11:04 | 只看该作者
To 9楼:为什么要

/************************************/
SystemInit();//重点加上这一句就好了,其他原封不动
/************************************/

使用特权

评论回复
13
logokfu| | 2012-4-23 11:15 | 只看该作者
这里发的可能不是很好看,自己go to definition一下就知道咯

使用特权

评论回复
14
lut1lut| | 2012-4-23 11:17 | 只看该作者
我知道这个函数是做什么的。

我要问的是,程序执行到main时,之前已经在跳到main之间执行了SystemInit(),下面是main()里的注释

/*!< At this stage the microcontroller clock setting is already configured,
       this is done through SystemInit() function which is called from startup
       file (startup_stm32f10x_xx.s) before to branch to application main.
       To reconfigure the default setting of SystemInit() function, refer to
       system_stm32f10x.c file
     */   

为何你还要再执行一遍?

使用特权

评论回复
15
logokfu| | 2012-4-23 11:23 | 只看该作者
你再配置一个新的参数就把之前启动文件里面的配置给覆盖咯,当然我用的STM32F107系列的,默认就是使用的72Mhz的。

使用特权

评论回复
16
logokfu| | 2012-4-23 11:29 | 只看该作者
至于说如果不配置的话,系统默认的配置应该是在这吧

使用特权

评论回复
17
lut1lut| | 2012-4-23 11:30 | 只看该作者
是已经被“调用了”,而不仅仅是“配置了”,好伐。

SystemInit() function which is called from startup file (startup_stm32f10x_xx.s) before to branch to application main

具体到你自己的应用,你应该只修改<system_stm32f10x.c>中对系统时钟的配置,如下之类的。。。

/***************************************/
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
#define SYSCLK_FREQ_24MHz  24000000
#else
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz  24000000 */
/* #define SYSCLK_FREQ_36MHz  36000000 */
/* #define SYSCLK_FREQ_48MHz  48000000 */
/* #define SYSCLK_FREQ_56MHz  56000000 */
#define SYSCLK_FREQ_72MHz  72000000
#endif
/***************************************/

当然你要重新配置AHB、APB分频因子,或重新配置闪存prefetch之类的特性,也应该在SetSysClock()中直接修改即可。而不是启动时跑一次默认的时钟配置,在main里再跑一次。

使用特权

评论回复
18
logokfu| | 2012-4-23 11:32 | 只看该作者
就是这个意思。

使用特权

评论回复
19
xqscu| | 2012-4-25 17:40 | 只看该作者
学习

使用特权

评论回复
20
lufeijian| | 2012-4-30 15:52 | 只看该作者
请教一下楼主,这么做有什么用呢?或者说在什么情况下要这样输出脉冲?

使用特权

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

本版积分规则

0

主题

21

帖子

0

粉丝