UDS升级入门,手把手教你———MCU相关驱动功能实现

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);
上一篇:【Spring】IoC&DI详解-2. DI详解


下一篇:docker简单使用1