LPC1768/1769之CAN控制器概述(附庫函數(shù)下載地址)
一、背景:使用LPC1769來做CAN的收發(fā),在此對使用LPC1769的CAN控制器進(jìn)行收發(fā)做個(gè)總結(jié)和記錄,以備下次開發(fā)快速上手使用。附:LPC1768/1769除了支持最高頻率不同以外,其它基本上一致。二、正文:先貼一張LPC1769CAN控制器的方框圖:
.
由上圖可見,整個(gè)CAN控制器一頭是CPU,另一頭是CAN收發(fā)器: CAN收發(fā)器負(fù)責(zé)CAN數(shù)據(jù)與CAN網(wǎng)絡(luò)的通信。CAN內(nèi)核模塊解析和封裝要發(fā)送到CAN收發(fā)器以及從CAN 收發(fā)器發(fā)過來的數(shù)據(jù),此處CAN內(nèi)核工作由硬件自行完成?! PU通過APB總線即可設(shè)置CAN控制器狀態(tài),以及讀取中斷信息和中斷狀態(tài)?! ∫还灿?個(gè)發(fā)送緩沖器(郵箱),這樣就可以保證,最少可以發(fā)送3組并發(fā)的CAN數(shù)據(jù);2個(gè)接收緩沖 器(郵箱),這樣就可以在CPU處理1個(gè)郵箱的接收數(shù)據(jù)的同時(shí),還能用另一個(gè)郵箱接收網(wǎng)絡(luò)上的數(shù)據(jù)?! PC1769CAN的驗(yàn)收濾波器比較特殊,它是一個(gè)獨(dú)立于CAN控制器的器件,也屬于一種外設(shè),不過 比較特殊的是,它是服務(wù)于CAN控制器的外設(shè),這么做的意義就在于,驗(yàn)收濾波這方面,不再需要軟件來 來做任何事情,直接由硬件來實(shí)現(xiàn)查表算法,節(jié)省寶貴的CPU資源,由于它也算是一個(gè)獨(dú)立的外設(shè),運(yùn)用 起來也比較復(fù)雜,而本篇篇幅有限,暫不詳述,下次再另開篇博客來說?! ≈链耍琇PC1769CAN的結(jié)構(gòu)就介紹完畢,接下說明,做哪些事情可讓其開始正確收發(fā)CAN數(shù)據(jù)。
CAN1/2使用以下寄存器進(jìn)行設(shè)置:a)電源使能:在PCONP寄存器中,設(shè)置PCAN1/2。注:復(fù)位時(shí),CAN1/2會被使能(PCAN1/2=0)。b)時(shí)鐘使能:在PCLK_SEL0寄存器中選擇PCLK_CAN1/2和驗(yàn)收濾波器的PCLK_ACF。注:如果所需使用的CAN波特率必須高于100kbit/s(參見表16.12),那么就不能選擇IRC 作為時(shí)鐘源。c)喚醒:CAN控制器能夠?qū)⑽⒖刂破鲝牡綦娔J絾拘?。d)引腳:通過PINSEL寄存器選擇CAN1/2引腳,并通過PINMODE寄存器選擇引腳模式。e)中斷:CAN中斷是通過CAN1/2IER寄存器來使能的。中斷的使能是通過在NIVC中使用相應(yīng)的中斷設(shè)置使能寄存器(InterruptSetEnableregister)來實(shí)現(xiàn)的。f)CAN控制器初始化:在CANNOD寄存器中設(shè)置。以上為數(shù)據(jù)手冊介紹的CAN控制器初始化過程,白話點(diǎn)說:"a)"CAN是LPC1769的外設(shè)器件,要讓其工作,首先要設(shè)置PCONP,該寄存器的各個(gè)位來決定外設(shè)的時(shí)鐘是否打開或關(guān)閉,若某個(gè)外設(shè)不被使用,則關(guān)閉它,以達(dá)到節(jié)省功耗的目的;此處要需 要使用CAN,所以先打開CAN的外設(shè)時(shí)鐘。"b)"其次,外設(shè)若要正常工作,則均需要一個(gè)合適的時(shí)鐘頻率,通PCLK_SEL0l來決定CAN的外設(shè)時(shí)鐘來源,以及大小。"c)"為了進(jìn)一步減少M(fèi)CU的功耗,當(dāng)CAN網(wǎng)絡(luò)上沒有數(shù)據(jù)傳輸時(shí),也沒有CAN中斷在處理,并且對應(yīng) 的睡眠位被置“1”,CAN外設(shè)會進(jìn)入睡眠狀態(tài),若CAN總線上出現(xiàn)了顯性位,則CAN外設(shè)從睡眠 狀態(tài)被喚醒。同時(shí),若已配置了相關(guān)位,且此時(shí)整個(gè)MCU都進(jìn)入掉電或者深度睡眠模式,則CAN 也可將MCU喚醒"d)"配置CAN的收發(fā)引腳,無需多言,告訴CAN控制器,從哪個(gè)引腳收發(fā)CAN數(shù)據(jù)。"e)"配置CAN的各種中斷使能條件,此處使能了發(fā)送/接收中斷,錯(cuò)誤中斷;以及配置NVIC內(nèi)CAN外設(shè)中斷。"f)"配置CAN相關(guān)的參數(shù),譬如波特率等等。至此,CAN控制器初始化部分完成,還需要做接收和發(fā)送函數(shù),以及中斷函數(shù),來實(shí)現(xiàn)CAN的收發(fā),和錯(cuò)誤管理。當(dāng)然,在CAN控制器初始化部分,波特率的參數(shù)設(shè)置還有許多要說,本篇篇幅有限,暫不詳述,下次再開篇博客進(jìn)行介紹。CAN中斷函數(shù):/*-----------------INTERRUPTSERVICEROUTINES--------------------------*//*********************************************************************//***@briefCAN_IRQHandler,controlreceivemessageoperation*param[in]none*@returnnone**********************************************************************/voidCAN_IRQHandler(){uint8_tIntStatus;uint32_tdata1;/*getinterruptstatus*Notethat:InterruptregisterCANICRwillberesetafterread.*Sofunction"CAN_IntGetStatus"shouldbecallonlyonetime*///以下函數(shù)獲取的是CAN1ICR/CAN2ICR的寄存器數(shù)據(jù),該寄存器指明了中斷來源IntStatus=CAN_IntGetStatus(LPC_CAN1);if((IntStatus>>0)&0x01){//接收中斷}...//省略的內(nèi)容為,根據(jù)寄存器的各位的中斷來源數(shù)據(jù)來解析中斷信息?! ?/IntStatus=CAN_IntGetStatus(LPC_CAN2); //if(...)...}CAN接收函數(shù):此函數(shù)為NXP提供的庫函數(shù),庫函數(shù)下載鏈接在本文第三部分,該函數(shù)做的內(nèi)容無非就是,在中斷內(nèi),檢查兩個(gè)接收郵箱內(nèi)是否有信息,若有,則將信息提取。/********************************************************************//***@briefReceivemessagedata*@param[in]CANxpointertoLPC_CAN_TypeDef,shouldbe:*-LPC_CAN1:CAN1peripheral*-LPC_CAN2:CAN2peripheral*@param[in]CAN_MsgpointtotheCAN_MSG_TypeStruct,itwillcontainreceived*messageinformationsuchas:ID,DLC,RTR,IDFormat*@returnStatus:*-SUCCESS:receivemessagesuccessfully*-ERROR:receivemessageunsuccessfully*********************************************************************/StatusCAN_ReceiveMsg(LPC_CAN_TypeDef*CANx,CAN_MSG_Type*CAN_Msg){uint32_tdata;CHECK_PARAM(PARAM_CANx(CANx));//checkstatusofReceiveBufferif((CANx->SR&0x00000001)){/*Receivemessageisavailable*//*Readframeinformations*/CAN_Msg->format=(uint8_t)(((CANx->RFS)&0x80000000)>>31);CAN_Msg->type=(uint8_t)(((CANx->RFS)&0x40000000)>>30);CAN_Msg->len=(uint8_t)(((CANx->RFS)&0x000F0000)>>16);/*ReadCANmessageidentifier*/CAN_Msg->id=CANx->RID;/*ReadthedataifreceivedmessagewasDATAFRAME*/if(CAN_Msg->type==DATA_FRAME){/*Readfirst4databytes*/data=CANx->RDA;*((uint8_t*)&CAN_Msg->dataA[0])=data&0x000000FF;*((uint8_t*)&CAN_Msg->dataA[1])=(data&0x0000FF00)>>8;;*((uint8_t*)&CAN_Msg->dataA[2])=(data&0x00FF0000)>>16;*((uint8_t*)&CAN_Msg->dataA[3])=(data&0xFF000000)>>24;/*Readsecond4databytes*/data=CANx->RDB;*((uint8_t*)&CAN_Msg->dataB[0])=data&0x000000FF;*((uint8_t*)&CAN_Msg->dataB[1])=(data&0x0000FF00)>>8;*((uint8_t*)&CAN_Msg->dataB[2])=(data&0x00FF0000)>>16;*((uint8_t*)&CAN_Msg->dataB[3])=(data&0xFF000000)>>24;/*releasereceivebuffer*/CANx->CMR=0x04;}else{/*ReceivedFrameisaRemoteFrame,nothavedata,wejustreceive*messageinformationonly*/CANx->CMR=0x04;/*releasereceivebuffer*/returnSUCCESS;}}else{//noreceivemessageavailablereturnERROR;}returnSUCCESS;}CAN發(fā)送函數(shù):該函數(shù)還是庫函數(shù),即依次查詢3個(gè)發(fā)送郵箱的狀態(tài),若郵箱狀態(tài)為空,則將數(shù)據(jù)填充到該郵箱并置位發(fā)送標(biāo)志,然后由CAN內(nèi)核模塊硬件自動(dòng)發(fā)送。發(fā)送的優(yōu)先級在寄存器內(nèi)均可配置,不詳述。篇幅不想過長,因此查詢郵箱2/3代碼部分省略。/********************************************************************//***@briefSendmessagedata*@param[in]CANxpointertoLPC_CAN_TypeDef,shouldbe:*-LPC_CAN1:CAN1peripheral*-LPC_CAN2:CAN2peripheral*@param[in]CAN_MsgpointtotheCAN_MSG_TypeStructure,itcontainsmessage*informationsuchas:ID,DLC,RTR,IDFormat*@returnStatus:*-SUCCESS:sendmessagesuccessfully*-ERROR:sendmessageunsuccessfully*********************************************************************/StatusCAN_SendMsg(LPC_CAN_TypeDef*CANx,CAN_MSG_Type*CAN_Msg){uint32_tdata;CHECK_PARAM(PARAM_CANx(CANx));CHECK_PARAM(PARAM_ID_FORMAT(CAN_Msg->format));if(CAN_Msg->format==STD_ID_FORMAT){CHECK_PARAM(PARAM_ID_11(CAN_Msg->id));}else{CHECK_PARAM(PARAM_ID_29(CAN_Msg->id));}CHECK_PARAM(PARAM_DLC(CAN_Msg->len));CHECK_PARAM(PARAM_FRAME_TYPE(CAN_Msg->type));//CheckstatusofTransmitBuffer1if(CANx->SR&(1<<2)){/*TransmitChannel1isavailable*//*WriteframeinformationsandframedataintoitsCANxTFI1,*CANxTID1,CANxTDA1,CANxTDB1register*/CANx->TFI1&=~0x000F0000;CANx->TFI1|=(CAN_Msg->len)<<16;if(CAN_Msg->type==REMOTE_FRAME){CANx->TFI1|=(1<<30);//setbitRTR}else{CANx->TFI1&=~(1<<30);}if(CAN_Msg->format==EXT_ID_FORMAT){CANx->TFI1|=(0x80000000);//setbitFF}else{CANx->TFI1&=~(0x80000000);}/*WriteCANID*/CANx->TID1=CAN_Msg->id;/*Writefirst4databytes*/data=(CAN_Msg->dataA[0])|(((CAN_Msg->dataA[1]))<<8)| ((CAN_Msg->dataA[2])<<16)|((CAN_Msg->dataA[3])<<24);CANx->TDA1=data;/*Writesecond4databytes*/data=(CAN_Msg->dataB[0])|(((CAN_Msg->dataB[1]))<<8)| ((CAN_Msg->dataB[2])<<16)|((CAN_Msg->dataB[3])<<24);CANx->TDB1=data;/*Writetransmissionrequest*///注意該值,置位發(fā)送郵箱1,告知硬件,郵箱1的信息已經(jīng)填充完畢可發(fā)送。CANx->CMR=0x21;returnSUCCESS;}//checkstatusofTransmitBuffer2elseif(CANx->SR&(1<<10)){/*TransmitChannel2isavailable*//*WriteframeinformationsandframedataintoitsCANxTFI2,*CANxTID2,CANxTDA2,CANxTDB2register*/.../*Writetransmissionrequest*///注意該值,置位發(fā)送郵箱2,告知硬件,郵箱2的信息已經(jīng)填充完畢可發(fā)送。CANx->CMR=0x41;returnSUCCESS;}//checkstatusofTransmitBuffer3elseif(CANx->SR&(1<<18)){/*TransmitChannel3isavailable*//*WriteframeinformationsandframedataintoitsCANxTFI3,*CANxTID3,CANxTDA3,CANxTDB3register*/.../*Writetransmissionrequest*///注意該值,置位發(fā)送郵箱3,告知硬件,郵箱3的信息已經(jīng)填充完畢可發(fā)送。CANx->CMR=0x81;returnSUCCESS;}else{//所有郵箱都處于非空閑狀態(tài),無法發(fā)送returnERROR;}}至此,有了初始化部分,CAN中斷函數(shù),CAN發(fā)送、接收函數(shù),也就實(shí)現(xiàn)了CAN數(shù)據(jù)的收發(fā)。濾波以波特率以及CAN總線錯(cuò)誤處理,下次再開博客詳述。三、參考文檔LPC175x_6xCMSIS-CompliantStandardPeripheralFirmwareDriverLibrary(Keil,IAR,GNU) https://www.lpcware.com/content/nxpfile/lpc175x6x-cmsis-compliant-standard-peripheral-firmware-driver-library-keil-iar-gnu至此,記錄完畢。