gscoolink:gsv2001的sdk移植
1 前言
以gsv2001的sdk的应用代码为例,将gsv2001 sdk代码移植到stm32f1xx的hal库的sdk上;
因为gsv2001的sdk也是使用stm32,也是使用hal库;所以移植起来改个头文件和iic gpio就行了;
stm32和gd32都是cm核,cm核的代码可以直接pin2pin互相运行,需要注意一下地址访问不越界,堆栈和rtos的m核配置;
2 修改项目名
很多项目在之前的项目基础上改改代码就行了,但是项目名和代码变量名都不匹配;
所以呀,注释可以不写,但命名务必正确;
所以呀,新的项目先不急着移植,先把项目代码框架的项目名和配置改好;
首先修改xx.uvprojx的名字为project名;然后打开keil5工程;
manage project items >> project targets >> 修改target名为project,移植就不用再命名了;
options for target >> target >> 勾选microLIB,核对IROM和IRAM的size匹配;
options for target >> output >> select folder for objects >> 选择output目录;
options for target >> output >> name for execucutable >> 命名改为output.axf;
options for target >> listing >> select folder for listing >> 选择listing目录,和output目录一起省的多个文件;
options for target >> user >> run >>
fromelf.exe --bin -o ./releaseFile/Test1_Z_SP12CS-V2_V1.0.0a_0691_08009000.bin ./outputFile/output.axf
fromelf.exe --bin -o ./releaseFile/Test2_Z_SP12CS-V2_V1.0.0a_0691_08009000.bin "#L"
options for target >> c/c++ >> 勾选c99 mode,消除'declaration may not appear after executable statement in block.'
3 sdk source代码移植
3.1 gsv2001_sdk_source目录复制到目标磁盘下
看一下gsv2001_sdk的代码和代码磁盘目录;source目录是gsv运行需要的代码,project目录是mcu和keil运行需要的代码;
确认要移植的代码是source目录下的代码,复制source目录到'dst_sdk'项目的磁盘下待移植;
3.2 在keil工程中包含gsv2001_sdk_source目录的xx.c和xx.h的文件
project目录下的xx.c文件在编译的时候分先后,所以要按原sdk工程的顺序包含;
IncludePaths框内的头文件在包含的时候也分先后,所以也要按原sdk工程的顺序包含;
如果不按原有目录的顺序包含,会打乱编译顺序,然后会报错很多undefined的问题;这里卡了一天;
3.3 点击编译,根据error报错大概修改如下,要修改的并不多
修改av_main.h和bsp.h的那几个#include "stm32f0xx.h" >> #include "stm32f1xx.h",
修改iic的gpio为cm3核的gpio寄存器,
sdk自带的key和uart通过宏不启用,这部分代码有的和cm0核相关注释起来地方挺多干脆不用,用已有的代码;
这样的话sdk基本就可以编译通过了,编译通过之后在具体修改一些细节;
4 sdk source代码修改
gsv的sdk将音视频的应用代码和bsp板间外设进行了分离,代码移植到不同板子上时只需要修改对应bsp,方便移植;
gsv给用户封装了两个接口用来作为bsp的回调注册,那么这两个函数都是如何工作的呢?如果要移植我们都需要改啥呢?
/* 1.2 init software package and hookup user's bsp functions */ AvApiInit(); AvApiHookBspFunctions(&BspI2cRead, &BspI2cWrite, &BspUartSendByte,&BspUartGetByte, &BspGetMilliSecond, &BspGetKey, &BspIrdaGetByte); AvApiHookUserFunctions(&ListenToKeyCommand, &ListenToUartCommand, &ListenToIrdaCommand);
4.1 AvApiHookBspFunctions函数
定义一个函数指针声明,然后将bsp的读写操作函数地址赋值,这样就可以用函数指针访问;作为一层封装;
然后再用宏二次封装,用二次封装的宏进行调用;
所以需要修改bsp回调代码的话,就直接修改一层封装的注册函数接口即可;
/** bsp 函数指针定义 ***************************************************************************/ //hal.h hardware access functions; cae:I would like to store definitions into uapi.h typedef AvRet (*AvFpI2cRead)(uint32, uint32, uint8 *, uint16); typedef AvRet (*AvFpI2cWrite)(uint32, uint32, uint8 *, uint16); typedef AvRet (*AvFpUartSendByte)(uint8 *, uint16); typedef AvRet (*AvFpUartGetByte)(uint8 *); typedef AvRet (*AvFpGetMilliSecond)(uint32 *); typedef AvRet (*AvFpGetKey)(uint8 *); typedef AvRet (*AvFpGetIrda)(uint8 *); //uapi.c hal functions variables AvFpI2cRead AvHookI2cRead; AvFpI2cWrite AvHookI2cWrite; AvFpUartSendByte AvHookUartTxByte; AvFpUartGetByte AvHookUartRxByte; AvFpGetMilliSecond AvHookGetMilliSecond; AvFpGetKey AvHookGetKey; AvFpGetIrda AvHookGetIrda; //uapi.h 下面的kapi.h就没有用extern;这个gsv的代码对称性不好; extern AvFpI2cRead AvHookI2cRead; extern AvFpI2cWrite AvHookI2cWrite; extern AvFpUartSendByte AvHookUartTxByte; extern AvFpUartGetByte AvHookUartRxByte; extern AvFpGetMilliSecond AvHookGetMilliSecond; extern AvFpGetKey AvHookGetKey; extern AvFpGetIrda AvHookGetIrda; /**av_main.c >> bsp 函数指针注册 *****************************************************************/ //uapi.c @brief hookup user's hardware access functions uapi AvRet AvUapiHookBspFunctions(pin AvFpI2cRead i2cRd, pin AvFpI2cWrite i2cWr, pin AvFpUartSendByte uartTxB, pin AvFpUartGetByte uartRxB, pin AvFpGetMilliSecond getMs, pin AvFpGetKey getKey,pin AvFpGetIrda getIrda) { AvRet ret = AvOk; AvHookI2cRead = i2cRd; AvHookI2cWrite = i2cWr; AvHookUartTxByte = uartTxB; AvHookUartRxByte = uartRxB; AvHookGetMilliSecond = getMs; AvHookGetKey = getKey; AvHookGetIrda = getIrda; AvUapiOutputDebugMessage(" "); AvUapiOutputDebugMessage("-------------------------------------------------------------------"); AvUapiOutputDebugMessage(" |> Audio/Video Software %s", AvVersion); AvUapiOutputDebugMessage("-------------------------------------------------------------------"); return ret; } //av_main.c AvApiHookBspFunctions(&BspI2cRead, &BspI2cWrite, &BspUartSendByte,&BspUartGetByte, &BspGetMilliSecond, &BspGetKey, &BspIrdaGetByte); /** bsp 函数指针二次封装,用来回调******************************************************************************/ //hal.h #define AvI2cRead AvHookI2cRead #define AvI2cWrite AvHookI2cWrite #define AvUartTxByte AvHookUartTxByte #define AvUartRxByte AvHookUartRxByte #define AvGetMilliSecond AvHookGetMilliSecond #define AvGetKey AvHookGetKey #define AvIrdaRxByte AvHookGetIrda //hal.c 以重新封装的Avxx宏去调用,这样就实现了bsp隔离; AvRet AvHalI2cRead(pin uint32 devAddress, pin uint32 regAddress, pout uint8 *avdata, pin uint16 count) { AvRet ret = AvOk; ret = AvI2cRead(devAddress, regAddress, avdata, count); return ret; } //把 &BspI2cRead 封装成 AvHookI2cRead,然后又封装成AvI2cRead; 双重封印; //如果是我我只会封一层,这玩意干嘛要封两层?
4.2 AvApiHookUserFunctions函数
/**kapi.h userFunction 函数指针定义 *****************************************************************/ typedef void (*AvFpKeyCommand) (AvPort *port); typedef void (*AvFpUartCommand) (AvPort *port); typedef void (*AvFpIrdaCommand) (AvPort *port); //kapi.c AvFpKeyCommand AvHookKeyCmd; AvFpUartCommand AvHookUartCmd; AvFpIrdaCommand AvHookIrdaCmd; /**kapi.h userFunction 函数指针注册 *****************************************************************/ //kapi.c @brief hookup user layer access functions kapi AvRet AvKapiHookUserFunctions(pin AvFpKeyCommand keyCmd, pin AvFpUartCommand uartCmd,pin AvFpIrdaCommand IrdaCmd) { AvRet ret = AvOk; AvHookKeyCmd = keyCmd; AvHookUartCmd = uartCmd; AvHookIrdaCmd = IrdaCmd; return ret; } //av_main.c AvApiHookUserFunctions(&ListenToKeyCommand, &ListenToUartCommand, &ListenToIrdaCommand); /**kapi.h userFunction 函数指针二次封装,用来回调 *****************************************************************/ //kapi.h #define AvUserUartCmd AvHookUartCmd #define AvUserKeyCmd AvHookKeyCmd #define AvUserIrdaCmd AvHookIrdaCmd //kapi.c while(TempPort){ /* Make Key Response and Uart Response faster */ AvUserUartCmd(FirstPort); AvUserKeyCmd(FirstPort); AvUserIrdaCmd(FirstPort); //... }
4.3 bsp修改
对于iic而言,软件模拟的,可以直接用gsv写的;只要改一下GPIO寄存器操作; 参考修改GPIO的IIC的CRH或CRL寄存器
对于uart而言,注释掉gsv的bsp回调函数,使用已有的uartBsp回调,把gsv的打印函数重新映射printf;
对于按键而言,注释掉gsv的bsp回调函数;
//kapi.h 下面的监听回调是封装在kapi.h中的;而bsp的调用宏是封装在hal.h中; #define AvUserUartCmd //AvHookUartCmd #define AvUserKeyCmd //AvHookKeyCmd #define AvUserIrdaCmd //AvHookIrdaCmd //i2c.c #define SET_SCL0_1 GPIOB->BSRR = GPIO_PIN_13 // Pin I2C_SCL #define SET_SDA0_1 GPIOB->BSRR = GPIO_PIN_14 // Pin I2C_SDA #define SET_SCL0_0 GPIOB->BSRR = GPIO_PIN_13<<16U // Pin I2C_SCL #define SET_SDA0_0 GPIOB->BSRR = GPIO_PIN_14<<16U // Pin I2C_SDA #define GET_SDA0 ((GPIOB->IDR & GPIO_PIN_14)? 1:0) // Pin I2C_SDA #define SCL0_IN GPIOB->CRH = ( ((GPIOB->CRH)&0xff0fffff)|0x00400000 ) #define SCL0_OUT GPIOB->CRH = ( ((GPIOB->CRH)&0xff0fffff)|0x00700000 ) #define SDA0_IN GPIOB->CRH = ( ((GPIOB->CRH)&0xf0ffffff)|0x04000000 ) #define SDA0_OUT GPIOB->CRH = ( ((GPIOB->CRH)&0xf0ffffff)|0x07000000 )
4.4 printf修改
//uapi.c 本来的打印函数使用gsv的bsp的uart,改一下用printf;这样关个宏就可以了,不用改bsp; uapi AvRet AvUapiOuputDbgMsg(pin schar *stringToFormat, ...){ AvRet ret = AvOk; #if AvEnableDebugFsm va_list ap; //声明一个va_list类型的指针变量ap,存储可变参数列表 va_start(ap, stringToFormat); //初始化ap,指向stringToFormat之后的第一个可变参数地址 vprintf(stringToFormat, ap); //使用vprintf直接打印字符串stringToFormat,以及它的可变参数列表指针ap va_end(ap); printf("\r\n"); #endif return ret; } //vsprintf((char *)dtsbuff,pString,ap); //vsprintf函数可以接受一个pString字符串指针,一个ap可变参数列表指针,然后把他们组合打印到dtsBuff数组中;
4.5 gsvMain
函数改成case语句,然后搞个while(1)或者task来调用即可;这样就移植完成了;
void gsv2k1_Main(void){ static uint8_t state = 0; switch(state){ case 0: CAE("gsv2k1_Main() "); GsvMain(); state++; break; case 1: AvApiUpdate(); AvPortConnectUpdate(&devices[0]); break; } }
5 小结
问题想清楚之后执行就好了,行动才是生产力;
这个东西移植起来事后复盘还是比较简单的,但是移植了好几天,因为还用了一半以上时间去确认有没有遗漏;
今天移植6k7代码用了一天;因为没有把串口打印出来,没有及时调试导致早早就飞了野指针;
写代码还是要及时调试;
所以总结一下gsv2001的移植需要干嘛呢?
首先按顺序包含一下xx.c和xx.h文件;然后修改头文件和iic gpio,然后把按键和串口回调注释掉并且重映射printf即可;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?