2014-02-03 02:27 AM
I am learning embedded development on the STM3220G-EVAL board with the STM32F207 microcontroller. I have tried to test the I2C interface by interfacing the two I2C2 and I2C3 modules on the same chip and sending/receiving a character. Here is the code I have currently written (using mdk-arm 5):
#include <stm32f2xx.h>
volatile
uint8_t data =
'a'
, recv =
'x'
;
void
i2c_init(
void
);
void
I2C2_EV_IRQHandler(
void
)
{
volatile
uint16_t stat, dummy;
stat = I2C2->SR1;
switch
(stat)
{
// SB set; read SR1 and write slave address in DR to clear
case
0x01:
dummy = I2C2->SR1;
// Send address of slave
I2C2->DR = (0x08 << 1);
break
;
// ADDR set; read SR1 and SR2 to clear
case
0x02:
dummy = I2C2->SR1;
dummy = I2C2->SR2;
break
;
// BTF set; generate stop condition to clear
case
0x04:
// Generate stop
I2C2->CR1 |= (1 << 9);
break
;
// TxE set; write to DR to clear
case
0x80:
I2C2->DR = data;
break
;
}
}
void
I2C3_EV_IRQHandler(
void
)
{
volatile
uint16_t stat, dummy;
stat = I2C3->SR1;
switch
(stat)
{
// ADDR set; read SR1 and SR2 to clear
case
0x02:
dummy = I2C3->SR1;
dummy = I2C3->SR2;
break
;
// STOPF set; read SR1 and write CR1 to clear
case
0x10:
dummy = I2C3->SR1;
I2C3->CR1 &= ~(1 << 0);
break
;
// RxNE set; read DR to clear
case
0x40:
recv = I2C3->DR;
break
;
}
}
int
main()
{
i2c_init();
while
(1)
{
if
(!(I2C2->OAR1 & (1 << 14)))
I2C2->OAR1 |= (1 << 14);
if
(!(I2C3->OAR1 & (1 << 14)))
I2C3->OAR1 |= (1 << 14);
if
(recv !=
'x'
)
break
;
}
return
0;
}
void
i2c_init(
void
)
{
// Enable GPIOF, GPIOH, I2C2 and I2C3 peripherals
RCC->AHB1ENR |= (1 << 5);
RCC->AHB1ENR |= (1 << 7);
RCC->APB1ENR |= (1 << 22);
RCC->APB1ENR |= (1 << 23);
// Set GPIO mode to AF
GPIOF->MODER |= (1 << 1);
GPIOF->MODER |= (1 << 3);
GPIOH->MODER |= (1 << 15);
GPIOH->MODER |= (1 << 17);
// Set GPIO type to OD
GPIOF->OTYPER |= (1 << 0);
GPIOF->OTYPER |= (1 << 1);
GPIOH->OTYPER |= (1 << 7);
GPIOH->OTYPER |= (1 << 8);
// Set GPIO speed to 50MHz
GPIOF->OSPEEDR |= (1 << 1);
GPIOF->OSPEEDR |= (1 << 3);
GPIOH->OSPEEDR |= (1 << 15);
GPIOH->OSPEEDR |= (1 << 17);
// Internal pullups
/*
GPIOF->PUPDR |= (1 << 0);
GPIOF->PUPDR |= (1 << 2);
GPIOH->PUPDR |= (1 << 14);
GPIOH->PUPDR |= (1 << 16);
*/
// Link to AFs
GPIOF->AFR[0] |= (1 << 2);
GPIOF->AFR[0] |= (1 << 6);
GPIOH->AFR[0] |= (1 << 30);
GPIOH->AFR[1] |= (1 << 2);
// Enable interrupts
I2C2->CR2 |= (1 << 9);
I2C2->CR2 |= (1 << 10);
I2C3->CR2 |= (1 << 9);
I2C3->CR2 |= (1 << 10);
NVIC_EnableIRQ(I2C2_EV_IRQn);
NVIC_EnableIRQ(I2C3_EV_IRQn);
// Must set bit 14 in OAR1 to 1
I2C2->OAR1 |= (1 << 14);
I2C3->OAR1 |= (1 << 14);
// Set addresses
I2C2->OAR1 |= (0x04 << 1);
I2C3->OAR1 |= (0x08 << 1);
// Set peripheral clock frequency
I2C2->CR2 |= 0x08;
I2C3->CR2 |= 0x08;
I2C2->CCR |= 0x28;
I2C3->CCR |= 0x28;
I2C2->TRISE |= 0x09;
I2C3->TRISE |= 0x09;
// Enable ACK
I2C3->CR1 |= (1 << 10);
// Enable I2C peripherals
I2C2->CR1 |= (1 << 0);
I2C3->CR1 |= (1 << 0);
// Generate START condition
I2C2->CR1 |= (1 << 8);
}
The problems I am facing are:
2014-02-03 07:03 AM
Try to reset the I2C clock during the initialization, that is ''mandatory'', also i2c gpio pin config interface should be open drain.
2014-02-05 02:42 AM
After setting up a few jumpers on the board, the master event handler is successfully being called. But still some problems persist. Now the acknowledge failure bit is being set, and the slave handler is not called. Bus lines have been verified to be HIGH when idle.
@Wapers : Thanks for the suggestions. Tried to reset the clock but that made no difference. The pins have already been set to open drain mode Here is the updated code:
#include <stm32f2xx.h>
volatile
uint8_t data =
'a'
, recv =
'x'
;
void
i2c_init(
void
);
void
I2C2_EV_IRQHandler(
void
)
{
volatile
uint16_t stat, dummy;
stat = I2C2->SR1;
switch
(stat)
{
// SB set; read SR1 and write slave address in DR to clear
case
0x01:
dummy = I2C2->SR1;
// Send address of slave
I2C2->DR = (0x08 << 1);
break
;
// ADDR set; read SR1 and SR2 to clear
case
0x02:
dummy = I2C2->SR1;
dummy = I2C2->SR2;
break
;
// TxE set; write to DR to clear
case
0x80:
I2C2->DR = data;
break
;
// TxE and BTF set; generate stop condition to clear
case
0x84:
// Generate stop
I2C2->CR1 |= (1 << 9);
break
;
}
}
void
I2C3_EV_IRQHandler(
void
)
{
volatile
uint16_t stat, dummy;
stat = I2C3->SR1;
switch
(stat)
{
// ADDR set; read SR1 and SR2 to clear
case
0x02:
dummy = I2C3->SR1;
dummy = I2C3->SR2;
break
;
// STOPF set; read SR1 and write CR1 to clear
case
0x10:
dummy = I2C3->SR1;
I2C3->CR1 &= ~(1 << 0);
break
;
// RxNE set; read DR to clear
case
0x40:
recv = I2C3->DR;
break
;
}
}
int
main()
{
i2c_init();
// Generate START condition
I2C2->CR1 |= (1 << 8);
while
(1)
{
if
(!(I2C2->OAR1 & (1 << 14)))
I2C2->OAR1 |= (1 << 14);
if
(!(I2C3->OAR1 & (1 << 14)))
I2C3->OAR1 |= (1 << 14);
if
(recv !=
'x'
)
break
;
}
return
0;
}
void
i2c_init(
void
)
{
// Enable GPIOA, GPIOC, GPIOF, I2C2 and I2C3 peripherals
RCC->AHB1ENR |= (1 << 0);
RCC->AHB1ENR |= (1 << 2);
RCC->AHB1ENR |= (1 << 5);
RCC->APB1ENR |= (1 << 22);
RCC->APB1ENR |= (1 << 23);
// Set GPIO mode to AF
GPIOA->MODER |= (1 << 17);
GPIOC->MODER |= (1 << 19);
GPIOF->MODER |= (1 << 1);
GPIOF->MODER |= (1 << 3);
// Set GPIO type to OD
GPIOA->OTYPER |= (1 << 8);
GPIOC->OTYPER |= (1 << 9);
GPIOF->OTYPER |= (1 << 0);
GPIOF->OTYPER |= (1 << 1);
// Set GPIO speed to 50MHz
GPIOA->OSPEEDR |= (1 << 17);
GPIOC->OSPEEDR |= (1 << 19);
GPIOF->OSPEEDR |= (1 << 1);
GPIOF->OSPEEDR |= (1 << 3);
// Link to AFs
GPIOA->AFR[1] |= (1 << 2);
GPIOC->AFR[1] |= (1 << 6);
GPIOF->AFR[0] |= (1 << 2);
GPIOF->AFR[0] |= (1 << 6);
// Reset clocks
I2C2->CR2 = 0x00;
I2C3->CR2 = 0x00;
I2C2->CCR = 0x00;
I2C3->CCR = 0x00;
// Enable interrupts
I2C2->CR2 |= (1 << 9);
I2C2->CR2 |= (1 << 10);
I2C3->CR2 |= (1 << 9);
I2C3->CR2 |= (1 << 10);
NVIC_EnableIRQ(I2C2_EV_IRQn);
NVIC_EnableIRQ(I2C3_EV_IRQn);
// Must set bit 14 in OAR1 to 1
I2C2->OAR1 |= (1 << 14);
I2C3->OAR1 |= (1 << 14);
// Set addresses
I2C2->OAR1 = (0x04 << 1);
I2C3->OAR1 = (0x08 << 1);
// Set peripheral clock frequency
I2C2->CR2 |= 0x08;
I2C3->CR2 |= 0x08;
I2C2->CCR |= 0x28;
I2C3->CCR |= 0x28;
I2C2->TRISE = 0x09;
I2C3->TRISE = 0x09;
// Enable ACK
I2C2->CR1 |= (1 << 10);
I2C3->CR1 |= (1 << 10);
// Enable I2C peripherals
I2C2->CR1 |= (1 << 0);
I2C3->CR1 |= (1 << 0);
}
2014-04-20 02:15 AM
Sorry for the delay in mentioning this, but I have successfully solved this problem by using the STM32 CPAL library available from ST. I have tested this library with the onboard accelerometer by reading the 'WHO_AM_I' register in the accelerometer. The code for this is:
#include ''cpal_i2c.h''
int
main()
{
// Configuration
CPAL_TransferTypeDef RxStruct;
uint8_t RxBuf;
RxStruct.pbBuffer = &RxBuf;
RxStruct.wAddr1 = 0x39;
// Initialization
CPAL_I2C_StructInit(&I2C1_DevStructure);
I2C1_DevStructure.CPAL_Mode = CPAL_MODE_MASTER;
I2C1_DevStructure.CPAL_ProgModel = CPAL_PROGMODEL_DMA;
I2C1_DevStructure.pCPAL_I2C_Struct->I2C_ClockSpeed = 100000;
I2C1_DevStructure.pCPAL_TransferRx = &RxStruct;
I2C1_DevStructure.pCPAL_TransferTx = pNULL;
CPAL_I2C_Init(&I2C1_DevStructure);
// Communication
RxStruct.wNumData = 1;
RxStruct.wAddr2 = 0x0F;
if
(CPAL_I2C_Read(&I2C1_DevStructure) != CPAL_PASS)
{
// Error
}
while
(I2C1_DevStructure.CPAL_State != CPAL_STATE_READY);
while
(1);
return
0;
}