簡體   English   中英

i2c傳輸,stm32f103作為Master,STOP條件生成問題

[英]i2c transmission, stm32f103 as a Master, problem with STOP condition generation

我正在使用 KEIL。 這是我的 I2C 設置代碼。 我正在嘗試使用中斷來設置它。 實際上,像這樣一切正常。 但我唯一的問題是我做了一件奇怪的事情才能讓它工作。

// Variables passed to I2C1_EV_IRQHandler 
static volatile uint8_t counter=0;
static uint8_t slave_address=0, *data_buff,buff_num_bytes=0;

//I2c event and error interrupts setup
void I2C_NVIC_setup(void){
    NVIC->ISER[0] |=NVIC_ISER_SETENA_31; //I2C_IRQ_EV is at 31 position
    NVIC->ISER[1] |=NVIC_ISER_SETENA_0; //I2C_IRQ_ER is at 32 position
    NVIC->IP[31] &= ~0xF0;
    NVIC->IP[31]= (uint8_t)(0x5<<4);    //Event has lower priority
    NVIC->IP[32] &= ~0xF0;
    NVIC->IP[32]= (uint8_t)(0x4<<4);    //Error has higher priority
    __enable_irq();         //ENABLE interrupts
}

//GPIO settings for PB6 and PB7
void I2C_GPIO_init(void){
    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; //PORTB clock enable

    GPIOB->CRL |= GPIO_CRL_CNF6 |GPIO_CRL_CNF7;         //PB6 and PB7- open drain
    uint32_t buff=GPIOB->CRL;
    buff &= ~GPIO_CRL_MODE6 & ~GPIO_CRL_MODE7;  
    buff |= GPIO_CRL_MODE6_0 | GPIO_CRL_MODE7_0 ;   //2MHz maximum output speed
    GPIOB->CRL=buff; 
    //Dont care about ODR register
}

// Initialization of I2C
bool I2C_init(void){
I2C_GPIO_init();
    I2C_NVIC_setup();
    RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;

    I2C1->CR2 &= ~I2C_CR2_FREQ;
    I2C1->CR2 |= 0x14; //APB1 frequency is 20MHz

    I2C1->CCR |=  I2C_CCR_FS; //Fast mode
    I2C1->CCR |= I2C_CCR_DUTY;  //Duty cycle 16/9(for fast mode)

    I2C1->CCR &= ~I2C_CCR_CCR;
    I2C1->CCR |=    0x04;           //Thigh=1800ns Tlow=3200ns -200KHz frequency

    I2C1->TRISE &= ~I2C_TRISE_TRISE;
    I2C1->TRISE |= 0x07;    //300ns(max Trise)/50ns(Tclck) +1

    I2C1->CR1 |=    I2C_CR1_PE; //Enable peripheral

    I2C1->CR2 |= I2C_CR2_ITBUFEN; //Enable interupts of TxE and RxNE
    I2C1->CR2 |= I2C_CR2_ITEVTEN; //Enable event interupts
    I2C1->CR2 |= I2C_CR2_ITERREN; //Enable error interupts
}
//Master transmitter
bool I2C_transmit(uint8_t b7_address, uint8_t* data, uint8_t num_bytes){
    counter=num_bytes;
    buff_num_bytes=num_bytes;
    data_buff=data;
    slave_address=b7_address<<1 ;//To enter transmiter mode LSB=0

    I2C1->CR1 |= I2C_CR1_START; //Start condition
    while(counter || (I2C1->SR2 & I2C_SR2_MSL) || (I2C1->CR1 & I2C_CR1_STOP)){ //Stop bit is checked because of the problem I have
    }
}   
//IRQ I2C1 event handler
void I2C1_EV_IRQHandler(void){ //Handle the interrupt of I2C1
    uint8_t buff_sr1=I2C1->SR1;
    if(buff_sr1 & I2C_SR1_SB){ //SB bit is set(unsetting by read SR1 and writing adress to DR) 
        I2C1->DR=slave_address; 
    }else if(buff_sr1 & I2C_SR1_ADDR){ //ADDR bit is set(unsetting by read SR1 and read SR2)            
        (void)I2C1->SR2; 
    }
    if ((buff_sr1 & I2C_SR1_TXE)&& !(counter==0)){  //Checking TxE( clearing by writting to DR)
        I2C1->DR=data_buff[buff_num_bytes-counter];
        counter--;
    } else if((buff_sr1 & I2C_SR1_TXE)&&(buff_sr1 & I2C_SR1_BTF)){ //Checking stop 
      //condition(TxE=1,BTF=1,counter=0)
        (void)I2C1->SR1; //Dont know why, but it works(just read some I2C1 register)
        I2C1->CR1 |= I2C_CR1_STOP;  //Generate stop condition
    }

}

如果你看一下最后幾行:

    } else if((buff_sr1 & I2C_SR1_TXE)&&(buff_sr1 & I2C_SR1_BTF)){ //Checking stop 
      //condition(TxE=1,BTF=1,counter=0)
        (void)I2C1->SR1; //Dont know why, but it works(just read some I2C1 register)
        I2C1->CR1 |= I2C_CR1_STOP;  //Generate stop condition
    }

在這里,當我調試時(這段代碼,沒有行 (void)I2C1->SR1;),當我嘗試發送數據時,第一個包將毫無問題地發送。 最后,它會生成停止條件(MSL 位將被清除,並釋放線路),但 STOP 位將保持設置(這就是我在 I2C_transmit while 循環中檢查 STOP 位的原因)。 如果我在調試窗口中手動清除 STOP 位,它會繼續,但在下一個傳輸周期它不會產生正確的啟動(SB 將被設置,但 MSL 位將保持在復位狀態)。

在調試時,如果我將斷點放在這一行之前:

(請記住,此時我沒有找到解決此問題的方法,因此沒有此行,一切都一樣- (void)I2C1->SR1;)

I2C1->CR1 |= I2C_CR1_STOP;  //Generate stop condition

在那里停下來,檢查寄存器,然后繼續,一切正常。 我在stackexchage 上發現:

特別是關於讀取寄存器的部分會給你一個調試地獄,因為調試器的讀取會像讀取你的代碼一樣觸發狀態機,所以只要你停下來檢查寄存器(有時調試器會自動完成這一切) ) 讀取發生,外圍設備將再次執行某些操作。

很明顯,當我觸發STOP條件時,一些要求沒有得到滿足。 所以我決定檢查是否是這種情況,似乎這是一個解決方案。 添加對 I2C((void)I2C1->SR1; // 或任何其他 I2C 寄存器) 的任何寄存器的讀取,解決了問題。 一定有合乎邏輯的解釋,但我找不到。 我非常仔細地研究了參考手冊,結果是這段代碼,但我沒有找到任何可以解釋我這一點的東西。

這是參考手冊中關於主傳輸的表格,供您參考: 在此處輸入圖片說明

你能告訴我不滿足什么條件,所以我的STOP沒有正確處理。

好的,我剛剛根據此代碼將我的測試程序轉換為使用中斷驅動傳輸。 我的測試是在 STM32F411RE 上進行的,它具有與 F103 類似的 I2C 實現(其他系列如 F0xx、F3xx 和 F7xx 使用另一個 I2C 實現)。 無論如何,至少我可以確認沒有“(void)I2C1->SR1;” 在傳輸中斷處理程序中,它不起作用。 它僅在添加該行時有效。

該測試使用 I2C 擴展器芯片使 8x8 LED 矩陣閃爍,因此有 64*2+ I2C 傳輸調用來遍歷 LED 矩陣。

由於 F411RE 是最新的且比 F103 更新,我猜這是一個未記錄的要求!

現在至少在我的測試中,傳輸函數中不需要“(I2C1->CR1 & I2C_CR1_STOP)”。

I2C1->CR1|=0x0200;  // stop (bit 9 set for stop)
while(I2C1->SR2&0x0002);  // Bus busy

這兩條指令用於設置停止位和清除總線忙標志。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM