網(wǎng)上有很多關(guān)于pos機(jī)驅(qū)動(dòng)教程,thread驅(qū)動(dòng)框架分析的知識(shí),也有很多人為大家解答關(guān)于pos機(jī)驅(qū)動(dòng)教程的問(wèn)題,今天pos機(jī)之家(www.tjfsxbj.com)為大家整理了關(guān)于這方面的知識(shí),讓我們一起來(lái)看下吧!
本文目錄一覽:
pos機(jī)驅(qū)動(dòng)教程
驅(qū)動(dòng)分析I2C設(shè)備驅(qū)動(dòng)框架圖:我們先RT-Thread的I2C框架圖(這是我自己理解的框架圖,如果不對(duì)的地方,請(qǐng)指出):上圖是我分析的RTT的I2C框架圖。主要分為三層,驅(qū)動(dòng)層-核心層-設(shè)備層。如果你分析過(guò)Linux的I2C框架,它的層次也是這樣子。所以你了解了RTT的I2C之后再去看Linux的I2C框架,其實(shí)問(wèn)題不大。驅(qū)動(dòng)層:分為硬件I2C驅(qū)動(dòng)和軟件I2C驅(qū)動(dòng)。核心層: ①其中bit_ops是RTT為軟件I2C提供的中間層,它的作用:為底層模擬I2C驅(qū)動(dòng)提供回調(diào)接口,為核心層提供統(tǒng)一I2C通信接口。②而硬件I2C則直接對(duì)接核心層,提供統(tǒng)一I2C通信接口。③RTT在核心層上,也像pin驅(qū)動(dòng)那樣,封裝了一套API(虛線箭頭),供用戶直接使用。④dev是提供RTT設(shè)備驅(qū)動(dòng)框架的統(tǒng)一的API(實(shí)現(xiàn)箭頭)。⑤注意的是:模擬I2C驅(qū)動(dòng)到核心層,增加了一層中間層。設(shè)備層:設(shè)備就是雜七雜八的使用I2C的總線的設(shè)備。而這些設(shè)備可以選擇使用RTT驅(qū)動(dòng)框架的API,也可以選擇RTT封裝好的API。通過(guò)上述的描述,可能還沒(méi)了解的很清晰。下面我根據(jù)兩種不同方式的驅(qū)動(dòng),兩種不同的API,逐一分析,并且會(huì)結(jié)合試驗(yàn)來(lái)驗(yàn)證。driver 層:RT-Thread的I2C驅(qū)動(dòng),分為兩種類(lèi)型:硬件I2C和軟件I2C。在stm32的BSP中提供了軟件I2C的驅(qū)動(dòng),不過(guò)為了全面介紹,硬件I2C的對(duì)接,作者也進(jìn)行簡(jiǎn)單的對(duì)接和實(shí)現(xiàn)。軟件I2C:軟件I2C的層次圖:drv_soft_i2c層: 主要進(jìn)行軟件I2C所用到scl引腳,sda引腳初始化。scl引腳和sda引腳的獲取電平和設(shè)置電平接口和延時(shí)函數(shù)(udelay)。并對(duì)接bit_opt層提供的操作結(jié)構(gòu)體:struct rt_i2c_bit_ops。并通過(guò)rt_i2c_bit_add_bus注冊(cè),提供給bit_opt層回調(diào)。struct rt_i2c_bit_ops結(jié)構(gòu)體:struct rt_i2c_bit_ops{ void *data; void (*set_sda)(void *data, rt_int32_t state); void (*set_scl)(void *data, rt_int32_t state); rt_int32_t (*get_sda)(void *data); rt_int32_t (*get_scl)(void *data); void (*udelay)(rt_uint32_t us); rt_uint32_t delay_us; rt_uint32_t timeout;};
函數(shù)指針 功能 void (set_sda)(void data, rt_int32_t state) 設(shè)置SDA電平 void (set_scl)(void data, rt_int32_t state); 設(shè)置SCL電平 rt_int32_t (get_sda)(void data); 獲取SDA電平 rt_int32_t (get_scl)(void data); 獲取SCL電平 void (*udelay)(rt_uint32_t us); 軟件I2C時(shí)序所需要的的延時(shí)函數(shù)
rt_i2c_bit_add_bus接口,主要注冊(cè)軟件I2C的引腳操作的回調(diào)函數(shù)。bit_opt層:可以歸納為驅(qū)動(dòng)層。其主要實(shí)現(xiàn)軟件I2C的時(shí)序等邏輯,并提供對(duì)應(yīng)的I2C的收發(fā)處理函數(shù),為drv_soft_i2c層提供提供了(struct rt_i2c_bit_ops)注冊(cè)接口和(rt_i2c_bit_add_bus)接口,為i2c_core層提供主機(jī)模式的數(shù)據(jù)處理函數(shù)。bit_opt層主要對(duì)接到i2c_core層提供操作結(jié)構(gòu)體:struct rt_i2c_bus_device_ops以及i2c總線的注冊(cè)函數(shù)rt_i2c_bus_device_register:struct rt_i2c_bus_device_ops結(jié)構(gòu)體:struct rt_i2c_bus_device_ops{ rt_size_t (*master_xfer)(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num); rt_size_t (*slave_xfer)(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num); rt_err_t (*i2c_bus_control)(struct rt_i2c_bus_device *bus, rt_uint32_t, rt_uint32_t);};
函數(shù)指針 功能 master_xfer 主機(jī)模式的數(shù)據(jù)收發(fā) slave_xfer 從機(jī)模式的數(shù)據(jù)收發(fā) i2c_bus_control i2c總線的的操作參數(shù)等設(shè)置
rt_i2c_bus_device_register接口:主要注冊(cè)I2C總線和收發(fā)數(shù)據(jù)的回調(diào)函數(shù)。軟件I2C驅(qū)動(dòng)總結(jié):rt-thread的軟件I2C,如果要對(duì)接其他平臺(tái),只需要對(duì)接好結(jié)構(gòu)體:struct rt_i2c_bit_ops。而軟件I2C的邏輯完全不用理會(huì),全部由bit_opt層管理。硬件I2C硬件I2C的層次圖:drv_hw_i2c層:沒(méi)有軟件I2C的bit_opt層,而是直接對(duì)接i2c_core層提供的結(jié)構(gòu)體:struct rt_i2c_bus_device_ops。作者為了簡(jiǎn)單說(shuō)明,寫(xiě)了個(gè)例子(簡(jiǎn)單粗暴的例子):struct rt_i2c_bus_device i2c1_bus;I2C_HandleTypeDef hi2c1;static rt_err_t i2c_hw_Init(void){ hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { Error_Handler(); } return RT_EOK;}static rt_size_t i2c_xfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[], rt_uint32_t num){ struct rt_i2c_msg *msg; rt_int32_t i, ret; for(i = 0; i< num; i++) { msg = &msgs[i]; if(msg->flags & RT_I2C_RD) { HAL_I2C_Master_Receive(&hi2c1, msg->addr, msg->buf, msg->len, 100); } else { HAL_I2C_Master_Transmit(&hi2c1, msg->addr, msg->buf, msg->len, 100); } } ret = i; return ret;}static const struct rt_i2c_bus_device_ops i2c_bus_ops ={ i2c_xfer, RT_NULL, RT_NULL};int rt_i2c_hw_init(void){ i2c_hw_init(); i2c1_bus.ops = &i2c_bus_ops; rt_i2c_bus_device_register(&i2c1_bus, "hw_i2c"); return RT_EOK;}INIT_DEVICE_EXPORT(rt_i2c_hw_init);以上硬件I2C對(duì)接,我只是對(duì)接了master_xfer。硬件I2C驅(qū)動(dòng)總結(jié):如果你是采用硬件I2C,那么就不需要去關(guān)乎bit_opt層,其實(shí)通過(guò)上面的描述,你不難理解bit_opt層和drv_hw_i2c層其實(shí)對(duì)接都是i2c_core層的結(jié)構(gòu)。這也是我為什么把bit_opt層歸納為驅(qū)動(dòng)層來(lái)講解了。core 層:i2c_core層為驅(qū)動(dòng)層提供結(jié)構(gòu)體:struct rt_i2c_bus_device_ops。為設(shè)備層提供I2C的數(shù)據(jù)收發(fā)處理函數(shù)。其實(shí)i2c_core層主要是封裝了一層API直接提供給用戶層設(shè)備調(diào)用。
函數(shù) 說(shuō)明 rt_i2c_bus_device_find 查找i2c總線 rt_i2c_transfer 主機(jī)模式的i2c數(shù)據(jù)傳輸 rt_i2c_master_send 主機(jī)模式的i2c數(shù)據(jù)發(fā)送 rt_i2c_master_recv 主機(jī)模式的i2c數(shù)據(jù)接受
其中rt_i2c_master_send函數(shù)和rt_i2c_master_recv函數(shù)是調(diào)用rt_i2c_transfer函數(shù),而rt_i2c_transfer函數(shù)是調(diào)用master_xfer回調(diào)函數(shù)。如果你是使用這些接口,那么device層可以不用理會(huì)。device 層:i2c_dev層,對(duì)接rt-thread設(shè)備驅(qū)動(dòng)框架。提供read,write,control函數(shù)。并通過(guò)函數(shù)rt_device_register注冊(cè)到設(shè)備驅(qū)動(dòng)框架。下面我也會(huì)使用這些接口來(lái)實(shí)現(xiàn)控制OLED。函數(shù) 說(shuō)明 i2c_bus_device_read I2C讀操作 i2c_bus_device_write I2C寫(xiě)操作 i2c_bus_device_control I2C總線的控制
軟件I2C設(shè)計(jì):關(guān)鍵代碼, 注意軟件I2C的地址需要偏移一位:struct rt_i2c_bus_device *i2c_bus;#define OLED_I2C_BUS_NAME "i2c1"#define OLED_ADDRESS 0x3cstatic rt_err_t write_reg(struct rt_i2c_bus_device *bus, rt_uint8_t reg, rt_uint8_t data){ rt_uint8_t buf[2]; struct rt_i2c_msg msgs; buf[0] = reg; buf[1] = data; msgs.addr = OLED_ADDRESS; msgs.flags = RT_I2C_WR; msgs.buf = buf; msgs.len = 2; /@@* 調(diào)用I2C設(shè)備接口傳輸數(shù)據(jù) */ rt_i2c_transfer(bus, &msgs, 1); return RT_EOK;}static rt_err_t read_regs(struct rt_i2c_bus_device *bus, rt_uint8_t len, rt_uint8_t *buf){ struct rt_i2c_msg msgs; msgs.addr = OLED_ADDRESS; msgs.flags = RT_I2C_RD; msgs.buf = buf; msgs.len = len; /@@* 調(diào)用I2C設(shè)備接口傳輸數(shù)據(jù) */ rt_i2c_transfer(bus, &msgs, 1); return RT_EOK;}int oled_init(void){ i2c_bus = rt_i2c_bus_device_find(OLED_I2C_BUS_NAME); if(i2c_bus == RT_NULL) { rt_kprintf("find i2c bus fail!\"); return RT_ERROR; } rt_kprintf("find i2c bus success!\"); ......}效果圖:硬件I2C設(shè)計(jì):關(guān)鍵代碼,注意硬件I2C的地址不需要偏移:
struct rt_i2c_bus_device *i2c_bus;#define OLED_I2C_BUS_NAME "hw_i2c"#define OLED_ADDRESS 0x78static rt_err_t write_reg(struct rt_i2c_bus_device *bus, rt_uint8_t reg, rt_uint8_t data){ rt_uint8_t buf[2]; struct rt_i2c_msg msgs; buf[0] = reg; buf[1] = data; msgs.addr = OLED_ADDRESS; msgs.flags = RT_I2C_WR; msgs.buf = buf; msgs.len = 2; /@@* 調(diào)用I2C設(shè)備接口傳輸數(shù)據(jù) */ rt_i2c_transfer(bus, &msgs, 1); return RT_EOK;}static rt_err_t read_regs(struct rt_i2c_bus_device *bus, rt_uint8_t len, rt_uint8_t *buf){ struct rt_i2c_msg msgs; msgs.addr = OLED_ADDRESS; msgs.flags = RT_I2C_RD; msgs.buf = buf; msgs.len = len; /@@* 調(diào)用I2C設(shè)備接口傳輸數(shù)據(jù) */ rt_i2c_transfer(bus, &msgs, 1); return RT_EOK;}int oled_init(void){ i2c_bus = rt_i2c_bus_device_find(OLED_I2C_BUS_NAME); if(i2c_bus == RT_NULL) { rt_kprintf("find i2c bus fail!\"); return RT_ERROR; } rt_kprintf("find i2c bus success!\"); ......}使用驅(qū)動(dòng)框架API實(shí)現(xiàn):關(guān)鍵代碼:
#define OLED_I2C_BUS_NAME "hw_i2c"struct rt_device *dev_i2c;#define OLED_ADDRESS 0x78static rt_err_t write_reg(struct rt_device *dev, rt_uint8_t reg, rt_uint8_t data){ rt_uint8_t buf[2]; rt_off_t pos; rt_uint16_t addr = OLED_ADDRESS; rt_uint16_t flags = RT_I2C_WR; buf[0] = reg; buf[1] = data; pos = (flags << 16) | addr; rt_device_write(dev, pos, buf, 2); return RT_EOK;}static rt_err_t read_regs(struct rt_device *dev, rt_uint8_t len, rt_uint8_t *buf){ rt_off_t pos; rt_uint16_t addr = OLED_ADDRESS; rt_uint16_t flags = RT_I2C_WR; pos = (flags << 16) | addr; rt_device_write(dev, pos, buf, 2); return RT_EOK;}int oled_init(void){ dev_i2c = rt_device_find(OLED_I2C_BUS_NAME); if(dev_i2c == RT_NULL) { rt_kprintf("find i2c bus fail!\"); return RT_ERROR; } rt_kprintf("find i2c bus success!\"); rt_device_open(dev_i2c, RT_DEVICE_OFLAG_RDWR); .... return RT_EOK;}總結(jié)有了I2C驅(qū)動(dòng)框架,對(duì)于上層來(lái)說(shuō),不管硬件I2C還是軟件I2C調(diào)用接口都是一樣的。rt-thread為了方便,直接在核心層提供了一套API,這樣用戶層調(diào)用就更加方便。
以上就是關(guān)于pos機(jī)驅(qū)動(dòng)教程,thread驅(qū)動(dòng)框架分析的知識(shí),后面我們會(huì)繼續(xù)為大家整理關(guān)于pos機(jī)驅(qū)動(dòng)教程的知識(shí),希望能夠幫助到大家!
