cancel
Showing results for 
Search instead for 
Did you mean: 

I2C start condition not working

ivanquiroz
Associate
Posted on June 23, 2016 at 20:11

I am working on getting familiar with the STM32F411 using ST evaluation board STM32F411E-DISCOVERY.

I have written the following code using Eclipse + Ac6 STM32 + gcc (arm-none-eabi5.3 2016q1) I am able to program the board with another program I created to control PWM on the LEDs (PD12-PD15). I can see the PWM signal on the o-scope moving as programmed When I switch to the I2C driver that I am writing, I cannot get a clock signal out on the I2C SCL nor a START signal on the I2C SDA. I have made lots of different changes but never get good results. Not sure what else I should change so perhaps someone here can point me in the right direction. Is almost as if I am not enabling the clock correctly. PB6=SCL and PB9=SDA


/**

******************************************************************************

* @file main.c

* @author Ac6

* @version V1.0

* @date 06/17/2016

* @brief I2C set up to SMT32F411 goal to connect to Accelerometer

*

*

******************************************************************************

*/


#include ''stm32f4xx.h''

//#include ''stm32f411e_discovery.h''


#define ACCEL_ADDR 0x32

#define xWrite 0x1

#define xRead 0x0


void
I2C1_PortInit(){

// Set port to use I2C1

RCC->CR |= 0x00000001; 
// enable HSION (High speed internal oscillator)

while
((RCC->CR & RCC_CR_HSIRDY) == 0); 
//Wait for HSI Ready RCC->CFGR = RCC_CFGR_SW_HSI;

while
((RCC->CFGR & RCC_CFGR_SWS) != 0) ; 
//wait for HSI used as system clock

RCC->CFGR |= 0x00009000;


I2C1->CR1 &= ~I2C_CR1_PE;

RCC->APB1ENR |= 0x00200000; 
// enable APB1 peripheral clock for I2C1 per section 6.3.11

RCC->AHB1ENR |= 0x00000002; 
// enable clock for GPIO PortB (PB6/SCL and PB9/SDA pins)


GPIOB->OSPEEDR |= 0x00082000; 
// set port speed to fast for ports PB6 and PB9 (50Mhz)

GPIOB->OTYPER |= 0x00000240; 
// I2C needs to be open drain (drives GND/0V only) for PB6 and PB9

GPIOB->PUPDR |= 0x00041000; 
// enable pull up resistors to PB6 and PB9

GPIOB-> AFR[1] |= 0x00000040; 
// Assign I2C1_SDA to Alternate Function per table-9 of 32F411xE Datasheet

GPIOB-> AFR[0] |= 0x04000000; 
// Assign I2C1_SCL to Alternate Function per table-9 of 32F411xE Datasheet

GPIOB->MODER |= 0x00042000; 
// Set Alternate Function to PB6 and PB9, which function defined below by GPIOB_AFR

//Configure I2C Port 1 settings






I2C1->CR1 &= 0xFFFE; 
// Must Disable the I2C peripheral to be able to change CCR and TRISE

I2C1->CR2 = 0x0008; 
// Program the peripheral input clock per APB1 Peripheral Clock of 8Mhz => b1000. Disable Interrupts, no DMA

I2C1->CCR = 0x0028; 
// Clock Standard mode (SM=100khz=> 10,000ns) Thigh = 5000ns = Tlow (50% duty cycle). Peripheral clk=8Mhz (APB1) then 1/8mhz= 125nsec 5000ns/125ns = 40 =>0x28= CCR

I2C1->TRISE = 0x0009; 
/* Configure the rise time register: If, in the I2C_CR2 register, the value of FREQ[5:0] bits is equal to 0x08 and TPCLK1 = 125 ns.

Therefore the TRISE[5:0] bits must be programmed with 09h.(1000 ns / 125 ns = 8 + 1) */

I2C1->OAR1 |= 0x4000; 
// Set I2C1 address not needed for master

I2C1->OAR2 |= 0x0000;

I2C1->CR1 |= 0x0001; 
// Enable Peripheral

// Set START bit to generate START condition

}




void
I2C1_Start(uint8_t I2C_Write_Slave_Address, uint8_t Slave_Internal_Address ){

volatile int32_t Busy_Flag=1;

volatile int32_t AK_Status=0;


// following description in pg 469 of reference manual

// while (Busy_Flag == 1){ // check if I2C Busy Flag is set (I2Cx_SR2.Bit2=1:Busy, SR2.Bit2=0:OK to transmit)

// Busy_Flag = I2C1->SR2 & 0x2; // Update Busy flag bit

// }


I2C1->CR1 |= 0x0100; 
// generate START condition I2Cx_CR1.Bit8=1:Start CR1.Bit8=0: No Start

I2C1->SR1;

//while (AK_Status == 0){ // check for (EV5) START condition was good(SB=1, cleared by reading SR1 register followed by writing DR register with Address)

// AK_Status = I2C1->SR1 & 0x1; // Update SB Start status

// }

//I2C1->CR1 |= 0x0400; //enable ack


I2C1->DR = I2C_Write_Slave_Address; 
// send Slave Address with WRITE (R/W=0). I2Cx_DR register with Address


//AK_Status = 0;

// while (AK_Status==0){ // check for (EV6) ACK (ADDR=1, cleared by reading SR1 register followed by reading SR2)

// AK_Status = I2C1->SR1 & 0x2; // Keep checking for ADRR bit to be 1

// }

I2C1->SR1;

I2C1->SR2; 
// Read SR2 after ADRR read at SR1 to clear the ADRR


I2C1->SR1 &=~(0x0020);


I2C1->DR = Slave_Internal_Address; 
// Prepare slave to read specific internal address


AK_Status = 0;

while
(AK_Status == 0 ){

AK_Status = I2C1->SR1 & 0x80; 
// Checking for TxE =1 to happen after ACK received

}


}


void
I2C1_Write(uint8_t I2C_Data_Out){

uint8_t AK_Status=0;

I2C1->DR = I2C_Data_Out; 
// Prepare slave to read specific internal address

while
(AK_Status == 0 ){

AK_Status = (I2C1->SR1 & 0x80);

AK_Status = AK_Status || ((I2C1->SR1 & I2C_SR1_BTF)); 
// Checking for TxE =1 to happen after ACK received)

}

}


void
I2C1_Stop(){

I2C1->CR1 |= 0x0200;

}


uint8_t I2C1_Read_Last(){


I2C1->CR1 &= ~(0x0400); 
// same as 0xF7FFF to clear ACK

I2C1->CR1 |= 0x0200; 
// same as 0xF7FFF to clear ACK

uint8_t I2C_Data_In = I2C1->DR;

return
I2C_Data_In;

}


int
main(
void
)

{

volatile uint8_t Acc_Data_in; 
// Define Buffer for data expected per frame of I2C communication

uint8_t Acc_Config_Out; 
// Define Buffer for data expected per frame of I2C communication

uint8_t Acc_Internal_Reg;


// SystemInit(); // Sets correct clock cycles APB1 Peripherals to 8Mhz, APB1 clock to 16Mhz

I2C1_PortInit(); 
// Initialize the I2C Port


//Read Accelerometer

Acc_Internal_Reg = 0x20;

Acc_Config_Out = 0xF7; 
//CTRL_REG1_A (20h) defaults to power down and all axis disable. Enable all axis and enable data rate


I2C1_Start(ACCEL_ADDR, Acc_Internal_Reg);

I2C1_Write(Acc_Config_Out);

I2C1_Stop();

// Acc_Data_in = I2C1_Read_Last(); // Stop the transmission


while
(1) {


I2C1_Start(ACCEL_ADDR, Acc_Internal_Reg);

}

}

#discovery #stm32f4 #i2c
0 REPLIES 0