I am trying to use the Primer 2's extension connector pins 3 and 4 to communicate with an FPGA on another board using I2C.
I have written a Circle OS application to enable I2C1 and test the I2C read operation, however i am not getting any signals on the exension connector, not even a START.
Below is the application code:
Application Initialisation function:
enum MENU_code Application_Ini ( void ) { // Ensure that the current OS version is recent enough if(strcmp(UTIL_GetVersion(), NEEDEDVERSION) < 0) { return MsgVersion(); }
// TODO: Write your application initialization function here.
// Configure the GPIO ports as alternate functions (PB6,7) GPIO_PinRemapConfig(GPIO_Remap_I2C1, ENABLE);
// First, initialise and configure the I2C1 peripheral
// Declare an I2C_InitTypeDef structure, with I2C_InitStructure variable I2C_InitTypeDef I2C_InitStructure;
// Fill the variable with allowed values of member structure I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; //only effects fast mode I2C_InitStructure.I2C_OwnAddress1 = 0x03A2; I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_InitStructure.I2C_ClockSpeed = 100000; // just as an example
// Initialise the I2C peripheral I2C_Init(I2C1, &I2C_InitStructure);
// Now enable I2C peripheral I2C_Cmd(I2C1, ENABLE);
// I2C1 can now be used through a set of specific I2C functions const char msg[] = "Init ok";
DRAW_DisplayString( 1, 7, msg, sizeof(msg)); // X, Y, string, length
return MENU_CONTINUE_COMMAND; }
Are there any obvious mistakes or special considerations to take when writing the Application Handler function?
Re: STM32 Primer 2 Extension connector - I2C problems
Thanks for your help, I have configured the GPIO pins and the RCC now, however there are still no I2C signals seen on the external connector pins when using a logic analyser. I am aiming to view anything on the pins to begin with.
I cannot think of anything i am missing
Code:
APPLICATION INITIALISATION
// RCC SYSTEM CLOCK CONFIG ----------------------------------------------------/
{
/* RCC system reset(for debug purpose) */ RCC_DeInit();
/* Enable HSE */ RCC_HSEConfig(RCC_HSE_ON);
/* Wait till HSE is ready */ HSEStartUpStatus = RCC_WaitForHSEStartUp();
Re: STM32 Primer 2 Extension connector - I2C problems
I suggest you look at the MEMSTOLCD example. It is not done for the Primers (but for the Raisonance' Reva board), but it manages the I2c controller to access the MEMS. I should be easy to adapt it to your case.
Re: STM32 Primer 2 Extension connector - I2C problems
Thank you very much for the help!
I have carefully looked at the MEMSTOLCD example, and used it as a base for my I2C operation. I have also initialised the RCC, GPIO and I2C, however i am still having problems when using the application in Circle OS. The problem occurs after the START is generated, the program sticks in the
Is this because the START is not generated because i have not pulled up the I2c pins PB6 and PB7?
If so, how do I go about pulling up these pins? Should it be done externally with 4.7k ohm resistors? Or with a function for the GPIOs? Or is it possible to use a different GPIO pin set up, such as Push-Pull to achieve the I2C operation?
Re: STM32 Primer 2 Extension connector - I2C problems
Hi !
Your problem probably come indeed of the fact that you don't put pull up resistors. It is something you do on the hardware. You put one resistor (4.7k should be ok) between your line and VCC.
Re: STM32 Primer 2 Extension connector - I2C problems
I have pulled up the SCL and SDA lines with 4k7 resistors, and checked this with an oscilloscope, but still no luck un running the application!
Here is the Circle OS application code i am using. The application gets stuck just after the START is generated. I can't see anything I have missed!
Code:
/* Includes ------------------------------------------------------------------*/
#include "circle_api.h"
/* Private defines -----------------------------------------------------------*/
// The following should be the minimal CircleOS version needed by your application
#define NEEDEDVERSION "V 1.5"
/* Private variables ---------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
enum MENU_code MsgVersion(void);
/* Public variables ----------------------------------------------------------*/
const char Application_Name[8+1] = {"I2C Test"}; // Max 8 characters
/*******************************************************************************
* Function Name : Application_Ini
* Description : Initialization function of Circle_App. This function will
* be called only once by CircleOS.
* Input : None
* Return : MENU_CONTINUE_COMMAND
*******************************************************************************/
enum MENU_code Application_Ini ( void )
{
// Ensure that the current OS version is recent enough
if(strcmp(UTIL_GetVersion(), NEEDEDVERSION) < 0)
{
return MsgVersion();
}
// TODO: Write your application initialization function here.
// RCC SYSTEM CLOCK CONFIG ----------------------------------------------------/
{
ErrorStatus HSEStartUpStatus;
/* RCC system reset(for debug purpose) */
RCC_DeInit();
/* Enable HSE */
RCC_HSEConfig(RCC_HSE_ON);
/* Wait till HSE is ready */
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS)
{
/* HCLK = SYSCLK */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* PCLK2 = HCLK */
RCC_PCLK2Config(RCC_HCLK_Div2);
/* PCLK1 = HCLK/2 */
RCC_PCLK1Config(RCC_HCLK_Div2);
/* Flash 2 wait state */
FLASH_SetLatency(FLASH_Latency_2);
/* Enable Prefetch Buffer */
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
/* PLLCLK = 8MHz * 9 = 72 MHz */
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
/* Enable PLL */
RCC_PLLCmd(ENABLE);
/* Wait till PLL is ready */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}
/* Select PLL as system clock source */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* Wait till PLL is used as system clock source */
while(RCC_GetSYSCLKSource() != 0x08)
{
}
}
/* Enable GPIOs clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/* Enable I2C1 clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 , ENABLE);
}
// GPIO CONFIGURATION --------------------------------------------------------/
// Configure all GPIOB in open drain AF mode (for different I2C levels)
// and Initialise
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// I2C CONFIGURATION ---------------------------------------------------------/
// Enable I2C1 peripheral
I2C_Cmd(I2C1, ENABLE);
// Configure I2C
I2C_InitTypeDef I2C_InitStructure;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; //only effects fast mode
I2C_InitStructure.I2C_OwnAddress1 = 0xA0;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000;
// Initialise the I2C1 peripheral after enabling it
I2C_Init(I2C1, &I2C_InitStructure);
// I2C1 can now be used through a set of specific I2C functions
const char msg[] = "Init ok";
DRAW_DisplayString( 2, 90, msg, sizeof(msg)); // X, Y, string, length
return MENU_CONTINUE_COMMAND;
}
/*******************************************************************************
* Function Name : Application_Handler
* Description : Management of the Circle_App.
*
* Input : None
* Return : MENU_CONTINUE
*******************************************************************************/
enum MENU_code Application_Handler ( void )
{
// TODO: Write your application handling here.
const char msg[] = "Display here";
DRAW_DisplayString( 10, 70, msg, sizeof(msg)); // X, Y, string, length
// Circle OS I2C Application Test - To read from a Read Only register specified
// in the FPGA.
// Using specific I2C functions, execute a combined message protocol
// to read from the Read Only Version register in the FPGA.
// Master generates START condition to start communication
I2C_GenerateSTART(I2C1, ENABLE);
// Test on EV5 and clear it
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
// APPLICATION GETS STUCK HERE - CANNOT EXIT APPLICATION
const char help2[] = "exitEV5while";
DRAW_DisplayString( 15, 15, help2, sizeof(help2));
// Send FPGA address for write
I2C_Send7bitAddress(I2C1, 0x20, I2C_Direction_Transmitter);
// Test on EV6 and clear it
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
const char help3[] = "afterEV6while";
DRAW_DisplayString( 15, 25, help3, sizeof(help3));
// Clear EV6 by setting again the PE bit
I2C_Cmd(I2C1, ENABLE);
// Send the FPGA's internal address to write to (24,hex 0x18)
I2C_SendData(I2C1, 0x18);
// Test on EV8 and clear it
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// Send START condition a second time
I2C_GenerateSTART(I2C1, ENABLE);
// Test on EV5 and clear it
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
// Send FPGA address for read
I2C_Send7bitAddress(I2C1, 0x20, I2C_Direction_Receiver);
// Test on EV6 and clear it
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
// For single data transfer - disable ACK before reading the data
I2C_AcknowledgeConfig(I2C1, DISABLE);
// Test on EV7 and clear it
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
// Read the data just received from the FPGA on I2C1
u8 ReceivedData;
ReceivedData = I2C_ReceiveData(I2C1);
// Send STOP condition on I2C1
I2C_GenerateSTOP(I2C1, ENABLE);
// Enable Acknowledgement to be ready for another reception
I2C_AcknowledgeConfig(I2C1, ENABLE);
// Using CircleOS Display the received data on the STM32 Primer 2
DRAW_DisplayString( 10, 60, ReceivedData, sizeof(ReceivedData)); // X, Y, string, length
#if 1
if ( BUTTON_GetState() == BUTTON_PUSHED )
{
BUTTON_WaitForRelease();
return MENU_Quit();
}
#endif
// This routine will get called repeatedly by CircleOS, until we
// return MENU_LEAVE
return MENU_CONTINUE; // Returning MENU_LEAVE will quit to CircleOS
}
I have tried everything I can think of but, as a beginner to I2C and application writing, perhaps there is something i am doing wrong!
Re: STM32 Primer 2 Extension connector - I2C problems
I remember we encountered some problems with I2C in CircleOS when accessing the audio device. The solution we found consisted in disabling the timer2 interrupt during the I2C access. At the end, we moved the code into the timer2 interrupt handler (MEMS_Handler) to avoid any interrupt, and it works. Not very satisfying... We thought that the issue was caused by the audio device, but the problem could be more general.
Re: STM32 Primer 2 Extension connector - I2C problems
I had got the same issue - no signals on SDA and SCL. To solve the problem you need to put: I2C_DeInit(I2C1); before starting to configure your I2C, I would suggest to put it after I2C_InitTypeDef I2C_InitStructure; and before rest of configuration. You should have your signals now!