[其他ST产品] stm32中DMA,时钟树、内存总线、配置时钟时先配置flash->acr、通过寄存器点亮led

[复制链接]
1742|43
 楼主| wang6623 发表于 2023-9-25 18:08 | 显示全部楼层
8889665115c139aa76.png
上图中的外部时钟源指的是相对于core的内部,但还是在stm32芯片上
 楼主| wang6623 发表于 2023-9-25 18:08 | 显示全部楼层
内核时钟数值上等于HCLK时钟,可以通过设置HCLK时钟来决定FCLK时钟的大小
1284465115c2fcefb8.png
参考:《Cortex-M3 权威指南》
 楼主| wang6623 发表于 2023-9-25 18:09 | 显示全部楼层
 楼主| wang6623 发表于 2023-9-25 18:09 | 显示全部楼层
整个系统有四个部分需要时钟

USB
各种外设
RTC
看门狗
前两种主要是靠内部或外部高速时钟,默认复位后是内部高数时钟
RTC通过RTCsel来从HSE、LSE、LSI中选择一个
看门狗就是内部低速时钟

PLL准确的的来说并不是一个时钟,它是将时钟源传过来的时钟信号倍频再传给后续的外设
 楼主| wang6623 发表于 2023-9-25 18:09 | 显示全部楼层
整个时钟树里有四个选择开关:

1.PLLXTPRE 倍频前分频选择开关,在传给PLLMUTL倍频前要不要分频
2.PLLSRC 倍频前输入信号来源选择开关,是选择内部的还是外部的
3.SW 各种外设时钟源选择开关,可以选择内部的还是外部的还是PLL倍频后 上面PLL倍频后的有内部倍频后的还是外部直接倍频 后的还是外部分频再倍频后的 所以SW切换后的有5种不同路径的时钟源个各种外设

4.RTCsel RTC时钟源选择开关,可以切换三种来源,一高速外部时钟128分频后,二外部低速,三内部低速
 楼主| wang6623 发表于 2023-9-25 18:09 | 显示全部楼层
复位后默认的都是内部高速和内部低速时钟源,倍频也没有打开
 楼主| wang6623 发表于 2023-9-25 18:12 | 显示全部楼层
(2)简述由8M晶振到72M主频的过程,以及通过寄存器方式配置72M主频的过程
要达到72MHz ,那就必须要开倍频,且必须使用外部高速时钟,内部高速时钟在倍频前有一个2分频所以最高只能倍频到64MHz

以外部晶振为8MHz来说,路径是,
PLLXTPRE不分频-> PLLSRC选外部高速 -> PLLMULT 设为9倍频 -> SW切换为PLL输入

上述路径可以使系统主频达到72MHz
 楼主| wang6623 发表于 2023-9-25 18:12 | 显示全部楼层
以下是整个的配置过程

RCC_CR 地址:0x40021000 + 0 = 0x40021000 复位值:0x00000083 16位HSEON置一,然后判断17位HSERDY,外部时钟就绪后进性下一步

RCC_CFGR 地址:0x40021000 + 0x04 = 0x40021004 复位值:0x00000000 就是我们上边说的哪个顺序,16位PLLSRC置1,17位PLLXTPRE置0 ,然后18-21位的PLLMUL
置0111,4-7位AHB预分频置0000不分频,8-10位APB1预分频置100,2分频(因为ahb是72mhz,apb1最高可以36mhz,所以必须分频)。11-13位APB2预分频置000,不分频。

RCC_CR 24位PLLON置一,判断25位PLLRDY,为1说明就绪,继续下一步。

RCC_CFGR 0-1位SW置10,PLL输出作为系统时钟,然后判断2-3位,是否为10(PLL输出作为系统时钟)
 楼主| wang6623 发表于 2023-9-25 18:13 | 显示全部楼层
(3)阅读如下代码,理解并解释每一步的作用
3472465115d299f6b8.png
typedef unsigned short int uint16_t;  //定义一个short型变量占两个字节长度
typedef unsigned       int uint32_t;  //定义一个int型变零占四个字节长度
#define   _IO  volatile

#define PERIPH_BASE      ((uint32_t)0x40000000)  //定义外设的基地址
#define APB2PPERIPH_BASE  (PERIPH_BASE + 0x10000)//定义外设总线APB2的基地址

#define GPIOC_BASE       (APB2PPERIPH_BASE + 0x1000)//定义外设总线APB2上挂载的GPIOC基地址
#define GPIOC            (GPIOC_BASE)//定义GPIOC引脚的基地址
#define GPIOC_CRH        (GPIOC + 0x04) //定义GPIOC端口配置高寄存器
#define GPIOC_ODH        (GPIOC + 0x0c)//定义端口数据输出寄存器

#define AHBPERIPH_BASE  (PERIPH_BASE + 0x20000)//定义高速总线AHB的基地址
#define RCC_BASE         (AHBPERIPH_BASE + 0x1000)//定义RCC时钟基地址
#define RCC              (RCC_BASE) //定义RCC时钟基地址
#define RCC_APB2ENR      (RCC + 0x18) //定义使能挂载在APB2上的外设的寄存器
#define RCC_CR           (RCC + 0x00)//定义时钟控制寄存器
#define RCC_CFGR         (RCC + 0x04)//定义时钟配置寄存器

#define FLASH_R_BASE     (AHBPERIPH_BASE + 0x2000)  //定义AHB上挂载的flash接口地址
#define FLASH            (FLASH_R_BASE )
#define FLASH_ACR        (FLASH + 0x00)

void RCC_init(uint16_t PLL)  //传入倍频数PLL
{
    uint32_t temp = 0;

    *((uint32_t *)RCC_CR) |= 0x00010000;//将HSEON位置1
    while (!(*((uint32_t*)RCC_CR) >> 17)); //等待HSERDY位硬件置1后跳出循环
    *((uint32_t *)RCC_CFGR) = 0X00000400; //将PPRE1位置100,,将HCLOCK二分频为PCLOCK1
    PLL -= 2;     //PLLMUL位是从0000开始二倍频,所以要将传入的倍频数减去一个2等于PLLMUL位实际应该写入的真实值
    *((uint32_t *)RCC_CFGR) |= PLL << 18;  //将倍频位置为需要的倍频
    *((uint32_t *)RCC_CFGR) |= 1 << 16;   //将PLLSRC位置1,选择HSE为倍频输入时钟源
    *((uint32_t *)FLASH_ACR) |= 0x2;      //将LATENCY位置为010,两个等待状态,闪存读取要和时钟频率一致不然程序会跑飞
    *((uint32_t *)RCC_CR) |= 0x01000000;  //将PLLON位置1,开启PLL倍频
    while (!(*((uint32_t*)RCC_CR) >> 25)); //等待PLLRDY位硬件置1后跳出循环
    *((uint32_t *)RCC_CFGR) |= 0x00000002; //将SW位置1,选择倍频后的时钟源作为系统时钟源
    while (temp !=0x02)                   //等待SWS位硬件置为10时,PLL成功作为系统时钟源输出
    {
        temp = *((uint32_t *)RCC_CFGR) >> 2; //将SWS的两位移到最右边
        temp &= 0x03;                       //与11取与
    }
   
}
 楼主| wang6623 发表于 2023-9-25 18:13 | 显示全部楼层
3.flash寄存器设置延时周期的作用
STM32配置时钟时注意设置FLASH等待周期

1582465115d3e69c09.png
 楼主| wang6623 发表于 2023-9-25 18:13 | 显示全部楼层
4.通过寄存器点亮led
  1. typedef  unsigned int  u32;

  2. #define GPIOC_BASE                        0x40011000
  3. #define PERIPH_BASE                        0x40000000
  4. #define APB2_BASE                                (PERIPH_BASE+0x10000)
  5. #define AHB_BASE                                (PERIPH_BASE+0x20000)
  6. #define RCC_BASE                                (AHB_BASE+0x1000)
  7. #define RCC_APB2ENR                        (RCC_BASE+0x18)

  8. #define GPIOx_CRH_OFF                0x0004
  9. #define GPIOx_ODR_OFF                0x000C
  10. #define GPIOx_CRH                          (GPIOC_BASE+GPIOx_CRH_OFF)//0x4001 1004
  11. #define GPIOx_ODR                                (GPIOC_BASE+GPIOx_ODR_OFF)//0x4001 100C

  12. void delay(u32 x)
  13. {
  14.         u32 i = 0;
  15.        
  16.         while(x--)
  17.         {
  18.                 i = 10000000;
  19.                 while(i--);
  20.         }
  21. }

  22. int main(void)
  23. {
  24.         *((unsigned int *)RCC_APB2ENR) |= 0x00000010;
  25.         //*((unsigned int *)GPIOx_CRH) = 0x00300000;//error
  26.         //先清除寄存器相应位的值
  27.         *((unsigned int *)GPIOx_CRH) &= 0xff0fffff;
  28.         //然后再进行对相应位赋值
  29.         *((unsigned int *)GPIOx_CRH) |= 0x00300000;
  30.         //*((unsigned int *)GPIOx_CRH) =  *((unsigned int *)GPIOx_CRH)  +  0x00300000;
  31.         //*(GPIOx_CRH) = 0x00300000;
  32.         *((unsigned int *)GPIOx_ODR) &= ~(1<<13);
  33.         *((unsigned int *)GPIOx_ODR) |= 0x00000000;
  34.        
  35.         //闪烁
  36.         while(1)
  37.         {
  38.                 //亮
  39.                 *((unsigned int *)GPIOx_ODR) &= ~(1<<13);
  40.                 *((unsigned int *)GPIOx_ODR) |= 0x00000000;
  41.                 //延时一些时间
  42.                 //sleep(2);
  43.                 delay(1);
  44.                 //循环
  45.                
  46.                 //灭
  47.                 *((unsigned int *)GPIOx_ODR) &= ~(1<<13);
  48.                 *((unsigned int *)GPIOx_ODR) |= 0x00002000;//0000 0000 0000 0000 0010 0000 0000 0000
  49.                 //延时一些时间
  50.                 delay(1);
  51.         }
  52.        
  53.         return 0;
  54. }

 楼主| wang6623 发表于 2023-9-25 18:13 | 显示全部楼层
上面一种是直接对ODR寄存器输出高低电平来控制亮灭

 楼主| wang6623 发表于 2023-9-25 18:13 | 显示全部楼层
下面这种是通过BSRR寄存器来控制输出高低电平来控制亮灭
 楼主| wang6623 发表于 2023-9-25 18:13 | 显示全部楼层
  1. /*******************************************************************************
  2. *                 
  3. *                                        普中科技
  4. --------------------------------------------------------------------------------
  5. * 实 验 名                 : 使用寄存器点亮一个LED
  6. * 实验说明       : 操作寄存器控制LED1指示灯闪烁
  7. * 连接方式       :
  8. * 注    意                 :        
  9. *******************************************************************************/

  10. #include "stm32f10x.h"

  11. typedef unsigned int u32;   //类型重定义 unsigned int -- u32

  12. void SystemInit()
  13. {
  14.        
  15. }

  16. /*******************************************************************************
  17. * 函 数 名         : delay
  18. * 函数功能                   : 延时函数,通过while循环占用CPU,达到延时功能
  19. * 输    入         : i
  20. * 输    出         : 无
  21. *******************************************************************************/
  22. void delay(u32 i)
  23. {
  24.         while(i--);
  25. }

  26. /*******************************************************************************
  27. * 函 数 名         : main
  28. * 函数功能                   : 主函数
  29. * 输    入         : 无
  30. * 输    出         : 无
  31. *******************************************************************************/
  32. int main()
  33. {
  34.         RCC_APB2ENR |= 1<<4;
  35.         GPIOC_CRH &= ~( 0x0F<< (4*5));//将MODE13和CONF13四位清零
  36.         GPIOC_CRH |= (1<<4*5);        //将MODE13和CONF13四位置为0100
  37.         GPIOC_ODR &=~(1<<13);//配置输出低电平
  38.         GPIOC_BSRR=(1<<(16+13));
  39.         while(1)
  40.         {
  41.                 GPIOC_BSRR=(1<<(16+13));
  42.                 delay(0x1FFFFF);
  43.                 GPIOC_BSRR=(1<<(13));
  44.                 delay(0x1FFFFF);
  45.         }
  46. }




Pulitzer 发表于 2024-2-21 07:06 | 显示全部楼层

通过访问寄存器来控制I2C1工作时钟的开启。
童雨竹 发表于 2024-2-21 09:02 | 显示全部楼层

这种方法可以使散热体积和表面面积增大两倍多
Wordsworth 发表于 2024-2-21 10:05 | 显示全部楼层

I2C1工作时钟源选择;I2C1模块工作时钟的开启使能。
Clyde011 发表于 2024-2-21 11:08 | 显示全部楼层

STM32芯片中有多个工作时钟源的外设很常见
公羊子丹 发表于 2024-2-21 12:01 | 显示全部楼层

功率开关漏极(或集电极)
万图 发表于 2024-2-21 13:04 | 显示全部楼层

CPU借助于APB总线访问相关寄存器达到对I2C1工作模块的控制
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部