项目移植
例程下载:
通过网盘分享的文件:cw32l012_serial_flash_prog_v2.rar
链接: https://pan.baidu.com/s/19AiNYkDXNBuqPAaoCWjxWQ?pwd=L012 提取码: L012
上位机下载:
通过网盘分享的文件:serial-flash-prog_v1.3.1.exe
链接: https://pan.baidu.com/s/12QMAex-y_3XgMx17ifGcKw?pwd=L012 提取码: L012
本期的串口flash下载库是依赖simple_queue队列库和sliding_window_parse滑动窗口解析库的,这里不对这两个库进行介绍,不懂的请看往期文章。
SFP库仅包含4个文件:sfp_core.c、sfp_core.h、comm_fmt.c、comm_fmt.h。使用时将其加入工程,然后按以下步骤在自己代码中完成移植。
配置参数
在 sfp_core.h 中根据实际硬件配置相关宏:
#define SFP_USE_ASSERT 0#define SFP_USE_PRINTF 0#define SFP_USE_CHECK_FRAME_INSIDE 0 // 是否在内部校验数据帧(一般情况下不校验,强烈推荐用户验证好完整帧信息再调用解码函数)#define SFP_USE_READ_AFTER_WRITE_CHECK 0 // 是否在写入后读出数据来校验(开启更加安全,关闭占用资源更少)#define SFP_USE_CHECK_FRAME_LEN 0 // 是否校验命令帧长度(开启更加安全,关闭占用资源更少)#define SFP_IO_LEN_DEFAULT 1024 // 单次读写最大长度#define SFP_FLASH_SIZE (16*1024*1024) // 物理存储介质大小 16MB#define SFP_PRINTF printf
实现底层接口
在自己的 .c 文件中实现 sfp_ops_t 声明的全部接口函数(以下以CW32平台为例,其他平台类似):
// CRC16-CCITT 校验接口static uint16_t sfp_crc16_ccitt(void *pdata, uint16_t len){// user code beginreturnproto_parser_crc16_ccitt(pdata, len);// user code end// return 0;}// 串口数据发送接口staticvoidsfp_data_tx_port(const sfp_download_info_t* download_info,uint8_t *pdata, uint16_t len){cw32_uart3_send_data(pdata, len);}// flash 擦除接口static sfp_err_code_t sfp_erase_port(const sfp_download_info_t* download_info, uint32_t start_addr, uint32_t len){if(start_addr + len > SFP_FLASH_SIZE){return SFP_ERR_OPERATION_ADDRESS;}// user code beginnor_flash_erase_auto(start_addr, len);// user code endreturn SFP_ERR_NONE;}// flash 写入接口static sfp_err_code_t sfp_write_port(const sfp_download_info_t* download_info, uint32_t start_addr, uint8_t *pdata, uint16_t len){if(start_addr + len > SFP_FLASH_SIZE){return SFP_ERR_OPERATION_ADDRESS;}elseif(len > download_info->io_len || len == 0){return SFP_ERR_OPERATION_LEN;}// user code beginnor_flash_write(start_addr, pdata, len);// user code endreturn SFP_ERR_NONE;}// flash 读取接口#if SFP_USE_READ_AFTER_WRITE_CHECKstatic sfp_err_code_t sfp_read_port(const sfp_download_info_t* download_info, uint32_tstart_addr, uint8_t *pdata, uint16_tlen){if(start_addr + len > SFP_FLASH_SIZE){return SFP_ERR_OPERATION_ADDRESS;}elseif(len > download_info->io_len || len == 0){return SFP_ERR_OPERATION_LEN;}// user code beginnor_flash_read(start_addr, pdata, len);// user code endreturn SFP_ERR_NONE;}#endif// 下载开始接口static sfp_err_code_t sfp_download_start_port(const sfp_download_info_t* download_info){// you can check file size, version, file name, io lenif(download_info->file_size > SFP_FLASH_SIZE){return SFP_ERR_FILE_TOO_LARGE;}elseif(download_info->io_len > SFP_IO_LEN_DEFAULT || download_info->io_len == 0){return SFP_ERR_IO_LEN;}// else if(strcmp(download_info->file_name, "xxx.bin") == 0)// {// return SFP_ERR_FILE_NAME;// }// else if(download_info->version == 0x00000000)// {// return SFP_ERR_VERSION;// }// user code begin// user code endreturn SFP_ERR_NONE;}// 下载完成接口static sfp_err_code_t sfp_download_stop_port(const sfp_download_info_t* download_info){// user code begin// user code endreturn SFP_ERR_NONE;}
实例化并初始化
先构建ops操作表,然后定义 sfp_module_t 实例和发送缓冲区,在系统初始化时调用 sfp_module_init
const sfp_ops_t sfp_ops ={.crc16_ccitt = sfp_crc16_ccitt,.data_tx_port = sfp_data_tx_port,.flash_erase_port = sfp_erase_port,.flash_write_port = sfp_write_port,#if SFP_USE_READ_AFTER_WRITE_CHECK.flash_read_port = sfp_read_port,#endif.download_start_port = sfp_download_start_port,.download_stop_port = sfp_download_stop_port,};uint8_t sfp_tx_buf[SFP_TX_BUF_SIZE_MIN] = {0};sfp_module_t sfp_module = {0};voidservice_sfp_init(void){sfp_init_t init = {0};init.ops = &sfp_ops;init.tx_buf = sfp_tx_buf;init.tx_buf_size = sizeof(sfp_tx_buf);init.self_dev_addr = 1;if(!sfp_module_init(&sfp_module,&init)){// init failed// user code begin// user code endwhile(1);}}
对接滑动串口解析层
对sfp层解析函数进行封装
voidservice_sfp_decode_full_frame(sfp_frame_msg_t* sfp_msg,uint8_t* frame_buf,uint16_t frame_len){sfp_decode_full_frame(&sfp_module,sfp_msg,frame_buf,frame_len);}在滑动窗口解析一帧的回调函数中调用我们刚刚写的函数voidparser_frame_dispose(frame_msg_t *msg,uint8_t* frame_buf, uint16_t len){/*frame_msg_t 与 sfp_frame_msg_t 结构体元素是相同的,为了降低依赖,将其区分了实际使用时强制类型转换即可*/service_sfp_decode_full_frame((sfp_frame_msg_t*)msg,frame_buf,len);}
至此,移植完成。核心工作就是配置宏 + 实现接口函数,后续收到完整命令帧后调用 sfp_decode_full_frame 即可自动完成命令处理、Flash操作和应答发送。
扫码加入QQ群,3群| 610403240
183