单片机/MCU论坛
直播中

箕尾1

3年用户 10经验值
擅长:接口/总线/驱动 控制/MCU
私信 关注
[文章]

【RA4M2设计挑战赛】基于CAN的固件升级引导程序设计

程序的主要目的是作为一个Bootloader的验证性试验,程序的主要框架如下:
下.jpg
程序主体使用FreeRTOS,使用MDK编译,需要注意的一点是瑞萨提供的MDK的DFP需要配合不同版本的mdk使用,最新的4.2.0版本需要使用MDK 5.31以上,而不能使用5.14版本。
使用RASC Configuration配置外设和任务很方便,在选择了FreeRTOS,MDK之后,在Stacks界面分别配置四个主任务,blinky_thread、can0_thread、uart9_thread、flash0_thread:
下1.jpg
配置任务过程中,主要是设置任务堆栈大小和任务名称,需要注意任务Symbol条目对应生成对应的任务入口函数:
下2.jpg

之后就是配置各个外设,由于开发板的外部时钟是12MHz,所以需要先把时钟源的频率从24改为12MHz,如果未更改的话,会导致CAN和Uart的频率异常,比如,CAN设置的500kbps可能就变成250kbps
下3.jpg
随后设置CAN的寄存器配置,CAN有两种模式,Normal和FIFO模式,两种模式的差别在邮箱配置上面,作为数据传输相对频率的引导刷写程序来讲,应当设置为FIFO模式,但是目前对于这个模式的理解还不够深入,所以当前就仅仅使用了一个接受邮箱和一个发送邮箱的Normal模式。
下4.jpg

下5.jpg

配置Uart9需要注意的是,需要把Debug模式配置为swd,然后将P109和P110引脚分配给uart
下6.jpg

下7.jpg

参考论坛的文章,重写fputc和fgetc函数,即可实现fprintf和fscanf,参考的代码如下:

#include "uart9_thread.h"
#include "stdio.h"
/* Uart0 Thread entry function */
/* pvParameters contains TaskHandle_t */
volatile bool     uart_send_complete_flag  = false;
volatile bool     uart_recv_complete_flag  = false;
volatile uint32_t uart_recv_char = '\0';


void uart9_thread_entry(void * pvParameters)
{
		FSP_PARAMETER_NOT_USED(pvParameters);

		/* TODO: add your own code here */
		fsp_err_t err = FSP_SUCCESS;
		
		err = R_SCI_UART_Open(&g_uart9_ctrl, &g_uart9_cfg);
		assert(FSP_SUCCESS == err);
		
		printf("printf and scanf test!!\n");
		while(1)
		{
				char recv_char[10] = "Hello";
			
				scanf("%s",recv_char);
			
				if(strcmp(recv_char, "open") == 0)
				{
					printf("Hello!! WangDip");
				}
				
				vTaskDelay(10);
		}
}


//callback function for uart9
void uart9_notification(uart_callback_args_t * p_args)
{
	if(p_args->event == UART_EVENT_TX_COMPLETE)
	{
		uart_send_complete_flag = true;
	}
	else if(p_args->event == UART_EVENT_RX_CHAR)
	{
		uart_recv_char = p_args->data;
		uart_recv_complete_flag = true;
	}
}


//fputs for printf or other print function instandard

int fputc(int ch, FILE *f)
{
	fsp_err_t err = FSP_SUCCESS;
	
	(void)f;
	
	err = R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t *)&ch, 1);
	if(FSP_SUCCESS != err)
		__BKPT();
	
	//Waiting until transmit finished 
	while(uart_send_complete_flag == false)
	{}
		
	uart_send_complete_flag = false;
		
	return ch;
}



//fgets for scanf or other input function in standard


int fgetc(FILE *f)
{
	(void)f;
	
	while(uart_recv_complete_flag == false)
	{}
		
	uart_recv_complete_flag = false;
	
	return (int)uart_recv_char;
}

最后就是配置,flash,由于需要操作code flash,所以后台刷写和中断都需要关闭,
image.png

flash代码参考RASC的例程,主要是配置应用程序的起始地址,写块的大小,同时参考了usb固件代码中的程序跳转的初始化代码,代码如下:

#include "flash0_thread.h"
#include "can0_thread.h"
/* Flash0 Thread entry function */
/* pvParameters contains TaskHandle_t */

#define FLASH_CF_BLOCK_8               0x00010000
#define FLASH_CF_BLOCK_22               0x00010000
#define FLASH_DATA_BLOCK_SIZE          (64)
#define CODE_FLASH_WRITE_SIZE    			 128

#define APP_START_ADDR                  0x80000

typedef int (*main_fnptr)(void);

uint8_t        g_dest[128];
uint8_t        g_src[128];
uint32_t addr;
extern bool isFull;
extern bool flsRqst;

static void execute_user_code(uint32_t address);

void flash0_thread_entry(void * pvParameters)
{
		FSP_PARAMETER_NOT_USED(pvParameters);

		/* TODO: add your own code here */
		fsp_err_t err = R_FLASH_HP_Open(&g_flash0_ctrl, &g_flash0_cfg);
		
		assert(FSP_SUCCESS == err);
		
		addr = FLASH_CF_BLOCK_8;
		
		uint32_t cnt_time = 0;
	
	
		while(1)
		{
			if(flsRqst)
			{
				 __disable_irq();
				
				if(isFull&&(addr<0x7FF7F))
				{
					
						if(addr%0x8000)
						{
							err = R_FLASH_HP_Erase(&g_flash0_ctrl, addr, 1);
							assert(FSP_SUCCESS == err);
							vTaskDelay(5);
						}
						
						err = R_FLASH_HP_Write(&g_flash0_ctrl, (uint32_t) g_src, addr, CODE_FLASH_WRITE_SIZE);
						assert(FSP_SUCCESS == err);
						
						isFull = false;
						__enable_irq();
						
						vTaskDelay(1);
						
						assert(0 == memcmp(g_src, (uint8_t *) FLASH_CF_BLOCK_8, CODE_FLASH_WRITE_SIZE));
						
						addr += 128;
				}
			}
			else
			{
				vTaskDelay(1);
				cnt_time++;
				if(cnt_time>500)
					execute_user_code(APP_START_ADDR);
			}
		}	
}

static void execute_user_code(uint32_t address)
{
    main_fnptr *p_jump_to_app; // Function pointer main that will be used to jump to application

    __disable_irq();

#if 0       //Commented out 2022.06.24 WangJin
    /* Disable the stack monitor */
    R_MPU_SPMON->SP[0].PT = 0xA500U;                /* Enable access to Main Stack Pointer Monitor Access Control Register */
    R_MPU_SPMON->SP[1].PT = 0xA500U;                /* Enable access to Process Stack Pointer Monitor Access Control Register */
    R_MPU_SPMON->SP[0].CTL = 0U;                    /* disable the Main stack monitor */
    R_MPU_SPMON->SP[1].CTL = 0U;                    /* disable the Process stack monitor */
#else
    __set_MSPLIM(0);
#endif
    SysTick->CTRL  = 0;                             /* Disable the systick timer */
    NVIC_DisableIRQ ( SysTick_IRQn );               /* Disable the systick timer IRQ */
    NVIC_ClearPendingIRQ( SysTick_IRQn );           /* Clear any pending systick timer IRQ */

    R_USB_FS0->SYSCFG = 0;                            /* Disable USB FS */
    R_USB_FS0->DVSTCTR0 = 0;
    R_USB_FS0->INTENB0 = 0;
    R_USB_FS0->INTENB1 = 0;
    R_USB_FS0->INTSTS0 = 0;
    R_USB_FS0->INTSTS1 = 0;
    R_USB_FS0->BRDYENB = 0;
    R_USB_FS0->NRDYENB = 0;
    R_USB_FS0->BEMPENB =0;
    R_USB_FS0->USBADDR = 0;

    // Clear all interrupts!
    // ICU Event Link Setting Register i (IELSRi) (RA6M3: i = 0 to 95)
    for (uint32_t i = 0; i<96; i++)
    {
        R_ICU->IELSR[i] = 0;
    }

    for (uint32_t i = 0; i<8; i++)
    {
        NVIC->ICER[i] = 0xFFFFFFFF;
        NVIC->ICPR[i] = 0xFFFFFFFF;
    }

    // IRQ Control Register i (IRQCRi) (RA6M3: i = 0 to 15)
    for  (uint32_t i = 0; i<16; i++)
    {
        R_ICU->IRQCR[i] = 0;
    }

    p_jump_to_app = (main_fnptr*)(address+4);

    SCB->VTOR = (address & 0x1FFFFF80);

    /* Complete all explicit memory accesses */
    __DSB();
    /* Flush the pipeline in the processor */
    __ISB();

    // Flush the ROM cache, or we won't see the changed data
    R_FCACHE->FCACHEE_b.FCACHEEN = 0;           //Disable Flash Memory Cache
    R_FCACHE->FCACHEIV_b.FCACHEIV = 1;          //Invalidate Flash Cache
    while (0 != R_FCACHE->FCACHEIV_b.FCACHEIV);
    R_FCACHE->FCACHEE_b.FCACHEEN = 1;           // Re-Enable ROM cache

    /* Set bits 20-23 to enable CP10 and CP11 coprocessor */
    SCB->CPACR = 0;

     /** Set stack here. */
    __set_MSP(*((uint32_t*)(address)));

    /* Ensure that when we jump we're using the Main Stack Pointer */
    __set_CONTROL(0);

    /* Clear lazy stacking for FPU operations */
    FPU->FPCCR &= 0xC0000000;

    /** Jump to image*/
     (*p_jump_to_app)();
     __NOP();
}

与上位机的交互主要在CAN模块中执行,主要代码如下:

#include "can0_thread.h"
#include "blinky_thread.h"


can_frame_t g_can_tx_frame;
can_frame_t g_can_rx_frame;
volatile bool     g_rx_flag  = false;
volatile bool     g_tx_flag  = false;
volatile bool     g_err_flag = false;
volatile uint32_t g_rx_id;

bool isFull = false;
bool flsRqst = false;
uint8_t g_data[128];
uint32_t len = 0;
bool vStart = false;

bsp_io_level_t pin_level_can = BSP_IO_LEVEL_LOW;


/* CAN0 Thread entry function */
/* pvParameters contains TaskHandle_t */ 
void can0_thread_entry(void * pvParameters)
{
		FSP_PARAMETER_NOT_USED(pvParameters);
		fsp_err_t err;
		uint32_t cnt = 0;
		uint8_t num = 0;
		
	

		/* TODO: add your own code here */
		/* Initialize the CAN module */
		err = R_CAN_Open(&g_can0_ctrl, &g_can0_cfg);
		while(1)
		{
				//vTaskDelay(10);
				num = g_can_rx_frame.data[0];
				if(g_can_rx_frame.data[0] == 0xA0 && g_can_rx_frame.data[1] == 0xB1 &&
				g_can_rx_frame.data[2] == 0xC2 && g_can_rx_frame.data[3] == 0xD3 && !vStart && g_rx_flag)
				{
					len = (uint32_t)(((g_can_rx_frame.data[4])<<24) + ((g_can_rx_frame.data[5])<<18) +
						((g_can_rx_frame.data[6])<<8) + g_can_rx_frame.data[7]);
					vStart = true;
					g_rx_flag = false;
					g_can_tx_frame.id = 0x777;
					g_can_tx_frame.data_length_code = 0x08;
					err = R_CAN_Write(&g_can0_ctrl, 0, &g_can_tx_frame);
				}
				
				if(vStart && g_rx_flag && num < len )
				{
					vStart = true;
					memcpy(g_data+cnt*7,(g_can_rx_frame.data + 1),7);
					cnt++;
					if(cnt == 8)
					{
						cnt = 0;
						isFull = true;
					}
					num ++;
				}
				
				if(num>=len && isFull == false)
					flsRqst = false;
				
				if(cnt < 150)
				{
					pin_level_can = BSP_IO_LEVEL_HIGH;
				}
				else
					pin_level_can = BSP_IO_LEVEL_LOW;
				
				cnt++;
				
				if(cnt == 310)
					cnt = 0;
				taskEXIT_CRITICAL();
				
				
				/* Since there is nothing else to do, block until Callback triggers*/
		}
}

void can_callback (can_callback_args_t * p_args)
{
    switch (p_args->event)
    {
        case CAN_EVENT_RX_COMPLETE:    /* Receive complete event. */
        {
            g_rx_flag = true;
            g_rx_id   = p_args->frame.id;
            /* Read received frame */
            g_can_rx_frame = p_args->frame;
            break;
        }
        case CAN_EVENT_TX_COMPLETE:    /* Transmit complete event. */
        {
            g_tx_flag = true;
            break;
        }
        case CAN_EVENT_ERR_BUS_OFF:          /* Bus error event. (bus off) */
        case CAN_EVENT_ERR_PASSIVE:          /* Bus error event. (error passive) */
        case CAN_EVENT_ERR_WARNING:          /* Bus error event. (error warning) */
        case CAN_EVENT_BUS_RECOVERY:         /* Bus error event. (bus recovery) */
        case CAN_EVENT_MAILBOX_MESSAGE_LOST: /* Overwrite/overrun error */
        {
            /* Set error flag */
            g_err_flag = true;
            break;
        }
        default:
        {
            break;
        }
    }
}

回帖(1)

jf_26147162

2023-3-9 12:10:33
IC:三峰伟业电子有限公司 大量品牌 库存 欢迎采购小哥哥小姐姐们 来咨询下单~ =sanfeng88
举报

更多回帖

发帖
×
20
完善资料,
赚取积分