赞
踩
S32K144在汽车电子领域得到广泛应用,由于支持CANFD,笔者展开对其Bootloader开发。
首先将开发用到的基本驱动搞定,包括CAN、定时器、FLASH代码,用Process Expert开发极大的简化了开发人员的工作量,但笔者感觉NXP的库代码的质量没有STM32质量高,有些函数调用太容易出问题了,代码的稳健性并不好。
代码如下:
#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; } } }
代码如下:
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); }
代码如下:
/* 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; }
代码如下:
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)
}
代码如下(示例):
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
}
至此分区工作完成
Bootloader开发的过程中一般需要注意App程序的中断向量问题,由于S32DS的启动代码已包含中断向量表的映射,故不需要应用程序过多处理。
设置栈指针,同时设置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);
解决办法,Boot代码跳转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();个人感觉更合适一点。
今天去文殊院走了一圈,希望文殊菩萨的智慧洒满人间。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。