一、STM32常识:
1、ARM平台汇编与MSC51平台汇编差异
指令集:C51所用的指令集应用于所有X86架构的系统,被称为CISC(复杂指令集),对应的ARM系列指列集为RSIC(精简指令集),一个指令集复杂,另一个简单。
系统资源:系统资源不一样。ARM的通用寄存器都是32位的,总共有31个,地址寄存器32位的,这样可以实现访问4GB的存储空间包括内部存储器及I/O端口。
操作运行环境:寄存器数量多,大部分操作都在寄存器中完成,从而提高处理速度。(而CISC有相当一部分在存储器中完成的:寄存器间接寻址,基址加变址寻址,相对寄存器寻址,相对基址加变址寻址等这些寻址方式都是对存储器进行操作的)。
异常处理模式:新增几种异常处理模式,即发生异常时,会自动跳入到相应的异常中断中去。
2、ARM讲一下其内部资源
中断:对一个中断资源的优先级进行设置时,需设置一个四位的优先级寄存器,来决定这两个优先级各自的大小,而优先级组号,定义了抢占优先级的位数,如当使用优先级组1时,表示四位寄存器仅最低位1位来决定抢占优先级的大小,当此位为0时,表示,抢占优先级大小为0,为1时亦然。其余的三位用于表示子优先级的大小,可表示从0~7任何优先级数。
时钟:根据速度及片内片外情况,分为HSE高速外部时钟;HSI调整内部时钟,LSE低速外部时钟,LSI低速内部时钟;共四个时钟源。
其中
HSE:一般通过外接一个3~25MHZ晶振产生,可作为系统时钟。
HSI:内部自带时钟,系统的默认时钟源,大小为8MHZ.
LSE:通过外接一个32.768KHZ的晶振产生,可作为RTC的时钟源;
LSI:内部自带时钟,大小为40Khz的晶振,一般将其32分频后作为内部看门狗的时钟源;
内存:不仅ARM,所有的嵌入式设备均将系统内存根据编译情况,分为代码段(CODE),只读数据段(RO),读写数据段(RW),未初始化读写数据段(ZI),堆(HEAP),栈(STACK),
注意:
①优先级数越低,优先级也低。因此可推算优先级组1可表示,两种抢占优先级,每种分别对应8种子优先级,共16个优先级别。另外,由于有些系统跑OS需要用到tick时钟,从而实现时间片轮转进行任务调试,且时间片轮转必须是抢占模式,因此,针对这种情况,不能使用优先级组0,因其0个位表示抢占优先级,即不支持抢占优先级。
二、STM32F205RET6工程应用
中断:使用优先级组1时,表示四位寄存器仅最低位1位来决定抢占优先级的大小,当此位为0时,表示,抢占优先级大小为0,为1时亦然。其余的三位用于表示子优先级的大小,可表示从0~7任何优先级数。
时钟:
SYSCLK_FREQ_72MHz:SYSCLK = PLL_VCO / PLL_P =144M/2 =72M
72M AHB Prescaler
36M APB1 Prescaler
72M APB2 Prescaler
8M System Clock source
内存:STM32F205RET6
Flash:512Kbps 184.91KB 36.1% (RO+RW)
SRAM:128K 103.27kB 80.7% (RW+ZI)
三、ucosII与ucosIII区别与应用
1、优先级:ucosii是原来只有0~63个优先级,而且优先级不能重复,ucos iii允许几个任务使用同一个优先级,在同一个优先级里面,支持时间片调度法;
2、资源管理:ucosiii允许用户在程序运行中动态配置实时操作系统内核资源,比如,任务、任务栈、信号量、事件标志组、消息队列、消息数、互斥型信号量、存储块划分和定时器,可以在程序运行中变更。这样,用户可以避免在程序编译过程中出现资源不够分配的问题。在资源复用上,也做了一些改进。
3、任务数:μC/OS-II中,最多任务数有64个,到了版本2.82以后是256个,μC/OS-III中,用户可以由任意多的任务、任意多的信号量、互斥型信号量、事件标志、消息列表、定时器和任意分配的存储块容量,仅受限于用户CPU可以使用的RAM量。
四、其它嵌入式实时操作系统
1、RTX(由KEIL公司设计,现在已经被并入ARM公司旗下)这个OS设计的也非常强劲,将基于Cortex-M3/M4架构的ARM芯片性能发挥到极致——零延迟中断、在任务切换等性能测试方面完爆其它RTOS。
2、FreeRTOS有GPL(修正版)许可证限制修改版的GPL许可证有如下几个缺陷(There are several reasons why developers may find the FreeRTOS modified GPL licence restrictive.)
公司可能有一个全面禁止在他们的项目中使用GPL授权的软件。
他们可能需要IP赔偿。
他们可能更愿意在他们的产品中,避免FreeRTOS的许可证要求
有出售STM32F205RET6,有需要可以扣扣联系我:707944539
ST,NXP,TI,BQ,华大,国民MCU
N32G455VEL7 替代ST 与GD 103VCT6和103VET6
N32G435CBL7 替代ST 与GD 103C8T6和103CBT6
N32G455REL7 替代ST 与GD 103RCT6和103RET6
N32G457REL7 替代ST 与GD 107RCT6和107RET6
N32G432C8L7 替换ST 与GD 103C8T6
下图是STM32F2系列的时钟树结构图:
1、内部高速时钟HSI、外部高速时钟HSE和PLL时钟PLLCLK时钟都接到了SW开关处,通过SW选择哪一路作为SYSCLK,SYSCLK经过AHB分频器进行分频得到HCLK,APB1和APB2是挂在总线AHB上的,通过APB1和APB2分频得出fpclk1和fpclk2。
2、PLL输入时钟源主要是靠外部高速时钟和内部高速时钟作为时钟源,通过PLLCFGR寄存器的bit22来选择具体哪一路作为时钟源。选择好了时钟源进入/M分频器,也就是PLLM进行分频,送入VCO,在通过xN,进行倍频,也就是PLLN1)通过/P进行分频(PLLP)得到PLLCLK;(2)通过/Q分频(PLLQ),得到PLL48CK。
然后边看代码边对照结构图进行分析,看软件如何给单片机配置系统时钟的。
然后找到启动代码“startup_stmf32xx.s”,该代码是用汇编写的,可以看到,在调用main函数之前,是先调用了SystemInit函数的,该函数是在“system_stm32f2xx.c”中
复制代码
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
复制代码
代码如下,变量直接赋个16进制的数,都不知道是啥意思,目的是干什么的,不知道,所以看下面代码时最好对照STM32F2x用户手册。当然这个只是一个初始化,待会主要看SetSysClock();这个函数,在调用该函数之前,我们知道单片机是先启用了内部高速时钟等一些配置。
复制代码
void SystemInit(void)
{
/* Reset the RCC clock configuration to the default reset state ------------/
/ Set HSION bit */
RCC->CR |= (uint32_t)0x00000001; //RCC_CR复位值0x0000_xx83,内部高速时钟使能,也就是说上电开始就使用内部高速时钟,16MHZ
/* Reset CFGR register */
RCC->CFGR = 0x00000000; //通过开关SW选择内部高速时钟作为系统时钟16MHZ
//AHB prescaler 不分频
//APB Low speed prescaler (APB1) 不分频,fplck1 = 16MHZ
//APB high-speed prescaler (APB2)不分频,fplck2 = 16MHZ
//MCO1和MCO2时钟输出等配置可参考用户手册Page95
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;
/* Reset PLLCFGR register */
RCC->PLLCFGR = 0x24003010; //RCC_CFGR复位值是0x2400_3010
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF; //对bit18 HSEBYP 设置为0,外部高速时钟被禁止
/* Disable all interrupts */
RCC->CIR = 0x00000000; //所有时钟中断都被禁止
#ifdef DATA_IN_ExtSRAM
SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM */
/* Configure the System clock source, PLL Multiplier and Divider factors,
AHB/APBx prescalers and Flash settings ----------------------------------*/
SetSysClock();
/* Configure the Vector Table location add offset address ------------------/
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; / Vector Table Relocation in Internal SRAM /
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; / Vector Table Relocation in Internal FLASH */
#endif
}
复制代码
在SystemInit(void)函数中在配置完一些参数后,还调用了SetSysClock()函数,该函数代码如下
复制代码
static void SetSysClock(void)
{
/*****************************************************************************/
/ PLL (clocked by HSE) used as System clock source /
/*****************************************************************************/
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON); //外部高速时钟使能,25MHZ
/* Wait till HSE is ready and if Time out is reached exit */ //外部时钟使能后,得需要一点时间到达各个端口
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY; //如果RCC_CR_HSERDY为0,说明外部时钟还没准备好,1说明外部时钟已准备好
StartUpCounter++;//对读的次数进行累加,当累加次数到达1280次时,就意味着启动时间超时
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)//这里判断上面的do while循环是因哪个条件结束的
{
HSEStatus = (uint32_t)0x01; //说明时钟已准备好了,才结束do whlie循环
}
else
{
HSEStatus = (uint32_t)0x00; //说明是因为超时了而退出do while循环
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK / 1*/
RCC->CFGR |= RCC_CFGR_HPRE_DIV1; //AHB不分频,AHB出来后时钟就是sysclk=120M
/* PCLK2 = HCLK / 2*/
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;//APB2 2分频,fpclk2 = sysclk/2 = 60M
/* PCLK1 = HCLK / 4*/
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; //APB1 4分频,fplck1 = sysclk/4 = 30M
/* Configure the main PLL */ //主要对PLL和PPI2S 进行配置
RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
1
2
3
4
5
6
7
8
9
//配置完后RCC->PLLCFGR = 0x05403c19,然后对照寄存器RCC_PLLCFGR查看哪些位对应哪些功能
//通过bit5~bit0可计算出PLLM=25,那么input VCO = PLL input clock /PLLM = 25M/25 = 1M,对应时钟结构图中的/M
//通过bit14~bit6可计算出倍频因子PLLN = 240,那么VCO output clock = PLLN * input VCO = 240 * 1 = 240M,对应时钟结构图中的xN
//bit17~bit16可计算出分频因子PLLP = 2,那么PLLCLK = VCO output clock /PLLP = 240/2 = 120M
//bit22是选择给PLL输入的时钟源,输入时钟源有外部和内部高速时钟,这里选择的是外部高速时钟即PLL input clock = HSE =25M
//bit27~24可计算出分频因子PLLQ = 5,那么PLL48CK = VCO output clock/PLLQ = 240/5 = 48M
/* Enable the main PLL */
RCC->CR |= RCC_CR_PLLON; //使能PLL
/* Wait till the main PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
//到这里RCC->CR已配置完,最终值0x03036783
//通过查看用户手册知道,内部高速时钟、外部高速时钟、PLL时钟都已开启
/* Configure Flash prefetch, Instruction cache, Data cache and wait state */
FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_3WS;
/* Select the main PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= RCC_CFGR_SW_PLL;
//到这里RCC->CFGR已配置完,最终值是0x0000_940A
//通过查看用户手册,知道,PLL时钟作为系统时钟即120M
//AHB不分频,即HCLK = 120M
//APB1 4分频,即fpclk1 = 120/4=30M
//APB2 2分频,即fpclk2 = 120/2=60M
/* Wait till the main PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
{
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
}
复制代码
OK,分析完这段代码后,调用系统固件函数后,现在知道了时钟树结构图中右边出来的时钟是多少MHz了吧。
总结:
1、使用的是外部时钟25MHZ,通过PLL进行分频倍频分频得到PLLCLK 120M,PLLCLK作为系统时钟SYSCLK。
2、APB1出来是30M,也就是FPCLK1。
3、APB2出来是60M,也就是FPCLK2。