moro Postat Mai 12, 2014 Partajează Postat Mai 12, 2014 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 I2C1RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);// enable clock for SCL and SDA pinsRCC_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 PB7GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // set pins to alternate functionGPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // set GPIO speedGPIO_InitStruct.GPIO_OType = GPIO_OType_OD; // set output to open drain --> the line has to be only pulled low, not driven highGPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; // enable pull up resistorsGPIO_Init(GPIOB, &GPIO_InitStruct); // init GPIOB// Connect I2C1 pins to AFGPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1); // SCLGPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1); // SDA// configure I2C1I2C_InitStruct.I2C_ClockSpeed = 100000; // 100kHzI2C_InitStruct.I2C_Mode = I2C_Mode_I2C; // I2C modeI2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 50% duty cycle --> standardI2C_InitStruct.I2C_OwnAddress1 = 0x00; // own address, not relevant in master modeI2C_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 addressesI2C_Init(I2C1, &I2C_InitStruct); // init I2C1// enable I2C1I2C_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 anymorewhile(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY)); // Send I2C1 START conditionI2C_GenerateSTART(I2Cx, ENABLE);// wait for I2C1 EV5 --> Slave has acknowledged start conditionwhile(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));// Send slave Address for writeI2C_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 transmittedwhile(!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 dataI2C_AcknowledgeConfig(I2Cx, ENABLE);// wait until one byte has been receivedwhile( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );// read data from I2C data register and return data byteuint8_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 infoI2C_AcknowledgeConfig(I2Cx, DISABLE);I2C_GenerateSTOP(I2Cx, ENABLE);// wait until one byte has been receivedwhile( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );// read data from I2C data register and return data byteuint8_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 ConditionI2C_GenerateSTOP(I2Cx, ENABLE);}int main(void){init_I2C1(); // initialize I2C peripheraluint8_t received_data[2];while(1){I2C_start(I2C1, SLAVE_ADDRESS<<1, I2C_Direction_Transmitter); // start a transmission in Master transmitter modeI2C_write(I2C1, 0x20); // write one byte to the slaveI2C_write(I2C1, 0x03); // write another byte to the slaveI2C_stop(I2C1); // stop the transmissionI2C_start(I2C1, SLAVE_ADDRESS<<1, I2C_Direction_Receiver); // start a transmission in Master receiver modereceived_data[0] = I2C_read_ack(I2C1); // read one byte and request another bytereceived_data[1] = I2C_read_nack(I2C1); // read one byte and don't request another byte, stop transmission}} Link spre comentariu
Liviu M Postat Mai 12, 2014 Partajează Postat Mai 12, 2014 (editat) 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 configurationsif (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 usingRCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);//(#) Peripherals alternate function:// (++) Connect the pin to the desired peripherals' AlternateGPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_1); //If I2C1, then PB8 && PB9GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_1);// i2c pins open collector & PullUp enabledGPIO_StructInit(&GPIO_InitStructure); //reset the GPIO_InitStructure to the default valuesGPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; //If I2C1, then PB8 && PB9GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //activate the internal pullup. For i2c communication should be enoughGPIO_InitStructure.GPIO_OType = GPIO_OType_OD; //for i2c should use the open drain outputsGPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);} else if (I2Cx == I2C2) {//(#) Enable peripheral clock usingRCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);//(#) Enable SDA, SCL and SMBA (when used) GPIO clocks usingRCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);//(#) Peripherals alternate function:// (++) Connect the pin to the desired peripherals' AlternateGPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_1); //If I2C1, then PB8 && PB9GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_1);// i2c pins open collector & PullUp enabledGPIO_StructInit(&GPIO_InitStructure); //reset the GPIO_InitStructure to the default valuesGPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; //If I2C1, then PB8 && PB9GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //activate the internal pullup. For i2c communication should be enoughGPIO_InitStructure.GPIO_OType = GPIO_OType_OD; //for i2c should use the open drain outputsGPIO_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 valuesI2C_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 itI2C_Init(I2Cx, &I2C_InitStructure);//(#) Enable the I2C using the I2C_Cmd() function.I2C_Cmd(I2Cx, ENABLE);} Editat Mai 12, 2014 de Liviu M Link spre comentariu
moro Postat Mai 13, 2014 Autor Partajează Postat Mai 13, 2014 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 registerI2C1->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.... Link spre comentariu
moro Postat Mai 14, 2014 Autor Partajează Postat Mai 14, 2014 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 0x2Ewhile(1){I2C_GenerateSTART(I2C1, ENABLE); // generate start conditionwhile( !(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} Link spre comentariu
Postări Recomandate
Creează un cont sau autentifică-te pentru a adăuga comentariu
Trebuie să fi un membru pentru a putea lăsa un comentariu.
Creează un cont
Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!
Înregistrează un nou contAutentificare
Ai deja un cont? Autentifică-te aici.
Autentifică-te acum