当前位置:   article > 正文

S32K144 Bootloader UDS 开发_s32k144 基于can uds的bootloader

s32k144 基于can uds的bootloader

S32K144


前言

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;
		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132

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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119

二、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)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

至此分区工作完成


三、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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

五、遇到的问题

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++;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

通过上述代码分析,开关全局中断的地方,由于代码写的太过严禁,规避中断嵌套时的问题,我能明白代码作者的意图,但是这里不太合适,因为初始化外设时最好先不开中断,所以这里很容易出问题。

解决办法,直接调用ENABLE_INTERRUPTS(); DISABLE_INTERRUPTS();个人感觉更合适一点。

六、最终的效果

在这里插入图片描述

总结

今天去文殊院走了一圈,希望文殊菩萨的智慧洒满人间。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/144646
推荐阅读
相关标签
  

闽ICP备14008679号