最近和对象一起学习硬件入门时,完成了开发板驱动接口的API函数编写任务。我们主要参考了例程文件,最终整合成一个.h和.c文件。其中遇到的第一个问题是如何整理I2C模块的6个例程文件,这些文件包含了Polling、中断和DMA三种工作模式。
思路分析
最初的设计思路是统一提供一套API,通过参数配置来选择内部模式、主从站等功能。然而这种实现方式会导致代码结构臃肿,需要大量#ifdef预处理指令配合,在编译时会消耗过多资源。
采用分体式设计更贴合用户习惯——*用户在使用前通常已明确所需模式。*这种设计遵循嵌入式开发"单一职责"原则(一个函数只做一件事情),同时有效降低了运行时开销。
整理经验
例程文件主要由头文件、数据预处理函数和测试函数组成。测试函数中包含了完整的运行测试流程,我们的核心任务是将其中使用的公共底层函数改写为自定义实现。
/* wait for address hit */
do {
stat = i2c_slave_read(TEST_I2C, data_buff, TEST_TRANSFER_DATA_IN_BYTE);
} while (stat == status_fail);
if (stat != status_success) {
printf("Slave read failed\n");
while (1) {
}
}
例如,i2c_slave_read()是一个底层内置函数,我们需要根据实际需求自行实现这个函数,并注意在编写时构建符合要求的参数结构体。
/ I2C通用配置
typedef struct {
I2C_Type *pstI2c;
uint32_t dwClockSpeedHz; // I2C总线速度(Hz)
i2c_config_t *pstI2cConfig;
uint16_t wSlaveAddres; // 从站地址(仅从站模式需要)
}STRU_I2cConfig ;
// I2C传输配置
typedef struct {
uint16_t wDeviceAddres; // 设备地址(主模式使用)
uint8_t *byBuf; // 数据缓冲区
uint32_t dwSize;// 数据长度
uint8_t *byAddr;// 地址缓冲区
uint32_t dwAddrSize;// 地址长度
}STRU_I2cTransfer;
hpm_stat_t ht_i2c_slave_read(STRU_I2cConfig *pstConfig, const STRU_I2cTransfer *pstHandle){
return i2c_slave_read(pstConfig->pstI2c, pstHandle->wDeviceAddres, pstHandle->byBuf, pstHandle->dwSize);
}
按照上述思路,最终只需编写一个test()函数进行功能测试。该函数可参考例程中的main()函数实现,只需将其内容替换为我们的自定义函数,并添加数据预处理代码即可运行验证。


567

被折叠的 条评论
为什么被折叠?



