cancel
Showing results for 
Search instead for 
Did you mean: 

I2C_DR register wont be cleared

Clyde_Xander
Associate II

I'm using stm32f103c8 and PCA9685 devices. I'm trying to send data to PCA9685 via I2C bus. I send data using I2C_DR register. But when i write a data to I2C_DR register it sticks to it. After the data is send thee I2C_DR register should be cleared but it wont happen in my code. I have no idea why this is happening. This is what i see in logic analyzer.

Clyde_Xander_0-1698781436153.png

 

#include "stm32f10x.h"


void I2C_Write_Single(int device_address, int mem_address, int data);
void I2C_Restart(int device_address, int data);


uint32_t temp = 0;

int main(){
/*********STEPS FOLLOWED*********
1. Enable the I2C Clock and GPIO Clock
2. Configure I2C Pins for alternate funtion
3. Reset I2C
4. Program the peripherald input clock in I2C_CR2 Register in order to generate correct timing
5. configure the clock control register
6. Configure the rise time register
7. Program the I2C_CR1 register to enable the peripheral
*/
	
	
	I2C1->CR1 |= (1<<15);
	I2C1->CR1 &=~ (1<<15);
	
	
	//GPIO Port B neabled
	RCC->APB2ENR |= (1<<3);
	//I2C enabled
	RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
	//timer enable TIM2 (general timer)
	RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
	
	//TIM2 config
	TIM4->PSC |= 0;
	TIM4->ARR |= 71;
	TIM4->CR1 |= TIM_CR1_URS;
	TIM4->DIER |= TIM_DIER_UIE;
	TIM4->EGR |= TIM_EGR_UG;
	
	NVIC_EnableIRQ(TIM4_IRQn);
	
	
	//Mode register set for 50MHz (B7 and B6)
	GPIOB->CRL |= (1<<25) | (1<<24);
	GPIOB->CRL |= (1<<29) | (1<<28);
	//GPIO B7 and B6 pin registers (alternate function open drain) 
	GPIOB->CRL |= (1<<27) | (1<<26);
	GPIOB->CRL |= GPIO_CRL_CNF7_1 | (1<<30);
	
	
	//Peripherald frequency (APB1) 36MHz (its written in datasheet)
	I2C1->CR2 |= 36 ;
	//I2C clock control register
	/* to calculate CCR (Clock Control Register) CCR= [((I2C_Period)/2)/(APB1_Period)] 
	I2C preiod is 400KHz(from user manual page 781) Ti2c= 1/100K = 10us
	APB1 Period = 1/36 = 27.7 ns
	CCR = [(5000ns)/(27.7ns)]= 180
	*/
	I2C1->CCR |= 180;
	I2C1->TRISE |= 37 ; // TRise = CR2+1 (from datasheet page 783)
	I2C1->CR1 |= I2C_CR1_ACK;
	I2C1->CR1 |= I2C_CR1_PE;
	
	
	
	I2C_Restart(0x00, 0x06);
	

	I2C_Write_Single( 0x80, 0x00, 0x08); //SLEEP bit gets cleared so we can get PWM signal
	
	I2C_Write_Single( 0x40, 0x00, 1<<6); //EXTERNAL CLOCK bit gets cleared so we can get PWM signal
	 
	I2C_Write_Single( 0x40, 0xFE, 0XB0); // PRE_SCALE registers set to 0xB0 that way PWM Frequency will be 50 MHz (PCA9685 Datasheet page 9)
	
	// PWM delay %0 so LED0_ON_L and LED0_ON_H registers set to 0
	I2C_Write_Single( 0x40, 0x06, 0X01);
	I2C_Write_Single( 0x40, 0x07, 0X99); 
	
	// 1.5ms PWM will be given (1,5/20)*4096=307 LED0_OFF_H= 3 (decimal) LED0_OFF_H= 07 (decimal)
	I2C_Write_Single( 0x41, 0x09, 0X08);
	I2C_Write_Single( 0x41, 0x08, 0X00); 
	
	
	return 0;
	
	
}

void I2C_Write_Single(int device_address, int mem_address, int data)
{
	
	
	I2C1->CR1 |= I2C_CR1_START; //generate start condition
	while (!(I2C1->SR1 & I2C_SR1_SB)); // we check the SB flag if start bit didnt sent master device will stay in this loop

	I2C1->DR |= device_address  ; // device adrees is 0x00 
	while (!(I2C1->SR1 & I2C_SR1_ADDR)); // we check ADDR flag. Once there is address mach dvice will exit the loop
	temp = I2C1->SR1 | I2C1->SR2; // we need to cleear ADDR bit after we checked the flags. To reset SR1 and SR2 registers we just read them

	while (!(I2C1->SR1 & I2C_SR1_TXE)); // wait for the byte transfer
	I2C1->DR |= mem_address  ; // MODE1 register (PCA9685 datasheet page 9)
	while (!(I2C1->SR1 & I2C_SR1_BTF));//wait for transmit
	
	while (!(I2C1->SR1 & I2C_SR1_TXE)); // wait for the byte transfer
	I2C1->DR |= data << 1  ; // to set PWM frequeency we set SLEEP bit 1 (PCA9685 datasheet page 24)
	while (!(I2C1->SR1 & I2C_SR1_BTF));//wait for transmit
	
	I2C1->CR1 |= I2C_CR1_STOP; //generate stop condition
	

}

void I2C_Restart(int device_address, int data){
	
	
	I2C1->CR1 |= I2C_CR1_START; //generate start condition
	while (!(I2C1->SR1 & I2C_SR1_SB)); // we check the SB flag if start bit didnt sent master device will stay in this loop

	I2C1->DR |= device_address; // device adrees is 0x00 
	while (!(I2C1->SR1 & I2C_SR1_ADDR)); // we check ADDR flag. Once there is address mach dvice will exit the loop
	temp = I2C1->SR1 | I2C1->SR2; // we need to cleear ADDR bit after we checked the flags. To reset SR1 and SR2 registers we just read them

	while (!(I2C1->SR1 & I2C_SR1_TXE)); // wait for the byte transfer
	I2C1->DR |= data; // MODE1 register (PCA9685 datasheet page 9)
	while (!(I2C1->SR1 & I2C_SR1_BTF));//wait for transmit
	while (!(I2C1->SR1 & I2C_SR1_TXE)); // wait for the byte transfer
	
	
	I2C1->CR1 |= I2C_CR1_STOP; //generate stop condition
	
}

 

1 ACCEPTED SOLUTION

Accepted Solutions

It's a register, the act of writing it pushes values data into combinational logic and flip-flops internally. It's not designed to be used as a memory cell, or for you to RMW values into it

I2C1->DR |= data << 1  ; // to set PWM frequeency we set SLEEP bit 1 (PCA9685 datasheet page 24)

WHY???

Write the value I2C1->DR = data << 1

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

View solution in original post

2 REPLIES 2

It's a register, the act of writing it pushes values data into combinational logic and flip-flops internally. It's not designed to be used as a memory cell, or for you to RMW values into it

I2C1->DR |= data << 1  ; // to set PWM frequeency we set SLEEP bit 1 (PCA9685 datasheet page 24)

WHY???

Write the value I2C1->DR = data << 1

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

The problem is i used I2C1->DR |= .... It should be I2C1->DR = ....