0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

英創(chuàng)信息技術(shù)嵌入式系統(tǒng)設(shè)備驅(qū)動接口的C#編程

英創(chuàng)信息技術(shù) ? 來源:英創(chuàng)信息技術(shù) ? 作者:英創(chuàng)信息技術(shù) ? 2020-01-15 11:29 ? 次閱讀

英創(chuàng)ARM9系列嵌入式主板,均預(yù)裝了WinCE 5.0、WinCE 6.0操作系統(tǒng),用戶可使用標(biāo)準(zhǔn)的C/C++C#進(jìn)行應(yīng)用程序的開發(fā)。英創(chuàng)的嵌入式板卡一大特色就是提供了豐富的通訊接口,并實(shí)現(xiàn)了相應(yīng)的驅(qū)動程序,用戶只需直接調(diào)用相應(yīng)的接口函數(shù)即可實(shí)現(xiàn)。

在使用C#進(jìn)行應(yīng)用程序開發(fā)時,由于C#無法使用C++的靜態(tài)庫函數(shù),對于一些流式驅(qū)動設(shè)備,比如ISA,GPIO,WDT,CAN,SPI,IRQ等,沒有封裝好的庫函數(shù)可操作,如果希望控制它們,一種辦法是使用C編寫com組件,在com組件中調(diào)用英創(chuàng)提供的相應(yīng)主板SDK包里的靜態(tài)庫函數(shù);另一種方法是直接調(diào)用API函數(shù)來訪問設(shè)備驅(qū)動。

對于大多數(shù)的流式驅(qū)動設(shè)備,應(yīng)用程序使用的一般過程:
1、通過CreatFile打開設(shè)備,獲得設(shè)備句柄。
2、使用ReadFile讀取數(shù)據(jù),使用WriteFile發(fā)送數(shù)據(jù),以及使用DeviceIoControl對設(shè)備驅(qū)動進(jìn)行設(shè)置、讀寫等操作。
3、使用完畢,用CloseHandle關(guān)閉設(shè)備。

在一般情況下,設(shè)備的專用功能都是通過DeviceIoControl來實(shí)現(xiàn)的,因此如何通過C#編程來操作DeviceIoControl尤為重要。本文以英創(chuàng)ARM9嵌入式主板EM9170為例,介紹如何使用DeviceIoControl來操作主板的ISA接口進(jìn)行讀寫。GPIO,WDT,CAN,SPI,IRQ等其他流式設(shè)備的操作請參看英創(chuàng)開發(fā)光盤內(nèi)提供的相關(guān)例程。

1、DeviceIoControl函數(shù)的定義
在wince中核心庫為coredll.dll,相當(dāng)于window的kernel32.dll和user32.dll。要調(diào)用核心庫,首先需要在代碼中添加引用:

using System.Runtime.InteropServices;

在c#中DeviceIoControl及CreatFiles,CloseHandle函數(shù)聲明,及相關(guān)變量定義方法如下(該寫法并不固定)。

[DllImport('coredll.dll', EntryPoint = 'CreateFile', CharSet = CharSet.Unicode)]
private static extern int CreateFile(String lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
int lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes,
int hTemplateFile);

[DllImport('coredll.dll', EntryPoint = 'CloseHandle')]
private static extern int CloseHandle(int hObject);

[DllImport('coredll.dll', EntryPoint = 'DeviceIoControl')]
private static extern bool DeviceIoControl(int hDevice,
uint dwIoControlCode,
byte[] lpInBuf,
uint nInBufSize,
byte[] lpOutBuf,
uint nOutBufSize,
ref uint lpBytesReturned,
uint lpOverlapped);

DeviceIoControl函數(shù)參數(shù)分析:

參數(shù) 定義
hDevice 設(shè)備句柄
Handle類型
c#中可以對應(yīng)成int或uint或IntPtr
通過CreatFiles獲得
dwIoControlCode 驅(qū)動控制命令
DWORD類型
C#中可以對應(yīng)成int或uint
不同設(shè)備該值定義不同,根據(jù)該參數(shù)lpInBuffer,nInBufSize,lpOutBuf,nOutBufSize參數(shù)定義也不同,在c中,該值的宏定義為
#define CTL_CODE(DeviceType, Function, Method, Access) (
((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) )

根據(jù)DeviceType, Function, Method, Access轉(zhuǎn)換而來
在前面代碼中為英創(chuàng)嵌入式主板EM9170的ISA及GPIO的CTL_CODE值定義,比如GPIO輸出控制的CTL_CODE定義
private const uint GPIO_IOCTL_OUT_ENABLE = (FILE_DEVICE_BUS_EXTENDER << 16) | (FILE_ANY_ACCESS << 14) | ( 3900<< 2) | (METHOD_BUFFERED);
更多的dwIoControlCode值定義和輸入輸出參數(shù)定義請參看英創(chuàng)相關(guān)例程
lpInBuffer 輸入BUFFER
LPVOID類型
C#中可以對應(yīng)成byte[]或ref Struct等,也可以使用unsafe傳遞指針
應(yīng)用程序傳遞給驅(qū)動的數(shù)據(jù)指針
一般用byte[]的通用性好些,對于需要傳遞結(jié)構(gòu)體指針的地方,可以使用Marshal類的方法拷貝結(jié)構(gòu)體到byte數(shù)組內(nèi),或者直接根據(jù)struct成員值修改byte數(shù)組的相應(yīng)位
nInBufSize 輸入BUFFER長度
DWORD類型
如果DeviceIoControl操作無輸出BUFFER,一般lpInBuffer為null,nInBufSize為0
lpOutBuf 輸出BUFFER
LPVOID類型
nOutBufSize 輸入BUFFER長度
DWORD類型
lpBytesReturned 操作程序?qū)嶋H返回的字節(jié)數(shù)指針
LPDWORD類型
C#中一般對應(yīng)為ref uint
lpOverlapped 重疊操作結(jié)構(gòu)
沒有使用,定為uint傳0,或者IntPtr傳IntPtr.Zero

在C#調(diào)用外部dll時,可以用uint來對應(yīng)DWORD,用ref uint來對應(yīng)LPDWORD,用IntPtr來對應(yīng)各種指針,更通用的,可以直接使用byte[]來對應(yīng)各種指針。

2、DeviceIoControl函數(shù)的操作實(shí)例
以英創(chuàng)嵌入式主板EM9170的ISA操作為例,以下代碼包括了CreatFile需要的參數(shù)定義,ISA操作的IOCTL定義,和ISA的DeviceIoControl操作傳入?yún)?shù)結(jié)構(gòu)體的定義,和封裝DeviceIoControl的兩個ISA函數(shù)定義。

主函數(shù)操作程序打開ISA設(shè)備,并操作ISA輸出輸入,最后關(guān)閉設(shè)備。

private const uint GENERIC_READ = 0x80000000;
private const uint GENERIC_WRITE = 0x40000000;
private const uint FILE_SHARE_READ = 0x00000001;
private const uint FILE_SHARE_WRITE = 0x00000002;
private const int OPEN_EXISTING = 3;
private const int FILE_FLAG_RANDOM_ACCESS = 0x10000000;
//------------------------bsp_drivers----------------------------------
//winioctl
private const uint FILE_DEVICE_BUS_EXTENDER = 0x0000002a;
private const uint METHOD_BUFFERED = 0;
private const uint FILE_ANY_ACCESS = 0;
// ISA IO Control Codes
private const uint ISA_IOCTL_READ_WRITE = (FILE_DEVICE_BUS_EXTENDER << 16) | (FILE_ANY_ACCESS << 14) | (3910 << 2) | (METHOD_BUFFERED);
private const uint ISA_IOCTL_BUS_RESET = (FILE_DEVICE_BUS_EXTENDER << 16) | (FILE_ANY_ACCESS << 14) | (3911 << 2) | (METHOD_BUFFERED);
//------------------------bsp_drivers_end------------------------------
[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct ISA_BUS_ACCESS
{
[FieldOffset(0)]public uint dwCmd; // = 0: Read, = 1: Write
[FieldOffset(4)]public uint dwSeg; // = 0: ISA_CS0, = 1: ISA_CS1
[FieldOffset(8)]public uint dwOffset;
[FieldOffset(12)]public uint dwValue; // only lower byte valid
}
public static int OpenISA_DIO(String DevName)
{
int handle;
handle = CreateFile(DevName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, // sharing mode
0, // security attributes (ignored)
OPEN_EXISTING, // creation disposition
FILE_FLAG_RANDOM_ACCESS, // flags/attributes
0);
return handle;
}
public static bool CloseISA_DIO(int hISA_DIO)
{
if (hISA_DIO != 0)
{
if (CloseHandle(hISA_DIO) != 0)
{
return false;
}
}
return true;
}
public static bool ISA_Read(int hISA_DIO, int nSeg, uint nOffset, ref byte pRdValue)
{
ISA_BUS_ACCESS isabus;
uint lpBytesReturned = 0;
isabus.dwCmd = 0;
isabus.dwSeg = (uint)nSeg;
isabus.dwOffset = nOffset;
isabus.dwValue = 0;
int size = Marshal.SizeOf(typeof(ISA_BUS_ACCESS));
byte[] lpIntBuf = new byte[size];
IntPtr buffer = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(isabus, buffer, false);
Marshal.Copy(buffer, lpIntBuf, 0, size);
}
finally
{
Marshal.FreeHGlobal(buffer);
}
byte[] lpOutBuf = new byte[sizeof(byte)];
if (!DeviceIoControl(hISA_DIO, // file handle to the driver
ISA_IOCTL_READ_WRITE, // I/O control code
lpIntBuf, // in buffer
(uint)size, // in buffer size
lpOutBuf, // out buffer
sizeof(byte), // out buffer size
ref lpBytesReturned, // pointer to number of bytes returned
0)) // ignored (=NULL)
{
return false;
}
pRdValue = lpOutBuf[0];
return true;
}
public static bool ISA_Write(int hISA_DIO, int nSeg, uint nOffset, byte ucWrValue)
{
ISA_BUS_ACCESS isabus;
uint lpBytesReturned = 0;
isabus.dwCmd = 1;
isabus.dwSeg = (uint)nSeg;
isabus.dwOffset = nOffset;
isabus.dwValue = (uint)ucWrValue;
int size = Marshal.SizeOf(typeof(ISA_BUS_ACCESS));
byte[] lpIntBuf = new byte[size];
IntPtr buffer = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(isabus, buffer, false);
Marshal.Copy(buffer, lpIntBuf, 0, size);
}
finally
{
Marshal.FreeHGlobal(buffer);
}
if (!DeviceIoControl(hISA_DIO, // file handle to the driver
ISA_IOCTL_READ_WRITE, // I/O control code
lpIntBuf, // in buffer
(uint)size, // in buffer size
null, // out buffer
0, // out buffer size
ref lpBytesReturned, // pointer to number of bytes returned
0)) // ignored (=NULL)
{
return false;
}
return true;
}
static void Main(string[] args)
{
const int ISA_CS1 = 1;
int hISA;
hISA = OpenISA_DIO('ISA1:');
if( hISA == -1 )
{
Console.Write('Open ISA_DIO device fail!');
return;
}
bRet = ISA_Write(hISA, ISA_CS1, 0, b);
bRet = ISA_Read(hISA, ISA_CS1, 0, ref b);
CloseISA_DIO(hISA);
return;
}

3、傳遞結(jié)構(gòu)體的操作說明
該例程的ISA_Read,ISA_Write和函數(shù)中,DeviceIoControl的參數(shù)lpIntBuf需要傳遞一個結(jié)構(gòu)體指針,關(guān)于結(jié)構(gòu)體的操作需要按以下步驟。

所以首先需要定義一個和接口定義相同的結(jié)構(gòu)體,在C#中定義與C接口的結(jié)構(gòu)體需要使用StructLayout字段聲明結(jié)構(gòu)體的大小,和對齊規(guī)則。

在每個成員前面用FieldOffset字段設(shè)定該成員在結(jié)構(gòu)體中的偏移。

[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct ISA_BUS_ACCESS
{
[FieldOffset(0)]public uint dwCmd; // = 0: Read, = 1: Write
[FieldOffset(4)]public uint dwSeg; // = 0: ISA_CS0, = 1: ISA_CS1
[FieldOffset(8)]public uint dwOffset;
[FieldOffset(12)]public uint dwValue; // only lower byte valid
}

然后設(shè)定結(jié)構(gòu)體各成員值,將結(jié)構(gòu)體拷貝到byte[]中,在C#中將結(jié)構(gòu)體拷貝到byte數(shù)組需要使用Marshal類。

首先計算結(jié)構(gòu)體大小
int size = Marshal.SizeOf(typeof(ISA_BUS_ACCESS));

創(chuàng)建一個byte[]
byte[] lpIntBuf = new byte[size];

用AllocHGlobal申請一塊非托管空間,并獲得該空間的指針
IntPtr buffer = Marshal.AllocHGlobal(size);

然后用StructureToPtr將結(jié)構(gòu)體拷貝到指針位置,再用Copy將指針位置數(shù)據(jù)拷貝到byte數(shù)組。因?yàn)橹吧暾埩藘?nèi)存空間,使用try-finally確報用FreeHGlobal釋放空間

try
{
Marshal.StructureToPtr(isabus, buffer, false);
Marshal.Copy(buffer, lpIntBuf, 0, size);
}
finally
{
Marshal.FreeHGlobal(buffer);
}

以上操作包括空間申請與釋放,效率并不高,為提高效率,應(yīng)當(dāng)將結(jié)構(gòu)體成員變量值直接賦值到byte數(shù)組相應(yīng)位置,如:
ISA_BUS_ACCESS isabus;
isabus.dwCmd = 1;

修改為
lpIntBuf[3] = 1;

注意整數(shù)的低位在高地址。

4、英創(chuàng)EM9170其他使用DeviceIoControl操作的設(shè)備dwIoControlCode值定義


//------------------------bsp_drivers----------------------------------
//winioctl
private const uint FILE_DEVICE_BUS_EXTENDER = 0x0000002a;
private const uint METHOD_BUFFERED = 0;
private const uint FILE_ANY_ACCESS = 0;
// GPIO IO Control Codes
private const uint GPIO_IOCTL_OUT_ENABLE = (FILE_DEVICE_BUS_EXTENDER << 16) | (FILE_ANY_ACCESS << 14) | ( 3900<< 2) | (METHOD_BUFFERED);
private const uint GPIO_IOCTL_OUT_DISABLE = (FILE_DEVICE_BUS_EXTENDER << 16) | (FILE_ANY_ACCESS << 14) | (3901 << 2) | (METHOD_BUFFERED);
private const uint GPIO_IOCTL_OUT_SET = (FILE_DEVICE_BUS_EXTENDER << 16) | (FILE_ANY_ACCESS << 14) | (3902 << 2) | (METHOD_BUFFERED);
private const uint GPIO_IOCTL_OUT_CLEAR = (FILE_DEVICE_BUS_EXTENDER << 16) | (FILE_ANY_ACCESS << 14) | (3903 << 2) | (METHOD_BUFFERED);
private const uint GPIO_IOCTL_PIN_STATE = (FILE_DEVICE_BUS_EXTENDER << 16) | (FILE_ANY_ACCESS << 14) | (3904 << 2) | (METHOD_BUFFERED);
// ISA IO Control Codes
private const uint ISA_IOCTL_READ_WRITE = (FILE_DEVICE_BUS_EXTENDER << 16) | (FILE_ANY_ACCESS << 14) | (3910 << 2) | (METHOD_BUFFERED);
private const uint ISA_IOCTL_BUS_RESET = (FILE_DEVICE_BUS_EXTENDER << 16) | (FILE_ANY_ACCESS << 14) | (3911 << 2) | (METHOD_BUFFERED);
//private const uint ISA_IOCTL_REDA_CS1 = (FILE_DEVICE_BUS_EXTENDER << 16) | (FILE_ANY_ACCESS << 14) | (3912 << 2) | (METHOD_BUFFERED);
//private const uint ISA_IOCTL_WRITE_CS1 = (FILE_DEVICE_BUS_EXTENDER << 16) | (FILE_ANY_ACCESS << 14) | (3913 << 2) | (METHOD_BUFFERED);
// SPI IO Control Codes
private const uint CSPI_IOCTL_EXCHANGE = (FILE_DEVICE_BUS_EXTENDER << 16) | (FILE_ANY_ACCESS << 14) | (3030 << 2) | (METHOD_BUFFERED);
// IRQ IO Control Codes
private const uint IOCTL_WAIT_FOR_IRQ = (FILE_DEVICE_BUS_EXTENDER << 16) | (FILE_ANY_ACCESS << 14) | (3920 << 2) | (METHOD_BUFFERED);
private const uint IOCTL_SEND_EOI = (FILE_DEVICE_BUS_EXTENDER << 16) | (FILE_ANY_ACCESS << 14) | (3921 << 2) | (METHOD_BUFFERED);
//------------------------bsp_drivers_end------------------------------

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 嵌入式主板
    +關(guān)注

    關(guān)注

    7

    文章

    6085

    瀏覽量

    35344
收藏 人收藏

    評論

    相關(guān)推薦

    新手怎么學(xué)嵌入式?

    基本的概念。嵌入式系統(tǒng)是一種將計算機(jī)技術(shù)嵌入到特定設(shè)備中的系統(tǒng),它通常具有特定的功能和有限的資源
    發(fā)表于 12-12 10:51

    嵌入式C編程常用的異常錯誤處理

    嵌入式C編程中,異常錯誤處理是確保系統(tǒng)穩(wěn)定性和可靠性的重要部分。以下是一些常見的異常錯誤處理方法及其詳細(xì)說明和示例: 1. 斷言 (Assertions) 斷言用于在開發(fā)階段捕獲程
    發(fā)表于 08-06 14:32

    嵌入式系統(tǒng)怎么學(xué)?

    一系列課程和技術(shù),包括但不限于以下內(nèi)容: 1、基礎(chǔ)知識:學(xué)習(xí)計算機(jī)組成原理、數(shù)字電路、模擬電路等基礎(chǔ)知識,建立對計算機(jī)硬件的認(rèn)知與理解。 2、編程語言:掌握至少一種嵌入式系統(tǒng)常用的
    發(fā)表于 07-02 10:10

    如何提升嵌入式編程能力?

    其他硬件的數(shù)據(jù)手冊,了解其特性和編程接口。 6. 學(xué)習(xí)低級編程嵌入式編程常常需要直接與硬件交互,因此學(xué)習(xí)如何進(jìn)行低級
    發(fā)表于 06-21 10:01

    嵌入式系統(tǒng)軟硬件基礎(chǔ)知識大全

    嵌入式系統(tǒng)是現(xiàn)代科技發(fā)展的一個重要分支,廣泛應(yīng)用于工業(yè)控制、消費(fèi)電子、醫(yī)療設(shè)備、汽車電子等領(lǐng)域。本文試圖全面解析嵌入式系統(tǒng)的軟基礎(chǔ)知識,以期
    發(fā)表于 05-09 14:12

    入門嵌入式系統(tǒng)這些知識你知道嗎?

    嵌入式系統(tǒng)是一種專用的計算機(jī)系統(tǒng),作為裝置或設(shè)備的一部分。通常,嵌入式系統(tǒng)是一個控制程序存儲在R
    發(fā)表于 05-03 09:54 ?579次閱讀

    如何成為一名嵌入式C語言高手?

    的特性和工作原理對于嵌入式C語言編程至關(guān)重要。你應(yīng)該學(xué)習(xí)如何與外設(shè)進(jìn)行交互、如何配置寄存器和控制器等。閱讀相關(guān)設(shè)備的數(shù)據(jù)手冊和技術(shù)文檔,參加
    發(fā)表于 04-07 16:03

    嵌入式編程片上系統(tǒng)是什么

    嵌入式編程片上系統(tǒng)(Embedded Programmable System-on-Chip,或簡稱EPSoC)是一種特殊的嵌入式系統(tǒng),它
    的頭像 發(fā)表于 03-28 15:33 ?570次閱讀

    如何成為一名嵌入式C語言高手?

    的特性和工作原理對于嵌入式C語言編程至關(guān)重要。你應(yīng)該學(xué)習(xí)如何與外設(shè)進(jìn)行交互、如何配置寄存器和控制器等。閱讀相關(guān)設(shè)備的數(shù)據(jù)手冊和技術(shù)文檔,參加
    發(fā)表于 03-25 14:12

    嵌入式fpga是什么意思

    嵌入式FPGA是指將FPGA技術(shù)集成到嵌入式系統(tǒng)中的一種解決方案。嵌入式系統(tǒng)是一種為特定應(yīng)用而設(shè)
    的頭像 發(fā)表于 03-15 14:29 ?1261次閱讀

    嵌入式工程師需要掌握哪些技術(shù)?

    一些必要的技術(shù)能力是至關(guān)重要的。在本篇中,我們將討論入行嵌入式所必須的技術(shù)能力。 1.C/C++編程
    發(fā)表于 03-04 16:38

    嵌入式人工智能的就業(yè)方向有哪些?

    網(wǎng)絡(luò)編程開發(fā)及實(shí)戰(zhàn)下 數(shù)據(jù)庫開發(fā) Linux應(yīng)用開發(fā)綜合實(shí)戰(zhàn) 三:嵌入式Linux系統(tǒng)工程師,Linuxkernel工程師,嵌入式Linux驅(qū)動
    發(fā)表于 02-26 10:17

    嵌入式系統(tǒng)發(fā)展前景?

    應(yīng)用領(lǐng)域。隨著汽車電子化和智能化程度的不斷提高,嵌入式系統(tǒng)將在汽車控制、安全系統(tǒng)、自動駕駛等方面發(fā)揮更為重要的作用。 工智能和機(jī)器學(xué)習(xí)技術(shù)的發(fā)展為
    發(fā)表于 02-22 14:09

    嵌入式軟件開發(fā)應(yīng)該掌握哪些知識?

    掌握的知識 1.基礎(chǔ)知識 1.1 c/c++編程語言和數(shù)據(jù)結(jié)構(gòu) C/C++ 是嵌入式
    發(fā)表于 02-19 11:23

    嵌入式學(xué)習(xí)步驟

    開發(fā)。 嵌入式學(xué)習(xí)步驟總結(jié)如下: (1).確定目標(biāo)平臺:選擇適合您要開發(fā)的嵌入式系統(tǒng)的硬件平臺。這取決于您要控制的設(shè)備以及您需要執(zhí)行的任務(wù)。 (2).選擇
    發(fā)表于 02-02 15:24