手柄代码篇
我们直接看代码部分,然后逐步深入了解,如有不对的地方,欢迎大家指证!!
第一阶段——设备内部的初始化
一、中断配置初始化
#define BOOTLOADER_SIZE (9*1024)
#define FLASH_BASE ((uint32_t)0x08000000)
#define FIRMWARE_START_ADDR (FLASH_BASE + BOOTLOADER_SIZE)
NVIC_SetVectorTable(FIRMWARE_START_ADDR,0);
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset)
{
assert_param(IS_NVIC_VECTTAB(NVIC_VectTab));
assert_param(IS_NVIC_OFFSET(Offset));
SCB->VTOR = NVIC_VectTab | (Offset & (uint32_t)0x1FFFFF80);
}
1.1 功能
设置向量表的位置和偏移
1.2 参数
FIRMWARE_START_ADDR:指定向量表位置在 RAM 还是在程序存储器:这里是位于FLASH中
0:向量表基地址的偏移量
1.3 返回值
指定中断活动位的新状态
1.4 具体实现
存放的是中断服务函数的入口地址,当发生中断时,CPU在这个表中查询,以此获取中断函数的入口地址
在stm32 的启动文件中,设置完成堆栈,就来设置中断向量表
既然看到这里了,我们不妨再进一步看看NVIC到底是什么?
1.5 NVIC概览
1、向量中断控制器,简称 NVIC,是 Cortex‐M3 不可分离的一 部分。
2、它与 CM3 内核的逻辑紧密耦合,有一部分甚至水乳交融在一起。
3、NVIC 的寄存器以存储 器映射的方式来访问。
4、除了包含控制寄存器和中断处理的控制逻辑之外,NVIC 还包含了 MPU 的控制寄存器、SysTick 定时器以及调试控制。
5、NVIC 共支持 1 至 240 个外部中断输入(通常外部中断写作 IRQs)
6、NVIC 的访问地址是 0xE000_E000。
7、NVIC 的中断控制/状态寄存器都只能在特权级下访问。有一个例外——软件触发中断寄存器可以在用户级下访问以产生软件中断。
参考:Cortex-M3权威指南第8章-NVIC与中断控制
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{
assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));
SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
}
看这个函数之前,我们回顾之前学习的一些关于中断优先级的相关知识
第0组:所有4位用于指定响应优先级(16种)
第1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级(8种)
第2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级(4种)
第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级(2种)
第4组:所有4位用于指定抢占式优先级
根据我上面给出的优先级分组,大家应该很容易可以看出,他使用的第4组,就是2^4组(16组)
二、 延时函数初始化
void delay_init()
{
u32 reload;
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
fac_us=SystemCoreClock/1000000;
reload=SystemCoreClock/1000000;
reload*=1000000/configTICK_RATE_HZ;
fac_ms=1000/configTICK_RATE_HZ;
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;
SysTick->LOAD=reload;
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;
}
2.1特点
1、CM3 内核的处理器,内部包含了一个 SysTick 定时器
2、SysTick 是一个 24 位的倒计数定时器,当计数到 0 时,将从RELOAD 寄存器中自动重装载定时初值,开始新一轮计数。
3、只要不把它在 SysTick 控制及状态寄存器中的使能位清除,就永不停息。
4、 SysTick 来实现延时的,这样既不占用中断,也不占用系统定时器。
参阅《Cortex-M3 权威指南》第 133 页
第二阶段——参数配置
这里面涵盖了很多之后飞控要使用到的参数,我们先简单看一下
一、配置参数初始化
void configParamInit(void)
{
if(isInit) return;
STMFLASH_Read(CONFIG_PARAM_ADDR,(u16*)&configParam,sizeof(configParam)/2);
if(configParam.version == VERSION)
{
u8 cksum = calculate_cksum(&configParam);
if(cksum == configParam.cksum)
isConfigParamOK = true;
else
isConfigParamOK = false;
}
else
{
isConfigParamOK = false;
}
if(isConfigParamOK == false)
{
configParam = configParamDefault;
writeConfigParamToFlash();
isConfigParamOK=true;
}
}
1.1 初始化参数地址
看完上面代码紧接着我们再看
void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)
{
u16 i;
for(i=0;i<NumToRead;i++)
{
pBuffer[i]=STMFLASH_ReadHalfWord(ReadAddr);
ReadAddr+=2;
}
}
1.2 参数存放地址
从上面可以看出,他将参数放到了FLASH里面,进行读取,地址在这里
#define CONFIG_PARAM_SIZE (127*1024)
#define FLASH_BASE ((uint32_t)0x08000000)
#define CONFIG_PARAM_ADDR (FLASH_BASE + CONFIG_PARAM_SIZE)
第三阶段——硬件外设初始化
一、LED初始化
void ledInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_3);
GPIO_SetBits(GPIOB,GPIO_Pin_7);
}
1.1 禁止JTA使能SWD口
上面的IO初始化学过STM32的很容易理解,这里我们主要看看什么这个函数的功能及用法
#define GPIO_Remap_SWJ_JTAGDisable ((uint32_t)0x00300200)
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState)
{
uint32_t tmp = 0x00, tmp1 = 0x00, tmpreg = 0x00, tmpmask = 0x00;
assert_param(IS_GPIO_REMAP(GPIO_Remap));
assert_param(IS_FUNCTIONAL_STATE(NewState));
if((GPIO_Remap & 0x80000000) == 0x80000000)
{
tmpreg = AFIO->MAPR2;
}
else
{
tmpreg = AFIO->MAPR;
}
tmpmask = (GPIO_Remap & DBGAFR_POSITION_MASK) >> 0x10;
tmp = GPIO_Remap & LSB_MASK;
if ((GPIO_Remap & (DBGAFR_LOCATION_MASK | DBGAFR_NUMBITS_MASK)) == (DBGAFR_LOCATION_MASK | DBGAFR_NUMBITS_MASK))
{
tmpreg &= DBGAFR_SWJCFG_MASK;
AFIO->MAPR &= DBGAFR_SWJCFG_MASK;
}
else if ((GPIO_Remap & DBGAFR_NUMBITS_MASK) == DBGAFR_NUMBITS_MASK)
{
tmp1 = ((uint32_t)0x03) << tmpmask;
tmpreg &= ~tmp1;
tmpreg |= ~DBGAFR_SWJCFG_MASK;
}
else
{
tmpreg &= ~(tmp << ((GPIO_Remap >> 0x15)*0x10));
tmpreg |= ~DBGAFR_SWJCFG_MASK;
}
if (NewState != DISABLE)
{
tmpreg |= (tmp << ((GPIO_Remap >> 0x15)*0x10));
}
if((GPIO_Remap & 0x80000000) == 0x80000000)
{
AFIO->MAPR2 = tmpreg;
}
else
{
AFIO->MAPR = tmpreg;
}
}
这里我们思考一下为什么要禁用SWD口呢?
我们查看STM32的数据手册和飞控原理图
1.2 总结
当要使用JTAG占用的IO口但还要使用SWD时,也就是要使用PB3当做IO口,但还要使用SWD下载或者调试时,就需要禁用JTAG,那么随之产生的副作用就是,我们不能使用JTAG功能。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)