動(dòng)-SPI-MCP2515 寫函數(shù)(收發(fā)操作))
Linux驅(qū)動(dòng)-SPI-MCP2515 寫函數(shù)收發(fā)操作文章目錄前言一、參考文檔二、使用手冊(cè)分析發(fā)送緩沖器-寄存器SRAM 理解流程步驟分析操作的寄存器分析梳理1、設(shè)置緩沖器優(yōu)先級(jí)2、從用戶空間復(fù)制數(shù)據(jù)到內(nèi)核緩沖區(qū)3、發(fā)送緩沖器數(shù)據(jù)到內(nèi)核4、啟動(dòng)發(fā)送5、驗(yàn)證是否發(fā)送成功-等待發(fā)送完畢6、清除發(fā)送完成標(biāo)志7、完整發(fā)送代碼如下總結(jié)前言在上個(gè)學(xué)習(xí)內(nèi)容Linux-SPI-位修改指令-屏蔽字節(jié)-修改CANINE寄存器的值-修改工作模式中對(duì) mcp2515 的工作模式進(jìn)行了修改 從配置模式修改為了環(huán)回模式 而這里學(xué)習(xí)將會(huì)繼續(xù)對(duì) mcp2515 的驅(qū)動(dòng)程序進(jìn)行完善 加入 mcp2515 的寫函數(shù)和讀函數(shù) 從而實(shí)現(xiàn)數(shù)據(jù)的發(fā)送和接收這里寫函數(shù)是什么呢 其實(shí)就是文件系統(tǒng)操作里面對(duì)外開放的接口那對(duì)外釋放的接口我們這里實(shí)驗(yàn)最終要做什么呢 暫且拋開CAN功能我們利用SPI協(xié)議對(duì)CAN 進(jìn)行收發(fā)操作 這里的發(fā)就是發(fā)給CAN。那為什么要進(jìn)行收發(fā)操作呢其實(shí)就是模擬收發(fā)數(shù)據(jù)操作不用借助CAN 輸出。為什么切換到回環(huán)模式回環(huán)才能收發(fā)呀。一、參考文檔RK3568驅(qū)動(dòng)指南第十六篇 SPI-第192章 mcp2515驅(qū)動(dòng)編寫完善write和read函數(shù)二、使用手冊(cè)分析發(fā)送緩沖器-寄存器MCP2515 有三個(gè)發(fā)送緩沖器 每個(gè)發(fā)送緩沖器都具有 14 字節(jié)的內(nèi)存空間 每個(gè)發(fā)送緩沖器的控制由 TXBnCTRL 寄存器管理 該寄存器決定了何時(shí)發(fā)送報(bào)文以及發(fā)送時(shí)的報(bào)文狀態(tài)SRAM 理解SRAM靜態(tài)隨機(jī)存儲(chǔ)器Static?RAM就是芯片內(nèi)部一小塊高速內(nèi)存。SRAM 和寄存器是什么關(guān)系MCP2515 把內(nèi)部這一塊 SRAM映射成 SPI 可以訪問(wèn)的寄存器地址。你通過(guò) SPI 寫寄存器0x31~0x3DTXB0 緩沖區(qū)本質(zhì)就是在讀寫 MCP2515 內(nèi)部的 SRAMSRAM 和 Flash閃存區(qū)別非常關(guān)鍵類型SRAM (MCP2515 內(nèi)部?jī)?nèi)存)Flash (閃存)斷電斷電數(shù)據(jù)全部丟失斷電數(shù)據(jù)保留讀寫速度極快慢MCP2515 用途臨時(shí)存發(fā)送 / 接收 CAN 報(bào)文MCP2515沒(méi)有 Flash上電所有寄存器都是默認(rèn)值流程步驟分析直接看數(shù)據(jù)手冊(cè) 總體上其實(shí)有三個(gè)步驟的下面會(huì)具體分析的。操作的寄存器分析梳理1、設(shè)置緩沖器優(yōu)先級(jí)如圖分析寄存器所以實(shí)際我們需要如何寫這個(gè)邏輯呢#defineTXB0CTRL0x30//發(fā)送緩沖器控制寄存器地址mcp2515_change_regbit(TXB0CTRL,0x03,0x03);// MCP2515修改寄存器位函數(shù)voidmcp2515_change_regbit(charreg,charmask,charvalue){intret;charwrite_buf[]{0x05,reg,mask,value};// SPI寫緩沖區(qū)用于發(fā)送修改寄存器位命令retspi_write(spi_dev,write_buf,sizeof(write_buf));// 發(fā)送SPI寫命令if(ret0){printk(mcp2515_change_regbit error\n);}}2、從用戶空間復(fù)制數(shù)據(jù)到內(nèi)核緩沖區(qū)我們的發(fā)送操作是寫在write 方法里面作為對(duì)應(yīng)用端提供的接口操作的所以 具體方法如下獲取用戶空間數(shù)據(jù)到內(nèi)核// 寫設(shè)備操作函數(shù)ssize_tmcp2515_write(struct file*file,constchar__user*buf,size_t size,loff_t*offset){......intret;inti;// 設(shè)置TXB0CTRL寄存器的部分位mcp2515_change_regbit(TXB0CTRL,0x03,0x03);// 從用戶空間復(fù)制數(shù)據(jù)到內(nèi)核緩沖區(qū)retcopy_from_user(w_kbuf,buf,size);if(ret){printk(copy_from_user w_kbuf is error\n);return-1;}......returnsize;}3、發(fā)送緩沖器數(shù)據(jù)到內(nèi)核再看一下使用手冊(cè)里面的發(fā)送緩沖器要求就是說(shuō)還要繼續(xù)發(fā)送13 個(gè)字節(jié)數(shù)據(jù)出去發(fā)送字節(jié)數(shù)據(jù)出去其實(shí)就是要寫到寄存器里面去既然寫值那么一定要知道寄存器地址吧。所以還是先看看寄存器具體啥情況看地址分析發(fā)送緩沖器控制寄存器 TXBnCTRL 為發(fā)送緩沖器的第一個(gè)字節(jié) 接下來(lái)的 5 個(gè)字節(jié)用來(lái)裝載標(biāo)準(zhǔn)和擴(kuò)展標(biāo)識(shí)符以及其他報(bào)文仲裁信息。 最后的 8 個(gè)字節(jié)用于裝載等待發(fā)送報(bào)文的 8 個(gè)可能的數(shù)據(jù)字節(jié) 這 13 個(gè)字節(jié)數(shù)據(jù)由用戶空間所傳遞 且地址是連續(xù)的。也就是說(shuō)地址連續(xù)的那么寫寄存器地址就簡(jiǎn)單了。// 寫設(shè)備操作函數(shù)ssize_tmcp2515_write(struct file*file,constchar__user*buf,size_t size,loff_t*offset){charw_kbuf[13]{0};intret;inti;// 設(shè)置TXB0CTRL寄存器的部分位mcp2515_change_regbit(TXB0CTRL,0x03,0x03);// 從用戶空間復(fù)制數(shù)據(jù)到內(nèi)核緩沖區(qū)retcopy_from_user(w_kbuf,buf,size);if(ret){printk(copy_from_user w_kbuf is error\n);return-1;}// 將數(shù)據(jù)寫入MCP2515寄存器for(i0;isizeof(w_kbuf);i){mcp2515_write_reg(0x31i,w_kbuf[i]);}.....4、啟動(dòng)發(fā)送繼續(xù)看使用手冊(cè)繼續(xù)看寄存器所以 發(fā)送一次寄存器數(shù)據(jù)如下#defineTXB0CTRL0x30//發(fā)送緩沖器控制寄存器地址// 設(shè)置TXB0CTRL寄存器的部分位啟動(dòng)發(fā)送mcp2515_change_regbit(TXB0CTRL,0x08,0x08);//采用位發(fā)送數(shù)據(jù)到寄存器// MCP2515修改寄存器位函數(shù)voidmcp2515_change_regbit(charreg,charmask,charvalue){intret;charwrite_buf[]{0x05,reg,mask,value};// SPI寫緩沖區(qū)用于發(fā)送修改寄存器位命令retspi_write(spi_dev,write_buf,sizeof(write_buf));// 發(fā)送SPI寫命令if(ret0){printk(mcp2515_change_regbit error\n);}}5、驗(yàn)證是否發(fā)送成功-等待發(fā)送完畢繼續(xù)看操作使用手冊(cè)如下所以檢查寄存器CANINTF寄存器中TXnIF 位置是否為1 即可。繼續(xù)查看寄存器 CANINTF地址ox2C 判斷的TXnIF 是bit2所以檢查寄存器CANINTF 對(duì)應(yīng)的位是不是1如果是1 代表成功。#defineCANINTF0x2c// 等待發(fā)送完成while(!(mcp2515_read_reg(CANINTF)(12)));綜合代碼編寫如下// 寫設(shè)備操作函數(shù)ssize_tmcp2515_write(struct file*file,constchar__user*buf,size_t size,loff_t*offset){charw_kbuf[13]{0};intret;inti;// 設(shè)置TXB0CTRL寄存器的部分位mcp2515_change_regbit(TXB0CTRL,0x03,0x03);// 從用戶空間復(fù)制數(shù)據(jù)到內(nèi)核緩沖區(qū)retcopy_from_user(w_kbuf,buf,size);if(ret){printk(copy_from_user w_kbuf is error\n);return-1;}// 將數(shù)據(jù)寫入MCP2515寄存器for(i0;isizeof(w_kbuf);i){mcp2515_write_reg(0x31i,w_kbuf[i]);}// 設(shè)置TXB0CTRL寄存器的部分位啟動(dòng)發(fā)送mcp2515_change_regbit(TXB0CTRL,0x08,0x08);// 等待發(fā)送完成while(!(mcp2515_read_reg(CANINTF)(12)));......returnsize;}6、清除發(fā)送完成標(biāo)志為什么要進(jìn)行這步操作繼續(xù)看操作手冊(cè)如上的寄存器CANINTF也就是說(shuō)我已經(jīng)驗(yàn)證了啟動(dòng)發(fā)送報(bào)文成功了接下來(lái)就是要復(fù)位操作一次是MCU 清零所以需要MCU端 代碼實(shí)現(xiàn)而不是外設(shè)自動(dòng)復(fù)位。所以要個(gè)這個(gè)寄存器復(fù)位操作很簡(jiǎn)單了還是找寄存器地址、復(fù)位操作的值、屏蔽字節(jié)即可mcp2515_change_regbit(CANINTF,0x04,0x00);7、完整發(fā)送代碼如下// 寫設(shè)備操作函數(shù)ssize_tmcp2515_write(struct file*file,constchar__user*buf,size_t size,loff_t*offset){charw_kbuf[13]{0};intret;inti;// 設(shè)置TXB0CTRL寄存器的部分位mcp2515_change_regbit(TXB0CTRL,0x03,0x03);// 從用戶空間復(fù)制數(shù)據(jù)到內(nèi)核緩沖區(qū)retcopy_from_user(w_kbuf,buf,size);if(ret){printk(copy_from_user w_kbuf is error\n);return-1;}// 將數(shù)據(jù)寫入MCP2515寄存器for(i0;isizeof(w_kbuf);i){mcp2515_write_reg(0x31i,w_kbuf[i]);}// 設(shè)置TXB0CTRL寄存器的部分位啟動(dòng)發(fā)送mcp2515_change_regbit(TXB0CTRL,0x08,0x08);// 等待發(fā)送完成while(!(mcp2515_read_reg(CANINTF)(12)));// 清除發(fā)送完成標(biāo)志mcp2515_change_regbit(CANINTF,0x04,0x00);returnsize;}總結(jié)寫入操作是提供給外部的接口實(shí)際操作的是SPI向CAN 發(fā)的操作整個(gè)過(guò)程完全是根據(jù)操作手冊(cè)來(lái)的讀懂、理解、根據(jù)操作手冊(cè)進(jìn)行編程 、業(yè)務(wù)實(shí)現(xiàn) 需要自己學(xué)會(huì)看 看得懂才行。