cancel
Showing results for 
Search instead for 
Did you mean: 

How do I configure MCU as an I2C slave device?

KSchr.11
Associate II

Remark : I am asking this question again, since even after trying multiple times on my own, and asking on other platforms, nobody has answered it yet. I can't figure out how am I supposed to configure as slave. So sorry for that. I am not able to delete my previous post, so mod/admin please don't delete this post for repeat.

I've been trying to set up MCU (STM32 L432KC) as an I2C slave device. I have previously tested it as a master device to interface with a port expander(MCP2307) and it works perfectly fine.

The following is the code I am running. The master sends 1,2,3 every 500 ms and the slave device is supposed to a glow a common anode RGB led (rgb led program works fine too, tested as SPI slave device before)

#include "stm32l4xx.h"                  // Device header
 
#define RED_ON (GPIOB->ODR &=~(1<<1))
#define RED_OFF (GPIOB->ODR |=1<<1)
 
#define BLUE_ON (GPIOB->ODR &=~(1<<6))
#define BLUE_OFF (GPIOB->ODR |= 1<<6)
 
#define GREEN_ON (GPIOB->ODR &=~(1<<7))
#define GREEN_OFF (GPIOB->ODR |= 1<<7);
 
 
void i2c1_init(void);
 
 
int main()
{
	i2c1_init();
	uint8_t c;
	
	RCC->AHB2ENR |= RCC_AHB2ENR_GPIOBEN;
	
	GPIOB->MODER &=~(3<<2 | 3<<12 | 3<<14);
	GPIOB->MODER |= 1<<2 | 1<<12 | 1<<14;
	
	GPIOB->ODR |= (1<<1 | 1<<6 | 1<<7);
 
	NVIC_EnableIRQ(I2C1_EV_IRQn);
	
	while(1)
	{
	}
	
}
 
void i2c1_init(void)
{
	RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN;
	RCC->APB1ENR1 |= RCC_APB1ENR1_I2C1EN;
	
	GPIOA->MODER &=~(3<<18 | 3<<20);
	GPIOA->MODER |= 2<<18 | 2<<20;
	
	GPIOA->AFR[1] &=~(0xF<<4 | 0xF<<8);
	GPIOA->AFR[1] |= (4<<4 | 4<<8);				//PA9, PA10 - AF i2c
	
	GPIOA->OTYPER &=~(1<<9 | 1<<10);
	GPIOA->OTYPER |= (1<<9 | 1<<10);			//configure as Open Drain
	
 
	I2C1->CR1 &=~(I2C_CR1_PE);
	
	I2C1->TIMINGR = 0x00400D10;			//100khz, 1000ns tr, 100ns tf
	
	
	I2C1->OAR1 |= 0X40;		//own address
	I2C1->OAR1 |= 1<<15;	//enable own address
	
	I2C1->CR1 |= I2C_CR1_RXIE | I2C_CR1_ADDRIE;			//enable addr match and RXNE interrupts
	
	
	I2C1->CR1 |= I2C_CR1_PE;
	
}
 
 
 
void I2C1_EV_IRQHandler(void)
{
	uint8_t c;
	
	
	if(I2C1->ISR & I2C_ISR_RXNE)
	{
		c = I2C1->RXDR;
		
		switch(c)
		{
			case 1: GREEN_OFF;
			BLUE_OFF;
			RED_ON;
			break;
			
			case 2: RED_OFF;
			BLUE_OFF;
			GREEN_ON;
			break;
			
			case 3: RED_OFF;
			GREEN_OFF;
			BLUE_ON;
			break;
			
		}
			
		I2C1->ICR |= I2C_ICR_ADDRCF;
		
	}
		
	
}
 

I've tried configuring Slave Byte Control (SBC) in CR1 and NBytes in CR2 registers too, but it didn't change anything. From the reference manual, the only step to configure as slave is enable Own address. Are there any other steps or event interrupts I need to configure too?

By the way, I've tried using polling too instead of interrupt previously and had no luck either.

PS: TIMINGR value was generated through xls file by ST (and verified in cubemx) and I've tried different clock frequency and different timing values too, just in case that comes as a suspicion. And I'm using external pullups on SCL and SDA lines.

2 REPLIES 2
TDK
Guru

> I2C1->OAR1 |= 0X40

Pretty sure you're specifying a 7-bit slave address as 0x20 here, not 0x40 as written. Is that your intention? The address is shifted left one bit.

Try to address the slave as both 0x20 and 0x40.

If you feel a post has answered your question, please click "Accept as Solution".

Hey, sorry for the late reply. I tried what you mentioned. Still no luck. Both lines still stay high all the time.