st_sys.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. #include "st_sys.h"
  2. //////////////////////////////////////////////////////////////////////////////////
  3. //本程序只供学习使用,未经作者许可,不得用于其它任何用途
  4. //ALIENTEK STM32开发板
  5. //系统时钟初始化(适合STM32F10x系列)
  6. //正点原子@ALIENTEK
  7. //技术论坛:www.openedv.com
  8. //创建日期:2010/1/1
  9. //版本:V1.9
  10. //版权所有,盗版必究。
  11. //Copyright(C) 广州市星翼电子科技有限公司 2009-2019
  12. //All rights reserved
  13. //********************************************************************************
  14. //V1.4修改说明
  15. //把NVIC KO了,没有使用任何库文件!
  16. //加入了JTAG_Set函数
  17. //V1.5 20120322
  18. //增加void INTX_DISABLE(void)和void INTX_ENABLE(void)两个函数
  19. //V1.6 20120412
  20. //1,增加MSR_MSP函数
  21. //2,修改VECT_TAB_RAM的默认偏移,设置为0.
  22. //V1.7 20120818
  23. //1,添加ucos支持配置宏SYSTEM_SUPPORT_UCOS
  24. //2,修改了注释
  25. //3,去掉了不常用函数BKP_Write
  26. //V1.8 20131120
  27. //1,修改头文件为stm32f10x.h,不再使用stm32f10x_lib.h及其相关头文件
  28. //V1.9 20150109
  29. //1,修改头文件为MY_NVIC_Init函数部分代码以支持向量号大于63的中断的设置
  30. //2,修改WFI_SET/INTX_DISABLE/INTX_ENABLE等函数的实现方式
  31. //V2.0 20150322
  32. //修改SYSTEM_SUPPORT_UCOS为SYSTEM_SUPPORT_OS
  33. //////////////////////////////////////////////////////////////////////////////////
  34. //设置向量表偏移地址
  35. //NVIC_VectTab:基址
  36. //Offset:偏移量
  37. void Sys_NVIC_SetVectorTable(u32 NVIC_VectTab, u32 Offset) {
  38. SCB->VTOR = NVIC_VectTab | (Offset & (u32)0x1FFFFF80); //设置NVIC的向量表偏移寄存器
  39. //用于标识向量表是在CODE区还是在RAM区
  40. }
  41. //设置NVIC分组
  42. //NVIC_Group:NVIC分组 0~4 总共5组
  43. void Sys_NVIC_PriorityGroupConfig(u8 NVIC_Group) {
  44. u32 temp, temp1;
  45. temp1 = (~NVIC_Group) & 0x07; //取后三位
  46. temp1 <<= 8;
  47. temp = SCB->AIRCR; //读取先前的设置
  48. temp &= 0X0000F8FF; //清空先前分组
  49. temp |= 0X05FA0000; //写入钥匙
  50. temp |= temp1;
  51. SCB->AIRCR = temp; //设置分组
  52. }
  53. //设置NVIC
  54. //NVIC_PreemptionPriority:抢占优先级
  55. //NVIC_SubPriority :响应优先级
  56. //NVIC_Channel :中断编号
  57. //NVIC_Group :中断分组 0~4
  58. //注意优先级不能超过设定的组的范围!否则会有意想不到的错误
  59. //组划分:
  60. //组0:0位抢占优先级,4位响应优先级
  61. //组1:1位抢占优先级,3位响应优先级
  62. //组2:2位抢占优先级,2位响应优先级
  63. //组3:3位抢占优先级,1位响应优先级
  64. //组4:4位抢占优先级,0位响应优先级
  65. //NVIC_SubPriority和NVIC_PreemptionPriority的原则是,数值越小,越优先
  66. void Sys_NVIC_Init(u8 NVIC_PreemptionPriority, u8 NVIC_SubPriority, u8 NVIC_Channel, u8 NVIC_Group) {
  67. u32 temp;
  68. Sys_NVIC_PriorityGroupConfig(NVIC_Group); //设置分组
  69. temp = NVIC_PreemptionPriority << (4 - NVIC_Group);
  70. temp |= NVIC_SubPriority & (0x0f >> NVIC_Group);
  71. temp &= 0xf; //取低四位
  72. NVIC->ISER[NVIC_Channel / 32] |= (1 << NVIC_Channel % 32); //使能中断位(要清除的话,相反操作就OK)
  73. NVIC->IP[NVIC_Channel] |= temp << 4; //设置响应优先级和抢断优先级
  74. }
  75. //外部中断配置函数
  76. //只针对GPIOA~G;不包括PVD,RTC和USB唤醒这三个
  77. //参数:
  78. //GPIOx:0~6,代表GPIOA~G
  79. //BITx:需要使能的位;
  80. //TRIM:触发模式,1,下升沿;2,上降沿;3,任意电平触发
  81. //该函数一次只能配置1个IO口,多个IO口,需多次调用
  82. //该函数会自动开启对应中断,以及屏蔽线
  83. void Ex_NVIC_Config(u8 GPIOx, u8 BITx, u8 TRIM) {
  84. u8 EXTADDR;
  85. u8 EXTOFFSET;
  86. EXTADDR = BITx / 4; //得到中断寄存器组的编号
  87. EXTOFFSET = (BITx % 4) * 4;
  88. RCC->APB2ENR |= 0x01; //使能io复用时钟
  89. AFIO->EXTICR[EXTADDR] &= ~(0x000F << EXTOFFSET); //清除原来设置!!!
  90. AFIO->EXTICR[EXTADDR] |= GPIOx << EXTOFFSET; //EXTI.BITx映射到GPIOx.BITx
  91. //自动设置
  92. EXTI->IMR |= 1 << BITx; // 开启line BITx上的中断
  93. //EXTI->EMR|=1<<BITx;//不屏蔽line BITx上的事件 (如果不屏蔽这句,在硬件上是可以的,但是在软件仿真的时候无法进入中断!)
  94. if (TRIM & 0x01) EXTI->FTSR |= 1 << BITx; //line BITx上事件下降沿触发
  95. if (TRIM & 0x02) EXTI->RTSR |= 1 << BITx; //line BITx上事件上升降沿触发
  96. }
  97. #define EVCR_PORTPINCONFIG_MASK ((uint16_t)0xFF80)
  98. #define LSB_MASK ((uint16_t)0xFFFF)
  99. #define DBGAFR_POSITION_MASK ((uint32_t)0x000F0000)
  100. #define DBGAFR_SWJCFG_MASK ((uint32_t)0xF0FFFFFF)
  101. #define DBGAFR_LOCATION_MASK ((uint32_t)0x00200000)
  102. #define DBGAFR_NUMBITS_MASK ((uint32_t)0x00100000)
  103. /**
  104. * 管脚复用设置
  105. *
  106. * @author lxz (121319 14:46:01)
  107. *
  108. * @param GPIOx
  109. * @param BITx
  110. * @param AFx
  111. */
  112. void GPIO_Remap_Set(uint32_t GPIO_Remap, u8 newstate) {
  113. uint32_t tmp = 0x00, tmp1 = 0x00, tmpreg = 0x00, tmpmask = 0x00;
  114. if ((GPIO_Remap & 0x80000000) == 0x80000000) {
  115. tmpreg = AFIO->MAPR2;
  116. } else {
  117. tmpreg = AFIO->MAPR;
  118. }
  119. tmpmask = (GPIO_Remap & DBGAFR_POSITION_MASK) >> 0x10;
  120. tmp = GPIO_Remap & LSB_MASK;
  121. if ((GPIO_Remap & (DBGAFR_LOCATION_MASK | DBGAFR_NUMBITS_MASK)) == (DBGAFR_LOCATION_MASK | DBGAFR_NUMBITS_MASK)) {
  122. tmpreg &= DBGAFR_SWJCFG_MASK;
  123. AFIO->MAPR &= DBGAFR_SWJCFG_MASK;
  124. } else if ((GPIO_Remap & DBGAFR_NUMBITS_MASK) == DBGAFR_NUMBITS_MASK) {
  125. tmp1 = ((uint32_t)0x03) << tmpmask;
  126. tmpreg &= ~tmp1;
  127. tmpreg |= ~DBGAFR_SWJCFG_MASK;
  128. } else {
  129. tmpreg &= ~(tmp << ((GPIO_Remap >> 0x15) * 0x10));
  130. tmpreg |= ~DBGAFR_SWJCFG_MASK;
  131. }
  132. if (newstate != 0) {
  133. tmpreg |= (tmp << ((GPIO_Remap >> 0x15) * 0x10));
  134. }
  135. if ((GPIO_Remap & 0x80000000) == 0x80000000) {
  136. AFIO->MAPR2 = tmpreg;
  137. } else {
  138. AFIO->MAPR = tmpreg;
  139. }
  140. }
  141. /**
  142. * 管脚模式设置
  143. *
  144. * @author lxz (121319 14:46:04)
  145. *
  146. * @param GPIOx
  147. * @param BITx
  148. * @param MODE
  149. * @param OTYPE
  150. * @param OSPEED
  151. * @param PUPD
  152. */
  153. void GPIO_Set(GPIO_TypeDef *GPIOx, u32 BITx, u32 MODE, u32 OSPEED, u32 PUPD) {
  154. u32 pinpos = 0, pos = 0, curpin = 0;
  155. int currentmode = 0;
  156. for (pinpos = 0; pinpos < 16; pinpos++) {
  157. pos = 1 << pinpos; //一个个位检查
  158. curpin = BITx & pos; //检查引脚是否要设置
  159. if (curpin == pos) { //需要设置
  160. //获取设置
  161. currentmode = 0;
  162. if (MODE != GPIO_MODE_IN_FLOATING && MODE != GPIO_MODE_AIN &&
  163. MODE != GPIO_MODE_IPD && MODE != GPIO_MODE_IPU) { //如果是输出模式
  164. currentmode |= OSPEED; //设置输出速度
  165. }
  166. if (PUPD == GPIO_PUPD_PU) { //设置上拉
  167. GPIOx->BSRR = 1 << pinpos;
  168. } else if (PUPD == GPIO_PUPD_PD) { //设置下拉
  169. GPIOx->BRR = 1 << pinpos;
  170. }
  171. currentmode |= MODE & 0x0f;
  172. //将设置保存到寄存器
  173. if (pinpos < 8) {
  174. GPIOx->CRL &= ~(0x0f << (pinpos * 4));
  175. GPIOx->CRL |= currentmode << (pinpos * 4);
  176. } else {
  177. GPIOx->CRH &= ~(0x0f << ((pinpos - 8) * 4));
  178. GPIOx->CRH |= currentmode << ((pinpos - 8) * 4);
  179. }
  180. }
  181. }
  182. }
  183. //不能在这里执行所有外设复位!否则至少引起串口不工作.
  184. //把所有时钟寄存器复位
  185. void MYRCC_DeInit(void) {
  186. RCC->APB1RSTR = 0x00000000; //复位结束
  187. RCC->APB2RSTR = 0x00000000;
  188. RCC->AHBENR = 0x00000014; //睡眠模式闪存和SRAM时钟使能.其他关闭.
  189. RCC->APB2ENR = 0x00000000; //外设时钟关闭.
  190. RCC->APB1ENR = 0x00000000;
  191. RCC->CR |= 0x00000001; //使能内部高速时钟HSION
  192. RCC->CFGR &= 0xF8FF0000; //复位SW[1:0],HPRE[3:0],PPRE1[2:0],PPRE2[2:0],ADCPRE[1:0],MCO[2:0]
  193. RCC->CR &= 0xFEF6FFFF; //复位HSEON,CSSON,PLLON
  194. RCC->CR &= 0xFFFBFFFF; //复位HSEBYP
  195. RCC->CFGR &= 0xFF80FFFF; //复位PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE
  196. RCC->CIR = 0x00000000; //关闭所有中断
  197. //配置向量表
  198. #ifdef VECT_TAB_RAM
  199. //Sys_NVIC_SetVectorTable(0x20000000, 0x0);
  200. #else
  201. //Sys_NVIC_SetVectorTable(0x08000000,0x0);
  202. #endif
  203. }
  204. //THUMB指令不支持汇编内联
  205. //采用如下方法实现执行汇编指令WFI
  206. void WFI_SET(void) {
  207. __ASM volatile("wfi");
  208. }
  209. //关闭所有中断
  210. void INTX_DISABLE(void) {
  211. __ASM volatile("cpsid i");
  212. }
  213. //开启所有中断
  214. void INTX_ENABLE(void) {
  215. __ASM volatile("cpsie i");
  216. }
  217. //设置栈顶地址
  218. //addr:栈顶地址
  219. void MSR_MSP(u32 addr)
  220. {
  221. __ASM volatile("MSR MSP, r0"); //set Main Stack value
  222. __ASM volatile("BX r14");
  223. }
  224. //进入待机模式
  225. void Sys_Standby(void) {
  226. SCB->SCR |= 1 << 2; //使能SLEEPDEEP位 (SYS->CTRL)
  227. RCC->APB1ENR |= 1 << 28; //使能电源时钟
  228. PWR->CSR |= 1 << 8; //设置WKUP用于唤醒
  229. PWR->CR |= 1 << 2; //清除Wake-up 标志
  230. PWR->CR |= 1 << 1; //PDDS置位
  231. WFI_SET(); //执行WFI指令
  232. }
  233. //系统软复位
  234. void Sys_Soft_Reset(void) {
  235. SCB->AIRCR = 0X05FA0000 | (u32)0x04;
  236. }
  237. //JTAG模式设置,用于设置JTAG的模式
  238. //mode:jtag,swd模式设置;00,全使能;01,使能SWD;10,全关闭;
  239. //#define JTAG_SWD_DISABLE 0X02
  240. //#define SWD_ENABLE 0X01
  241. //#define JTAG_SWD_ENABLE 0X00
  242. void JTAG_Set(u8 mode) {
  243. u32 temp;
  244. temp = mode;
  245. temp <<= 25;
  246. RCC->APB2ENR |= 1 << 0; //开启辅助时钟
  247. AFIO->MAPR &= 0XF8FFFFFF; //清除MAPR的[26:24]
  248. AFIO->MAPR |= temp; //设置jtag模式
  249. }
  250. //系统时钟初始化函数
  251. //pll:选择的倍频数,从2开始,最大值为16
  252. void Stm32_Clock_Init(u8 PLL) {
  253. unsigned char temp = 0;
  254. MYRCC_DeInit(); //复位并配置向量表
  255. //RCC->APB1ENR |=1<<28;
  256. //PMU->CTL |= 3<<14;
  257. RCC->CR |= 0x00010000; //外部高速时钟使能HSEON
  258. while (!(RCC->CR >> 17)); //等待外部时钟就绪
  259. RCC->CFGR = 0X00000400; //APB1=DIV2;APB2=DIV1;AHB=DIV1;
  260. PLL -= 2; //抵消2个单位(因为是从2开始的,设置0就是2)
  261. RCC->CFGR |= PLL << 18; //设置PLL值 2~16
  262. RCC->CFGR |= 1 << 16; //PLLSRC ON
  263. FLASH->ACR |= 0x32; //FLASH 2个延时周期
  264. RCC->CR |= 0x01000000; //PLLON
  265. while (!(RCC->CR >> 25)); //等待PLL锁定
  266. /* enable the high-drive to extend the clock frequency to 120 MHz */
  267. //PMU->CTL |= 1<<16;
  268. //while(0U == (PMU->CS & (1<<16))){
  269. //}
  270. /* select the high-drive mode */
  271. // PMU->CTL |= 1<<17;
  272. //while(0U == (PMU->CS & (1<<17))){
  273. //}
  274. RCC->CFGR |= 0x00000002; //PLL作为系统时钟
  275. while (temp != 0x02) { //等待PLL作为系统时钟设置成功
  276. temp = RCC->CFGR >> 2;
  277. temp &= 0x03;
  278. }
  279. }