OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4689|回复: 9

打算做个 时钟【无缝切换】高可靠度的 STM32 基础程序。

[复制链接]

87

主题

569

帖子

0

精华

高级会员

Rank: 4

积分
831
金钱
831
注册时间
2014-9-30
在线时间
140 小时
发表于 2015-2-27 21:59:16 | 显示全部楼层 |阅读模式

不知道为什么?STM32 没有做成时钟完全硬件自动备用
虽然有 HSE时钟 失效后 自动切换到 HSI的 功能,但是:
由于大多数情况下都使用了 PLL倍频,因此切换到 HSI
之后:系统的工作频率就变为 8MHz,必须通过软件去
做重新设置,才能在 HSI 条件下、重新使用 PLL 时钟。

考虑到 USB 48MHz 时钟的兼容需要,俺打算:平常 HSE
模式的时候,不使 PLL倍频到72Mhz ,只倍频到 48 Mhz。

由于 HSI时钟在进入 PLL的时候被无条件的2分频,所以
俺这里也把 HSE时钟做2分频之后再提供给 PLL这样一来
若发生时钟切换的时候, PLL的输入都统一为 4MHz 。。
 LL倍频系数也统一为12倍频 =48MHz 。

可靠性高于一切的情况下:怎么没有人写出现成的完全切换
代码呢??72Mhz需要插入2个等待,48MHz只插入1个等待
其实 CPU的运行速度相差也就不到 1.5倍咯。。。

图为:用导线 短路PD0(OSC_IN)与+3.3V 强迫 HSE停振。
波形对比,可是很奇怪:频率差 不是 6倍明天继续找原因
俺使用 PLL输出48MHz ,切换到 HSI(8MHz) 应该 6倍频差 啊?
。。。


奇怪 频率差 不是 6倍。。。(程序完全 没变化。。。)

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

87

主题

569

帖子

0

精华

高级会员

Rank: 4

积分
831
金钱
831
注册时间
2014-9-30
在线时间
140 小时
 楼主| 发表于 2015-2-27 22:03:28 | 显示全部楼层
/*  STM32F10X_MD
USE_STDPERIPH_DRIVER
SYSCLK_FREQ_48MHz  都需要在工程中C、C++ 预处理栏目去定义  */

#include "stm32f10x.h"
#include <stdio.h>
#include "My_Stm32F103.h"

int main(void) {
  __IO uint32_t MyTemp_1 = 0;

  RCC_CFGR = RCC_CFGR | 0x06000000; //设置MCO输出—(HSE)—信号

  RCC_AHBENR  = 0xffffffff;     //Open FLASH,SRAM,DMA;clock
  RCC_APB2ENR = 0xffffffff;     //Open All clock
  RCC_APB1ENR = 0xffffffff;     //Open All clock

  AFIO_MAPR = 0x02000000;       //释放出三个JTAG的口,做普通IO口线。

  GPIOA_ODR = 0x0000ffff;       //凡是输入:全部搞成“上拉”
  GPIOA_CRL = 0x88888888;
  GPIOA_CRH = 0x3888888B;       //PA15 做普通IO(3),PA8复用推挽(B)做MCO

  GPIOB_ODR = 0x0000ffff;
  GPIOB_CRL = 0x88833888;       //PB3,4做普通IO(3)—推挽50MHz—
  GPIOB_CRH = 0x88888888;

  GPIOC_ODR = 0x0000ffff;
  GPIOC_CRL = 0x88888888;
  GPIOC_CRH = 0x88888888;

  GPIOD_ODR = 0x0000ffff;
  GPIOD_CRL = 0x88888888;       //晶体振荡器"88"带上拉也可起振
  GPIOD_CRH = 0x88888888;

  RCC_ClockSecuritySystemCmd(ENABLE);//使能或者失能时钟安全系统

while(1)
  {
    // 没事空转...
  GPIO_WriteBit(GPIOB, GPIO_Pin_3, Bit_RESET);
  MyTemp_1++;
  GPIO_WriteBit(GPIOB, GPIO_Pin_3, Bit_SET);

  GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET);//设置或者清除指定的数据端口位

  GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET);  //设置或者清除指定的数据端口位
 
  GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET);//设置或者清除指定的数据端口位 重复100次

  GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET);   //设置或者清除指定的数据端口位  重复100次
 
  }
}

———————————NMI中断—————————stm32f10x_it.c 中——

void NMI_Handler(void)
{
  GPIO_ResetBits(GPIOB, GPIO_Pin_4);//清除指定的数据端口位(给逻辑分析仪提供触发)

  RCC_ClearITPendingBit(RCC_IT_CSS);//清除RCC的中断待处理位

  RCC->CFGR = 0x066A0400;       // HSI x 12倍频=48MHz(若用HSE也要先除以2得到4Mhz)
  /*   RCC->CFGR = 0x066B0400;     HSE x 12倍频=48MHz  */

  /* Enable PLL */
  RCC->CR |= RCC_CR_PLLON;

  /* Wait till PLL is ready */
  while((RCC->CR & RCC_CR_PLLRDY) == 0)
  {
  }

  /* Select PLL as system clock source */
  RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
  RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;   

  /* Wait till PLL is used as system clock source */
  while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
  {
  }
    GPIO_SetBits(GPIOB, GPIO_Pin_4);//设置指定的数据端口位(给逻辑分析仪提供NMI结束标示)
  }

————————————NMI 结束————————————

SystemInit 里面 修改(添加)

    RCC->CFGR = 0x066B0400; //直接HSE /2=4MHz x 12倍频 添加这行在system_stm32f10x.c
    /* RCC->CFGR = 0x066A0400; //直接hsI/2=4MHz x 12倍频  */

    //  位置在 PLL 使能 之前。。。
    /* Enable PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* Wait till PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }



    /* 后面没多少行  就是 SetSysClockTo56() 的程序体 */

回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2015-2-27 22:16:32 | 显示全部楼层
既然这么要求高,楼主何不直接用内部HSI得了?还省了个晶振。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

87

主题

569

帖子

0

精华

高级会员

Rank: 4

积分
831
金钱
831
注册时间
2014-9-30
在线时间
140 小时
 楼主| 发表于 2015-2-27 22:38:50 | 显示全部楼层
回复【3楼】正点原子:
---------------------------------
谢谢 原子老大 关注。。。

总感觉:STM32 —— HSE主,HSI备——的模式 要可靠一些 。。。
(可惜 HSI 若是损坏【哪怕 HSE完好起振】CPU 仍将完全 无法 启动。)
俺这————唯一的理由是:HSE 频率 毕竟还是要准确 一些。————

前几天在贵论坛 找到一个好工具 “STM32库函数代码自动生成器V1[1].2.rar”

要不然:使用库、那一长串的 英文字,,俺 看着 就“眼花” 42寸显示 仍然眼花。

这样 也好 练习练习 NMI 中断的写法。。。做到 时钟无缝 切换。。正式程序会用

PA15 做个指示灯:HSI 模式的时候:这个灯会常亮=以示告警 HSE 已经失效。。

很不习惯:V3.5库 中:结构体的 写法 【XXX -> YYY】所以 2009年 就自己做 头。

缩减头My_Stm32F103.h

30.17 KB, 下载次数: 41

回复 支持 反对

使用道具 举报

87

主题

569

帖子

0

精华

高级会员

Rank: 4

积分
831
金钱
831
注册时间
2014-9-30
在线时间
140 小时
 楼主| 发表于 2015-2-28 11:35:16 | 显示全部楼层
今天 在 NMI 中断中 ,写了 几条 读状态的 语句。
拔掉短路线,时钟无法自己恢复 原样了。。。。
但是:频率比 6比1 ,莫名其妙的 正常了 。。。



语句如下:
void NMI_Handler(void)
{
  __IO uint32_t MyTemp_1 = 0;
  __IO uint32_t MyTemp_2 = 0;
 
  GPIO_ResetBits(GPIOB, GPIO_Pin_4);//清除指定的数据端口位
  MyTemp_2 = RCC_GetITStatus(RCC_IT_CSS);      //检查指定的RCC中断发生与否
  MyTemp_2 ++;
  MyTemp_1 = RCC_CIR;
  MyTemp_1 ++;
  RCC_ClearITPendingBit(RCC_IT_CSS);//清除RCC的中断待处理位
  MyTemp_1 = RCC_CIR;
  MyTemp_1 ++;
  GPIO_SetBits(GPIOB, GPIO_Pin_4);//设置指定的数据端口位
}
回复 支持 反对

使用道具 举报

4

主题

125

帖子

1

精华

高级会员

Rank: 4

积分
870
金钱
870
注册时间
2014-8-7
在线时间
49 小时
发表于 2015-2-28 14:19:33 | 显示全部楼层
我来学习的~
回复 支持 反对

使用道具 举报

87

主题

569

帖子

0

精华

高级会员

Rank: 4

积分
831
金钱
831
注册时间
2014-9-30
在线时间
140 小时
 楼主| 发表于 2015-2-28 16:09:12 | 显示全部楼层
 回复【6楼】 正.点.原.子 :
---------------------------------
坛主 太谦虚了。。。俺这【时钟无缝切换】初步取得 成功 。

——切换居然 只用了 120uS ——比我想象的 短。待优化。
——还有就是,从 HSI 切换回去的 思路,还在思考中。

这下可以专心做程序了。惭愧:我自2009年学到现在 才算入门。
多亏有了“STM32库函数代码自动生成器V1[1].2.rar”这个好工具。



void NMI_Handler(void)
{
  GPIO_ResetBits(GPIOB, GPIO_Pin_4);//清除指定的数据端口位(给逻辑分析仪提供触发)

  RCC_ClearITPendingBit(RCC_IT_CSS);//清除RCC的中断待处理位

  RCC->CFGR = 0x066A0400;       // HSI x 12倍频=48MHz(若用HSE也要先除以2得到4Mhz)
  /*   RCC->CFGR = 0x066B0400;     HSE x 12倍频=48MHz  */

  /* Enable PLL */
  RCC->CR |= RCC_CR_PLLON;

  /* Wait till PLL is ready */
  while((RCC->CR & RCC_CR_PLLRDY) == 0)
  {
  }

  /* Select PLL as system clock source */
  RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
  RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;   

  /* Wait till PLL is used as system clock source */
  while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
  {
  }
 
  GPIO_SetBits(GPIOB, GPIO_Pin_4);//设置指定的数据端口位(给逻辑分析仪提供NMI结束标示)
 
}

回复 支持 反对

使用道具 举报

87

主题

569

帖子

0

精华

高级会员

Rank: 4

积分
831
金钱
831
注册时间
2014-9-30
在线时间
140 小时
 楼主| 发表于 2015-2-28 16:34:00 | 显示全部楼层
主要是:要 事先 在 system_stm32f10x.c 这个文件 对应的 48Mhz 时钟
函数中PLL 使能前 添加 【 RCC->CFGR = 0x066B0400; //直接HSE /2=4MHz x 12倍频】

SetSysClockTo48() 其上下文如下:

  if (HSEStatus == (uint32_t)0x01)
  {
    /* Enable Prefetch Buffer */
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    /* Flash 1 wait state */
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_1;   
 
    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
     
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
   
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
    。
    。
    。
    /* Enable PLL */
    RCC->CFGR = 0x066B0400; //直接HSE /2=4MHz x 12倍频
/*  RCC->CFGR = 0x066A0400; //直接hsI/2=4MHz x 12倍频  */

    RCC->CR |= RCC_CR_PLLON;



下面 没几行 就是 SetSysClockTo56()  的 函数 了。。。

回复 支持 反对

使用道具 举报

4

主题

40

帖子

0

精华

初级会员

Rank: 2

积分
76
金钱
76
注册时间
2015-3-17
在线时间
0 小时
发表于 2015-4-4 14:52:48 | 显示全部楼层
楼主这是什么软件,可否分享一下
回复 支持 反对

使用道具 举报

87

主题

569

帖子

0

精华

高级会员

Rank: 4

积分
831
金钱
831
注册时间
2014-9-30
在线时间
140 小时
 楼主| 发表于 2015-4-5 11:00:20 | 显示全部楼层
这个 【无缝切换】 已经做成功了。。。48MHz 主频,是考虑到 USB 使用。。。

其实 修改一下,就可以做成 60MHz 无缝切换 —— 是 我最喜欢的。不支持USB。

V35_01学中断48MHz_无缝切换.rar

448.92 KB, 下载次数: 67

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-24 03:20

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表