STM32F4 I2C kilitleniyor.

Başlatan baran123, 07 Temmuz 2015, 02:31:07

baran123

HTU21D ile sıcaklık ve nem ölçümü yapacağım fakat program maine gelmeyince breakpoint ile takip ettim.Önce şu işlemi yaparak HTU21D sensörüne yazılımsal reset attırıyorum.

HTU21D_Write(HTU21D_ADDRESS, HTU21D_SOFT_RESET, HTU21D_WRITE_ADDRESS);


Bu fonksiyon icabı ile program fonksiyonda takılı kalıyor.
/*******************************************************************************
* Function Name  : HTU21D_Write
* Description    :
* Input          : u8, u8, u8
* Return         : void
*******************************************************************************/
void HTU21D_Write(u8 slaveAddr, u8 buffer, u8 writeAddr)
{
    /* Send START condition */
    I2C_GenerateSTART(HTU21D_I2C, ENABLE);
    /* Test on EV5 and clear it */
    while(!I2C_CheckEvent(HTU21D_I2C, I2C_EVENT_MASTER_MODE_SELECT));
    /* Send HTU address for write */
    I2C_Send7bitAddress(HTU21D_I2C, slaveAddr, I2C_Direction_Transmitter);
    /* Test on EV6 and clear it */
    while(!I2C_CheckEvent(HTU21D_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    /* Send the HTU's internal address to write to */
    I2C_SendData(HTU21D_I2C, writeAddr);
    /* Test on EV8 and clear it */
    while(!I2C_CheckEvent(HTU21D_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    /* Send the byte to be written */
    I2C_SendData(HTU21D_I2C, buffer);
    /* Test on EV8 and clear it */
    while(!I2C_CheckEvent(HTU21D_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    /* Send STOP condition */
    I2C_GenerateSTOP(HTU21D_I2C, ENABLE);
}


Bu fonksiyonda şu satırda takılıyor.
while(!I2C_CheckEvent(HTU21D_I2C, I2C_EVENT_MASTER_MODE_SELECT));


Bunun kaynağına gittim.
I2C_CheckEvent()


ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)
{
  uint32_t lastevent = 0;
  uint32_t flag1 = 0, flag2 = 0;
  ErrorStatus status = ERROR;

  /* Check the parameters */
  assert_param(IS_I2C_ALL_PERIPH(I2Cx));
  assert_param(IS_I2C_EVENT(I2C_EVENT));

  /* Read the I2Cx status register */
  flag1 = I2Cx->SR1;
  flag2 = I2Cx->SR2;
  flag2 = flag2 << 16;

  /* Get the last event value from I2C status register */
  lastevent = (flag1 | flag2) & FLAG_MASK;

  /* Check whether the last event contains the I2C_EVENT */
  if ((lastevent & I2C_EVENT) == I2C_EVENT)
  {
    /* SUCCESS: last event is equal to I2C_EVENT */
    status = SUCCESS;
  }
  else
  {
    /* ERROR: last event is different from I2C_EVENT */
    status = ERROR;
  }
  /* Return status */
  return status;
}

if ve else ye breakpoint koydum program sürekli olarak "else" e düşüyor.
Haliyle
while(!I2C_CheckEvent(HTU21D_I2C, I2C_EVENT_MASTER_MODE_SELECT));

dedik true dönene kadar çıkmayacak.
Niye true dönmüyor ?
Where is the problem ?

Karamel

hocam i2c hakkinda pek deney yapmadim ama forumda CLR hocamizinin bu protocol ile calisirken cok dikkatli olunmasi gerektigini. takilma sorunlari yasanabilecegini anlatan bir yada birkac mesajini okumustum diye animsiyorum. hocamiz mesajlari gorunce ayrintili olarak bilgilendirir bileri.

Klein

STM32 serisinin sorun yaşadığım tek donanımı desem yeridir.  Her denememde başka başka sorunlarla boğuşmak zorunda kaldım. sonunda bıraktım. Bir ara bolca zamanım olduğunda tekrar açacağım o sayfayı.

baran123

Bende PIC de daha oncelerde beceremedim bu protokolu biraktim kaldi oyle.Simdi lazim oldu cozmeye calisiyorum gunlerdir boyle.SPI olaydi keskeee:)

CLR

stm32 I2C modülünü diğer modüllerden farklı olarak önce enable edip sonra registerlerine yazmak gerekiyor yani init etmek gerekiyor. Bu ST library'de modülü enable ederken yazıyor. 
Bu sorunla 2008'de ilk stm32 i2c ile uğraşırkan register formatlı program yazarken karşılaşmıştım, o zamanlar TR'de stm32 bilen çok az sayıda olduğu için ve register formatlı yazan en azından ben görmediğim için,
sebebini bir haftada bulabildim,  Aşağıya o zamnalar yazdığım initi ekledim. Programa uyarıyı yazmışım , modül önce enable edilmeli diye.

Modülü sonra enable edince bazı şeyleri düzgün yapıyor bazılarını düzgün yapmıyordu.

void
I2c_Init(void){
// i2c reset/set
    i2c1_reset();
    i2c1_enable();       
    
// port ayarları        
// SCK
    gpiob_crl.bits.MODE6=GpioMODE_50mhz_out;
    gpiob_crl.bits.CNF6=GpioCNF_AOD_out;
// SDA
    gpiob_crl.bits.MODE7=GpioMODE_50mhz_out;
    gpiob_crl.bits.CNF7=GpioCNF_AOD_out;

    
    gpiob_crl.bits.MODE4=GpioMODE_input;
    gpiob_crl.bits.CNF4=GpioCNF_PUPD_in_APP_out;
    
//  i2c1_cr1.bits.PE=1;
//  i2c1_cr1.bits.PE=0;         // flag'leri sil

/* 
Konfigürasyondan önce modul enable edilmeli yoksa düzgün çalışmıyor 
*/
    i2c1_cr1.bits.PE=1;         // I2c enable

// freq gir
    i2c1_cr2.bits.FREQ=pclk1;

// speed
    if(ds1337_speed<=100000){    
// Standard mode I2C (entegre datasheet'ten) Maximum Rise Time: 1000ns  
// 1000ns/35,71=28 bulunur (her zaman +1 eklenir) veya 
// Set Maximum Rise Time: ((1000/(1000000000/pclk1_full))+1 kısaca
// Set Maximum Rise Time:  pclk1+1 olur        
      i2c1_trise.bits.TRISE=pclk1+1;
      i2c1_ccr.b16.low=ds1337_std_ccr;
    }else{
        i2c1_ccr.b16.low=ds1337_fast_ccr;   // 
        i2c1_ccr.bits.F_S=1;                // fast mode


// Fast mode I2C (entegre datasheet'ten) Maximum Rise Time: 300ns 
// 300ns/35,71=8,4 (her zaman +1 eklenir)
// Set Maximum Rise Time: ((300/(1000000000/pclk1_full))+1 
// Set Maximum Rise Time: ((pclk1*300)/1000)+1
        i2c1_trise.bits.TRISE=ds1337_fast_trise;
    }
    
//  i2c1_oar1.bits.ADDMODE=0;               // 7bit
//  i2c1_oar1.bits.ADD0=0;                  // bit0 'a 0
    i2c1_oar1.bits.ADD1_7=(ds1337_adr>>1);
    i2c1_oar1.bits.KEEP_AT_1=1;             // bu bit 1 olmalı 

    i2c1_cr1.bits.ACK=1;                    // ack active
//    i2c1_cr1.bits.PE=1;                   // I2c enable
    i2c1_cr2.bits.ITERREN=1;
}


I2C_P_clock enable
I2C_module enable
I2C_Init
şeklinde olmalı

Bu düzeltmeden sonra çalıştı ama o sıralar ST dökümanlarını çok kurcalamıştım ve  ST, I2C ile çalışırkan I2C interrupt veya DMA öneriyordu, bende dma ile kullanmaya başladım. Sonrasında da sorun olmadı hiç.
DMA ile çalışılacak olsada modül önce enable edilmeli.

Tabii bu söylediklerim STM32F1xx serisinde, F4 seriside aynıdır diye düşünüyorum.

Ayrıca @baran'ın yaptığı gibi while ile ack beklersek sonsuza kadar beklemek zorunda kalabiliriz, doğru çalışan I2C modülünde bile çevresel şartlardan ack'da sorun olabilir, karşıdaki device ack gönderecek bir data almadıysa veya
bir sorun olduysa ack'yı asla göndermeyebilir. Timeout koymak gerekiyor.
Knowledge and Experience are Power

baran123

Hocam init işlemini ben şöyle yaptım.Aslında bir kütüphane oluşturmaya çalışıyorum.

htu.c
/*****************************************************************************

* File Name         : stm32f4xx_htu21d.c

* Description       : HTU21D - Read the Temperature and humidity

* Author            : Baran EKREM

*******************************************************************************/
#include "stm32f4xx_htu21d.h"

uint8_t TimeCounter = 0;
uint8_t Htu_Ready = 0;

/*******************************************************************************
* Function Name  : HTU21D_Init
* Description    :
* Input          : void
* Return         : void
*******************************************************************************/
void HTU21D_Init(void)
{
    GPIO_InitTypeDef    GPIO_InitStructure;
    I2C_InitTypeDef     I2C_InitStructure;

    GPIO_InitStructure.GPIO_Mode   = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType  = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd   = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Speed  = GPIO_Speed_100MHz;

    if(HTU21D_I2C == I2C1)
    {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_I2C1);
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_I2C1);
    }

    if(HTU21D_I2C == I2C2)
    {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
        GPIO_Init(GPIOB, &GPIO_InitStructure);

        GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_I2C2);
        GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_I2C2);
    }

    if(HTU21D_I2C == I2C3)
    {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C3, ENABLE);
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
        GPIO_Init(GPIOF, &GPIO_InitStructure);

        GPIO_PinAFConfig(GPIOF, GPIO_PinSource10, GPIO_AF_I2C3);
        GPIO_PinAFConfig(GPIOF, GPIO_PinSource11, GPIO_AF_I2C3);
    }

    I2C_DeInit(HTU21D_I2C);

    I2C_InitStructure.I2C_Ack                   = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress   = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed            = 10000;
    I2C_InitStructure.I2C_DutyCycle             = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_Mode                  = I2C_Mode_I2C;
    I2C_InitStructure.I2C_OwnAddress1           = 0x30;

    I2C_Init(HTU21D_I2C, &I2C_InitStructure);
    I2C_Cmd(HTU21D_I2C, ENABLE);
    I2C_AcknowledgeConfig(HTU21D_I2C, ENABLE);

    HTU21D_SoftwareReset();
}

/*******************************************************************************
* Function Name  : HTU21D_SoftwareReset
* Description    :
* Input          : void
* Return         : void
*******************************************************************************/
void HTU21D_SoftwareReset(void)
{
    HTU21D_Write(HTU21D_ADDRESS, HTU21D_SOFT_RESET, HTU21D_WRITE_ADDRESS);
}

/*******************************************************************************
* Function Name  : HTU21D_Write
* Description    :
* Input          : u8, u8, u8
* Return         : void
*******************************************************************************/
void HTU21D_Write(u8 slaveAddr, u8 buffer, u8 writeAddr)
{
    /* Send START condition */
    I2C_GenerateSTART(HTU21D_I2C, ENABLE);
    /* Test on EV5 and clear it */
    while(!I2C_CheckEvent(HTU21D_I2C, I2C_EVENT_MASTER_MODE_SELECT));
    /* Send HTU address for write */
    I2C_Send7bitAddress(HTU21D_I2C, slaveAddr, I2C_Direction_Transmitter);
    /* Test on EV6 and clear it */
    while(!I2C_CheckEvent(HTU21D_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    /* Send the HTU's internal address to write to */
    I2C_SendData(HTU21D_I2C, writeAddr);
    /* Test on EV8 and clear it */
    while(!I2C_CheckEvent(HTU21D_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    /* Send the byte to be written */
    I2C_SendData(HTU21D_I2C, buffer);
    /* Test on EV8 and clear it */
    while(!I2C_CheckEvent(HTU21D_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    /* Send STOP condition */
    I2C_GenerateSTOP(HTU21D_I2C, ENABLE);
}

/*******************************************************************************
* Function Name  : HTU21D_Read
* Description    :
* Input          : u8, u8*, u8, u16
* Return         : void
*******************************************************************************/
void HTU21D_Read(u8 slaveAddr, u8* buffer, u8 readAddr, u16 NumByteToRead)
{
    /* While the bus is busy */
    while(I2C_GetFlagStatus(HTU21D_I2C, I2C_FLAG_BUSY));
    /* Send START condition */
    I2C_GenerateSTART(HTU21D_I2C, ENABLE);
    /* Test on EV5 and clear it */
    while(!I2C_CheckEvent(HTU21D_I2C, I2C_EVENT_MASTER_MODE_SELECT));
    /* Send MPU6050 address for write */
    I2C_Send7bitAddress(HTU21D_I2C, slaveAddr, I2C_Direction_Transmitter);
    /* Test on EV6 and clear it */
    while(!I2C_CheckEvent(HTU21D_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    /* Clear EV6 by setting again the PE bit */
    I2C_Cmd(HTU21D_I2C, ENABLE);
    /* Send the MPU6050's internal address to write to */
    I2C_SendData(HTU21D_I2C, readAddr);
    /* Test on EV8 and clear it */
    while(!I2C_CheckEvent(HTU21D_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    /* Send STRAT condition a second time */
    I2C_GenerateSTART(HTU21D_I2C, ENABLE);
    /* Test on EV5 and clear it */
    while(!I2C_CheckEvent(HTU21D_I2C, I2C_EVENT_MASTER_MODE_SELECT));
    /* Send MPU6050 address for read */
    I2C_Send7bitAddress(HTU21D_I2C, slaveAddr, I2C_Direction_Receiver);
    /* Test on EV6 and clear it */
    while(!I2C_CheckEvent(HTU21D_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
    /* While there is data to be read */
    while(NumByteToRead)
    {
        if(NumByteToRead == 1)
        {
            /* Disable Acknowledgement */
            I2C_AcknowledgeConfig(HTU21D_I2C, DISABLE);
            /* Send STOP Condition */
            I2C_GenerateSTOP(HTU21D_I2C, ENABLE);
        }
        /* Test on EV7 and clear it */
        if(I2C_CheckEvent(HTU21D_I2C, I2C_EVENT_MASTER_BYTE_RECEIVED))
        {
            /* Read a byte from the MPU6050 */
            *buffer = I2C_ReceiveData(HTU21D_I2C);
            /* Point to the next location where the byte read will be saved */
            buffer++;
            /* Decrement the read bytes counter */
            NumByteToRead--;
        }
    }
    /* Enable Acknowledgement to be ready for another reception */
    I2C_AcknowledgeConfig(HTU21D_I2C, ENABLE);
}

/*******************************************************************************
* Function Name  : HTU21D_ReadTemperature
* Description    : !!! bitmedi !!!
* Input          : void
* Return         : float
*******************************************************************************/
float HTU21D_ReadTemperature(void)
{
    float temperature;
    unsigned int ValueTemp;

	temperature = (-46.85 + 175.72 * (ValueTemp / 65536.0));
	return temperature;
}

/*******************************************************************************
* Function Name  : HTU21D_ReadHumidity
* Description    : !!!! bitmedi !!!!
* Input          : void
* Return         : float
*******************************************************************************/
float HTU21D_ReadHumidity(void)
{
    float humidity;
    unsigned int ValueTemp;

	humidity = (-6.0 + 125.0 * (ValueTemp / 65536.0));
	return humidity;
}


htu.h
/*****************************************************************************

* File Name         : stm32f4xx_htu21d.h

* Description       : Header file for main.c

* Author            : Baran EKREM

*******************************************************************************/
#ifndef STM32F4XX_HTU21_H
#define STM32F4XX_HTU21_H

#include "stm32f4xx_conf.h"

#define HTU21D_I2C	                I2C1    /* HTU I2C Modul define */

#define HTU21D_ADDRESS              0x40	/* Read user register   */
#define HTU21D_WRITE_ADDRESS        0xE6	/* Write user register  */
#define HTU21D_READ_ADDRESS         0xE7    /* Read  user register  */
#define HTU21D_SOFT_RESET  	        0xFE    /* Reset Command        */

void HTU21D_Init(void);
void HTU21D_SoftwareReset(void);
void HTU21D_Write(u8 slaveAddr, u8 buffer, u8 writeAddr);
void HTU21D_Read(u8 slaveAddr, u8* buffer, u8 readAddr, u16 NumByteToRead);

float HTU21D_ReadHumidity(void);
float HTU21D_ReadTemperature(void);

extern uint8_t TimeCounter, Htu_Ready;

#endif

muhittin_kaplan

i2c ile çalışıpta hata almadığım olmamıştır. bencede en problemli ünitesi.

sseedat

Start oluşturmadan önce i2c busy durumunu kontrol etmediğinizden dolayı olabilirmi?

while(I2Cx->SR2&0x02) //I2Cx kullandığın i2c
{
   
}
I2C_GenerateSTART(HTU21D_I2C, ENABLE);
Görünmez bir mezarlıktır Zaman...

Mucit23

Alıntı yapılan: muhittin_kaplan - 07 Temmuz 2015, 12:23:08
i2c ile çalışıpta hata almadığım olmamıştır. bencede en problemli ünitesi.

++

baran123

Ne çekmişsiniz bu I2C dende haberimiz yok imiş :)
@sseedat şimdide o satırda kitleniyor.

sseedat

 i2c busy flag'e takılıyor gibi.

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

    clock speed'in 100khz olacak şekilde denermisin. Sorunu çözermi bilmiyorum ama dikkatimi çekti.
 

Görünmez bir mezarlıktır Zaman...

baran123

Onunla bir alakası olacağını sanmıyorum ama yinede denedim olmadı.Sanırım protokol de kaçırdığım bir nokta var.

CLR

@baran

Mesajımda yazdım, hatta örnek verdim ama sanırım hiç okumamışsın. Eğer başka hata yoksa aşağıdaki durumdan kaynaklanıyor.

// Bu yanlış 
I2C_Init(HTU21D_I2C, &I2C_InitStructure);
I2C_Cmd(HTU21D_I2C, ENABLE);

// doğrusu
I2C_Cmd(HTU21D_I2C, ENABLE);
I2C_Init(HTU21D_I2C, &I2C_InitStructure);

Knowledge and Experience are Power

baran123

Yok hocam okudum estağfurullah.Denedim fakat olmadı. :/

CLR

belki stm32f4'te bu durumu düzeltmişlerdir, F1xx serinde ST'nin uyarısı aşağıdaki gibi

Workaround 1
Use the I2C with DMA in general, except when the Master is receiving a single byte.
Knowledge and Experience are Power