cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4Discovery I2C in Slave mode

vasyl
Associate
Posted on December 24, 2014 at 19:14

Hello!

I need to connect two STM32F407Discovery board via i2c for my task. First board is master which send data packet to slave board and receive data back. Slave board just receive data and save it for master. Next part works correct, slave send ack to master; led is blinking.

uint8_t received_data[2];
while
(1)
{
I2C_start(I2C1, SLAVE_ADDRESS, I2C_Direction_Transmitter);
I2C_write(I2C1, 0x20);
I2C_write(I2C1, 0x40);
I2C_write(I2C1, 0x80);
I2C_stop(I2C1);
LED_GREEN_TOGGLE;
_delay_ms(50);
}
}

When I try to receive data from slave:

uint8_t received_data[2];
while
(1)
{

I2C_start(I2C1, SLAVE_ADDRESS, I2C_Direction_Transmitter);
I2C_write(I2C1, 0x20);
I2C_write(I2C1, 0x40);
I2C_write(I2C1, 0x80);
I2C_stop(I2C1);
I2C_start(I2C1, SLAVE_ADDRESS, I2C_Direction_Receiver);
received_data[0] = I2C_read_ack(I2C1);
received_data[1] = I2C_read_nack(I2C1);
I2C_stop(I2C1);
LED_GREEN_TOGGLE;
_delay_ms(50);
}
}

my program is freezing on line:

I2C_start(I2C1, SLAVE_ADDRESS, I2C_Direction_Receiver); ,

Led isn't blinking. Code for slave board:

void
I2C_Initialization(
void
)
{
GPIO_InitTypeDef gpio_init;
I2C_InitTypeDef i2c_init;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
gpio_init.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
gpio_init.GPIO_Mode = GPIO_Mode_AF;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
gpio_init.GPIO_PuPd = GPIO_PuPd_UP; 
//Pull up resistor
gpio_init.GPIO_OType = GPIO_OType_OD; 
//Open Drain
GPIO_Init(GPIOB, &gpio_init);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1 ); 
// SCL
GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1 ); 
// SDA
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
I2C_DeInit(I2C1);
I2C_SoftwareResetCmd(I2C1, ENABLE);
I2C_SoftwareResetCmd(I2C1, DISABLE);
i2c_init.I2C_ClockSpeed = 100000;
i2c_init.I2C_Mode = I2C_Mode_I2C;
i2c_init.I2C_DutyCycle = I2C_DutyCycle_2;;
i2c_init.I2C_OwnAddress1 = SLAVE_ADDRESS;
i2c_init.I2C_Ack = I2C_Ack_Enable;
i2c_init.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C1, &i2c_init);
I2C_ITConfig(I2C1, I2C_IT_ERR, ENABLE);
I2C_ITConfig(I2C1, I2C_IT_EVT, ENABLE);
I2C_ITConfig(I2C1, I2C_IT_BUF, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
// Configure the I2C event priority
NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
I2C_StretchClockCmd(I2C1, ENABLE);
I2C_Cmd(I2C1, ENABLE);
}
//Clear ADDR by reading SR1, then SR2
void
I2C_clear_ADDR(I2C_TypeDef* I2Cx)
{
I2C_GetFlagStatus(I2Cx, I2C_FLAG_ADDR);
((
void
)(I2Cx->SR2));
}
//Clear STOPF by reading SR1, then writing CR1
void
I2C_clear_STOPF(I2C_TypeDef* I2Cx)
{
I2C_GetFlagStatus(I2Cx, I2C_FLAG_STOPF);
I2C_Cmd(I2Cx, ENABLE);
}
void
I2C1_EV_IRQHandler()
{
//Clear AF from slave-transmission end
if
(I2C_GetITStatus(I2C1, I2C_IT_AF)) I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
switch
(I2C_GetLastEvent(I2C1))
{
//SLAVE
//Receive
case
I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED: 
//EV1
I2C_clear_ADDR(I2C1);
break
;
case
I2C_EVENT_SLAVE_BYTE_RECEIVED: 
//EV2
//Read it, so no one is waiting, clears BTF if necessary
data[i++] = I2C_ReceiveData(I2C1);
if
(i == 3) i = 0;
break
;
/*
//Do something with it
if(I2C_GetFlagStatus(I2C1, I2C_FLAG_DUALF))
{//Secondary Receive
}
else if(I2C_GetFlagStatus(I2C1, I2C_FLAG_GENCALL))
{//General Receive
}
else
{//Normal
}
break;
*/
case
I2C_EVENT_SLAVE_STOP_DETECTED: 
//End of receive, EV4
I2C_clear_STOPF(I2C1);
break
;
//Transmit
case
I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED: 
//EV1
I2C_clear_ADDR(I2C1);
//Send first byte
//I2C_SendData(I2C1, 0x25);
break
;
case
I2C_EVENT_SLAVE_BYTE_TRANSMITTED: 
//EV3
//Determine what you want to send
//data = 5;
if
(I2C_GetFlagStatus(I2C1, I2C_FLAG_DUALF))
{
//Secondary Transmit
//I2C_SendData(I2C1, 0x33);
}
else
if
(I2C_GetFlagStatus(I2C1, I2C_FLAG_GENCALL))
{
//General Transmit
//I2C_SendData(I2C1, 0x11);
}
else
{
//Normal
//I2C_SendData(I2C1, 0x44);
}
//Read flag and write next byte to clear BTF if present
I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF);
I2C_SendData(I2C1, 0x44);
break
;
case
I2C_EVENT_SLAVE_ACK_FAILURE:
//End of transmission EV3_2
LED_ORANGE_ENABLE;
//TODO: Doesn't seem to be getting reached, so just
//check at top-level
I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
break
;
default
:
break
;
}
}
void
I2C1_ER_IRQHandler(
void
)
{
//GPIO_SetBits(GPIOD, RED);
//Can't use nice switch statement, because no fxn available
if
(I2C_GetITStatus(I2C1, I2C_IT_SMBALERT)) {
} 
else
if
(I2C_GetITStatus(I2C1, I2C_IT_TIMEOUT)) {
} 
else
if
(I2C_GetITStatus(I2C1, I2C_IT_PECERR)) {
} 
else
if
(I2C_GetITStatus(I2C1, I2C_IT_OVR)) {
//Overrun
//CLK stretch disabled and receiving
//DR has not been read, b4 next byte comes in
//effect: lose byte
//should:clear RxNE and transmitter should retransmit
//Underrun
//CLK stretch disabled and I2C transmitting
//haven't updated DR since new clock
//effect: same byte resent
//should: make sure discarded, and write next
} 
else
if
(I2C_GetITStatus(I2C1, I2C_IT_AF)) {
//Detected NACK
//Transmitter must reset com
//Slave: lines released
//Master: Stop or repeated Start must must be generated
//Master = MSL bit
//Fixup
I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
} 
else
if
(I2C_GetITStatus(I2C1, I2C_IT_ARLO)) {
//Arbitration Lost
//Goes to slave mode, but can't ack slave address in same transfer
//Can after repeat Start though
} 
else
if
(I2C_GetITStatus(I2C1, I2C_IT_BERR)) {
//Bus Error
//In slave mode: data discarded, lines released, acts like restart
//In master mode: current transmission continues
}
}

Image from logic analyzer: 0690X00000602zPQAQ.jpg Also are attached source projects in CooCox IDE 1.7.6 Can anyone share working code for I2C slave (it doesn't matter with interrupt or without it) Thanks. #i2c #stm32f4discovery #slave
0 REPLIES 0