cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F103 I2C Slave Transmitter

emilio
Associate II
Posted on December 13, 2014 at 17:41

Hello everybody,

I am developing a system in wich a STM32F103 microcontroller has to communicate with a master receiver external device. I have to configure the STM32 as a I2C slave transmitter in order to send data after the address match. Where can I find a code example to operate in this way?

Thanks in advance
6 REPLIES 6
emilio
Associate II
Posted on December 14, 2014 at 10:48

I'm now writing the code to configure the master receiver and the slave transmitter. Following I'm pasting the master receiver code that currently isn't working properly. Can anybody help me debugging it?

Thanks

GPIO_InitTypeDef    GPIO_InitStructure;

I2C_InitTypeDef     I2C_InitStructure;

     

    //enable clocks

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

 

    // I2C1 SDA and SCL configuration

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;

    GPIO_Init(GPIOB, &GPIO_InitStructure);

 

    I2C_DeInit(I2C1);

    I2C_Cmd(I2C1, ENABLE);

 

    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;

    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;

    I2C_InitStructure.I2C_OwnAddress1 = 0x01;

    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;

    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

    I2C_InitStructure.I2C_ClockSpeed = 100000;

    I2C_Init(I2C1, &I2C_InitStructure);

  

  /* infinite loop */

  while (1)

  {

    

   I2C_GenerateSTART(I2C1, ENABLE); 

   while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

   I2C_Send7bitAddress(I2C1, 0x00, I2C_Direction_Receiver);

   while(!I2C_CheckEvent(I2C1,         I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

   while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));

   dato=I2C_ReceiveData(I2C1);   

   I2C_GenerateSTOP(I2C1, ENABLE);

   

   for(int i=0; i<8000; i++);

      

    

  }

Amel NASRI
ST Employee
Posted on December 16, 2014 at 10:15

Hi,

1- Will the STM32 I2C be used as a master receiver or a slave transmitter?

2- what is exactly the problem? is there any error flag set?

3- You can use the CPAL library (all resources are available in http://www.st.com/web/en/catalog/tools/FM147/CL1794/SC961/SS1743/LN1734/PF258336)

-Mayla-

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

emilio
Associate II
Posted on December 17, 2014 at 12:17

Thanks for answering.

1 - For my application I need to use the STM32 as slave transmitter (the master receiver will be a different device). In order to improve my experience with STM32 I'm curretly trying to start a communication between two STM32 NUCLEO board.

2 - The problem is that I after I2C configuration I try to start a communication sending a start bit but, checking the flag MASTER_MODE_SELECTED, it isn't 'true' and it seems not to send anything and the communication can't go further (and send the 7bit address).

3 - Thanks for the link. I'll study the library.

Below the code I'm using to configure the I2C1

  I2C_InitTypeDef  I2C_InitStructure;

  GPIO_InitTypeDef GPIO_InitStructure;

 

  /* Enable I2C and GPIO clocks */

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

    

  /* Configure I2C pins: SCL and SDA */

  GPIO_StructInit(&GPIO_InitStructure); // reset GPIO_InitStructure to default values

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;

  GPIO_Init(GPIOB, &GPIO_InitStructure);

  GPIO_PinRemapConfig(GPIO_Remap_I2C1, ENABLE);

 

 

  /* I2C configuration */

  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;

  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;

  I2C_InitStructure.I2C_OwnAddress1 = 0x01;    

  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;

  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

  I2C_InitStructure.I2C_ClockSpeed = 25000;

 

 

 

  /* I2C Peripheral Enable */

  I2C_Cmd(I2C1, ENABLE);

 

  /* Apply I2C configuration after enabling it */

  I2C_Init(I2C1, &I2C_InitStructure);

emilio
Associate II
Posted on December 19, 2014 at 16:12

I'm doing some tests using the code I've posted and the problem is that, after the GPIO_Init, the SDA and SCL lines remain low even after the I2C Init (so it's impossible to generate a start condition). What about the possible causes?

Amel NASRI
ST Employee
Posted on December 22, 2014 at 16:09

Do you have pull-ups on the I2C bus?

-Mayla-

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

emilio
Associate II
Posted on December 23, 2014 at 17:53

Yes I'm using 4.7k resistors.

I've found the problem in my code, the lack of the following instruction

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

Now I'm able to open the I2C communication and I'm debugging the MasterReceiver/SlaveTransmitter configuration.

I'm using the following code for the MasterReceiver (using polling)

I2C_AcknowledgeConfig(I2C1, ENABLE);

 

while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

 

I2C_GenerateSTART(I2C1, ENABLE);

 

while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));    

 

I2C_Send7bitAddress(I2C1, 0x00, I2C_Direction_Receiver);

 

while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

 

while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));

 

I2C_NACKPositionConfig(I2C1, I2C_NACKPosition_Current);

 

I2C_AcknowledgeConfig(I2C1, DISABLE);

 

data1=I2C_ReceiveData(I2C1);

 

while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));

 

 I2C_GenerateSTOP(I2C1, ENABLE);

 

while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF)); 

 

data2=I2C_ReceiveData(I2C1); 

 

And the following ISR in order to debug the SlaveTransmitter

void I2C1_EV_IRQHandler()

 

{

 

     switch (I2C_GetLastEvent(I2C1))

 

     { 

 

        case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:

 

          i=I2C1->SR1;

 

          i=I2C1->SR2;          

 

          I2C_SendData(I2C1, 0xAA);  

 

         break;   

 

         case I2C_EVENT_SLAVE_BYTE_TRANSMITTED:

 

          I2C_SendData(I2C1, 0xAA); 

 

         break;

 

         case I2C_EVENT_SLAVE_STOP_DETECTED:

 

          I2C_CleanADDRandSTOPF();

 

         break;          

 

        case I2C_EVENT_SLAVE_ACK_FAILURE:

 

          I2C1->SR1&=0x1111101111111111;

 

        break;

 

    }

 

}

 

Now I have the following problem: after the slave sends the second byte it is unable to detect the ACK_FAILURE or a STOP. Where am I making a mistake?