完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
前言
S32K144在汽车电子领域得到广泛应用,由于支持CANFD,笔者展开对其Bootloader开发。 一、Bootloader驱动相关代码 首先将开发用到的基本驱动搞定,包括CAN、定时器、FLASH代码,用Process Expert开发极大的简化了开发人员的工作量,但笔者感觉NXP的库代码的质量没有STM32质量高,有些函数调用太容易出问题了,代码的稳健性并不好。 1.CAN驱动 代码如下: #define TX_MAILBOX1 0UL #define RX_MAILBOX1 1UL #define RX_MAILBOX2 2UL #define RX_MSG_ID1 UDS_PHYS_REQ_ID #define RX_MSG_ID2 UDS_FUNC_REQ_ID #define TX_MSG_ID UDS_PHYS_RSP_ID can_buff_config_t RxBuffCfg = { .enableFD = false, .enableBRS = false, .fdPadding = 0U, .idType = CAN_MSG_ID_STD, .isRemote = false }; can_buff_config_t TxBuffCfg = { .enableFD = false, .enableBRS = false, .fdPadding = 0U, .idType = CAN_MSG_ID_STD, .isRemote = false }; can_message_t TxMsg = { .cs = 0U, .id = TX_MSG_ID, .data[0] = 0xAA, .length = 1U }; can_message_t RxMsg; void CAN0_CallBackHandle(uint32_t instance, can_event_t eventType, uint32_t objIdx, void *driverState) { (void)driverState; (void)instance; switch(eventType) { case CAN_EVENT_RX_COMPLETE: if(objIdx == RX_MAILBOX1) { CAN_Receive(&can_pal1_instance, RX_MAILBOX1, &RxMsg); //CAN_Send(&can_pal1_instance, TX_MAILBOX1, &TxMsg); } if(objIdx == RX_MAILBOX2) { CAN_Receive(&can_pal1_instance, RX_MAILBOX2, &RxMsg); //CAN_Send(&can_pal1_instance, TX_MAILBOX1, &TxMsg); } CanRxPoll(RxMsg); break; case CAN_EVENT_TX_COMPLETE: break; default: break; } } void InitCan(void) { CAN_Init(&can_pal1_instance, &can_pal1_Config0); CAN_ConfigRxBuff(&can_pal1_instance, RX_MAILBOX1, &RxBuffCfg, RX_MSG_ID1); CAN_SetRxFilter(&can_pal1_instance, CAN_MSG_ID_STD, RX_MAILBOX1, 0); CAN_ConfigTxBuff(&can_pal1_instance, TX_MAILBOX1, &TxBuffCfg); CAN_InstallEventCallback(&can_pal1_instance, CAN0_CallBackHandle, NULL); CAN_Receive(&can_pal1_instance, RX_MAILBOX1, &RxMsg); } int16_t CanTxFrame(CAN_FRAME *frame, uint8_t chn) { can_message_t TxMessage; TxMessage.cs = 0; TxMessage.id = SendMbox[chn].id; if(SendMbox[chn].ext) { //TxMessage.IDE = 1; } else { //TxMessage.IDE = 0; } //TxMessage.RTR = 0; TxMessage.length = frame->len; TxMessage.data[0] = frame->data[0]; TxMessage.data[1] = frame->data[1]; TxMessage.data[2] = frame->data[2]; TxMessage.data[3] = frame->data[3]; TxMessage.data[4] = frame->data[4]; TxMessage.data[5] = frame->data[5]; TxMessage.data[6] = frame->data[6]; TxMessage.data[7] = frame->data[7]; CAN_Send(&can_pal1_instance, TX_MAILBOX1, &TxMessage); return SUCCESS; } void CanRxPoll(can_message_t RxMessage) { uint16_t n, index; for (n = 0; n < MAX_CHN; n++) { if(RecvMbox[n].id == RxMessage.id /*&& RecvMbox[n].ext == RxMsg.IDE*/) { for (index = 0; index < RxMessage.length; index++) { RecvMbox[n].data[index] = RxMessage.data[index]; } RecvMbox[n].flag = 1; RecvMbox[n].len = RxMessage.length; break; } } } 2.PIT驱动 代码如下: void LPIT_ISR(void) { static volatile uint32_t SysCnt = 0; //PIT_DRV_ClearStatusFlags(INST_PIT1, 0U); LPIT_DRV_ClearInterruptFlagTimerChannels(INST_LPIT1, 1UL<<0); isr_timer_1ms_handle(); if((SysCnt++ % 50) == 0) { //PINS_DRV_TogglePins(PTA, 1UL<<0); PINS_DRV_TogglePins(PTC, 1UL<<17); } } void timer_init(void) { INT_SYS_InstallHandler(LPIT0_Ch0_IRQn, &LPIT_ISR, (isr_t*)0); LPIT_DRV_Init(INST_LPIT1, &lpit1_InitConfig); LPIT_DRV_InitChannel(INST_LPIT1, 0, &lpit1_ChnConfig0); LPIT_DRV_StartTimerChannels(INST_LPIT1, 1UL<<0); } 3.FLASH驱动 代码如下: /* Declare a FLASH config struct which initialized by FlashInit, and will be used by all flash operations */ flash_ssd_config_t flashSSDConfig; /* Data source for program operation */ #define BUFFER_SIZE 0x100u /* Size of data source */ uint8_t sourceBuffer[BUFFER_SIZE]; /* Function declarations */ void CCIF_Handler(void); /* If target is flash, insert this macro to locate callback function into RAM */ START_FUNCTION_DECLARATION_RAMSECTION void CCIF_Callback(void) END_FUNCTION_DECLARATION_RAMSECTION void PFLASH_UnlockCtrl(void) { status_t ret; /* Disable cache to ensure that all flash operations will take effect instantly, * this is device dependent */ //#ifdef S32K144_SERIES MSCM->OCMDR[0u] |= MSCM_OCMDR_OCM1(0x3u); MSCM->OCMDR[1u] |= MSCM_OCMDR_OCM1(0x3u); //#endif /* S32K144_SERIES */ /* Always initialize the driver before calling other functions */ ret = FLASH_DRV_Init(&Flash1_InitConfig0, &flashSSDConfig); DEV_ASSERT(STATUS_SUCCESS == ret); } void PFLASH_LockCtrl(void) { #if 0 /* Restore flash controller cache */ RestoreFlashControllerCache(FLASH_PFCR1, pflash_pfcr1); RestoreFlashControllerCache(FLASH_PFCR2, pflash_pfcr2); #endif } int16_t pflash_erase(uint32_t addr, uint32_t len) { #if 1 volatile const uint8_t buf[8] = {0x7F, 0x31, NRC_RCRRP, 0, 0, 0, 0, 0}; volatile uint32_t page_nbr = (len+PAGE_SIZE-1) / PAGE_SIZE, i; status_t ret; PFLASH_UnlockCtrl(); for(i = 0; i < page_nbr; i++) { if((i&7) == 0) { isotp_snd_sf(&isotp, (uint8_t *)buf, 3); //resply first } ret = FLASH_DRV_EraseSector(&flashSSDConfig, addr + i * PAGE_SIZE, PAGE_SIZE); DEV_ASSERT(STATUS_SUCCESS == ret); if (STATUS_SUCCESS != ret) { return ret; } } PFLASH_LockCtrl(); #endif return 0; } int16_t pflash_write(uint32_t addr, uint8_t *buf, uint32_t len) { #if 1 //volatile EFLASH_STATUS status = EFLASH_STATUS_SUCCESS; status_t ret; PFLASH_UnlockCtrl(); if((len%FEATURE_FLS_PF_BLOCK_WRITE_UNIT_SIZE) == 0) { ret = FLASH_DRV_Program(&flashSSDConfig, addr, len, buf); if (STATUS_SUCCESS != ret) { return ret; } } else { UserMemSet((buf+len), 0xFF, 8); ret = FLASH_DRV_Program(&flashSSDConfig, addr, (len+7)/8*8, buf); if (STATUS_SUCCESS != ret) { return ret; } } PFLASH_LockCtrl(); if(UserMemCmp((const uint8_t *)addr, buf, len) == 0) return 0; #endif return 1; } int16_t pflash_read(uint32_t addr, uint8_t *buf, uint32_t len) { UserMemCpy(buf, (uint8_t *)addr, len); return 0; } 二、Boot和App分区 1.Boot分区如下 代码如下: MEMORY { /* Flash */ m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x00000400 m_flash_config (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010 m_text (RX) : ORIGIN = 0x00000410, LENGTH = 0x0000EBF0 m_boot_config (RX) : ORIGIN = 0x0000F000, LENGTH = 0x00001000 /* SRAM_L */ m_data (RW) : ORIGIN = 0x1FFF8000, LENGTH = 0x00008000 /* SRAM_U */ m_data_2 (RW) : ORIGIN = 0x20000000, LENGTH = (0x00007000-0x10) } 2.App分区 代码如下(示例): MEMORY { /* Flash */ m_interrupts (RX) : ORIGIN = 0x00010000, LENGTH = 0x00000400 m_flash_config (RX) : ORIGIN = 0x00010400, LENGTH = 0x00000010 m_text (RX) : ORIGIN = 0x00010410, LENGTH = 0x0006FBF0 /* SRAM_L */ m_data (RW) : ORIGIN = 0x1FFF8000, LENGTH = 0x00008000 /* SRAM_U */ m_data_2 (RW) : ORIGIN = 0x20000000, LENGTH = 0x00007000 } 至此分区工作完成 三、App分区中断向量表 Bootloader开发的过程中一般需要注意App程序的中断向量问题,由于S32DS的启动代码已包含中断向量表的映射,故不需要应用程序过多处理。 四、Boot跳转到App 设置栈指针,同时设置PC指针,跳到APP的入口地址,由于S32K144的复位向量偏移地址4,故跳转到应用起始地址加4的地址。 void JumpToUserApplication(unsigned int userSP, unsigned int userStartup, unsigned int vectorBase) { /* Check if Entry address is erased and return if erased */ if(userSP == 0xFFFFFFFF){ return; } /* Set up stack pointer */ __asm("msr msp, r0"); __asm("msr psp, r0"); /* Relocate vector table */ //S32_SCB->VTOR = (uint32_t)vectorBase; /* Jump to application PC (r1) */ __asm("mov pc, r1"); } JumpToUserApplication(*((uint32_t*)APP_ENTRY_POINT), *((uint32_t*)(APP_ENTRY_POINT + 4)), APP_ENTRY_POINT); 五、遇到的问题 1.Boot跳转到App时跑飞 解决办法,Boot代码跳转App前进行外设的反初始化。 2.App执行过程中无法进中断 /*FUNCTION********************************************************************** * * Function Name : INT_SYS_EnableIRQGlobal * Description : Enable system interrupt * This function will enable the global interrupt by calling the core API * Implements INT_SYS_EnableIRQGlobal_Activity * *END**************************************************************************/ void INT_SYS_EnableIRQGlobal(void) { /* Check and update */ if (g_interruptDisableCount > 0) { g_interruptDisableCount--; if (g_interruptDisableCount <= 0) { /* Enable the global interrupt*/ ENABLE_INTERRUPTS(); } } } /*FUNCTION********************************************************************** * * Function Name : INT_SYS_DisableIRQGlobal * Description : Disable system interrupt * This function will disable the global interrupt by calling the core API * Implements INT_SYS_DisableIRQGlobal_Activity * *END**************************************************************************/ void INT_SYS_DisableIRQGlobal(void) { /* Disable the global interrupt */ DISABLE_INTERRUPTS(); /* Update counter*/ g_interruptDisableCount++; } 通过上述代码分析,开关全局中断的地方,由于代码写的太过严禁,规避中断嵌套时的问题,我能明白代码作者的意图,但是这里不太合适,因为初始化外设时最好先不开中断,所以这里很容易出问题。 解决办法,直接调用ENABLE_INTERRUPTS(); DISABLE_INTERRUPTS();个人感觉更合适一点。 六、最终的效果 总结 今天去文殊院走了一圈,希望文殊菩萨的智慧洒满人间。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1609 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1540 浏览 1 评论
970 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
681 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1587 浏览 2 评论
1861浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
643浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
515浏览 3评论
528浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
503浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-20 13:44 , Processed in 4.379232 second(s), Total 77, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号