久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4039|回復: 1
打印 上一主題 下一主題
收起左側

STM32 IIC 硬件通信解決關鍵點,已驗證通過

[復制鏈接]
跳轉到指定樓層
樓主
ID:102668 發表于 2016-1-11 04:54 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
本帖最后由 51hei社區 于 2016-1-11 04:55 編輯


本文已假設你了解了STM32的IIC的基礎知識,也大概了解了IIC會出現問題。
本文只簡單介紹兩個具體例子,其他依照處理即可。
準備物品:一個邏輯分析儀,這樣才能可靠了解I2C在哪里出錯了。某寶上很便宜,100以內。
例子:1BYTE接受和2BYTE接收。
解決辦法有兩種,意思都一樣:
1:暫時提升權限到“最高”,在"最高"中斷運行花費時間在10個C指令運行時間內,保守估計在1us以內(通過邏輯分析儀也可看到)。這基本滿足了大部分人需要,也應該能滿足實時系統需求。
2:禁止中斷,也是在特定IIC操控指令段運行的時候禁止中斷,花費時間和方法1比應該少一點。

本文借鑒了 這篇文章的方法 《淺談 STM32 硬件I2C的使用 (中斷方式 無DMA無最高優先級)》,可baidu獲得
但實際使用結果是,上文并沒有完全解決硬件I2C的方法,上文在測試中沒有出現異常時因為I2C被中斷打斷的次數不夠密集,只有在外部中斷剛好擊中I2C運行的某兩個指令之間的時候,I2C通信才會出現問題。

那么在解決I2C問題之前,需要創造一個足夠強悍的中斷,使得I2C中斷在運行的時候,基本每執行一句話都被打斷,這樣才能有效驗證I2C。以下測試環境都在STM32F103(72Mhz)芯片上運行

通過TIM2定時器產生中斷,在中斷函數里面進行延時,通過設定時間設定,產生一個基本都在中斷函數里運行的狀態,兩個中斷之間的時隙在1.25us,通過邏輯分析儀觀察,在每個I2C的中斷之間,例如開始發送中斷(EV5)和收到地址響應中斷(EV6)之間會被上述中斷函數打斷幾十到上百次(由于被打斷次數太多,沒數。只是看邏輯分析儀上面密密麻麻的被不停打斷)而EV5 和EV6中斷之間運行的I2C代碼一共也只有十幾條,所以驗證了I2C沒執行一句會被打斷一次。(如果還不放心,可以對一次發送或讀取操作進行多次反復,確保I2C每條語句執行之間都會被打斷)
中斷函數為,特別注意 delay_usj(25);
  • void TIM2_IRQHandler(void)
  • {
  • if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET)
  • {
  • TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
  • LED_ON;
  • //nop;
  • delay_usj(25);
  • LED_OFF;
  • }
  • }

[color=rgb(51, 102, 153) !important]復制代碼

延時函數
  • void delay_usj(u32 n)
  • {
  • u8 j;
  • while(n--)
  • for(j=0;j<7;j++);
  • }

[color=rgb(51, 102, 153) !important]復制代碼

中斷設置語句,特別注意TIM_TimeBaseStructure.TIM_Period = 22;//自動重裝值  ,TIM_TimeBaseStructure.TIM_Prescaler = 71;     //36000

  • TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  • RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 ,ENABLE);
  • TIM_DeInit(TIM2);
  • TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  • TIM_TimeBaseStructure.TIM_Period = 22;//自動重裝值
  • TIM_TimeBaseStructure.TIM_Prescaler = 71;//36000
  • TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1;
  • TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;
  • TIM_TimeBaseStructure.TIM_RepetitionCounter =0x0;
  • TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
  • TIM_ClearFlag(TIM2, TIM_FLAG_Update);
  • TIM_ITConfig(TIM2, TIM_IT_Update,ENABLE);
  • TIM_Cmd(TIM2, ENABLE);

[color=rgb(51, 102, 153) !important]復制代碼

通過特定時間設置,即上述特別注意的三個地方,通過這幾個值,能保證在我的機器上stm32f103上產生連綿不斷的中斷,中斷之間的運行時間有1.25us,在實際測試i2c時,在連續兩個事件之間,例如ev5和ev6之間會被打斷非常多次,而ev5和ev6之間的運行代碼才寥寥十幾行,再通過反復多次運行測試,可以確保了i2c的每條語句執行完畢后都會被外部中斷打斷。從而有效驗證i2c是否編寫正確。對于你的平臺,可以通過觀看中斷中的LED_ON;LED_OFF(實際是某個GPIO電燈管教),通過檢測邏輯分析儀來查看是否中斷足夠熱烈,足夠讓I2C事件之間產生足夠多的中斷。這個延時設置需要稍微花一點時間才能找到。

說完測試環境,說如何編寫I2C
根據相關芯片referencemanual和errata sheet,例如下文
I2C eventmanagement
Description
As describedin the I2C section of the STM8S microcontroller reference manual(RM0016),
theapplication firmware has to manage several software events beforethe current byte is
transferred.If the EV7, EV7_1, EV6_1, EV6_3, EV2, EV8, and EV3 events are notmanaged
before thecurrent byte is transferred, problems may occur such as receivingan extra byte,
reading thesame data twice, or missing data.
Workaround
When the EV7,EV7_1, EV6_1, EV6_3, EV2, EV8, and EV3 events cannot bemanaged
before thecurrent byte transfer, and before the acknowledge pulse when theACK control bit
changes, itis recommended to use I2C interrupts in nested mode and to makethem
uninterruptible byincreasing their priority to the highest priority in theapplication.
No fix isplanned for this limitation.
上述意思是說 EV7,EV7_1, EV6_1, EV6_3, EV2, EV8, andEV3這幾個事件不能被打斷,除了最高中端不會被打斷外沒有其他解決方法。

那么既然不能被打斷,就是用文頭說的兩個解決發放解決。
對于1BYTE接收,用解決方法1
例子如下
  •             switch(RxLength)
  • {
  • case 1:
  • //I2C_StretchClockCmd(I2C1,ENABLE);//經過驗證此句無用
  • I2C1->CR1 &=((uint16_t)0xFBFF);//I2C_AcknowledgeConfig(I2C1,DISABLE);
  • #ifdef ENABLEHIGHIRQ //暫時I2C1權限提升到NVIC_IRQChannelPreemptionPriority = 0,NVIC_IRQChannelSubPriority =15;實際上就是不可打斷。是否用此保護塊依賴于你的使用環境,如果沒有外部中斷或者外部中斷優先級比i2c低,可以不使用此保護塊
  • tmppriority = (0x700 - ((SCB->AIRCR) &(uint32_t)0x700))>> 0x08;
  • tmppre = (0x4 - tmppriority);
  • tmpsub = tmpsub >> tmppriority;
  • tmppriority = (uint32_t)0 << tmppre;//NVIC_IRQChannelPreemptionPriority = 0
  • tmppriority |= 15 & tmpsub; // NVIC_IRQChannelSubPriority =15;
  • tmppriority = tmppriority << 0x04;
  • NVIC->IP[I2C1_EV_IRQn] = tmppriority;//I2C1_EV_IRQn=31
  • NVIC->ISER[I2C1_EV_IRQn >> 0x05] =
  • (uint32_t)0x01 << (I2C1_EV_IRQn &(uint8_t)0x1F);
  • #endif
  • //以下兩句為必須一起執行的語句,如果讀了SR2后被外部中斷打斷,則I2C一但讀取SR2后則硬件開始傳送下一個數據,而STOP位沒有被及時賦值,則導致I2C通信異常。加上保護塊后則沒有問題。
  • //在最高終端運行的時間是,上一句+本保護塊2句+收尾幾局,運行時間很短暫
  • (void) I2C1->SR2;//讀SR2
  • I2C1->CR1 |= ((uint16_t)0x0200); //write stop bit;
  • #ifdef ENABLEHIGHIRQ //回復之前的I2C權限
  • tmppriority = (0x700 - ((SCB->AIRCR) &(uint32_t)0x700))>> 0x08;
  • tmppre = (0x4 - tmppriority);
  • tmpsub = tmpsub >> tmppriority;
  • tmppriority = (uint32_t)PreemptionPriority <<tmppre;
  • tmppriority |= SubPriority & tmpsub;
  • tmppriority = tmppriority << 0x04;
  • NVIC->IP[I2C1_EV_IRQn] = tmppriority;
  • NVIC->ISER[I2C1_EV_IRQn >> 0x05] =
  • (uint32_t)0x01 << (I2C1_EV_IRQn &(uint8_t)0x1F);
  • #endif

[color=rgb(51, 102, 153) !important]復制代碼
2BYTE接收,用解決方法2:


  •              case2:
  • I2C1->CR1 |= ((uint16_t)0x0400);//I2C_AcknowledgeConfig(I2C1,ENABLE);
  • I2C1->CR1 |=I2C_NACKPosition_Next;//I2C_NACKPositionConfig(I2C1,I2C_NACKPosition_Next);
  • I2C_StretchClockCmd(I2C1,ENABLE);
  • I2C_ITConfig(I2C1, I2C_IT_EVT ,ENABLE);
  • level = rt_hw_interrupt_disable(); //保護塊開始
  • (void) I2C1->SR2;// once addr is clearing .the above code isgoing to run ,and bus is busy.
  • I2C1->CR1 &=((uint16_t)0xFBFF);//I2C_AcknowledgeConfig(I2C1,DISABLE);
  • rt_hw_interrupt_enable(level);
  • return;

[color=rgb(51, 102, 153) !important]復制代碼

rt_hw_interrupt_disable,rt_hw_interrupt_enable的意思是只允許NMI 和 hard  fault異常,其他中斷/  異常都被屏蔽(當前 CPU優先級=0)。是我在rtthread rtos里面找到的代碼


  • ;
  • rt_hw_interrupt_disable PROC
  • EXPORT rt_hw_interrupt_disable
  • MRS r0, PRIMASK
  • CPSID I
  • BX LR
  • ENDP
  • ;
  • rt_hw_interrupt_enable PROC
  • EXPORT rt_hw_interrupt_enable
  • MSR PRIMASK, r0
  • BX LR
  • ENDP

[color=rgb(51, 102, 153) !important]復制代碼

代碼用匯編編寫,簡潔快速。可以參看rtthread相關代碼。

對于2byte以上,推薦dma方法,也請使用上述中斷方法測試,可以確保dma的操控也不會出錯。


實際使用效果如邏輯分析儀展示
S1是最低放大圖片,由于中斷過于頻繁,導致I2C的每傳送一個BYTE,或者說每一個中斷事件之間都被密密麻麻的中斷擁塞,導致I2C的運行時間被長時間阻隔,同時,I2C的中斷運行代碼也意味著每運行一句會被中斷打斷。
S2是最高放大圖片,對應著一個EV5開始事件,CHANEL2的低電平意味著LED中斷運行,高電平意味著LED中斷退出,CPU運行其他程序和I2C中斷。可以看到每個LED中斷之間間隔很短(實際不是1.25us,受邏輯分析數據采樣率影響,但也差不多,不影響分析)
S3可以看到在每個I2C事件之間都填充了非常多的LED中斷事件,由于事件過多,以至于圖片無法展示到下一個I2C中斷
S4對應著某個I2C事件,可以看到I2C的事件處理完后和LED中斷并行的畫面
S1 可以看到SCL和SDA







]



分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:103938 發表于 2016-1-20 21:10 | 只看該作者
這個好,樓主弄一個完整的例子更好。
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 久久激情网 | 综合久久99 | 99热这里有精品 | 欧美精品一区二区三区在线 | 国产麻豆乱码精品一区二区三区 | 日日淫| 看片wwwwwwwwwww| 日韩伦理一区二区 | 国产亚洲人成a在线v网站 | 欧美成人a | 免费久久久 | 91在线观看视频 | 久草免费在线视频 | 日韩伦理一区二区 | 日韩在线中文字幕 | 日韩国产一区二区三区 | 中日字幕大片在线播放 | 欧美a级成人淫片免费看 | 日韩欧美三区 | 91av免费看 | 91一区二区三区 | 国产区一区二区三区 | 黄色成人在线 | 久草免费在线视频 | 亚洲精品aⅴ | 在线午夜 | 秋霞在线一区 | 午夜精品一区 | 久久国产精品视频 | 日韩在线视频一区二区三区 | 欧美精品乱码久久久久久按摩 | 中文字幕一级 | 一区二视频| 成人在线一级片 | 日韩精品一区二区三区视频播放 | 四虎在线观看 | 亚洲人在线观看视频 | 亚洲天堂中文字幕 | 请别相信他免费喜剧电影在线观看 | 久视频在线观看 | 成年人视频在线免费观看 |