標(biāo)題: 【NUCLEO-L476RG開(kāi)發(fā)】硬件I2C [打印本頁(yè)]

作者: 51hei大小    時(shí)間: 2016-6-17 15:27
標(biāo)題: 【NUCLEO-L476RG開(kāi)發(fā)】硬件I2C
NUCLEO-L476RG到手一段時(shí)間了,今天來(lái)測(cè)試一下硬件I2C的操作,聽(tīng)說(shuō)很多BUG,試一試看如何。

準(zhǔn)備用I2C來(lái)訪問(wèn)AT24C02 EEPROM,將數(shù)據(jù)寫(xiě)入到EEPROM中,然后再讀取出來(lái),驗(yàn)證讀寫(xiě)操作的正確性。

硬件平臺(tái)如下


NUCLEO-L476RG



前段時(shí)間FSL的KL02Z套裝,上面的MINIDOCK擴(kuò)展板上恰好有AT24C02,所以借過(guò)來(lái)用一下,F(xiàn)SL不要生氣啊



標(biāo)準(zhǔn)的ARDUINO接口,放到哪都行。合體照。



硬件連接及原理圖

MINI DOCI上的AT24C02連接



ARDUINO接口:SCL及SDA



NUCLEO-L476RG上對(duì)應(yīng)的接口




寫(xiě)程序之前,要了解硬件的基本特性,首先是STM32L476RG上I2C接口支持的特性;其次是AT24C02的特性。

STM32L476RG的I2C功能框圖如下



值得一提的是,L4的I2C有自己獨(dú)立的內(nèi)核時(shí)鐘,可以在SYSCLK、PCLK及HSI中任選一種做為I2C的內(nèi)核時(shí)鐘。另外L4的I2C支持三種不同的通信速率:100KHZ, 400KHZ,1MHZ。由于AT24C02只支持最高400KHZ,所以這里就選擇400KHZ做為內(nèi)核時(shí)鐘。

創(chuàng)建I2C測(cè)試工程,建立過(guò)程略。幾點(diǎn)要注意的地方。

首先,本例程中使用的是I2C1,對(duì)應(yīng)的SCL及SDA引腳為PB8及PB9,時(shí)鐘配置后SYSCLK為80MHZ。

I2C硬件配置參數(shù)如圖



速度有三種可選:標(biāo)準(zhǔn),快速,快速加。另外針對(duì)不同的特定應(yīng)用,可以選擇設(shè)置上升和下降沿的時(shí)間,以納秒為單位,范圍為0-120納秒之間。注意這個(gè)TIMING參數(shù),是灰色的,CUBEMX自動(dòng)計(jì)算并設(shè)置該值,不像以前的F0和F3系列,需要一個(gè)專門(mén)的工具來(lái)設(shè)置TIMING的值,夠麻煩的。

下面是使用HAL庫(kù)與EEPROM通信的主要代碼。

  1. /* USER CODE BEGIN PV */
  2. /* Private variables ---------------------------------------------------------*/
  3. #define EEPROM_ADDRESS        0xA0
  4. #define EEPROM_PAGESIZE        0x11
  5. #define EEPROM_TIMEOUT        1000

  6. extern I2C_HandleTypeDef hi2c1;

  7. char msg[] = "This is a test!";

  8. char buf[40];

  9. int16_t Remaining_Bytes;
  10. uint16_t Memory_Address;

  11. uint16_t len;

  12. ......

  13. //write msg to eeprom
  14. Remaining_Bytes = strlen(msg);
  15. Memory_Address = 0;
  16.         
  17. while(Remaining_Bytes > 0)
  18. {
  19.       if(HAL_I2C_Mem_Write_DMA(&hi2c1, EEPROM_ADDRESS, Memory_Address, I2C_MEMADD_SIZE_8BIT, (uint8_t *)(msg + Memory_Address), EEPROM_PAGESIZE) != HAL_OK)
  20.       {
  21.               Error_Handler();
  22.                         
  23.        }
  24.                
  25.        while(HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
  26.        {
  27.        }
  28.                
  29.        while (HAL_I2C_IsDeviceReady(&hi2c1, EEPROM_ADDRESS, 10, 300) == HAL_TIMEOUT);
  30.                
  31.        while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
  32.         {
  33.         }
  34.                
  35.          Remaining_Bytes -= EEPROM_PAGESIZE;
  36.                
  37.          Memory_Address += EEPROM_PAGESIZE;
  38.         }
  39.         
  40. //read msg to buff

  41.   if(HAL_I2C_Mem_Read_DMA(&hi2c1 , EEPROM_ADDRESS, 0, I2C_MEMADD_SIZE_8BIT, (uint8_t*)buf, strlen(msg))!= HAL_OK)
  42.   {
  43.     /* Reading process Error */
  44.     Error_Handler();        
  45.   }
  46.   
  47.   /* Wait for the end of the transfer */  
  48.   while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
  49.   {
  50.   }
復(fù)制代碼




根據(jù)STD庫(kù)中用戶的反饋,I2C出錯(cuò)的原因主要由幾方面造成,一是ST設(shè)計(jì)的I2C接口,通信過(guò)程中一些狀態(tài)變量及標(biāo)志位的設(shè)置非常嚴(yán)格,如果程序邏輯考慮不周全,會(huì)導(dǎo)致I2C停止工作,需要軟復(fù)位后才能繼續(xù);另一方面,I2C接口在處理單個(gè),雙字節(jié)及多字節(jié)傳輸過(guò)程中要分開(kāi)考慮,進(jìn)一步將問(wèn)題復(fù)雜化了;還有就是結(jié)合具體的I2C設(shè)備,不同的時(shí)序要求,進(jìn)一步復(fù)雜化了通信過(guò)程。

這些問(wèn)題在HAL庫(kù)中都得到了很好的解決,為此,HAL庫(kù)中設(shè)計(jì)了幾種不同類型的API函數(shù)供調(diào)用。一類是通用的接收和發(fā)送函數(shù),這類API函數(shù)將I2C接口視為類似于“流對(duì)象”,通信時(shí)從流對(duì)象中接收或發(fā)送數(shù)據(jù);另一類則是類似于EEPROM之類的特殊存儲(chǔ)對(duì)象,從這些存儲(chǔ)對(duì)象中接收或發(fā)送數(shù)據(jù)時(shí),都需要提供一個(gè)地址,以便準(zhǔn)確定位。使用EEPROM來(lái)實(shí)驗(yàn)時(shí),我們使用的是第二類API函數(shù)。兩個(gè)主要的API函數(shù)原型及參數(shù)如下。

  1.     /**
  2.       * @brief  Transmit in master mode an amount of data in non-blocking mode with DMA
  3.       * @param  hi2c : Pointer to a I2C_HandleTypeDef structure that contains
  4.       *                the configuration information for the specified I2C.
  5.       * @param  DevAddress: Target device address
  6.       * @param  pData: Pointer to data buffer
  7.       * @param  Size: Amount of data to be sent
  8.       * @retval HAL status
  9.       */
  10.     HAL_StatusTypeDef HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)
復(fù)制代碼


  1.     /**
  2.       * @brief  Reads an amount of data in non-blocking mode with DMA from a specific memory address.
  3.       * @param  hi2c : Pointer to a I2C_HandleTypeDef structure that contains
  4.       *                the configuration information for the specified I2C.
  5.       * @param  DevAddress: Target device address
  6.       * @param  MemAddress: Internal memory address
  7.       * @param  MemAddSize: Size of internal memory address
  8.       * @param  pData: Pointer to data buffer
  9.       * @param  Size: Amount of data to be read
  10.       * @retval HAL status
  11.       */
  12.     HAL_StatusTypeDef HAL_I2C_Mem_Read_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size)
復(fù)制代碼

關(guān)于這兩個(gè)函數(shù)的更詳細(xì)的調(diào)用方法及說(shuō)明,請(qǐng)參考API文檔。

注意在具體操作EEPROM的時(shí)候,還要注意,EEPROM分字節(jié)讀寫(xiě)及頁(yè)面讀寫(xiě)兩種類型,對(duì)HAL API的調(diào)用還要進(jìn)行適當(dāng)?shù)男薷摹?br />
由于ST HAL API做了大量的后臺(tái)工作,上面的代碼看起來(lái)過(guò)于簡(jiǎn)單了。但實(shí)際上API函數(shù)在后臺(tái)做了大量的工作,這不正是我們期待的么!

最后來(lái)看看運(yùn)行結(jié)果。

UART打印的寫(xiě)入及讀取取結(jié)果



邏輯分析儀LA



I2C通信全程,LA分析結(jié)果



開(kāi)始通信,順序依次是開(kāi)始信號(hào),地址,EEPROM寫(xiě)入地址,第一個(gè)數(shù)據(jù)字節(jié)



字符0x0D, 0x0A, 結(jié)束信號(hào)。



接收開(kāi)始,順序依次是開(kāi)始信號(hào),地址,EEPROM讀取地址,第一個(gè)數(shù)據(jù)字節(jié)



讀取結(jié)束





附工程
eeprom.zip (3.17 MB, 下載次數(shù): 28)


作者: IC90    時(shí)間: 2019-7-31 17:47
樓主用的哪家的邏輯分析儀




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1