AnsweredAssumed Answered

Frustrating I2C Problem: STM32L-Discovery

Question asked by hoodjay on Nov 20, 2012
Latest reply on Mar 18, 2014 by faulhaber.chris
I am using the STM32L152RB. It's nice, I like it. I want to get it talking on an I2C bus. The bus is setup correctly, I've used a TotalPhase Aardvark (USB i2c controller) to send messages across it and write to a nice little EEPROM (http://ww1.microchip.com/downloads/en/DeviceDoc/21178d.pdf), but I'll be damned if I can get the microcontroller to do the same thing.

I have been reading through the reference manuals and datasheets looking for something I've missed, but I'm stumped and need another set of eyes. 

On this board, the I2C2 bus works on Pins PB6 (SCL) and PB7 (SDA). The primary function of those two pins is LED3 (green) and LED4 (blue). I am able to initialize the GPIO pins for LED use, and toggle the LEDs by writing to their respective registers (using both the library functions and hand coded pointers). 

When I set the GPIOs to AF_Mode and use the library functions to initialize the I2C Alternate Function, there seem to be no problems. However, whenever I try to send a message to my EEPROM, the code blocks on the following line:

while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));

Potentially important information:
1) When I hooked up an oscilloscope to the bus with only the Aardvark and EEPROM attached there was no issue with communication. It was easy to see the data being sent along the wire. When I attach the STM, I cannot get the line to go low. I've tried changing a number of different values during the I2C_Init() phase, but none seem to change the fact that the STM32 is holding the line high.

2) When the EEPROM is sitting on the bus by itself, the voltage of both SCL and SDA are 5.04V. When I attach the STM32 (without main power), the voltage of SCL (PB6, Blue LED) drops to 3.06V and the Blue LED powers on (not unexpected, without power the pin is floating, and its primary function is the Blue LED), and the voltage of SDA (PB7, Green LED) drops to 2.05V and the Green LED powers on (again, not unexpected).When I turn on the STM, even after AF_config, this remains true. Even though I am trying to change the pins from their main function to their alternate function, the voltage on the pins stays the same and the LEDs that they run as their main function remain powered.

Any help with this problem would be greatly appreciated. My own thoughts are that perhaps I am initializing something incorrectly, or that a clock is misconfigured, but I cannot seem to make progress.

Below is relevant code, and attached is my full source. I am using Atollic TrueStudioLite.

/* Includes */
#include <stddef.h>
#include "stm32l1xx.h"
#include "discover_board.h"
#include "stm32l_discovery_lcd.h"
 
/* 7bit add. of slave is 1010.xxx ... does STM library left shift? should it be x50?*/
#define I2C2_SLAVE_ADDRESS7 0xA0
#define ClockSpeed 100000 /*tried multiple speeds, no difference */
 
/* Private macro */
/* Private variables */
 USART_InitTypeDef USART_InitStructure;
 
/* Private function prototypes */
/* Private functions */
 void Init_GPIOs (void); /* <--- I2C Init() and Cmd() is performed in here */
 void RCC_Configuration(void);
 
 static volatile uint32_t TimingDelay;
 RCC_ClocksTypeDef RCC_Clocks;
 
 void Config_Systick()
 {
   RCC_GetClocksFreq(&RCC_Clocks);
   SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);
 }
 
 void Delay(uint32_t); //forward declaration
 
int main(void)
{
 
  int i = 0; /* dummy variable */
  RCC_Configuration();
 
  /* Init I/O ports */
  Init_GPIOs ();
 
  /* Init Systick */
  Config_Systick();
 
  /* Initializes the LCD glass */
  LCD_GLASS_Init();
  LCD_GLASS_DisplayString((uint8_t*)"STM32L-DISCOVERY");
 
while (1)
  {
    i++;
 
    /* Check if the User Button is pressed */
    if ((GPIOA->IDR & USER_GPIO_PIN) != 0x0)
    {
      LCD_GLASS_DisplayString((uint8_t*)"SEND   ");
 
      /* Send I2C2 START condition */
      I2C_GenerateSTART(I2C2, ENABLE);
 
      /* Test on I2C2 EV5 and clear it */
      while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
 
      /* Send EEPROM slave Address for write */
      I2C_Send7bitAddress(I2C2, I2C2_SLAVE_ADDRESS7, I2C_Direction_Transmitter);
 
      /* Test on I2C2 EV6 and clear it */
      while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
 
      /* Send I2C2 EEPROM internal address */
      I2C_SendData(I2C2, 0x00);
 
      /* Test on I2C2 EV8 and clear it */
      while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
 
      /* Send I2C2 EEPROM data */
      I2C_SendData(I2C2, 0x05);
 
      /* Test on I2C2 EV8 and clear it */
      while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
 
      /* Send I2C2 STOP Condition */
      I2C_GenerateSTOP(I2C2, ENABLE);
 
      Delay(500); /*pause for half a second*/
    }
    else /*user button is not pressed */
    {
      LCD_GLASS_DisplayString((uint8_t*)"BLOCK  ");
 
      Delay(500); /*pause for half a second*/
    }
  }
  return 0;
}
 
void RCC_Configuration(void)
{
  /* Enable the GPIOs Clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOC| RCC_AHBPeriph_GPIOD| RCC_AHBPeriph_GPIOE| RCC_AHBPeriph_GPIOH, ENABLE);
 
  /* Enable comparator clock */
 /* I enable I2C1 and I2C2 clocks, only using I2C2, makes no difference */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_COMP | RCC_APB1Periph_I2C1 | RCC_APB1Periph_I2C2 | RCC_APB1Periph_LCD | RCC_APB1Periph_PWR,ENABLE);
 
  /* Enable SYSCFG */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG , ENABLE);
 
  /* Allow access to the RTC */
  PWR_RTCAccessCmd(ENABLE);
 
  /* Reset Backup Domain */
  RCC_RTCResetCmd(ENABLE);
  RCC_RTCResetCmd(DISABLE);
 
  /*!< LSE Enable */
  RCC_LSEConfig(RCC_LSE_ON);
 
  /*!< Wait till LSE is ready */
  while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
  {}
 
  /*!< LCD Clock Source Selection */
  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
}
 
void  Init_GPIOs (void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  I2C_InitTypeDef I2C_InitStructure;
 
  /* Configure User Button pin as input */
  GPIO_InitStructure.GPIO_Pin = USER_GPIO_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_Init(BUTTON_GPIO_PORT, &GPIO_InitStructure);
 
 
/* Configure the GPIO pins  PB6 & PB7 for i2c*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; /* <--- is this needed? */
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz; /*tried, 2, 10 and 40Mhz*/
  GPIO_Init(GPIOB, &GPIO_InitStructure);
 
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource6,GPIO_AF_I2C2) ;
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource7,GPIO_AF_I2C2) ;
 
  /* I2C2 configuration */
  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
  I2C_InitStructure.I2C_OwnAddress1 = I2C2_SLAVE_ADDRESS7;
  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  I2C_InitStructure.I2C_ClockSpeed = ClockSpeed ;
  I2C_Init(I2C2, &I2C_InitStructure);
  I2C_Cmd(I2C2, ENABLE);
 
/* Configure Output for LCD */
/* Port A */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_8 | GPIO_Pin_9 |GPIO_Pin_10 |GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_Init( GPIOA, &GPIO_InitStructure);
 
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource1,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource2,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource3,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource8,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource9,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource10,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource15,GPIO_AF_LCD) ;
 
/* Configure Output for LCD */
/* Port B */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_8 | GPIO_Pin_9 \
                                 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_Init( GPIOB, &GPIO_InitStructure);
 
/*Im not using all the LCD segments */
#ifdef USE_ALL_LCD_SEGMENTS
/**
 * Note!
 * PB3 is connected to C, M, COLON, and DP segments for the second digit on the LCD
 * PB3 is also the SWO pin used for the Serial Wire Viewer (SWV)
 * If PB3 is used by LCD then SWV will not work for the STM32L_DISCOVERY board
 **/
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource3,GPIO_AF_LCD) ;
#endif
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource4,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource5,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource8,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource9,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource10,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource11,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource12,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource13,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource14,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource15,GPIO_AF_LCD) ;
 
/* Configure Output for LCD */
/* Port C*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_6 \
                                 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 |GPIO_Pin_11 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_Init( GPIOC, &GPIO_InitStructure);
 
 
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource0,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource1,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource2,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource3,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource6,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource7,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource8,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource9,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource10,GPIO_AF_LCD) ;
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource11,GPIO_AF_LCD) ;
}
 
 
 
/**
  * @brief  Inserts a delay time.
  * @param  nTime: specifies the delay time length, in 1 ms.
  * @retval None
  */
void Delay(uint32_t nTime)
{
  TimingDelay = nTime;
 
  while(TimingDelay != 0);
 
}
 
/**
  * @brief  Decrements the TimingDelay variable.
  * @param  None
  * @retval None
  */
void TimingDelay_Decrement(void)
{
 
  if (TimingDelay != 0x00)
  {
    TimingDelay--;
  }
}

Attachments

Outcomes