2014-11-04 147 views
2

最近我一直在嘗試使用STM32F030F4P6 MCU工作的I2C總線,但運氣不大。如何在STM32F0上初始化I2C?

我正在使用一個STM32F0模塊,並已經找到了大量用於STM32F1模塊I2C初始化的資源,但沒有具體說明STM32F0初始化/傳輸過程。

這裏是我的初始化代碼:

void i2c_init(uint8_t ownAddress) 
{ 
GPIO_InitTypeDef GPIO_InitStructure; 
I2C_InitTypeDef I2C_InitStructure; 

// Enable GPIOA clocks 

RCC_APB2PeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); 

// Configure I2C1 clock and GPIO 

GPIO_StructInit(&GPIO_InitStructure); 


/* I2C1 clock enable */ 

RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); 

/* I2C1 SDA and SCL configuration */ 

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; 
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; 
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; 
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; 
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; 
GPIO_Init(GPIOA, &GPIO_InitStructure); 

/* I2C1 Reset */ 

RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE); 
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE); 


/* Configure I2C1    */ 

I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable; 
I2C_StructInit(&I2C_InitStructure); 
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; 
//I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; 
I2C_InitStructure.I2C_OwnAddress1 = ownAddress; 
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; 
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; 
//I2C_InitStructure.I2C_ClockSpeed = ClockSpeed; 


I2C_Init(I2C1, &I2C_InitStructure); 
I2C_Cmd(I2C1, ENABLE); 

} 

爲了測試,看看我的設置是正確的,我設計了一些I2C傳輸代碼,將在永無止境的循環傳輸數據。下面是該代碼:

while(1) 
{ 
I2C_SlaveAddressConfig(I2C1, RegName); 
I2C_GenerateSTART(I2C1, ENABLE); 
I2C_NumberOfBytesConfig(I2C1, 8); 
I2C_SendData(I2C1,0b00000000); 
I2C_GenerateSTOP(I2C1, ENABLE); 
} 

其中:

寄存器名= 0x75

SDA = GPIO_PIN_10上GPIOA

SCL = GPIO_PIN_9上GPIOA

I2C = I2C1

ownAdrress = 0x68

當我在啓動此代碼後對I2C線進行範圍調整時,我會獲得大約160mV的浮動電壓。當我逐步完成代碼時,每一個I2C函數調用都會發生並完成,所以這就是爲什麼我認爲它更像是我自己初始化引腳的原因。

我的問題是非常相似,這個線程,但從未回答:

https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https%3a%2f%2fmy%2est%2ecom%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fcortex_mx_stm32%2fSTM32F0%20I2C%20code%20doesn%27t%20work&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=1342

編輯1:這是我最新的代碼;仍然沒有工作(編輯2:更新什麼,我現在有;感動的事情到更正確的位置):

void i2c_init(uint8_t ownAddress) 
{ 

    /* TypeDefs for GPIOA and I2C1 */ 

    GPIO_InitTypeDef GPIO_InitStructure; 
    I2C_InitTypeDef I2C_InitStructure; 

    /* Enable GPIOA clocks and I2C1 clock enable */ 

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); 

    /* Configure I2C1 clock and GPIO */ 

    GPIO_StructInit(&GPIO_InitStructure); 

    /* I2C1 SDA and SCL configuration */ 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; 
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //UP 
    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; 

    /* GPIO AF Configuration -> GPIO_AF_1: USART2, CEC, Tim3, USART1, USART2,EVENTOUT, I2C1, I2C2, TIM15 */ 

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1); 
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1); 

    GPIO_Init(GPIOA, &GPIO_InitStructure); 

    /* I2C1 Reset */ 

    RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE); 
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE); 


    //I2C_DeInit(I2C1); 

    /* Configure I2C1 */ 

    I2C_StructInit(&I2C_InitStructure); 

    I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable; 
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; 
    I2C_InitStructure.I2C_OwnAddress1 = ownAddress; 
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; 
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; 

    I2C_Init(I2C1, &I2C_InitStructure); 
    I2C_Cmd(I2C1, ENABLE); 
    //I2C_AcknowledgeConfig(I2C1, ENABLE); 

} 

正如你可以看到我添加了兩行GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);在那裏我發現GPIO_AF_1有I2C1的備用功能從the STM32F0 Standard Peripheral bibliotheek

還有其他想法嗎?我一直在玩弄時鐘,看看是否改變了任何內容,並且已經添加了其他人的代碼片斷,只是爲了看看它是否對我的設備輸出有任何影響。

編輯3:我曾嘗試用1kΩ的電阻上拉SDA和SCL線至VCC通過本指南的指示:https://electronics.stackexchange.com/questions/57121/i2c-pullup-resistor-calculations

- >(3.3V-0.4)/3毫安〜=1kΩ的

編輯4:經過我的代碼行,我試着輸出各種標誌位寄存器。特別是這些寄存器:isr = I2C1->ISR;cr1 = I2C1->CR1;,並且cr2 = I2C1->CR2;

發起I2C傳輸與I2C_TransferHandling(I2C1, 0x02, 1, I2C_AutoEnd_Mode, I2C_Generate_Start_Write);處理後,我得到的標誌是0x8001可以破譯到兩個錯誤:

#define I2C_ISR_BUSY ((uint32_t)0x00008000) /*!< Bus busy */

#define I2C_ISR_TXE ((uint32_t)0x00000001) /*!< Transmit data register empty */

我找到了一些解決辦法在這裏的鏈接(刪除https後的空間:去鏈接 - >由於某種原因,堆棧溢出不會讓我發佈超過1個鏈接):https://my.st.com/public/STe2ecommunities/mcu /Lists/cortex_mx_stm32/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2Fcortex_mx_stm32%2FSTM32L151RB%20I2C%20Busy%20flag%20always%20set & FolderCTID = 0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B & currentviews = 690,我正在尋找實施和將只要我嘗試一下就回報。

+0

可能是一個愚蠢的問題。你有SDA和SDL上的pullups嗎?你運行這段代碼之前它們高嗎? – DoxyLover 2014-11-04 20:18:32

+0

嘿有DoxyLover, 試過這個,並沒有工作。在我運行此代碼之前,不要相信它們被設置得很高。 – Stroodlemuffin 2014-11-04 22:15:44

+0

你有什麼精確連接到I2C線?什麼是從屬設備?您是否知道每條I2C線和Vcc之間必須連接上拉電阻? – DoxyLover 2014-11-04 22:37:46

回答

0

問題是,您沒有爲I2C引腳配置適當的AF(備用功能)源。在配置AF的寄存器全部爲0並且I2C的功能爲1後,您的I2C外設實際上與GPIO斷開連接。

從技術上講,配置時沒有什麼區別,但在GPIO配置之前最好這樣做,以儘量減少引腳上的任何不需要的轉換。

編輯:您必須對I2C引腳上拉電阻 - 你有「低」的水平有沒有他們,和I2C周邊檢測到的總線錯誤,這顯然阻止其正常工作。要麼連接外部電阻,要麼至少啓用內部上拉,而不是「無上拉/無拉」配置。

此外 - 「漏極開路」引腳不能上拉無法正常工作。

+0

如果你指的是我的評論,那麼「must」這個詞不會出現在那裏,所以你不能說這個評論是誤導性的(事實上,你應該給這個評論一些信用,因爲你的答案是基本相同)。 – 2014-11-05 08:45:38

+0

好吧,我可能誤讀了「可能」的「必須」 - 這是早...(無論如何 - 你的評論並沒有解釋問題和解決方案,並可能(我不使用SPL作爲廢話)代碼是錯誤的 - 你應該給自動對焦源而不是「GPIO_Pin_9」 - 有一些像AF_SOURCE_I2C這樣的宏或者這樣的代碼 – 2014-11-05 09:08:26

+0

增加了這些代碼行;請參閱我上面編輯的迴應以獲取更新情況。 – Stroodlemuffin 2014-11-05 19:06:08

1

我有I2C作爲主站和從站的F0。我可以在代碼中看到的主要問題是,在主模式下,您必須設置初始化結構成員I2C_Timing。請參閱RM0091瞭解與您希望在SCL上生成的頻率相對應的樣本值。在從機模式下,時鐘從主機恢復,因此時序成員似乎不被使用。

正如其他人所說,外部上拉至Vcc在SCL和SDA是不可選的,當你錯誤地評論說必須出現一次,每個總線每外設。你正確的使用計算器來選擇合適的值,因爲在大約30-50K的STM32內部上拉電阻對於I2C上拉電路來說太弱。

+0

所以我發現了一些其他的代碼,所有的時序計算都已完成,並將此行插入到我的I2C總線設置中:'I2C_InitStructure.I2C_Timing = 0x50330309; // 400kHz'然而,SCL和SDA線路上仍然沒有收到任何信息。我現在只有一個主設備,並且有上拉功能,但我會記住,我只需要每個總線一個上拉電阻以供將來參考。 – Stroodlemuffin 2014-11-06 15:11:59

+0

現在來看看你的傳輸邏輯,指的是ST如何在他們的示例代碼中完成它。傳輸地址的基本僞代碼序列爲:I2C_TransferHandling() - >等待TXIS - > I2C_SendData(地址) - >等待TCR。 – 2014-11-06 15:52:01

+0

從理論上說,如果我是跳過等待TXIS和TCR位,將我的車不只是傳輸數據,而不管任何形式的確認從奴隸?到目前爲止,爲了簡單起見,我只在整個公共汽車上有一個主人,而只是試圖查看公共汽車是否會輸出某些東西。在我的主循環中,上面的代碼是不是很重要,只是爲了獲得我可以研究的範圍? – Stroodlemuffin 2014-11-06 16:11:17

0

Cortex M0的核心與Cortex M3的核心不同,STM32f030f4只有AHB和APB1(橋接)。 STM32f1xx的C代碼不能在STM32f0xx下運行。 使用STM32F0xx_Snippets_Package解決您的關鍵問題。

0

我注意到您正在將引腳映射到AF_1,這是針對UART函數。

GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1); 
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1); 

你需要將它們映射到AF_4使用I2C功能。

GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_4); 
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_4); 
0

我只注意到這個太:

RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE); 
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE); 

所以,你已經禁用了時鐘已啓用後。我沒有看到你以後重新啓用它的位置。