Haberler:

Eposta uyarılarını yanıtlamayınız ( ! ) https://bit.ly/2J7yi0d

Ana Menü

Cortex ve I2C

Başlatan muhittin_kaplan, 02 Temmuz 2013, 22:41:39

muhittin_kaplan

#15
Tekrar Dönelim Geriye,,

I2C ile F4 discovery Kart la, Master ve Slave çalışacak vaziyette iki I2C kurarak Jojik Analizörden gözlemlemek istiyorum,
I2C de Problem Yaşıyor ve çözemiyorum. iyice Kavramam Gerek..

mesaj birleştirme:: 28 Aralık 2013, 16:15:09

#include <stm32f4xx.h>
#include <stm32f4xx_gpio.h>
#include <stm32f4xx_rcc.h>
#include <stm32f4xx_i2c.h>


#define SLAVE_ADDRESS 0x3D // the slave address (example)

void init_I2C1(void){

	GPIO_InitTypeDef GPIO_InitStruct;
	I2C_InitTypeDef I2C_InitStruct;

	// enable APB1 peripheral clock for I2C1
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
	// enable clock for SCL and SDA pins
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

	/* setup SCL and SDA pins
	 * You can connect I2C1 to two different
	 * pairs of pins:
	 * 1. SCL on PB6 and SDA on PB7
	 * 2. SCL on PB8 and SDA on PB9
	 */
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // we are going to use PB6 and PB7
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;			// set pins to alternate function
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;		// set GPIO speed
	GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;			// set output to open drain --> the line has to be only pulled low, not driven high
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;			// enable pull up resistors
	GPIO_Init(GPIOB, &GPIO_InitStruct);					// init GPIOB

	// Connect I2C1 pins to AF
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);	// SCL
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1); // SDA

	// configure I2C1
	I2C_InitStruct.I2C_ClockSpeed = 100000; 		// 100kHz
	I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;			// I2C mode
	I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;	// 50% duty cycle --> standard
	I2C_InitStruct.I2C_OwnAddress1 = 0x00;			// own address, not relevant in master mode
	I2C_InitStruct.I2C_Ack = I2C_Ack_Disable;		// disable acknowledge when reading (can be changed later on)
	I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // set address length to 7 bit addresses
	I2C_Init(I2C1, &I2C_InitStruct);				// init I2C1

	// enable I2C1
	I2C_Cmd(I2C1, ENABLE);
}

/* This function issues a start condition and
 * transmits the slave address + R/W bit
 *
 * Parameters:
 * 		I2Cx --> the I2C peripheral e.g. I2C1
 * 		address --> the 7 bit slave address
 * 		direction --> the tranmission direction can be:
 * 						I2C_Direction_Tranmitter for Master transmitter mode
 * 						I2C_Direction_Receiver for Master receiver
 */
void I2C_start(I2C_TypeDef* I2Cx, uint8_t address, uint8_t direction){
	// wait until I2C1 is not busy anymore
	while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));

	// Send I2C1 START condition
	I2C_GenerateSTART(I2Cx, ENABLE);

	// wait for I2C1 EV5 --> Slave has acknowledged start condition
	while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));

	// Send slave Address for write
	I2C_Send7bitAddress(I2Cx, address, direction);

	/* wait for I2C1 EV6, check if
	 * either Slave has acknowledged Master transmitter or
	 * Master receiver mode, depending on the transmission
	 * direction
	 */
	if(direction == I2C_Direction_Transmitter){
		while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
	}
	else if(direction == I2C_Direction_Receiver){
		while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
	}
}

/* This function transmits one byte to the slave device
 * Parameters:
 *		I2Cx --> the I2C peripheral e.g. I2C1
 *		data --> the data byte to be transmitted
 */
void I2C_write(I2C_TypeDef* I2Cx, uint8_t data)
{
	I2C_SendData(I2Cx, data);
	// wait for I2C1 EV8_2 --> byte has been transmitted
	while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}

/* This function reads one byte from the slave device
 * and acknowledges the byte (requests another byte)
 */
uint8_t I2C_read_ack(I2C_TypeDef* I2Cx){
	// enable acknowledge of recieved data
	I2C_AcknowledgeConfig(I2Cx, ENABLE);
	// wait until one byte has been received
	while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
	// read data from I2C data register and return data byte
	uint8_t data = I2C_ReceiveData(I2Cx);
	return data;
}

/* This function reads one byte from the slave device
 * and doesn't acknowledge the recieved data
 */
uint8_t I2C_read_nack(I2C_TypeDef* I2Cx){
	// disabe acknowledge of received data
	// nack also generates stop condition after last byte received
	// see reference manual for more info
	I2C_AcknowledgeConfig(I2Cx, DISABLE);
	I2C_GenerateSTOP(I2Cx, ENABLE);
	// wait until one byte has been received
	while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
	// read data from I2C data register and return data byte
	uint8_t data = I2C_ReceiveData(I2Cx);
	return data;
}

/* This funtion issues a stop condition and therefore
 * releases the bus
 */
void I2C_stop(I2C_TypeDef* I2Cx){
	// Send I2C1 STOP Condition
	I2C_GenerateSTOP(I2Cx, ENABLE);
}

int main(void){

	init_I2C1(); // initialize I2C peripheral

	uint8_t received_data[2];

	while(1){

		I2C_start(I2C1, SLAVE_ADDRESS<<1, I2C_Direction_Transmitter); // start a transmission in Master transmitter mode
		I2C_write(I2C1, 0x20); // write one byte to the slave
		I2C_write(I2C1, 0x03); // write another byte to the slave
		I2C_stop(I2C1); // stop the transmission

		I2C_start(I2C1, SLAVE_ADDRESS<<1, I2C_Direction_Receiver); // start a transmission in Master receiver mode
		received_data[0] = I2C_read_ack(I2C1); // read one byte and request another byte
		received_data[1] = I2C_read_nack(I2C1); // read one byte and don't request another byte, stop transmission
	}
}


ile nedense 3d olan adres analizörde 7a olarak görünüyor (sola kaydırıyor start da)
Sebep ?

z

En saga R/W biti ekleniyor.

-------------------------------------------------

STM32F4 de I2C yi register erisimi ile kullanan varmi?
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

muhittin_kaplan

bir ara bende low level kod aradım nedir diye.
ama sonra kütüphneyi inceledim.
belki kütüphanesinden birşeyler çıkartırsın.

http://www.coocox.org/repo/25ae8068-c084-4524-9538-6dfce062fab3/src/STM32F4-FreeRTOS-Demo1/Test1/Libraries/STM32F4xx_StdPeriph_Driver/src/stm32f4xx_i2c.c.htm

Mucit23

Aynı şekilde STM32F10x low level I2C rutinlerini kullanmıştım.

I2C.c
/******************************************************************************/
/* I2C_STM32.c: STM32 low level I2C routines                                  */
/******************************************************************************/
/* This file is part of the uVision/ARM development tools.                    */
/* Copyright (c) 2005-2009 Keil Software. All rights reserved.                */
/* This software may only be used under the terms of a valid, current,        */
/* end user licence from KEIL for a compatible version of KEIL software       */
/* development tools. Nothing else gives you the right to use this software.  */
/******************************************************************************/

#include "I2C.h"

/************************ Local auxiliary functions ***************************/

/*******************************************************************************
* I2C communication status                                                     *
*   Parameter:                                                                 *
*   Return:               status                                               *
*******************************************************************************/

static __inline unsigned int I2C_sr (void) {
  unsigned int sr;

  sr  = I2C1->SR1;
  sr |= I2C1->SR2 << 16;
  return (sr);
}

/************************ Exported functions **********************************/

/*******************************************************************************
* Initialize I2C interface in master mode                                      *
*   Parameter:                                                                 *
*   Return:                                                                    *
*******************************************************************************/

void I2C_Setup (void) {
  unsigned int tout;

  /* Enable clock for I2C1, GPIOB and AFIO                                    */
  RCC->APB2ENR |= (1 << 3) | (1 << 0); //
  RCC->APB1ENR |= (1 << 21);

  /* I2C1 pins remapped, use PB8, PB9                                         */
  AFIO->MAPR   |= 0x00000002;  // Remap=1: (SCL/PB8, SDA/PB9)
  GPIOB->CRH   |= 0x000000FF;  // Alternate IO PB8 and PB9

  I2C1->CR1     = 0x8000;               /* Reset I2C peripheral               */
  for (tout = 1000000; tout; tout--);
  I2C1->CR1     = 0x0000;

  /* Configure I2C peripheral                                                 */
  I2C1->CR1     = 0x0001;		// PE - Peripheral Enable
  I2C1->CR2     = 0x0024;	  	// Freq 36 MHz
  I2C1->CR1     = 0x0000; 		// PE Disable
  I2C1->TRISE   = 0x0025;  		//Time Rise - program when PE=0 
  I2C1->CCR     = 0x00B4;  		// 0x005A = 400 KHz (36MHz / 90) 	0x00B4 = 200 KHz
  I2C1->CR1    |= 0x0401;
  I2C1->OAR1    = 0x40A0;
}


/*******************************************************************************
* Generate start condition on I2C bus                                          *
*   Parameter:                                                                 *
*   Return:                                                                    *
*******************************************************************************/

void I2C_Start (void) {
if ( I2C1->CR1 & ( 1 << 10 ) ) {
		I2C1->CR1 &= ~(1 << 10 );
	} 
  I2C1->CR1 |= 0x0100; //start genneration when bus free
  while (!(I2C_sr() & 0x0001));
}

/*******************************************************************************
* Generate stop condition on I2C bus                                           *
*   Parameter:                                                                 *
*   Return:                                                                    *
*******************************************************************************/

void I2C_Stop (void) {

  I2C1->CR1 |= 0x0200;
  while (I2C_sr() & 0x00020000);        /* Wait until BUSY bit reset          */
}


/*******************************************************************************
* Write address on I2C interface                                               *
*   Parameter:    adr:    address to be written                                *
*   Return:                                                                    *
*******************************************************************************/

void I2C_Addr (unsigned char adr) {

  I2C1->DR = adr;
  while (!(I2C_sr() & 0x0002));	//Addr sent 
}


/*******************************************************************************
* Write a byte to I2C interface                                                *
*   Parameter:    c:      data to be written                                   *
*   Return:                                                                    *
*******************************************************************************/

void I2C_Write (unsigned char c) {

  I2C1->DR = c;
  while (!(I2C_sr() & 0x00000004));     /* Wait until BTF bit set             */ 
}


/*******************************************************************************
* Read a byte from I2C interface                                               *
*   Parameter:                                                                 *
*   Return:               read data                                            *
*******************************************************************************/

unsigned char I2C_Read (int ack) {

  /* Enable/disable Master acknowledge                                        */
  if (ack) I2C1->CR1 |=  0x0400;
  else     I2C1->CR1 &= ~0x0400;

  while (!(I2C_sr() & 0x00000040));     /* Wait until RxNE bit set            */
  return (I2C1->DR);
}

/******************************************************************************/

unsigned char I2C_getbyte(unsigned char address, unsigned char cmd) {
	unsigned char uc;
	I2C_Start();		  	// Initial Start bit sequence
	I2C_Addr(address);	 	// Address I2C Device. (Base address is Write Address)
	I2C_Write(cmd);			// Transfer Command to I2C Device (Register to be Read) 
	I2C_Start(); 			// Repeated start bit sequence
	I2C_Addr(address+1);	// Address I2C Device. (Base address + 1 is Read Address)
	uc = I2C_Read(0);		// Read 1 byte without Acknowledge
	I2C_Stop();				// Stop I2C transfer
	return( uc );
}

unsigned short int I2C_getword(unsigned char address, unsigned char cmd) {
	unsigned short int uw;
	//unsigned short int uw2;
	I2C_Start();		  	// Initial Start bit sequence
	I2C_Addr(address);	 	// Address I2C Device. (Base address is Write Address)
	I2C_Write(cmd);			// Transfer Command to I2C Device (Register to be Read) 
	I2C_Start(); 			// Repeated start bit sequence
	I2C_Addr(address+1);	// Address I2C Device. (Base address + 1 is Read Address)
	uw = I2C_Read(1) << 8;		// Read MSB  without Acknowledge
	uw |= I2C_Read(0); 			// Read LSB	 with Acknowledge
	I2C_Stop();				// Stop I2C transfer
	return( uw );
}
void I2C_putbyte(unsigned char address, unsigned char cmd, unsigned char data) {
	I2C_Start();		  	// Initial Start bit sequence
	I2C_Addr(address);	 	// Address I2C Device. (Base address is Write Address)
	I2C_Write(cmd);			// Transfer Command to I2C Device (Register to be Read) 
	I2C_Write(data);		// Transfer Data to I2C device
	I2C_Stop();				// Stop I2C transfer
}

int I2C_getbytearray(unsigned char address, unsigned char cmd, int number, unsigned char *data) {
	int count;
	I2C_Start();		  	// Initial Start bit sequence
	I2C_Addr(address);	 	// Address I2C Device. (Base address is Write Address)
	I2C_Write(cmd);			// Transfer Command to I2C Device (Register to be Read) 
	I2C_Start(); 			// Repeated start bit sequence
	I2C_Addr(address+1);	// Address I2C Device. (Base address + 1 is Read Address)
	// Read number - 1 bytes with Acknowledge
	for ( count=0; count < number - 2; count++ ) {
		data[count] = I2C_Read(1);		// Read with Acknowledge
	}
	data[count] = I2C_Read(0);		// Last byte without Acknowledge
	I2C_Stop();				// Stop I2C transfer
	return( count+1 );
}


I2C.h

/******************************************************************************/
/* I2C.h: I2C function prototypes                                             */
/******************************************************************************/
/* This file is part of the uVision/ARM development tools.                    */
/* Copyright (c) 2005-2009 Keil Software. All rights reserved.                */
/* This software may only be used under the terms of a valid, current,        */
/* end user licence from KEIL for a compatible version of KEIL software       */
/* development tools. Nothing else gives you the right to use this software.  */
/******************************************************************************/

#include "stm32f10x_lib.h"
#include <stdint.h>

#ifndef _I2C_H
#define _I2C_H

extern void          I2C_Setup  (void);
extern void          I2C_Start  (void);
extern void          I2C_Stop   (void);
extern void          I2C_Addr   (unsigned char adr);
extern void          I2C_Write  (unsigned char c);
extern unsigned char I2C_Read   (int ack);
extern unsigned char I2C_getbyte(unsigned char address, unsigned char cmd);
extern void I2C_putbyte(unsigned char address, unsigned char cmd, unsigned char data);
extern unsigned short int I2C_getword(unsigned char address, unsigned char cmd);
#endif /* _I2C_H */

z

2 gundur ugrasiyorum hala I2C den data yollayamadim.

Registerleri init ediyorum.

Start diyorum, Data ve Clk hatti low'a iniyor. Start durumu olusuyor.

Daha sonra gonderilecek adres bilgisini DR registerine yukluyorum. Byte transfer finished flagi set olmuyor. Dogrudan Acknowledge fail biti set oluyor.

Isin ilginci scopla clk hattina bahtigimda clk vs de gitmiyor.

Cok temel bir hata yapiyorum ama bulamadim.

OAR1 ve OAR2 registerlerinin master modda onemi varmi? Bana bunlar sadece slvae modunda kendi adresimizi tanimlamak icin kullanilacaklar gibi geliyor.

Kendi yazdigim kodlar bu sekilde davraniyor. Mucit23'un verdigi kodlar da ayni sekilde davraniyor.

Muhittinkaplanin verdigi kutuphanede define ile tanitilmis oldugunu dusundugum bazi veriler elimde olmadigi icin onu kullanmadim.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

ErsinErce

I2C_OAR1, I2C_OAR2  bağlanacağınız adresi girdiğiniz yer hocam

z

Ben dediginden emin değilim.

Bu registerler sanki STM32F4 slave bir I2C cihaz olacak ise bu registerlere bize ulasilmasini istedigimiz adresleri yazacagiz gibi geliyor.

Biz master iken slave cihaza adresi gene i2C->DR register uzerinden yolluyoruz.

Fakat start ile clk low olduktan sonra DR registerine yazdigimda neden I2C den clock cikmiyor anlamadim.

Sen OAR1 ve OAR2 nin biz master iken kullanilacagindan eminmisin?
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

ErsinErce

#22
master iken erişeceğimiz adres
slave iken kendi adresimiz
hatta I2C_SR1 içeriğine bakarsak ADDR biti master modda gönderildi, slave modda match uyarısı için kullanılıyor

OAR1 ve OAR2 den ayrıca 7-10 bit adres seçimini ayarlamak gerekiyor, diyor datasheet te

buradaki akış ve event oluşumu için harici bir register gerekli ztn



Alıntı YapMaster transmitter
Following the address transmission and after clearing ADDR, the master sends bytes from
the DR register to the SDA line via the internal shift register.
The master waits until the first data byte is written into I2C_DR (see Figure 213 Transfer
sequencing EV8_1).
When the acknowledge pulse is received, the TxE bit is set by hardware and an interrupt is
generated if the ITEVFEN and ITBUFEN bits are set.
If TxE is set and a data byte was not written in the DR register before the end of the last data
transmission, BTF is set and the interface waits until BTF is cleared by a write to I2C_DR,
stretching SCL low.
Closing the communication
After the last byte is written to the DR register, the STOP bit is set by software to generate a
Stop condition (see Figure 213 Transfer sequencing EV8_2). The interface automatically
goes back to slave mode (M/SL bit cleared).
Note: Stop condition should be programmed during EV8_2 event, when either TxE or BTF is set.


fakat kendi kütüphanesinde dediğiniz gibi DR den direk gönderiyor, kafam karıştı

void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction)
{
  /* Check the parameters */
  assert_param(IS_I2C_ALL_PERIPH(I2Cx));
  assert_param(IS_I2C_DIRECTION(I2C_Direction));
  /* Test on the direction to set/reset the read/write bit */
  if (I2C_Direction != I2C_Direction_Transmitter)
  {
    /* Set the address bit0 for read */
    Address |= I2C_OAR1_ADD0;
  }
  else
  {
    /* Reset the address bit0 for write */
    Address &= (uint8_t)~((uint8_t)I2C_OAR1_ADD0);
  }
  /* Send the address */
  I2Cx->DR = Address;
}


Bu adreste çalışan bir örnek mevcut gibi gözüküyor hocam kendi kodlarınızla karşılaştırmada kullanabilirsiniz belki
http://www.electroons.com/blog/2013/01/hello-world/

berat23

yanılmıyorsam yollanacak adres byte'ını start vermeden önce yazmanız lazım

muhittin_kaplan

Hocam Aşağıdaki kodlar I2cEpromla İletişim Sağlayan Kodlar ve çalışıyor.

http://www.dosya.tc/server22/WVmOni/Sym32f4_i2c_eeprom.rar.html

z

#25
Kabus bitti.

Uzerinde fazla durmadigim CLK frekans degerleri ve I2C_TRISE register degeri 3 gundur ot yoldurtuyormus.

Artik clock sinyali pinde belirdi.

Olay su sekilde;

I2C yi 42 Mhz ile besliyoruz.  Bu durumda I2C_CR2 registerinin ilk alti bitine 42 yaziyoruz.

I2C clk frekansi 400Khz olsun.

Standart modda Duty bitimiz 0 olsun.

Bu sartlarda I2C_CCR degerimiz  42E6/(2x400000)=52.5 olur. 53 yuklersek tersden gidelim I2C clk frekansimiz 396 Khz olacaktir.

Ilk asamada clk frekansiyla vs ilgilenmedigim icin (amac scopla pulslari gozlemlemekti) frekans degerleri ve rise time degerini sallama belirlemistim.

Frekans ne olursa olsun clk pininden clock sinyalini gormeyi umuyordum.

Bana e^st de diyebilirsiniz.   www.cncdesigner.com

z

Kabus bitmedi.

Simdi de 24LC64 de sorun yasamaya basladim.

Bu I2C ile ugrasanlar  bu donanimla ilgili bir sekilde yasamis galiba.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

z

Bana e^st de diyebilirsiniz.   www.cncdesigner.com

muhittin_kaplan


z

Evet o mesajları okusaymışım daha önce uyanacakmışım. Aslında bilinen şey ama eşeklik işte.

Şimdi bundan sonrasına, delay ile değil de peş peşe sorgulama yaparak ACK gelip gelmediğine bakmak suretiyle devam edeceğim.

Bu arada;

I2C donanımına ait interruptlar açılmadan bu donanım kullanılırsa hardware kullanmanın hiç ama hiç bir esprisi yok. Soft I2C yapmakla hemen hemen aynı şey.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com