程序的主要目的是作为一个Bootloader的验证性试验,程序的主要框架如下:
程序主体使用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:
配置任务过程中,主要是设置任务堆栈大小和任务名称,需要注意任务Symbol条目对应生成对应的任务入口函数:
之后就是配置各个外设,由于开发板的外部时钟是12MHz,所以需要先把时钟源的频率从24改为12MHz,如果未更改的话,会导致CAN和Uart的频率异常,比如,CAN设置的500kbps可能就变成250kbps
随后设置CAN的寄存器配置,CAN有两种模式,Normal和FIFO模式,两种模式的差别在邮箱配置上面,作为数据传输相对频率的引导刷写程序来讲,应当设置为FIFO模式,但是目前对于这个模式的理解还不够深入,所以当前就仅仅使用了一个接受邮箱和一个发送邮箱的Normal模式。
配置Uart9需要注意的是,需要把Debug模式配置为swd,然后将P109和P110引脚分配给uart
参考论坛的文章,重写fputc和fgetc函数,即可实现fprintf和fscanf,参考的代码如下:
#include "uart9_thread.h"
#include "stdio.h"
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);
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);
}
}
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;
}
}
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();
while(uart_send_complete_flag == false)
{}
uart_send_complete_flag = false;
return ch;
}
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,所以后台刷写和中断都需要关闭,
flash代码参考RASC的例程,主要是配置应用程序的起始地址,写块的大小,同时参考了usb固件代码中的程序跳转的初始化代码,代码如下:
#include "flash0_thread.h"
#include "can0_thread.h"
#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);
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;
__disable_irq();
#if 0
R_MPU_SPMON->SP[0].PT = 0xA500U;
R_MPU_SPMON->SP[1].PT = 0xA500U;
R_MPU_SPMON->SP[0].CTL = 0U;
R_MPU_SPMON->SP[1].CTL = 0U;
#else
__set_MSPLIM(0);
#endif
SysTick->CTRL = 0;
NVIC_DisableIRQ ( SysTick_IRQn );
NVIC_ClearPendingIRQ( SysTick_IRQn );
R_USB_FS0->SYSCFG = 0;
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;
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;
}
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);
__DSB();
__ISB();
R_FCACHE->FCACHEE_b.FCACHEEN = 0;
R_FCACHE->FCACHEIV_b.FCACHEIV = 1;
while (0 != R_FCACHE->FCACHEIV_b.FCACHEIV);
R_FCACHE->FCACHEE_b.FCACHEEN = 1;
SCB->CPACR = 0;
__set_MSP(*((uint32_t*)(address)));
__set_CONTROL(0);
FPU->FPCCR &= 0xC0000000;
(*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;
void can0_thread_entry(void * pvParameters)
{
FSP_PARAMETER_NOT_USED(pvParameters);
fsp_err_t err;
uint32_t cnt = 0;
uint8_t num = 0;
err = R_CAN_Open(&g_can0_ctrl, &g_can0_cfg);
while(1)
{
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();
}
}
void can_callback (can_callback_args_t * p_args)
{
switch (p_args->event)
{
case CAN_EVENT_RX_COMPLETE:
{
g_rx_flag = true;
g_rx_id = p_args->frame.id;
g_can_rx_frame = p_args->frame;
break;
}
case CAN_EVENT_TX_COMPLETE:
{
g_tx_flag = true;
break;
}
case CAN_EVENT_ERR_BUS_OFF:
case CAN_EVENT_ERR_PASSIVE:
case CAN_EVENT_ERR_WARNING:
case CAN_EVENT_BUS_RECOVERY:
case CAN_EVENT_MAILBOX_MESSAGE_LOST:
{
g_err_flag = true;
break;
}
default:
{
break;
}
}
}