Jump to content


Photo

Problema de comunicare pe i2c


  • Please log in to reply
3 replies to this topic

#1 OFFLINE   moro

moro

    Membru avansat

  • Membri
  • PipPipPipPip
  • 1,027 posts

Posted 12 May 2014 - 08:32 AM

Va salut, de 2 zile ma chinui sa fac un stm32f4 sa "vorbeasca" cu un senzor bmp085 pe i2c, dupa ce am incercat de la propriile initializari ale registrilor , precum si diferite exemple de pe net, la care ma voi opri cu urmatorul cod postat jos ( sursa )

 

Ideea e ca luand la puricat cu analizorul logic, nu se intampla nimic pe SDA si SCL, pentru moment am incercat doar sa trimit date catre senzor cu el/fara scos din montaj

 

In schimb daca pastrez aceiasi parametrii de initializare a gpio`ului si i2c si fac o bucla doar cu start si stop, pe sda si scl vad intradevar semnalele de start si stop, precum si clock-ul ok.

 

while(1) {

I2C_GenerateSTART(I2C1, ENABLE);

I2C_GenerateSTOP(I2C1, ENABLE);

 

}

 

 

Din ce am citit pe net, initializarea i2c-ului la arm... e mai buclucasa...

Codul il scriu in IAR 6.30, n-am nici o eroare la compilare, debuggerul merge... totul e atza.... Imi scapa ceva?

#include <stm32f4xx.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
}
}


Cu_reclama

Cu_reclama
  • Membri

#2 OFFLINE   Liviu M

Liviu M

    -

  • Membri
  • PipPipPipPipPip
  • 3,076 posts
  • Locatie:In sat cu Doru

Posted 12 May 2014 - 09:44 PM

Cel putin la M0 (cu care m-am jucat eu), I2C1 mai are nevoie de o setare pentru ceas. Rutina mea (pentru stm32f0 si testata cu I2C2) arata ca mai jos. Codul e scris in arm-gcc... (compilatorul oficial arm). Poti incerca sa folosesti rezistente pull-up externe, la mine parca n-a mers fara (desi nu mai sunt sigur).

void vInitI2C(I2C_TypeDef* I2Cx) {
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;

I2C_DeInit(I2Cx);  //clear any previous settings

//I2C1 & I2C2 have different configurations
if (I2Cx == I2C1) {
// Set I2C1 clock to SYSCLK (see system_stm32f0.c)
RCC_I2CCLKConfig(RCC_I2C1CLK_SYSCLK);

//(#) Enable peripheral clock using
// RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2Cx, ENABLE)
//    function for I2C1 or I2C2.
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

//(#) Enable SDA, SCL  and SMBA (when used) GPIO clocks using
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);

//(#) Peripherals alternate function:
//    (++) Connect the pin to the desired peripherals' Alternate
GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_1); //If I2C1, then PB8 && PB9
GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_1);

// i2c pins open collector & PullUp enabled
GPIO_StructInit(&GPIO_InitStructure); //reset the GPIO_InitStructure to the default values
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; //If I2C1, then PB8 && PB9
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //activate the internal pullup. For i2c communication should be enough
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; //for i2c should use the open drain outputs
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
} else if (I2Cx == I2C2) {
//(#) Enable peripheral clock using
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);

//(#) Enable SDA, SCL  and SMBA (when used) GPIO clocks using
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);

//(#) Peripherals alternate function:
//    (++) Connect the pin to the desired peripherals' Alternate
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_1); //If I2C1, then PB8 && PB9
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_1);

// i2c pins open collector & PullUp enabled
GPIO_StructInit(&GPIO_InitStructure); //reset the GPIO_InitStructure to the default values
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; //If I2C1, then PB8 && PB9
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //activate the internal pullup. For i2c communication should be enough
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; //for i2c should use the open drain outputs
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
} // else if (I2Cx == I2C2)

// Settings common for both port types
//(#) Program the Mode, Timing , Own address, Ack and Acknowledged
//    Address using the I2C_Init() function.
I2C_StructInit(&I2C_InitStructure); //reset the I2C_InitStructre to the default values
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress =
I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable;
I2C_InitStructure.I2C_DigitalFilter = 0;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_OwnAddress1 = 0;
I2C_InitStructure.I2C_Timing = 0x10805E89; // ~100 kHz. @ 48 MHz (HSI) see the script to calculate it
I2C_Init(I2Cx, &I2C_InitStructure);

//(#) Enable the I2C using the I2C_Cmd() function.
I2C_Cmd(I2Cx, ENABLE);
}

 


Edited by Liviu M, 12 May 2014 - 09:44 PM.


#3 OFFLINE   moro

moro

    Membru avansat

  • Membri
  • PipPipPipPip
  • 1,027 posts

Posted 13 May 2014 - 08:03 AM

Salut, m-am uitat si n-am gasit registrul ala. Oricum sunt ceva mai optimist astazi, am observat ca daca nu apelez rutina pentru stop, am comunicare normala pe i2c. M-am jucat toata noaptea cu registrii direct cum is definiti in stm34f4xxx.h fara sa apelez la libraria i2c

 

I2C1->CR1 |=I2C_CR1_START;  /* Generate a START condition */  
I2C1->DR =0x33; // writes adress value to register

I2C1->CR1 |=I2C_CR1_STOP;  /* Generate a STOP condition */  

 

Daca nu apelez CR1_Stop ala, pe SDA imi trimite 0x33 si clock-ul este ok.

M-am uitat sa vad daca nu`s ceva intreruperi pornite, dar sunt doate pe default reset 0. Ideea e ca imi termina comunicarea, apuca sa de-ie start si apoi stop, intr-o bucla infinita....



Cu_reclama

Cu_reclama
  • Membri

#4 OFFLINE   moro

moro

    Membru avansat

  • Membri
  • PipPipPipPip
  • 1,027 posts

Posted 14 May 2014 - 02:02 PM

Pana la urma am reusit sa-i dau de cap oarecum,  in cazul de fata lucrez cu un senzor de presiune/temperatura de la bosch, pe care acum o luna, doua l-am folosit cu succes pe un PIC18F si stiam ca este functional.
 
Dupa ce am stat vreo 4 zile cu nasu` prin headere si librariile de la ST, m-am enervat si am luat "tzaraneste" fiecare bit cu bit si registru si n-am mai folosit nici o librarie.
 
In datasheet  RM0090 la pagina 829 prezinta o diagrama cu time event-ul transmisiei pe i2c, dupa ce am citit putin mai atent eventurile alea , am vazut ca in st32f4xx.h is definite niste flag-uri care desciu exact acele eventuri.
 
Asa ca m-am pus sa verific fiecare event din i2c, acum vad ca functioneaza

#define Addr 0xEE
#define Regg 0xF6
#define Data 0x2E

while(1){

I2C_GenerateSTART(I2C1, ENABLE); // generate start condition
while( !(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)) );  

I2C_Send7bitAddress(I2C1,Addr , I2C_Direction_Transmitter);  
while( !(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) );  
  

I2C1->DR = Regg;   /* Send the  Register address */
while( !(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTING)));

I2C1->DR = Data;   /* Send the Data to Register */
while( !(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTING)));


I2C1->CR1 |= I2C_CR1_STOP; /* Generate a STOP condition */
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF)); // stop bit flag

}

Attached Files






0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users