中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

深一集團(tuán)的網(wǎng)站誰做的360開戶推廣

深一集團(tuán)的網(wǎng)站誰做的,360開戶推廣,java wordpress 密碼錯(cuò)誤,河南建設(shè)部網(wǎng)站RT-Thread在STM32硬件I2C的踩坑記錄 0.前言一、軟硬件I2C區(qū)別二、RT Thread中的I2C驅(qū)動(dòng)三、嘗試適配硬件I2C四、i2c-bit-ops操作函數(shù)替換五、Attention Please!六、總結(jié) 參考文章: 1.將硬件I2C巧妙地將“嫁接”到RTT原生的模擬I2C驅(qū)動(dòng)框架 2.基于STM32F4平臺(tái)的硬件I…

RT-Thread在STM32硬件I2C的踩坑記錄

  • 0.前言
  • 一、軟硬件I2C區(qū)別
  • 二、RT Thread中的I2C驅(qū)動(dòng)
  • 三、嘗試適配硬件I2C
  • 四、i2c-bit-ops操作函數(shù)替換
  • 五、Attention Please!
  • 六、總結(jié)


參考文章:
1.將硬件I2C巧妙地將“嫁接”到RTT原生的模擬I2C驅(qū)動(dòng)框架
2.基于STM32F4平臺(tái)的硬件I2C驅(qū)動(dòng)實(shí)現(xiàn)筆記
3.《rt-thread驅(qū)動(dòng)框架分析》- i2c驅(qū)動(dòng)

0.前言

??最近打算用RT-Thread做一個(gè)小demo玩玩,其中需要用I2C通信驅(qū)動(dòng)一個(gè)oled屏幕,但是找了一圈也沒找到RTT中對(duì)硬件I2C的支持方式以及使用案例,好像大家都心照不宣的用這個(gè)好用又不好用的軟件I2C。這里還是忍不住吐槽兩句,連硬件SPI都已經(jīng)支持了,甚至支持SPI DMA模式了,硬件I2C這么多年了也沒適配。也希望有大佬能貢獻(xiàn)一份力量,做出一份能讓DIY玩家湊合用的第三方硬件I2C驅(qū)動(dòng)也行。

一、軟硬件I2C區(qū)別

??有關(guān)I2C通信協(xié)議的原理部分就不多介紹了,這個(gè)算是很常見的通信協(xié)議了,CSDN論壇一搜一大把,RT Thread文檔中心也有較詳細(xì)的介紹。
??軟件I2C是使用GPIO的電平翻轉(zhuǎn)模擬出I2C信號(hào),它的好處是方便移植,下至51單片機(jī),上至linux平臺(tái),只要有GPIO都能適用(當(dāng)然linux下也不會(huì)有人用這個(gè))。缺點(diǎn)則是速率很低,軟件操作GPIO電平翻轉(zhuǎn)不可避免的有時(shí)延以及毛刺,為了消除這種現(xiàn)象的影響,模擬的I2C信號(hào)之間就需要稍微大點(diǎn)的時(shí)間間隔。軟件I2C的信號(hào)頻率一般在30KHz ~ 50KHz,即便優(yōu)化相當(dāng)好的情況也差不多在這個(gè)量級(jí)。用來操作128x64的oled屏幕,幀率基本在2幀左右。
??硬件I2C則是通過操作芯片自帶的寄存器進(jìn)行I2C通信,缺點(diǎn)就是不同芯片間驅(qū)動(dòng)不通用,優(yōu)點(diǎn)則是速度更快,并且可以適配DMA模式,降低CPU負(fù)載。筆者使用的STM32RCT6,硬件I2C標(biāo)準(zhǔn)模式信號(hào)頻率為100KHz,快速模式400KHz,一些性能較好的芯片還有1MHz的極速模式。400kHz情況下操作128x64的oled幀率在25幀左右,可以說是提升巨大了。

二、RT Thread中的I2C驅(qū)動(dòng)

??關(guān)于RT Thread中的I2C驅(qū)動(dòng)框架的實(shí)現(xiàn)方式,可以參考上述的第三篇參考文章,個(gè)人覺得寫的很詳細(xì)也好懂。RT Thread為類Linux的實(shí)時(shí)操作系統(tǒng),所以I2C框架的實(shí)現(xiàn)方式和linux中的也比較相像:I2C驅(qū)動(dòng)提供一些操作相關(guān)的ops函數(shù),并注冊(cè)到內(nèi)核中,I2C設(shè)備則可以通過probe函數(shù)掛載到總線上,通過ops操作函數(shù)進(jìn)行I2C通信。
在這里插入圖片描述
并且在該篇文章中,該作者跳過原本的bit_ops,重新設(shè)計(jì)了一個(gè)硬件I2C的實(shí)現(xiàn)方式,將驅(qū)動(dòng)直接掛載到內(nèi)核core中,也實(shí)現(xiàn)了作為master設(shè)備的硬件I2C驅(qū)動(dòng)。不過筆者認(rèn)為這種方式對(duì)通用結(jié)構(gòu)的兼容性不太好,所以又找了一些其他方式。
在這里插入圖片描述

三、嘗試適配硬件I2C

參考文章1和2中,通過修改I2C總線的實(shí)現(xiàn)函數(shù),“嫁接”一個(gè)硬件的I2C驅(qū)動(dòng)實(shí)現(xiàn)方式。這里就先放上代碼,首先在原drv_soft_i2c.c和drv_soft_i2c.h的同級(jí)目錄下,分別創(chuàng)建drv_hard_i2c.c和drv_hard_i2c.h:
drv_hard_i2c.h:

/** Copyright (c) 2006-2018, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2018-11-08     balanceTWK   first version*/#ifndef __DRV_I2C__
#define __DRV_I2C__#include <rtthread.h>
#include <rthw.h>
#include <rtdevice.h>#ifdef BSP_USING_HARD_I2C/* stm32 config class */
typedef void (*pI2cConfig)(void);
struct stm32_hard_i2c_config
{rt_uint8_t scl;                     /* scl pin */rt_uint8_t sda;                     /* sda pin */const pI2cConfig pFunc;             /* i2c init function */const char* pName;                  /* i2c bus name */I2C_HandleTypeDef* pHi2c;           /* i2c handle */struct rt_i2c_bus_device i2c_bus;   /* i2c bus device */
};
/* stm32 i2c dirver class */
struct stm32_i2c
{struct rt_i2c_bit_ops ops;struct rt_i2c_bus_device i2c2_bus;
};#define HARD_I2C_CONFIG(x)  \
{.scl        = BSP_I2C##x##_SCL_PIN,    \.sda        = BSP_I2C##x##_SDA_PIN,    \.pFunc      = MX_I2C##x##_Init,         \.pHi2c      = &hi2c##x,                 \.pName      = "i2c"#x,                  \.i2c_bus    = {.ops = &i2c_bus_ops,},
}int rt_hw_i2c_init(void);#endif#endif /* RT_USING_I2C */

其中stm32_hard_i2c_config可以理解為i2c實(shí)例對(duì)象,屬性包括scl和sda引腳、總線名稱及初始化函數(shù)等。(注:在參考文章2中的總線速度、信號(hào)量及互斥鎖則不需要,因?yàn)槭褂肅ubeMx生成的初始化函數(shù)中已有總線速度,HAL庫中的I2C操作函數(shù)內(nèi)部已有總線鎖)
stm32_i2c則封裝了設(shè)備操作函數(shù)及總線,用于與內(nèi)核對(duì)接。
函數(shù)宏HARD_I2C_CONFIG(x)則用來后續(xù)創(chuàng)建I2C設(shè)備對(duì)象。

drv_hard_i2c.c:

/** Copyright (c) 2006-2018, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2018-11-08     balanceTWK   first version*/#include <board.h>
#include "drv_hard_i2c.h"
#include "drv_config.h"
#include<rtthread.h>
#include<rtdevice.h>#ifdef BSP_USING_HARD_I2C//#define DRV_DEBUG
#define LOG_TAG              "drv.i2c"
#include <drv_log.h>static const struct stm32_hard_i2c_config hard_i2c_config[] =
{
#ifdef BSP_USING_HARD_I2C1HARD_I2C_CONFIG(1),
#endif
#ifdef BSP_USING_HARD_I2C2HARD_I2C_CONFIG(2),
#endif
#ifdef BSP_USING_HARD_I2C3HARD_I2C_CONFIG(3),
#endif
#ifdef BSP_USING_HARD_I2C4HARD_I2C_CONFIG(4),
#endif
};static struct stm32_i2c i2c_obj[sizeof(hard_i2c_config) / sizeof(hard_i2c_config[0])];/*** This function initializes the i2c pin.** @param Stm32 i2c dirver class.*/
static void stm32_i2c_gpio_init(struct stm32_i2c *i2c)
{struct stm32_soft_i2c_config* cfg = (struct stm32_soft_i2c_config*)i2c->ops.data;rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT_OD);rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT_OD);rt_pin_write(cfg->scl, PIN_HIGH);rt_pin_write(cfg->sda, PIN_HIGH);
}/*** The time delay function.** @param microseconds.*/
static void stm32_udelay(rt_uint32_t us)
{rt_uint32_t ticks;rt_uint32_t told, tnow, tcnt = 0;rt_uint32_t reload = SysTick->LOAD;ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);told = SysTick->VAL;while (1){tnow = SysTick->VAL;if (tnow != told){if (tnow < told){tcnt += told - tnow;}else{tcnt += reload - tnow + told;}told = tnow;if (tcnt >= ticks){break;}}}
}/*** if i2c is locked, this function will unlock it** @param stm32 config class** @return RT_EOK indicates successful unlock.*/
static rt_err_t stm32_i2c_bus_unlock(const struct stm32_soft_i2c_config *cfg)
{rt_int32_t i = 0;if (PIN_LOW == rt_pin_read(cfg->sda)){while (i++ < 9){rt_pin_write(cfg->scl, PIN_HIGH);stm32_udelay(100);rt_pin_write(cfg->scl, PIN_LOW);stm32_udelay(100);}}if (PIN_LOW == rt_pin_read(cfg->sda)){return -RT_ERROR;}return RT_EOK;
}/* I2C initialization function */
int rt_hw_i2c_init(void)
{rt_int8_t ret = RT_ERROR;rt_size_t obj_num = NR(hard_i2c_config);rt_err_t result;for (int i = 0; i < obj_num; i++){//GPIO初始化stm32_i2c_gpio_init(&hard_i2c_config[i]);//檢測(cè)SDA是否為低電平,低電平則通過管腳模擬9個(gè)CLK解鎖stm32_i2c_bus_unlock(&hard_i2c_config[i]);//調(diào)用Hal庫MX_I2Cx_Init(),配置硬件I2Chard_i2c_config[i].pFunc();//向內(nèi)核注冊(cè)I2C Bus設(shè)備if(rt_i2c_bus_device_register(&(hard_i2c_config[i].i2c_bus), hard_i2c_config[i].pName) != RT_EOK){LOG_E("%s bus init failed!\r\n", hard_i2c_config[i].pName);ret |= RT_ERROR;}else{ret |= RT_EOK;LOG_I("%s bus init success!\r\n", hard_i2c_config[i].pName);}}return ret;
}
//INIT_BOARD_EXPORT(rt_hw_i2c_init);#endif /* BSP_USING_HARD_I2C */

此文件中則主要根據(jù)宏定義開關(guān)創(chuàng)建I2C實(shí)例對(duì)象,并對(duì)其進(jìn)行初始化。主要函數(shù)為rt_hw_i2c_init(),此函數(shù)中所需要的gpio init、delay函數(shù)等,則保留軟件i2c中的初始化操作。

user_i2c.h:

/** Copyright (c) 2006-2021, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date           Author       Notes* 2023-08-27     14187       the first version*/
#ifndef DRIVERS_HARD_I2C_H_
#define DRIVERS_HARD_I2C_H_//硬件i2c宏開關(guān)
//#define     BSP_USING_HARD_I2C
#ifdef      BSP_USING_HARD_I2C
//      #define BSP_USING_HARD_I2C1
//      #define BSP_USING_HARD_I2C2
//      #define BSP_USING_HARD_I2C3
//      #define BSP_USING_HARD_I2C4#if defined(BSP_USING_HARD_I2C1 || BSP_USING_HARD_I2C2 || BSP_USING_HARD_I2C3 || BSP_USING_HARD_I2C4)//#define BSP_USING_DMA_I2C_TX//#define BSP_USING_DMA_I2C_RX#endif
#endif#endif /* DRIVERS_HARD_I2C_H_ */

為了不在每次保存RT Thread Settings時(shí),自己的配置被覆蓋刷新,所以額外定義了一個(gè)頭文件,用于保存自定義的I2C宏開關(guān),這樣每次刷新后只需要重新在board.h中包含此頭文件即可。

至此自定義的硬件I2C宏開關(guān)及設(shè)備對(duì)象創(chuàng)建已完成,剩下的則只需要替換內(nèi)核中的bit_ops操作函數(shù)即可。

四、i2c-bit-ops操作函數(shù)替換

在rt thread項(xiàng)目根目錄下的 rt-thread/components/drivers/i2c/ 目錄下,有一個(gè)i2c-bit-ops.c文件,其中則保存了i2c驅(qū)動(dòng)框架中注冊(cè)的ops操作函數(shù):

static rt_size_t i2c_bit_xfer(struct rt_i2c_bus_device *bus,struct rt_i2c_msg         msgs[],rt_uint32_t               num)
{struct rt_i2c_msg *msg;struct rt_i2c_bit_ops *ops = (struct rt_i2c_bit_ops *)bus->priv;rt_int32_t i, ret;rt_uint16_t ignore_nack;if (num == 0) return 0;for (i = 0; i < num; i++){msg = &msgs[i];ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;if (!(msg->flags & RT_I2C_NO_START)){if (i){i2c_restart(ops);}else{LOG_D("send start condition");i2c_start(ops);}ret = i2c_bit_send_address(bus, msg);if ((ret != RT_EOK) && !ignore_nack){LOG_D("receive NACK from device addr 0x%02x msg %d",msgs[i].addr, i);goto out;}}if (msg->flags & RT_I2C_RD){ret = i2c_recv_bytes(bus, msg);if (ret >= 1){LOG_D("read %d byte%s", ret, ret == 1 ? "" : "s");}if (ret < msg->len){if (ret >= 0)ret = -RT_EIO;goto out;}}else{ret = i2c_send_bytes(bus, msg);if (ret >= 1){LOG_D("write %d byte%s", ret, ret == 1 ? "" : "s");}if (ret < msg->len){if (ret >= 0)ret = -RT_ERROR;goto out;}}}ret = i;out:if (!(msg->flags & RT_I2C_NO_STOP)){LOG_D("send stop condition");i2c_stop(ops);}return ret;
}
...
static const struct rt_i2c_bus_device_ops i2c_bit_bus_ops =
{i2c_bit_xfer,RT_NULL,RT_NULL
};

這段代碼中實(shí)現(xiàn)了對(duì)每個(gè)i2c設(shè)備發(fā)送對(duì)應(yīng)的i2c msg流程,將其修改為硬件i2c的發(fā)送方式:

static rt_size_t i2c_xfer(struct rt_i2c_bus_device *bus,struct rt_i2c_msg     msgs[],rt_uint32_t           num)
{rt_uint32_t i;struct rt_i2c_msg *msg;struct stm32_hard_i2c_config *Pconfig = rt_container_of(bus, struct stm32_hard_i2c_config, i2c_bus);fot(i = 0;i < num;i++){msg = &msgs[i];if(msg->flags & RT_I2C_RD){
#if defined(BSP_USING_DMA_I2C_RX)HAL_I2C_Master_Receive_DMA(Pconfig->pHi2c, (msg->addr)<<1, msg->buf, msg->len);rt_hw_us_delay(100);
#elseHAL_I2C_Master_Receive(Pconfig->pHi2c, (msg->addr)<<1, msg->buf, msg->len, 100);
#endif}else{
#if defined(BSP_USING_DMA_I2C_TX)HAL_I2C_Master_Transmit_DMA(Pconfig->pHi2c, (msg->addr)<<1, msg->buf, msg->len);rt_hw_us_delay(100);
#elseHAL_I2C_Master_Transmit(Pconfig->pHi2c, (msg->addr)<<1, msg->buf, msg->len, 100);
#endif}}return i;
}static const struct rt_i2c_bus_device_ops i2c_bit_bus_ops =
{i2c_xfer,RT_NULL,RT_NULL
};

參考軟件i2c的發(fā)送方式,創(chuàng)建一個(gè)新的發(fā)送函數(shù)rt_size_t i2c_xfer(),并將rt_i2c_bus_device_ops 中對(duì)應(yīng)的發(fā)送方式修改為此方式。

至此,硬件I2C的驅(qū)動(dòng)則算是完成了一部分,可以通過與軟件i2c一樣的聲明及掛載方式,將設(shè)備掛載到硬件I2C總線上。

五、Attention Please!

問題1:在上述的實(shí)現(xiàn)方式中,可以根據(jù)宏定義通過HAL_I2C_Master_Transmit()或HAL_I2C_Master_Transmit_DMA()方式發(fā)送I2C消息,但并未對(duì)是否發(fā)送成功做出判斷。
問題2:ST官方的HAL庫中,I2C發(fā)送消息共有三種方式,polling模式(輪詢)、中斷模式、DMA模式,HAL_I2C_Master_Transmit()則對(duì)應(yīng)輪詢模式,此模式相對(duì)于軟件I2C雖然速率有所提升,但實(shí)際的提升效果其實(shí)不是特別大。而對(duì)于中斷模式,則需要移植并實(shí)現(xiàn)對(duì)應(yīng)的中斷處理函數(shù),可以按照參考文章2進(jìn)行實(shí)現(xiàn),不過筆者認(rèn)為該篇需要注意的地方很多,比如在中斷處理函數(shù)中釋放信號(hào)量的操作,可能會(huì)造成一些隱患(可以直接去除信號(hào)量)。對(duì)于DMA模式,理論上也需要移植一些中斷處理函數(shù),但筆者目前沒有用這種方式,所以也沒有細(xì)究。所以理論上只能停留在polling模式。
問題3:在drv_hard_i2c.c中,INIT_BOARD_EXPORT(rt_hw_i2c_init);這個(gè)注冊(cè)步驟,需要根據(jù)實(shí)際情況而定,如果想要使用DMA模式,則在此注冊(cè)步驟之前,需要先注冊(cè)MX_DMA_Init(),此函數(shù)為CubeMX生成,用來初始化DMA功能。中斷模式同理。

六、總結(jié)

??目前看來,移植ST的硬件I2C驅(qū)動(dòng)還是困難重重,所以筆者選則了更換平臺(tái)(我逃避。。。)將oled的電路修改成了SPI模式,并更換了芯片平臺(tái),手頭還有一個(gè)LPC54110和一個(gè)CH32的開發(fā)板,這兩個(gè)板子的RTT BSP支持包好像有適配硬件I2C驅(qū)動(dòng),ST再見,希望下次回來有大佬適配了硬件I2C。

http://www.risenshineclean.com/news/44403.html

相關(guān)文章:

  • 武漢哪家網(wǎng)站建設(shè)公司好怎么用手機(jī)創(chuàng)建網(wǎng)站
  • 萍鄉(xiāng)做網(wǎng)站的百度云網(wǎng)盤資源搜索引擎入口
  • 卡姐的wap是什么意思百度seo站長(zhǎng)工具
  • 網(wǎng)站怎么做搜索引擎才能收錄百度指數(shù)有什么參考意義
  • 做照片書的模板下載網(wǎng)站好惠州網(wǎng)站推廣排名
  • 沈陽網(wǎng)站建設(shè)專家seo營銷方案
  • 建站免費(fèi)加盟網(wǎng)絡(luò)營銷推廣的優(yōu)勢(shì)
  • 有哪些做普洱茶網(wǎng)站的女生讀網(wǎng)絡(luò)營銷與電商直播
  • 廣州開發(fā)區(qū)醫(yī)院南崗院區(qū)莆田seo推廣公司
  • app開發(fā)公司收費(fèi)seo優(yōu)化包括哪些
  • 哪個(gè)公司網(wǎng)站做的好網(wǎng)站推廣的目的是什么
  • 沈陽犀牛云做網(wǎng)站怎么樣長(zhǎng)沙正規(guī)seo優(yōu)化價(jià)格
  • 杭州 手機(jī)網(wǎng)站免費(fèi)搭建網(wǎng)站的軟件
  • 使用tag的網(wǎng)站最近一周的新聞大事10條
  • 織夢(mèng)學(xué)校網(wǎng)站seo關(guān)鍵詞推廣方式
  • 百度搜索推廣技巧免費(fèi)外鏈網(wǎng)站seo發(fā)布
  • 沈陽做網(wǎng)站哪家便宜深圳最新消息今天
  • 做的好的國外網(wǎng)站東莞做好網(wǎng)絡(luò)推廣
  • 貿(mào)易公司寮步網(wǎng)站建設(shè)極致發(fā)燒百度在線入口
  • 赤峰做企業(yè)網(wǎng)站公司企業(yè)網(wǎng)站建設(shè)方案策劃
  • 網(wǎng)站彈出信息怎么做怎么快速優(yōu)化關(guān)鍵詞排名
  • 專門做娛樂場(chǎng)所的設(shè)計(jì)網(wǎng)站近三天發(fā)生的大事
  • 可以做動(dòng)效的網(wǎng)站百度競(jìng)價(jià)代運(yùn)營外包
  • 深圳室內(nèi)設(shè)計(jì)公司排行關(guān)鍵詞優(yōu)化一年的收費(fèi)標(biāo)準(zhǔn)
  • 網(wǎng)站被k申訴電商還有發(fā)展前景嗎
  • 網(wǎng)站開發(fā) 性能方面百度的網(wǎng)址怎么寫
  • 購物網(wǎng)站app騰訊域名
  • 做網(wǎng)站有發(fā)票嗎站外推廣怎么做
  • 紅河北京網(wǎng)站建設(shè)百度輿情
  • 國內(nèi)室內(nèi)設(shè)計(jì)師南寧百度seo軟件