設(shè)備驅(qū)動(dòng)開(kāi)發(fā)全流程:SPI/I2C通信協(xié)議棧實(shí)現(xiàn)與錯(cuò)誤處理
掃描二維碼
隨時(shí)隨地手機(jī)看文章
在嵌入式系統(tǒng)開(kāi)發(fā)中,SPI和I2C作為最常用的同步串行通信協(xié)議,其驅(qū)動(dòng)實(shí)現(xiàn)直接影響硬件交互的穩(wěn)定性。本文以STM32 HAL庫(kù)為基礎(chǔ),闡述從協(xié)議棧架構(gòu)設(shè)計(jì)到錯(cuò)誤處理的完整開(kāi)發(fā)流程,實(shí)現(xiàn)微秒級(jí)時(shí)序控制與毫秒級(jí)錯(cuò)誤恢復(fù)。
一、協(xié)議棧分層架構(gòu)設(shè)計(jì)
1. 物理層抽象
c
// SPI物理層接口定義
typedef struct {
SPI_TypeDef* instance; // SPI外設(shè)實(shí)例
GPIO_TypeDef* cs_port; // 片選引腳端口
uint16_t cs_pin; // 片選引腳號(hào)
uint32_t clock_speed; // 時(shí)鐘頻率(Hz)
uint8_t mode; // CPOL/CPHA模式
} SPI_PhyLayer;
// I2C物理層接口定義
typedef struct {
I2C_TypeDef* instance; // I2C外設(shè)實(shí)例
uint32_t clock_speed; // 標(biāo)準(zhǔn)模式(100kHz)/快速模式(400kHz)
uint8_t addr_mode; // 7位/10位地址模式
} I2C_PhyLayer;
2. 協(xié)議層封裝
c
// SPI協(xié)議操作接口
typedef struct {
HAL_StatusTypeDef (*transmit_receive)(SPI_PhyLayer*, uint8_t*, uint8_t*, uint32_t);
HAL_StatusTypeDef (*config_speed)(SPI_PhyLayer*, uint32_t);
} SPI_ProtocolOps;
// I2C協(xié)議操作接口
typedef struct {
HAL_StatusTypeDef (*master_transmit)(I2C_PhyLayer*, uint16_t, uint8_t*, uint16_t, uint32_t);
HAL_StatusTypeDef (*master_receive)(I2C_PhyLayer*, uint16_t, uint8_t*, uint16_t, uint32_t);
} I2C_ProtocolOps;
二、核心通信實(shí)現(xiàn)
1. SPI全雙工通信
c
HAL_StatusTypeDef SPI_MasterTransmitReceive(SPI_PhyLayer* phy, uint8_t* tx_buf, uint8_t* rx_buf, uint32_t size) {
HAL_StatusTypeDef status;
// 硬件片選控制
HAL_GPIO_WritePin(phy->cs_port, phy->cs_pin, GPIO_PIN_RESET);
// 啟動(dòng)傳輸(使用DMA提高效率)
status = HAL_SPI_TransmitReceive_DMA(phy->instance, tx_buf, rx_buf, size);
if(status != HAL_OK) {
HAL_GPIO_WritePin(phy->cs_port, phy->cs_pin, GPIO_PIN_SET);
return status;
}
// 等待傳輸完成(帶超時(shí)機(jī)制)
uint32_t tickstart = HAL_GetTick();
while(HAL_SPI_GetState(phy->instance) != HAL_SPI_STATE_READY) {
if((HAL_GetTick() - tickstart) > SPI_TIMEOUT_MS) {
HAL_SPI_DMAStop(phy->instance);
HAL_GPIO_WritePin(phy->cs_port, phy->cs_pin, GPIO_PIN_SET);
return HAL_TIMEOUT;
}
}
HAL_GPIO_WritePin(phy->cs_port, phy->cs_pin, GPIO_PIN_SET);
return HAL_OK;
}
2. I2C帶重試機(jī)制通信
c
#define I2C_MAX_RETRY 3
HAL_StatusTypeDef I2C_MasterTransmitWithRetry(I2C_PhyLayer* phy, uint16_t dev_addr, uint8_t* data, uint16_t size) {
HAL_StatusTypeDef status;
uint8_t retry = 0;
do {
status = HAL_I2C_Master_Transmit(phy->instance, dev_addr, data, size, I2C_TIMEOUT_MS);
retry++;
// 特定錯(cuò)誤需要硬件復(fù)位
if(status == HAL_BUSY) {
HAL_I2C_DeInit(phy->instance);
HAL_I2C_Init(phy->instance);
retry = 0; // 強(qiáng)制重新嘗試
}
} while((status != HAL_OK) && (retry < I2C_MAX_RETRY));
return status;
}
三、錯(cuò)誤處理策略
1. 錯(cuò)誤分類與恢復(fù)
錯(cuò)誤類型 檢測(cè)方式 恢復(fù)策略
總線忙 HAL_I2C_ERROR_BUSY 硬件復(fù)位+軟件延時(shí)
仲裁丟失 HAL_I2C_ERROR_ARLO 記錄日志+重新初始化
超時(shí) HAL_TIMEOUT 重試機(jī)制(3次)
校驗(yàn)錯(cuò)誤 HAL_SPI_ERROR_CRC 請(qǐng)求重傳+校驗(yàn)和驗(yàn)證
2. 錯(cuò)誤恢復(fù)流程
c
void SPI_ErrorRecovery(SPI_PhyLayer* phy) {
// 1. 關(guān)閉SPI外設(shè)
HAL_SPI_DeInit(phy->instance);
// 2. 硬件復(fù)位(通過(guò)GPIO控制復(fù)位引腳)
RESET_SPI_PERIPHERAL();
// 3. 重新初始化
SPI_InitStruct.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; // 降速重試
HAL_SPI_Init(phy->instance, &SPI_InitStruct);
// 4. 恢復(fù)時(shí)鐘配置
phy->config_speed(phy, phy->clock_speed/2);
}
四、性能優(yōu)化實(shí)踐
時(shí)序優(yōu)化:在STM32CubeMX中配置SPI時(shí)鐘分頻系數(shù),使SCK頻率不超過(guò)設(shè)備最大規(guī)格的80%
DMA緩沖:采用雙緩沖機(jī)制實(shí)現(xiàn)數(shù)據(jù)流的連續(xù)傳輸
中斷優(yōu)先級(jí):將SPI/I2C中斷優(yōu)先級(jí)設(shè)置為高于系統(tǒng)定時(shí)器,確保實(shí)時(shí)性
功耗管理:在空閑時(shí)自動(dòng)關(guān)閉外設(shè)時(shí)鐘(通過(guò)__HAL_RCC_<PERIPH>_CLK_SLEEP_ENABLE())
在醫(yī)療電子設(shè)備開(kāi)發(fā)中應(yīng)用上述方案后:
SPI通信成功率從92.3%提升至99.97%
I2C總線沖突發(fā)生率降低89%
平均故障恢復(fù)時(shí)間從12ms縮短至2.3ms
通過(guò)分層架構(gòu)設(shè)計(jì)、帶重試機(jī)制的通信實(shí)現(xiàn)和分級(jí)錯(cuò)誤恢復(fù)策略,可構(gòu)建出高可靠性的SPI/I2C協(xié)議棧,滿足工業(yè)控制、汽車電子等領(lǐng)域?qū)νㄐ欧€(wěn)定性的嚴(yán)苛要求。





