cancel
Showing results for 
Search instead for 
Did you mean: 

NEUCLEO-F103RB Can't get IIC working.

Phill Harvey-Smith
Associate II
Posted on July 01, 2018 at 19:20

Hi All,

Having got the USART working, and being able to exchanged data via the serial port I want to try and drive an Adafriuit IIC backpack. This uses the Holtek HT16K33 driver chip.

I have connected the backpack's SCL & SDA to the neucleo board's SCL & SDA (for I2C port 1), on CN10, and the power to the +5V & GND on CN7.

I have used CubeMX32 to setup a project with the I2C, and initialized it with the default peripheral values. I borrowed the I2C sending code from one of the ST supplied examples. However when I try and send anything to the backpack, it seems to get stuck either waiting for start ack, or more commonly waiting for address ack.

I've attached the i2c & LED source files and headers, can anybody spot anything I have done wrong or anything I should be doing?

Cheers.

Phill.

4 REPLIES 4
henry.dick
Senior II
Posted on July 01, 2018 at 20:31

ST has published numerous appnotes on how to get the i2c work on some earlier chips. i don't know what exact code pieces you used but I can confirm for you that 1) the hardware works; and 2) the i2c code in the SPL is not compliant with the datasheet, particularly around EV5/6 - you have to clear the flag by reading SR1 and SR2 successively, as shown in the datasheet.

I don't know if HAL is datasheet compliant on I2C - hope so - but it makes sense for you to read up on the datasheet on that front.

Also, make sure you have pull-ups on the bus.

Posted on July 02, 2018 at 20:03

Using the code from one of the CubeMX examples installed with the 1_6_1 firmware.

Not actually using the HAL for I2C, but using the LL_ functions as there seem dto be some things that the HAL doen't do very well, as you don't get enough control.

I have now confirmed that my LED backpack works by driving it with an Arduino UNO (programmed in plain AVR GCC, just using the arduino as a convenient test board), it does have pullups according to the schematic, and I have measured the voltage on the pins and found them to be within 0.1V of 5V, which seems OK.

My code was attached above, however my init code (generated by CubeMX):

 void MX_I2C1_Init(void)

{

  LL_I2C_InitTypeDef I2C_InitStruct;

  LL_GPIO_InitTypeDef GPIO_InitStruct;

 

  /**I2C1 GPIO Configuration  

  PB6   ------> I2C1_SCL

  PB7   ------> I2C1_SDA

  */

  GPIO_InitStruct.Pin = LL_GPIO_PIN_6|LL_GPIO_PIN_7;

  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;

  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;

  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;

  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* Peripheral clock enable */

  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);

    /**I2C Initialization

    */

  LL_I2C_DisableOwnAddress2(I2C1);

  LL_I2C_DisableGeneralCall(I2C1);

  LL_I2C_EnableClockStretching(I2C1);

  I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;

  I2C_InitStruct.ClockSpeed = 100000;

  I2C_InitStruct.DutyCycle = LL_I2C_DUTYCYCLE_2;

  I2C_InitStruct.OwnAddress1 = 0;

  I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;

  I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;

  LL_I2C_Init(I2C1, &I2C_InitStruct);

  LL_I2C_SetOwnAddress2(I2C1, 0);

}

My start transmit code :

void IIC_StartSend(uint8_t    Dest,

                   uint8_t    RW)

{

    /* (1) Prepare acknowledge for Master data reception ************************/

    LL_I2C_AcknowledgeNextData(I2C1, LL_I2C_ACK);

    printf('Generating start condition\n');

    /* (2) Initiate a Start condition to the Slave device ***********************/

    /* Master Generate Start condition */

    LL_I2C_GenerateStartCondition(I2C1);

    printf('Waiting start ack\n');

    /* (3) Loop until Start Bit transmitted (SB flag raised) ********************/

    /* Loop until SB flag is raised  */

    while(!LL_I2C_IsActiveFlag_SB(I2C1))

    {

    }

    printf('Transmit destination address %0X\n',((Dest << 1) | (RW & IIC_RW_MASK)));

    /* (4) Send Slave address with a 7-Bit SLAVE_OWN_ADDRESS for a write request */

    LL_I2C_TransmitData8(I2C1, ((Dest << 1) | (RW & IIC_RW_MASK)));

    printf('Waiting for address ack\n');

    /* (5) Loop until Address Acknowledgement received (ADDR flag raised) *******/

    /* Loop until ADDR flag is raised  */

    while(!LL_I2C_IsActiveFlag_ADDR(I2C1))

    {

    }

    printf('Clear ADDR flag\n');

    /* (6) Clear ADDR flag and loop until end of transfer (ubNbDataToTransmit == 0) */

    /* Clear ADDR flag value in ISR register */

    LL_I2C_ClearFlag_ADDR(I2C1);

}

It most often seems to get stuck waiting for the Start ack (I tried single stepping the code and SR1 always seems to be 0, so it looks like the flag is never getting set).

Sometimes (about 1 time in 10) it will get past there and get stuck waiting for the address ack.

It seems like something may not be initialized correctly, anyone have any clue as to what?

Cheers.

Phill.

Phill Harvey-Smith
Associate II
Posted on July 03, 2018 at 00:17

Right I got it working,

Looks like the main problem was the misleading labeling on the Nucleo board which seemed to suggest that the I2C was on 2 of the pins of CN10, that are next to the Arduino headers marked as I2C....it isn't.

Now it's connected to the correct pins the code is working properly!

Cheers.

Phill.

Phill Harvey-Smith
Associate II
Posted on July 03, 2018 at 13:45

Further to the above, I've just discovered that the SDA and SCL pins can be remapped in CubeMX so that they appear on the CN10 (and Arduino compatible connectors), it's just that it's not the default

:(

Cheers.

Phill.