MCU相关功能实现 驱动部分
STM32F103RCT6
Flash:256k RAM:48K
FLASH驱动
各个扇区空间大小
分区
//62k
#define BOOT_ADDRESS 0x08000000
#define BOOT_SIZE 0xF800
//2k
#define BOOT_PARAM_ADDRESS 0x0800F800
#define BOOT_PARAM_SIZE 0x800
//96k
#define APP1_ADDRESS 0x08010000
#define APP1_SIZE 0x18000
//96k
#define APP2_ADDRESS 0x08028000
#define APP2_SIZE 0x18000
static void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite)
{
FLASH_Status status = FLASH_COMPLETE;
u32 addrx=0;
u32 endaddr=0;
if(WriteAddr<NVIC_VectTab_FLASH||WriteAddr%4)return; //非法地址
FLASH_Unlock(); //解锁
addrx=WriteAddr; //写入的起始地址
endaddr=WriteAddr+NumToWrite*4; //写入的结束地址
if(status==FLASH_COMPLETE)
{
while(WriteAddr<endaddr)//写数据
{
if(FLASH_ProgramWord(WriteAddr,*pBuffer)!=FLASH_COMPLETE)//写入数据
{
break; //写入异常
}
WriteAddr+=4;
pBuffer++;
}
}
FLASH_Lock();//上锁
}
u32 STMFLASH_ReadWord(u32 faddr)
{
return *(vu32*)faddr;
}
static void STMFLASH_Read(u32 ReadAddr,u32 *pBuffer,u32 NumToRead)
{
u32 i;
for(i=0;i<NumToRead;i++)
{
pBuffer[i]=STMFLASH_ReadWord(ReadAddr);//读取2个字节.
ReadAddr+=4;//偏移2个字节.
}
}
static void Flash_Erase(u32 addr,u32 size)
{
u8 result = 0;
u32 secpos = (addr-NVIC_VectTab_FLASH)/2048;
u32 page = size/2048 +1;
FLASH_Unlock();
for(int i = 0;i<page;i++)
FLASH_ErasePage((secpos+i)*2048 + NVIC_VectTab_FLASH);
FLASH_Lock();
}
CAN驱动:
500k 波特率,设置滤波器,只允许两个诊断物理寻址通过
CAN_FilterInitStructure.CAN_FilterNumber=0;
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdList; //列表模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //筛选器位宽 32位
/* 验证码配置 */
/*32筛选器寄存器 包括 11位标准id 18位扩展id 1位IDE 1位RTR 1位0*/
/*报文的标准id是11位,需要向左移5位传入16位的寄存器 STID[10:0]*/
uint32_t StdId[2] = {udsAdress.requestId,udsAdress.funcId};
CAN_FilterInitStructure.CAN_FilterIdHigh= StdId[0]<<5;//验证码32位中高16位
CAN_FilterInitStructure.CAN_FilterIdLow= 0|CAN_ID_STD|CAN_RTR_DATA; //验证码32位中低16位
/*32筛选器寄存器 包括 11位标准id 18位扩展id 1位IDE 1位RTR 1位0*/
/*扩展id左移3位,腾出IDE、RTR和0,再向右移得出高16位*/
CAN_FilterInitStructure.CAN_FilterMaskIdHigh= StdId[1]<<5;//屏蔽码高16位,
/*扩展id左移3位,腾出IDE、RTR和0,标记扩展和数据类型*/
CAN_FilterInitStructure.CAN_FilterMaskIdLow= 0|CAN_ID_STD|CAN_RTR_DATA; //屏蔽码低16位,只允许一个通过
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0 ; //筛选器关联FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //使能筛选器
CAN_FilterInit(&CAN_FilterInitStructure);
CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO0消息挂号中断允许.
定时器:
设置毫米级的定时器 Tim3,用于UDS中的心跳时钟。
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); ///使能TIM3时钟
TIM_TimeBaseInitStructure.TIM_Period = arr; //自动重装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //定时器分频
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//初始化TIM3
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //允许定时器3更新中断
TIM_Cmd(TIM3,ENABLE); //使能定时器3
NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; //定时器3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; //抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
TIM3_Int_Init(1000,72);
程序跳转:
汇编程序执行
void jump_to_app(void)
{
upgrade_fun.Deinit_perip();
start_app((*(uint32_t *)(APP1_ADDRESS)),(*(uint32_t *)(APP1_ADDRESS + 4)));
}
__asm void start_app(uint32_t r0_msp, uint32_t r1_pc)
{
MOV SP, R0
BX R1
}
解释下面函数意思
__asm void start_app(uint32_t r0_msp, uint32_t r1_pc)
{
MOV SP, R0 //R0的数值 其实就是参数r0_msp
BX R1 //R1 其实就是r1_pc
}
解释下为什么是这样写?
在跳到用户程序前,需要设置用户程序MSP堆栈指针,以及reset入口地址。
可以参考 任务调度原理 通俗详解(FreeRTOS)
用户程序
进入用户程序时,main函数一定要对中断向量表进行偏移.如果不偏移中断向量表还是用boot中,所以需要对中断向量表偏移到用户程序中。
跳转APP1用户程序
NVIC_SetVectorTable(FLASH_BASE,0x10000);
生成bin文件
fromelf --bin !L --output .\BIN\LED.bin
在BIN目录下即可找到LED.bin文件
跳转APP2用户程序
NVIC_SetVectorTable(FLASH_BASE,0x28000);