2019-09-27 09:31 AM
I'm creating an I2C library for PCA8596 to control servos using STM32F4 Discovery as master. I already checked the PCA using arduino, and it worked. It also compiled well and can be uploaded.
The problem is the SCL and SDA from the stm didn't generate any signal. My friend checked it, and said that the transmission stopped at the address. It confussed me, bcs i input the right address of PCA9685.
Please anyone can check and find out the mistakes i made on my library.
#define I2C2_TIMEOUT 0x3000
#define I2C_ACK_ENABLE 1
#define I2C_ACK_DISABLE 0
static __IO uint32_t TimingDelay = 0;
/*---------------------------
* I2C Initialization
---------------------------*/
void PCA_init_I2C (void)
{
// Clock enable for I2Cx bus
RCC_APB1PeriphClockCmd(RCC_PCA,ENABLE);
//Clock enable for SCL and SDA pins
RCC_AHB1PeriphClockCmd(PCA_RCC,ENABLE);
// Configuration for Alternative Function in SCL and SDA pins
GPIO_PinAFConfig(PCA_PORT,PS_SCL_PCA,AF_PCA);
GPIO_PinAFConfig(PCA_PORT,PS_SDA_PCA,AF_PCA);
//I2C pin init SCL PIN SDA PIN
GPIO_InitStructure.GPIO_Pin = PIN_SCL_PCA | PIN_SDA_PCA ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_Init(PCA_PORT, &GPIO_InitStructure);
// I2C_DeInit(I2C2);
//// Initialization of I2C_InitTypeDef
I2C_InitStructure.I2C_Mode = I2Cx_MODE;
I2C_InitStructure.I2C_DutyCycle = I2Cx_DUTY_CYCLE;
I2C_InitStructure.I2C_OwnAddress1 = I2Cx_OWN_ADDRESS;
I2C_InitStructure.I2C_Ack = I2Cx_ACK;
I2C_InitStructure.I2C_ClockSpeed = 100000; //5kHz
I2C_InitStructure.I2C_AcknowledgedAddress = I2Cx_ACKNOWLEDGED_ADDRESS;
I2C_Init(I2C_PCA,&I2C_InitStructure);
I2C_Cmd(I2C_PCA,ENABLE);
}
/*---------------------------
* Primary Function of I2C
---------------------------*/
int16_t PCA_readByte_I2C(uint8_t reg)
{
uint8_t received_data;
uint32_t TimeOut = I2C2_TIMEOUT;
//Generate I2C start pulse
I2C_GenerateSTART(I2C2, ENABLE);
//Wait till I2C is busy
while (!I2C_GetFlagStatus(I2C2, I2C_FLAG_SB)) {
if (TimeOut != 0)
TimeOut--;
}
//Ack disable
I2C_AcknowledgeConfig(I2C2, DISABLE);
//Send address with zero last bit
I2C_Send7bitAddress(I2C2,(i2cadd<<1),I2C_Direction_Transmitter);
//Wait till finished
while (!I2C_GetFlagStatus(I2C2, I2C_FLAG_ADDR)) {
if (TimeOut != 0)
TimeOut--;
}
//Read status register to clear ADDR flag
I2C2->SR2;
//Wait till I2C is not busy anymore
while (!I2C_GetFlagStatus(I2C2, I2C_FLAG_TXE)) {
if (TimeOut != 0)
TimeOut--;
}
//Send I2C Register Address
I2C_SendData(I2C2, reg);
while ((!I2C_GetFlagStatus(I2C2, I2C_FLAG_TXE)) || (!I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF))){
if (TimeOut != 0)
TimeOut--;
}
I2C_AcknowledgeConfig(I2C2, ENABLE);
//Generate I2C start pulse
I2C_GenerateSTART(I2C2, ENABLE);
//Wait till I2C is busy
while (!I2C_GetFlagStatus(I2C2, I2C_FLAG_SB)) {
if (TimeOut != 0)
TimeOut--;
}
//Send address with zero last bit
I2C_Send7bitAddress(I2C2,(i2cadd<<1),I2C_Direction_Receiver);
//Wait till finished
while (!I2C_GetFlagStatus(I2C2, I2C_FLAG_ADDR)) {
if (TimeOut != 0)
TimeOut--;
}
//Read status register to clear ADDR flag
I2C2->SR2;
while (!I2C_GetFlagStatus(I2C2, I2C_FLAG_RXNE)){
if (TimeOut != 0)
TimeOut--;
}
// Stop Sequences
I2C_GenerateSTOP(I2C2, ENABLE);
received_data=I2C_ReceiveData(I2C2);
//Ack enable
I2C_AcknowledgeConfig(I2C2, ENABLE);
return received_data;
}
int16_t PCA_writeByte_I2C(uint8_t reg,uint8_t value)
{
uint32_t TimeOut = I2C2_TIMEOUT;
//Generate I2C start pulse
I2C_GenerateSTART(I2C2, ENABLE);
//Wait till I2C is busy
while (!I2C_GetFlagStatus(I2C2, I2C_FLAG_SB)) {
if (TimeOut != 0)
TimeOut--;
}
//Send slave address write
I2C_Send7bitAddress(I2C2,(i2cadd<<1),I2C_Direction_Transmitter);
//Wait till finished
while (!I2C_GetFlagStatus(I2C2, I2C_FLAG_ADDR)) {
if (TimeOut != 0)
TimeOut--;
}
//Read status register to clear ADDR flag
I2C2->SR2;
while(!I2C_GetFlagStatus(I2C2, I2C_FLAG_TXE)) {
if(TimeOut != 0)
TimeOut--;
}
// Value Send
I2C_SendData(I2C2, reg);
while(!I2C_GetFlagStatus(I2C2, I2C_FLAG_TXE)) {
if(TimeOut != 0)
TimeOut--;
}
// Value Send
I2C_SendData(I2C2, value);
//Wait till transmitter not empty
while ((!I2C_GetFlagStatus(I2C2, I2C_FLAG_TXE)) || (!I2C_GetFlagStatus(I2C2, I2C_FLAG_BTF))) {
if (TimeOut != 0) {
TimeOut--;
}
}
//Generate stop
I2C_GenerateSTOP(I2C2, ENABLE);
return 0;
}
int16_t PCA_writeMultiByte_I2C(uint8_t reg, uint8_t jumlahdata)
{
int a, value[jumlahdata];
uint32_t TimeOut = I2C2_TIMEOUT;
//Generate I2C start pulse
I2C_GenerateSTART(I2C2, ENABLE);
//Wait till I2C is busy
while (!I2C_GetFlagStatus(I2C2, I2C_FLAG_SB)) {
if (TimeOut != 0)
TimeOut--;
}
//Send slave address write
I2C_Send7bitAddress(I2C2,(i2cadd<<1),I2C_Direction_Transmitter);
//Wait till finished
while (!I2C_GetFlagStatus(I2C2, I2C_FLAG_ADDR)) {
if (TimeOut != 0)
TimeOut--;
}
//Read status register to clear ADDR flag
I2C2->SR2;
while(!I2C_GetFlagStatus(I2C2, I2C_FLAG_TXE)) {
if(TimeOut != 0)
TimeOut--;
}
// Value Send
I2C_SendData(I2C2, reg);
for(a=0;a<jumlahdata;a++){
while(!I2C_GetFlagStatus(I2C2, I2C_FLAG_TXE)) {
if(TimeOut != 0)
TimeOut--;
}
// Value Send
I2C_SendData(I2C2, (value[a] & 0xFF));
while(!I2C_GetFlagStatus(I2C2, I2C_FLAG_TXE)) {
if(TimeOut != 0)
TimeOut--;
}
// Value Send
I2C_SendData(I2C2, (value[a] >> 8));
}
//Wait till transmitter not empty
while ((!I2C_GetFlagStatus(I2C2, I2C_FLAG_TXE)) || (!I2C_GetFlagStatus(I2C2, I2C_FLAG_BTF))) {
if (TimeOut != 0) {
TimeOut--;
}
}
//Generate stop
I2C_GenerateSTOP(I2C2, ENABLE);
return 0;
}
and this my lib.h
#define i2cadd 0x40 //PCA Address
#define OSC_FREQ 25000000L
#define I2C_PCA I2C2 //Selected I2C peripheral
#define RCC_PCA RCC_APB1Periph_I2C2 //Bus where the peripheral is connected
#define AF_PCA GPIO_AF_I2C2 //Alternate function for GPIO pins
//Bus for GPIO Port of SCL-SDA
#define PCA_RCC RCC_AHB1Periph_GPIOB
#define PCA_PORT GPIOB
//for SCL pin
#define PIN_SCL_PCA GPIO_Pin_10
#define PS_SCL_PCA GPIO_PinSource10
//for SDA pin
#define PIN_SDA_PCA GPIO_Pin_11
#define PS_SDA_PCA GPIO_PinSource11
#define I2Cx_ACKNOWLEDGED_ADDRESS I2C_AcknowledgedAddress_7bit
#define I2Cx_MODE I2C_Mode_I2C
#define I2Cx_OWN_ADDRESS 0x00
#define I2Cx_ACK I2C_Ack_Disable
#define I2Cx_DUTY_CYCLE I2C_DutyCycle_2
/*
* REGISTERS OF PCA
*/
#define MODE1 0x00
#define MODE1_ALLCALL_BIT 0
#define MODE1_ALLCALL_MASK ~(1 << MODE1_ALLCALL_BIT)
#define MODE1_SUB3_BIT 1
#define MODE1_SUB3_MASK ~(1 << MODE1_SUB3_BIT)
#define MODE1_SUB2_BIT 2
#define MODE1_SUB2_MASK ~(1 << MODE1_SUB2_BIT)
#define MODE1_SUB1_BIT 3
#define MODE1_SUB1_MASK ~(1 << MODE1_SUB1_BIT)
#define MODE1_SLEEP_BIT 4
#define MODE1_SLEEP_MASK ~(1 << MODE1_SLEEP_BIT)
#define MODE1_AI_BIT 5
#define MODE1_AI_MASK ~(1 << MODE1_AI_BIT)
#define MODE1_EXTCLK_BIT 6
#define MODE1_EXTCLK_MASK ~(1 << MODE1_EXTCLK_BIT)
#define MODE1_RESTART_BIT 7
#define MODE1_RESTART_MASK ~(1 << MODE1_RESTART_BIT)
#define MODE2 0x01
#define MODE2_OUTNE_BIT 0
#define MODE2_OUTNE_MASK ~(3 << MODE2_OUTNE_BIT)
#define MODE2_OUTDRV_BIT 2
#define MODE2_OUTDRV_MASK ~(1 << MODE2_OUTDRV_BIT)
#define MODE2_OCH_BIT 3
#define MODE2_OCH_MASK ~(1 << MODE2_OCH_BIT)
#define MODE2_INVRT_BIT 4
#define MODE2_INVRT_MASK ~(1 << MODE2_INVRT_BIT)
#define OCH_ACK 1
#define OCH_STOP 0
#define OUTDRV_TOTEM_POLE 1
#define OUTDRV_OPEN_DRAIN 1
#define OUTNE_LOW 0
#define OUTNE_HIGH 1
#define OUTNE_HIGH_IMPEDANCE 2
#define SUBADR1 0x02
#define SUBADR2 0x03
#define SUBADR3 0x04
#define ALLCALLADR 0x05
#define LED0_ON_L 0x06
#define LED0_ON_H 0x07
#define LED0_OFF_L 0x08
#define LED0_OFF_H 0x09
#define ALL_LED_ON_L 0xFA
#define ALL_LED_ON_H 0xFB
#define ALL_LED_OFF_L 0xFC
#define ALL_LED_OFF_H 0xFD
#define PRE_SCALE 0xFE
#define false 0
#define true 1
static __IO uint32_t TimingDelay;
//Functions
void PCA_init();
void PCA_init_I2C ();
int16_t PCA_readByte_I2C(uint8_t reg);
int16_t PCA_writeByte_I2C(uint8_t reg, uint8_t value);
int16_t PCA_readMultiByte_I2C(uint8_t reg, uint8_t jumlahdata);