一.前言:
通信模塊可以大致分為三大功能:數據發送功能,數據接收功能,狀態切換和管理功能。
我們的系列按照這樣的功能排序和自底向上的模塊排序,每次只介紹其中的一個模塊的其中一個功能的實現,所以在每篇文章中對于模塊不會事無巨細的介紹所有它所具備的功能,而是選擇性的介紹三大功能中的其中一個。BSW往上的所有模塊示例,為最大程度了解其設計思路以及避免侵權風險,將會采用遵循AUTOSAR架構的非商業代碼作為示例,其部分細節不保證完全遵循AUTOSAR最新的標準,不保證所有功能的具備,敬請理解。
二.Canif模塊及其發送函數CanIf_Transmit
在上節的文章中介紹了CAN模塊的發送底層邏輯,Can_Write函數的介紹。Can_Write函數已經對CAN驅動進行了抽象。抽象為了HOH供上層使用。而它的上層就是CanIf層.在CanIf模塊中,主要實現的功能如下:
1.傳輸請求(Transmit request)
傳輸請求功能的實現主體函數是CanIf_Transmit,這個函數內部調用Can_Write進行報文的發送
2.傳輸確認(Transmit confirmation)
傳輸確認功能的實現主體函數是CanIf_TxConfirmation,這個函數在CAN發送完成后被調用,作用是調用更上層的發送確認回調函數通知更上層的各個模塊對應的PDU已發送成功。
3.接收提示(Reception indication)
傳輸確認功能的實現主體函數是CanIf_RxIndication,這個函數在CAN發送完成后被調用,作用是調用更上層的發送確認回調函數通知更上層的各個模塊對應的PDU已發送成功。
4.CAN控制器模式切換(Controller mode control)
controller模式切換的功能實現主體函數是CanIf_SetControllerMode,涉及到模式切換的功能后面專題詳解
5.PDU模式切換(PDU mode control)
PDU模式切換的功能實現主體函數是CanIf_SetPduMode,涉及到模式切換的功能后面專題詳解
整個CanIf模塊實現的基本函數如下:
本文側重介紹CanIf模塊的發送功能。CanIf的報文發送功能由CanIf_Transmit函數實現,此函數原型如下:
Std_ReturnType CanIf_Transmit(PduIdType CanTxPduId,
const PduInfoType *PduInfoPtr)
此函數會調用MCAL的Can模塊中的Can_Write函數進行報文的發送。在上節介紹Can_Write函數的時候,說過其傳入的參數是以下:
- HOH
- CAN id:報文ID
- length:報文長度
- sdu:報文數據
- swPduHandle :tx_confirm的ID
而CanIf層的傳入參數變為了:
- CanTxPduId,
- PduInfoPtr這個參數包括了SduDataPtr和SduLength
所以CanTxPduId對Can_Write函數所需的HOH,CAN ID,swPduHandle做了抽象。我們基本也可以推斷出CanIf的TxPDU所需要配置的主要內容了。
三.Canif模塊的發送配置解析
以下例子用于說明CanIf層的tx配置。
Canif涉及到發送報文的主要配置結構體如下:
const CanIf_InitConfigType CanIfInitConfig =
{
.CanIfConfigSet = 0,
.CanIfNumberOfCanRxPduIds = sizeof(CanIfRxPduConfigData)/sizeof(CanIf_RxPduConfigType),
.CanIfNumberOfCanTXPduIds = sizeof(CanIfTxPduConfigData)/sizeof(CanIf_TxPduConfigType),
.CanIfNumberOfDynamicCanTXPduIds = 0,
// Containers
.CanIfHohConfigPtr = CanIfHohConfigData,
.CanIfRxPduConfigPtr = CanIfRxPduConfigData,
.CanIfTxPduConfigPtr = CanIfTxPduConfigData,
};
我們以下主要關注:
1.HOH的配置結構體CanIfHohConfigData,
2.發送PDU配置結構體CanIfTxPduConfigData
1.HOH的配置結構體CanIfHohConfigData,
對于HOH的配置結構體CanIfHohConfigData的結構如下:
const CanIf_InitHohConfigType CanIfHohConfigData[] = {
{
#if(CANIF_CONTROL_CAN_DRIVER ==STD_ON)
.CanConfigSet = &CanConfigSetData,
#endif
.CanIfHrhConfig = CanIfHrhConfigData_Hoh_1,
.CanIfHthConfig = CanIfHthConfigData_Hoh_1,
},
};
其中配置了發送的HTH和接收的HRH。對于發送的HTH配置如下:
const CanIf_HthConfigType CanIfHthConfigData_Hoh_1[] =
{
{
.CanIfHthType = CAN_BASIC,
.CanIfCanControllerIdRef = CANIF_Channel_1,
.CanIfHthIdSymRef = HOH_3_UDSTX_Node,
},
{
.CanIfHthType = CAN_BASIC,
.CanIfCanControllerIdRef = CANIF_Channel_1,
.CanIfHthIdSymRef = HOH_3_NMTX_Node,
},
{
.CanIfHthType = CAN_BASIC,
.CanIfCanControllerIdRef = CANIF_Channel_1,
.CanIfHthIdSymRef = HOH_3_XCPTX_Node,
},
{
.CanIfHthType = CAN_BASIC,
.CanIfCanControllerIdRef = CANIF_Channel_1,
.CanIfHthIdSymRef = HOH_3_EcuTestNode_CanCluster,
},
};
主要就是引用了上節文章例子中介紹的CAN模塊配置的四個HOH。
2.發送PDU配置結構體數組CanIfTxPduConfigData
這個結構體數組有所有的發送PDU配置,每個PDU都是一個結構體成員,其中的一個成員配置示例如下:
const CanIf_TxPduConfigType CanIfTxPduConfigData[] = {
{
.CanIfTxConfrimPduId = CANTP_PDU_ID_UDS_PHYS_TX,
.CanIfCanTxPduIdCanId = 0x7ea,
.CanIfCanTxPduIdDlc = 8,
.CanIfCanTxPduType = CANIF_PDU_TYPE_STATIC,
#if ( CANIF_READTXPDU_NOTIFY_STATUS_API == STD_ON )
.CanIfReadTxPduNotifyStatus = false,
#endif
.CanIfTxPduIdCanIdType = CANIF_CAN_ID_TYPE_11,
.CanIfUserTxConfirmation = CanTp_TxConfirmation,
.CanIfCanTxPduHthRef = &CanIfHthConfigData_Hoh_1[0],
.PduIdRef = NULL,
},
.....
}
關鍵的參數解釋如下:
- CanIfTxConfrimPduId :用于為swPduHandle 復值,向對應的TxConfirm函數傳入參數。
- CanIfCanTxPduIdCanId:對應PDU的報文ID
- CanIfCanTxPduIdDlc:對應PDU的報文長度
- CanIfUserTxConfirmation:發送確認回調函數
- CanIfCanTxPduHthRef:發送此PDU要使用的HOH
類似上節的結尾說到的抽象。這些配置元素打包成一個結構體數組元素,
CanIf_Transmit需要傳入的CanTxPduId,即代表這個配置結構體數組的數組下標。用來索引到其抽象的對象屬性。說起來比較枯燥,以下是CanIf_Transmit的實現函數:
Std_ReturnType CanIf_Transmit(PduIdType CanTxPduId,
const PduInfoType *PduInfoPtr)
{
Can_PduType canPdu;
const CanIf_TxPduConfigType *txEntry;
CanIf_ControllerModeType csMode;
CanIf_ChannelGetModeType pduMode;
VALIDATE(CanIf_Global.initRun, CANIF_TRANSMIT_ID, CANIF_E_UNINIT );
VALIDATE((PduInfoPtr != 0), CANIF_TRANSMIT_ID, CANIF_E_PARAM_POINTER );
// Get the controller from L-PDU handle
txEntry = CanIf_FindTxPduEntry(CanTxPduId);
if (txEntry == 0)
{
VALIDATE(FALSE, CANIF_TRANSMIT_ID, CANIF_E_INVALID_TXPDUID);
return E_NOT_OK;
}
CanIf_Arc_ChannelIdType channel = txEntry- >CanIfCanTxPduHthRef- >CanIfCanControllerIdRef;
// Get and verify the controller mode
if (CanIf_GetControllerMode(channel, &csMode) == E_NOT_OK){
return E_NOT_OK;
}
if (csMode != CANIF_CS_STARTED){ // CANIF_161
return E_NOT_OK;
}
// Get and verify the PDU channel mode control
if (CanIf_GetPduMode(channel, &pduMode) == E_NOT_OK){
return E_NOT_OK;
}
if ((pduMode != CANIF_GET_TX_ONLINE) && (pduMode != CANIF_GET_ONLINE)){
return E_NOT_OK;
}
canPdu.id = txEntry- >CanIfCanTxPduIdCanId;
canPdu.length = PduInfoPtr- >SduLength;
canPdu.sdu = PduInfoPtr- >SduDataPtr;
canPdu.swPduHandle = CanTxPduId;
Can_ReturnType rVal = Can_Write(txEntry- >CanIfCanTxPduHthRef- >CanIfHthIdSymRef, &canPdu);
if (rVal == CAN_NOT_OK){
return E_NOT_OK;
}
if (rVal == CAN_BUSY) // CANIF 082, CANIF 161
{
// Tx buffering not supported so just return.
return E_NOT_OK;
}
return E_OK;
}
注意到其中CanIf_Transmit的傳入參數CanTxPduId的使用方式:
txEntry = CanIf_FindTxPduEntry(CanTxPduId);
CanIf_FindTxPduEntry的函數原型如下
static const CanIf_TxPduConfigType * CanIf_FindTxPduEntry(PduIdType id)
{
if (id >= CanIf_ConfigPtr- >InitConfig- >CanIfNumberOfCanTXPduIds) {
return NULL;
} else {
return &CanIf_ConfigPtr- >InitConfig- >CanIfTxPduConfigPtr[id];
}
}
就是以CanIf_Transmit的傳入參數CanTxPduId為下標,找到對應的CanIfTxPduConfigData的數組成員。并獲取其屬性,對Can_Write函數的傳入參數進行配置。調用Can_Write函數進行發送。
四.發送確認函數:CanIf_TxConfirmation
CanIf_TxConfirmation是由Can模塊底層驅動在PDU傳輸完成后調用的。之前講到Can_Write函數的其中一個傳入參數:swPduHandle是用來在底層標記傳輸的PDU ID,在更新MessageBuffer前記住PDU對應的swPduHandle參數,在對應的PDU發出去后,底層驅動函數調用CanIf_TxConfirmation傳入swPduHandle。
而我們的CanIf_TxConfirmation實現如下:
void CanIf_TxConfirmation(PduIdType canTxPduId)
{
VALIDATE_NO_RV(CanIf_Global.initRun, CANIF_TXCONFIRMATION_ID, CANIF_E_UNINIT)
VALIDATE_NO_RV(canTxPduId < CanIf_ConfigPtr- >InitConfig- >CanIfNumberOfCanTXPduIds, CANIF_TXCONFIRMATION_ID, CANIF_E_PARAM_LPDU);
const CanIf_TxPduConfigType* entry =
&CanIf_ConfigPtr- >InitConfig- >CanIfTxPduConfigPtr[canTxPduId];
if (entry- >CanIfUserTxConfirmation != NULL)
{
CanIf_ChannelGetModeType mode;
CanIf_GetPduMode(entry- >CanIfCanTxPduHthRef- >CanIfCanControllerIdRef, &mode);
if ((mode == CANIF_GET_TX_ONLINE) || (mode == CANIF_GET_ONLINE)
|| (mode == CANIF_GET_OFFLINE_ACTIVE) || (mode == CANIF_GET_OFFLINE_ACTIVE_RX_ONLINE) )
{
entry- >CanIfUserTxConfirmation(entry- >CanIfTxPduId); /* CANIF053 */
}
}
return;
}
在這個函數中,會直接向上文CanIfTxPduConfigData配置的CanIfUserTxConfirmation中傳入swPduHandle。
而在CanIf_Transmit中,swPduHandle又是由CanIfTxPduConfigData配置的CanIfTxConfrimPduId決定的。所以CanIfTxConfrimPduId會作為參數傳入對應的CanIfUserTxConfirmation。
這期的介紹就到這,本期介紹了CanIf主要實現的功能,主要函數,主要的發送配置以及CanIf_Transmit,CanIf_TxConfirmation的機制,可以了解CanIf做了更進一步的抽象,將HOH進一步抽象為了PDU。各個AUTOSAR架構的代碼實現并不一致,文中所有的函數實現和配置思路僅作參考。
-
CAN通信
+關注
關注
5文章
94瀏覽量
17943 -
接收機
+關注
關注
8文章
1184瀏覽量
53637 -
AUTOSAR
+關注
關注
10文章
363瀏覽量
21781 -
PDU
+關注
關注
0文章
94瀏覽量
17033 -
CAN控制器
+關注
關注
3文章
74瀏覽量
15103
發布評論請先 登錄
相關推薦
cubemx配置的串口中斷發送HAL_UART_Transmit_IT不行
請問怎么用HAL_UART_Transmit發送數值型數據?
AUTOSAR_MCAL_CAN_IM.pdf提示找不到 config/CanIf.xdm怎么解決?
在EB tresos 23.0.0中配置模塊時出錯怎么解決?
Verilog實現UART之二:發送模塊
![Verilog實現UART之二:<b class='flag-5'>發送</b>模塊](https://file1.elecfans.com//web2/M00/A6/A9/wKgZomUMP3OAMVeQAAAlTzlfAkk497.jpg)
發送隊列長度功率控制
![<b class='flag-5'>發送</b>隊列長度功率控制](https://file.elecfans.com/web1/M00/4B/0A/pIYBAFqws7OAYbg7AABevkBquJA864.jpg)
如何讓接收端知道發送端將要發送的字節流長度?
![如何讓接收端知道<b class='flag-5'>發送</b>端將要<b class='flag-5'>發送</b>的字節流長度?](https://file.elecfans.com/web2/M00/63/55/pYYBAGL-5cuAOVptAACt-k3cEww678.png)
基于CAN總線進行網絡管理與Transceiver的關系梳理
![基于CAN總線進行網絡管理與Transceiver的關系梳理](https://file.elecfans.com/web2/M00/63/A9/poYBAGMERuWAbOKhAACdNB6kSzo352.png)
AUTOSAR通信之CanIf模塊簡介1
![AUTOSAR通信之<b class='flag-5'>CanIf</b>模塊簡介1](https://file.elecfans.com/web2/M00/90/DC/pYYBAGPp2ACALdC4AACrynUDXMU100.jpg)
AUTOSAR通信之CanIf模塊簡介2
![AUTOSAR通信之<b class='flag-5'>CanIf</b>模塊簡介2](https://file.elecfans.com/web2/M00/90/DC/pYYBAGPp2ACAG_qfAAEC7bYxm3A803.jpg)
AUTOSAR通信之CanIf模塊簡介3
![AUTOSAR通信之<b class='flag-5'>CanIf</b>模塊簡介3](https://file.elecfans.com/web2/M00/90/DC/pYYBAGPp2ACALlivAAEA_avR2lM454.jpg)
EthIf模塊的主要作用是什么?Ethif的常見函數接口有哪些呢?
云途正式發布量產版本AUTOSAR MCAL驅動軟件和配置工具
![云途正式發布量產版本AUTOSAR MCAL驅動軟件和<b class='flag-5'>配置</b>工具](https://file1.elecfans.com/web2/M00/8D/2D/wKgZomS3kUmAVPtcAAA43pztL7g942.png)
評論