STM32F1系列用的最多,最大72MHz
STM32固件库(函数)使用手册
1 ST开发板种类
1.1 ST开发板种类
ST官方出的有NUCLEO板、Discovery板以及评估板,配置从低到高,价格也是从低到高。
NUCLEO:一般只将MCU引脚引出,还有一个串口(通过STLINK USB虚拟),价格也就几十到100RMB左右。
Discovery板:一般比NUCLEO板多USB(MCU带USB),音频解码,耳机插孔。价格也就100多点。
评估板:功能是最全的,一般外设都有引出,功能最全,价格最高,几百到1000+RMB。
2 How-to Find Reference Manual
2.1
In search engine, key-in <STM32中文参考手册>, then find "百度文库", open it.
2.2 百度知道
如何在STM官网下载STM32英文数据手册datasheet
第一步 百度“ST官网”,点击进入第一个链接
第二步 点击目录Products-Microcontrollers(微控制器),进入芯片选择的页面
第三步,找到你对应的芯片型号,进到芯片的详细页面。这里我以STM32F103ZE为例。
第四步,芯片详细页面往下翻,找到Reference Manuals点击跳转到下载页面。
第五步,点击PDF下载,完成。
3.1 外部触发转换
3.1.1 TRGO (trigger output)原理
当TIM1 (需要配置成PWM模式) 每次计数溢出时就会产生所期待的TRGO事件。
对于TIM1, TRGO的事件源有多个选项可以选择, 默认状态只有RESET事件才产生TRGO,对于ADC应该配置为UPDATE 事件, 所以即使使能ADC外部触发和选择外部触发事件TRGO,还要记得对TIM1的TRGO事件进行配置,否则不会触发ADC捕获功能。
示例代码如下所示:
TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);
3.2 URLs
STM32F0定时器触发ADC,多通道采样、DMA传输数据的配置
http://blog.csdn.net/xuezhimeng2010/article/details/15157911
4 NVIC
4.1 中断服务程序在什么地方
STM32的中断服务程序的名字不能自定义,必须使用官方已经定义好的名字,名字可参考如下的文件。
@ Drivers\CMSIS\Device\ST\STM32L0xx\Source\Templates\iar\startup_stm32l061xx.s
当然服务程序的具体内容还是自己写,放在stm32f10x_it.c里。
4.2 Cortex-M BASEPRI-IPR-SHPRx
4.2.1 BASEPRI
FreeRTOS中进入临界区时没有关闭所有中断,而是使用优先级屏蔽寄存器BASEPRI(= configMAX_SYSCALL_INTERRUPT_PRIORITY)关闭了部分中断;这个寄存器最多有9位(由表达优先级的位数决定)。它定义了被屏蔽优先级的阈值。当它被设成某个值后,所有优先级号大于等于此值的中断都被关(优先级号越大,优先级越低)。但若被设成0,则不关闭任何中断,0也是缺省值。
FreeRTOS任务代码中临界段的进入和退出主要是通过操作寄存器BASEPRI实现的。进入临界区BASEPRI关闭了所有大于等于宏定义configMAX_SYSCALL_INTERRUPT_PRIORITY所定义的中断优先级,这样临界段代码就不会被中断干扰到,而且实现任务切换功能的 PendSV 中断和SysTick滴答定时器中断是最低优先级中断,所以此任务在执行临界段代码期间是不会被其它高优先级任务打断的。退出临界段时重新操作BASEPRI寄存器,即打开被关闭的中断(这里我们不考虑不受FreeRTOS 管理的更高优先级中断)。
Cortex-M内核的“中断优先级寄存器”是以最高位(MSB)对齐的。STM32使用了优先级寄存器中的4位,则这4个位位于中断优先级寄存器的bit 4、bit5、bit6、bit7位。剩余的bit0 ~ bit3可以设置成任何值。所以FreeRTOS中的中断优先级计算是有移位操作的。
CMSIS以及不同的微控制器供应商提供了可以设置某个中断优先级的库函数。一些库函数的参数使用最低位对齐,另一些库函数的参数可能使用最高位对齐,所以,使用时应该查阅库函数的应用手册进行正确设置。
可以在FreeRTOSConfig.h中设置宏configMAX_SYSCALL_INTERRUPT_PRIORITY和
configKERNEL_INTERRUPT_PRIORITY的值。(关于这两个宏可以参考参数设置一章,网址:http://openmcu.net/post/kernel-config.html)。这两个宏需要根据Cortex-M内核自身的情况进行设置,要以最高有效位对齐。比如某MCU使用中断优先级寄存器中的4位,设置configKERNEL_INTERRUPT_PRIORITY的值为5,则代码为:
#define configKERNEL_INTERRUPT_PRIORITY (5<<(8-4))
对于每一个官方FreeRTOS演示例程,这也是在FreeRTOSConfig.h中要设置宏configKERNEL_INTERRUPT_PRIORITY为最低优先级时,为什么要将它设置为255(1111 1111B)的原因。使用这种方式指定这个值的原因是,FreeRTOS内核是直接在Cortex-M内核硬件上运行的(没有使用第三方接口库函数),要比大多数库函数先运行。现在也有开发第一个Cortex-M库函数计划。
4.2.2 IPR
typedef struct
{
vu32 ISER[2];
u32 RESERVED0[30];
vu32 ICER[2];
u32 RSERVED1[30];
vu32 ISPR[2];
u32 RSERVED2[30];
vu32 ICPR[2];
u32 RSERVED3[30];
vu32 IABR[2];
u32 RSERVED4[30];
vu32 IPR[15];
} NVIC_TypeDef;
NVIC IPR[15]:Interrupt Priority Registers,中断优先级控制寄存器组。STM32的中断分组与这个寄存器密切相关。因为STM32的中断多达60多个,所以STM32采用中断分组的办法来确定中断的优先级。IPR寄存器由15个32bit的寄存器组成,每个可屏蔽中断占8bit,这样总共可以表示15x4=60个可屏蔽中断。IPR[0]的[31:24],[23:16],[15:8],[7:0]分别对应中断3到0,总共对应60个外部中断。而每个可屏蔽中断占用的8bit并没有全部使用,只用了高4位。这4位又分为抢占优先级和子优先级。这两个优先级要根据SCB->AIRCR(System Control Block,Application Interrupt and Reset Register)中断分组的设置来决定。
简单介绍STM32的中断分组:STM32将中断分为0~4共5个组,该组是由SCB->AIRCR寄存器的bit10:8来定义的。如Table 4-1所示。
Table 4-1 AIRCR中断分组设置表
组 |
AIRCR[10:8] |
bit[7:4]分配情况 |
分配结果 |
0 |
111 |
0:4 |
0位抢占优先级,4位响应优先级 |
1 |
110 |
1:3 |
1位抢占优先级,3位响应优先级 |
2 |
101 |
2:2 |
2位抢占优先级,2位响应优先级 |
3 |
100 |
3:1 |
3位抢占优先级,1位响应优先级 |
4 |
011 |
4:0 |
4位抢占优先级,0位响应优先级 |
通过这个表,可以清楚的看到组0~4对应的配置关系,例如组设置为0x03,此时所有的60个中断,每个中断的中断优先级寄存器的高四位中最高3位是抢占优先级,低1位是响应优先级。每个中断都可以设置抢占优先级为0~7,响应优先级为1或0。抢占优先级的级别高于响应优先级,数值越小所代表的优先级越高。
具体优先级的确定和嵌套规则:
(1)只能高抢先优先级的中断可以打断低抢占优先级的中断服务,构成中断嵌套;
(2)当2个(N个)相同抢占优先级的中断出现,他们之间不能构成中断嵌套,但STM32首先响应子优先级高的中断;
(3)当2个(N个)个抢占优先级和子优先级相同的中断出现,STM32首先响应中断通道所对应的中断向量地址低的中断,就是谁先发生谁先被执行。
4.2.3 SHPRx-System Handler Priority Registers
Cortex M4系统中断的中断号从-15~-1(优先级由SHPRx控制),外设中断的中断号从0~63(优先级由IPR控制)。
SHPR1至SHPR3,3个32位寄存器,每8位设置一个中断优先级,共12个可配置的系统中断,8为里面用了高位configPRIO_BITS,其它位写无效,读为0。还有3个中断的优先级系统默认为-3、-2、-1。
Figure 4-1 Cortex-M中断分布
Figure 4-2 SHPRx寄存器的位分配
4.2.4 示例代码
/* interrupt priority register */
static int command_dump_ipr(cli_node_t *cmd, int argc, char **argv)
{
const volatile uint8_t * const pcInterruptPriorityRegisters =
(const volatile uint8_t * const)0xE000E3F0;
uint8_t i;
console_puts_lite(""CR_LF);
console_puts_lite("configPRIO_BITS = %d"CR_LF,
configPRIO_BITS);
console_puts_lite("configKERNEL_INTERRUPT_PRIORITY = 0x%02x"CR_LF,
configKERNEL_INTERRUPT_PRIORITY);
console_puts_lite("configMAX_SYSCALL_INTERRUPT_PRIORITY = 0x%02x"CR_LF,
configMAX_SYSCALL_INTERRUPT_PRIORITY);
console_puts_lite(""CR_LF);
/* (4-7, 8-11, 12-15) */
console_puts_lite("System Handler Priority Registers"CR_LF);
for (i = 0; i < 12; i++){
console_puts_lite("PRI_%d - 0x%02x"CR_LF, (4 + i), SCB->SHP[i]);
}
console_puts_lite(""CR_LF);
console_puts_lite("User Interrupt Priority Registers"CR_LF);
for (i = 16; i < (16 + IRQ_NUMBER_MAX); i++) {
console_puts_lite("IRQ%d - 0x%02x"CR_LF,
(i - 16), pcInterruptPriorityRegisters[i]);
}
return 0;
}
DECLARE_CONSOLE_COMMAND(dump_ipr, command_dump_ipr, NULL);
5 Timer
5.1 捕获模式
如果要测量占空比就要在中断中重新设置边沿即可。
定时器计数器最大值为0xffff。
5.1.1 TIM_Prescaler、TIM_Period和TIM_ClockDivision的区别
TIM_Prescaler(PSC):用来指定TIM时钟的分频值,也就是说它是进一步来分频TIM clock的,简单来说也就是定时器每一次计数的时间间隔是多少。
TIM_Period(ARR):它控制的是定时周期。比如说将TIM_Period(TIM1_ARR)设置成999,则计数器向上计数到1000(999+1)后产生更新事件,计数值归零。
TIM_ClockDivision:时钟分割,通常值为0。
假设时钟频率为48MHZ,如果指定预分频器即TIM_Prescaler的值为48000(-1),那么经48000分频之后的工作频率就是1000,也就是所谓的1KHz;如果再指定计数值即TIM_Period为1000(-1)的话,恰好就是1秒了。
比如官方例程中的,要用TIM3来实现输出36KHz(大约)。
1) 首先规定了TIM3要运行在24000000Hz下,由此可以得出TIM_Prescaler的大小
PrescalerValue = (uint16_t) (SystemCoreClock/ 24000000) - 1;
所以 TIM_Prescaler为2。
2) 然后由The TIM3 is running at 36 KHz:
TIM3 Frequency = TIM3 counter clock / (ARR+ 1) = 24 MHz / 666 = 36 KHz
得到TIM_Period 为666-1。
3) 如果要修改占空比需要修改参数 TIM_Pulse
TIM3 Channel1 duty cycle = (TIM3_CCR1/TIM3_ARR)* 100 = 50%
TIM3 Channel2 duty cycle = (TIM3_CCR2/TIM3_ARR)* 100 = 37.5%
TIM3 Channel3 duty cycle = (TIM3_CCR3/TIM3_ARR)* 100 = 25%
TIM3 Channel4 duty cycle = (TIM3_CCR4/TIM3_ARR)* 100 = 12.5%
5.1.2 捕获示例代码
5.1.2.1 单通道捕获模式
STM32并不支持双边沿捕获,因此我们要手工实现双边沿,也就是在中断中我们可以选择检测本次中断是上升沿中断还是下降沿中断,如果是上升沿中断,就修改为下降沿中断,反之就修改为上升沿中断。
5.1.2.2 双通道捕获模式
@ stm32f10x_it.c
该函数是TIM捕获波形的中断函数,同一个(TIM5)中断入口,有两个通道,也是计算频率和占空比重要的函数。
Figure 5-2 捕获下降沿
5.1.3 URLs
STM32 通用定时器作为输入捕获 学习笔记
http://www.2cto.com/kf/201707/660425.html
STM32F4_TIM输入波形捕获(脉冲频率、占空比)
http://www.cnblogs.com/strongerHuang/p/5668361.html
双边沿捕获
stm32 PWM input捕获输入模式
http://blog.csdn.net/u012271722/article/details/42173823
红外学习
STM32输入捕获模式设置并用DMA接收数据
http://blog.csdn.net/jdh99/article/details/23224041
5.2 Abbreviations
ARR: Automatic Reload Register
BKP: BackUp
CCER: Capture/Compare Enable Register,用来判断当前是下降沿捕获中断还是上升沿捕获中断,同时也能随时改变上升沿捕获还是下降沿捕获
CCR: Capture/Compare Register,表示当前中断发生时的CNT寄存器的值,也就是用来判断时间的;PWM输出时作为占空比寄存器,函数是TIM_SetCompare1(...)
CNT: Counter Register,用来计数的,每个定时器时钟周期自动+1,在需要的时间将其清零,便于计时
OC:Output Compare(输出比较),用于输出PWM信号;寄存器CNT与CCR比较,大于输出1,小于输出0
PSC:PreSCaler register,预分频寄存器
RCR:Repetition Counter Register,重复次数寄存器
SR: Status Register,用来判断是不是输入捕获中断
6 USART
6.1 空闲中断
空闲中断:
1. 检测到接收数据后,在数据总线上的一个字节时间内,没有接收到数据触发空闲中断。RXNE置位一次,空闲总线就检测一次。
2. 空闲中断是接受数据后出现一个byte的高电平(空闲)状态,就会触发空闲中断。并不是空闲就会一直中断,准确的说应该是上升沿(停止位)后一个byte,如果一直是低电平是不会触发空闲中断的(会触发break中断)。
stm32的串口空闲中断接收数据
http://blog.csdn.net/bobbat/article/details/39813647
7 自定义section
7.1 IAR
char *start = section_begin(“my_section”);
char *end = section_end(“my_section”);
如何让程序在RAM中运行
https://wenku.baidu.com/view/dc74c276aeaad1f347933f3a.html
7.2 KEIL MDK(被ARM收购了)
ER:EXEC_ROM,系统启动后,应用程序进行执行和数据访问的存储器区域,系统在实时运行时可以有一个或多个执行块。
LR:LOAD_ROM,当系统启动或加载时应用程序的存放区。
sct:scatter file
__attribute__这个关键词是GNU编译器中的编译属性,ARM编译器也支持这个用法。MDK section的使用与GCC差不多。
例子,只有段的概念,不用计算多少个函数,由编译器来动作即可。
typedef int (*FunInit)(void);
#define INIT_FUNCTION(func) \
FunInit __Fun_##func __attribute__((used,section("mySection"))) = func
void InitFun1(void)
{
printf("InitFun1 init\r\n");
}
INIT_FUNCTION(InitFun1);
void InitFun2(void)
{
printf("InitFun2 init \r\n");
}
INIT_FUNCTION(InitFun2);
就这样,可以遍历整个段中定义好的函数了。
keil MDK 同时使用内部和外部RAM的方法
https://www.amobbs.com/forum.php?mod=viewthread&action=printable&tid=5183550&_dsign=6678729f
IAR和KEIL中以常量形式存储到ROM或FLASH的指定的位置
https://blog.csdn.net/guoggn/article/details/53097067
stm32函数放入段section中
http://www.eeworld.com.cn/mcu/article_2016100530057.html
armlink -Scatter file文件实现将函数放在指定内存地址
https://blog.csdn.net/maochengtao/article/details/41544935
基于MDK的分散加载文件
https://blog.csdn.net/tracing/article/details/9720157
ARM C语言编程优化策略(KEIL平台)
https://zhuanlan.zhihu.com/p/24402180
8 URLs
STM32F05x 培训手册
https://wenku.baidu.com/view/8720b06ee2bd960591c67715.html
9 General Abbreviations
AIRC:Application Interrupt and Reset Register
BSP:Board Support Package
CmBacktrace:Cortex Microcontroller Backtrace,是一款针对ARM Cortex-M系列MCU的错误代码自动追踪、定位、错误原因自动分析的开源库。
CubeMX:Microcontroller GUI
eCC-USB:eCos Centric USB
IAR icf:ILINK Configuration File
MSP:MCU Specific Package
NVIC:Nested Vectors Interrupts Controller
NVIC IPR:Interrupt Priority Registers
RCC:Reset and Clock Control
SHPRx:System Handler Priority Registers
ST AMG:Analog and MEMS Group,模拟和MEMS部门(现在改成了Analog, MEMS and Sensors Group)
STM32H7:High-perf Cortex-M7
PendSV:Pendable 服务是一个中断请求,如果没有其他中断需要响应时,系统将强制执行上下文切换
SVCall:SuperVisor Call由SVC指令触发,FreeRTOS用它来启动任务调度