This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hi
Thanks for your support. I have to move on to i2c bus. Below is the code that I have written for i2c2 channel which is connected to a temperature sensor device. The slave address of temperature sensor is 0x90 . I could only get the first 9 clocks of address sent and not the data clocks. The data value is 0. Below is my code. Please comment on my code below.
Hi LayEng,
I could only get the first 9 clocks of address sent and not the data clocks.
This condition will occur when we don't get any ack from slave after sending address..
If you see above waveforms, the slave should bring down SDA line low in 9th clock pulse but it is not happening so Master doesn't send any further bytes.
The reason might be due to
1. Slave may not connect properly to SDA and SCL lines.
2. Slave may not powerup.
3. Master not sending proper address.
4. Pull-ups may not connect properly.
If you enable Ignore NACK option in HALCoGen, master will send data by ignoring NACK, but don't do this in your example because slave should give ACK after sending proper address.
--
Thanks & regards,
Jagadish.
Dear Jagadish
Thank you for your reply. It helps me to understand the behaviour of TI i2c bus driver. In answer to my other question, I also got the NACK interrupt (I enable in halcogen) which I use to detect defective or missing IC.
I would like to ask about the slave device address that I have to fill in. If the slave device is PCA9535, what is the slave address that I should set in i2cSetSlaveAdd(i2c, PCA9535_3_I2C_ADDR). Is PCA9535_3_I2C_ADDR = 0x20 or 0x40 assuming a2, a1, a0=0?
I find that my software can get stuck at the bus busy while loop:
while(i2cIsBusBusy(i2c) == true);
What is the cause?
Looking forward to your reply. Thank you
Hi LayEng,
I would like to ask about the slave device address that I have to fill in. If the slave device is PCA9535, what is the slave address that I should set in i2cSetSlaveAdd(i2c, PCA9535_3_I2C_ADDR). Is PCA9535_3_I2C_ADDR = 0x20 or 0x40 assuming a2, a1, a0=0?
We have to write 0x20 if a2,a1 and a0 are zero.
This is because we should not give R/W bit to the address
So, the binary value of slave address if the a2,a1 and a0 are zero is b(0100000) and its equivalent hex is 0x20.
--
Thanks & regards,
Jagadish.
Dear Jagadish
Thank you for your reply. I have 7 i2c devices. I need to test whether the i2cdevices are available. I am using NACK interrupt to tell me and set the error bits.
I have 3 PCA9535 using 3 addresses; Below is my code. I have no devices attached to the mcu. I want to poll the 3 PCA9535. However, I find that after the first transmission to the first pca9535, the scl remain low(bus busy) even if I do a i2c reset. This will cause an inability to send i2c instructions to the next device. Please let me know what is wrong with my code. Thank you.
Hi Jagadish
Mysteriously, the bus busy bit BB is ok now, without having to do i2c reset. But the stop bit is still =0. As a result, I can't move on to check the next pca9535. Hope you can provide a sample code or correct my code such that I can test every non existent device and set the error code accordingly. At the moment, I can only test the first device and the i2c bus will not move on to the next device in my for loop, ie move on to idx 1, 2 .
Thank you.
Hi LayEng,
I am attaching the code for your reference, please go through it.
In this code, I am using trying to communicate with 3 slaves and if one slave is not available than i am checking whether second slave available or not and continued this operation.
Verify and let me know if you have any doubts.
--
Thanks & regards,
Jagadish.
Dear Jagadish
I have gone through the hcg file and your source code. I would like to ask the following questions:
1. I notice that you didn't use interrurpt (eg nack interrupt) to check if there is nack. Instead you use polling. Is this better? It definitely breaks these 2 while loops :
while(i2cIsBusBusy(i2cREG1) == true)
while(i2cIsStopDetected(i2cREG1) == 0)
2. The only means to force the scl to go high is reset? I was toying the idea of using repeat mode for startup and then change to non repeat mode by setting RM bit and clearing RM bit in MDR register.
You use below to reset i2c.
i2cREG1->MDR = (uint32)((uint32)0U << 5U) is the same as
i2cREG1->MDR =0
I notice that my reset doesn't work.
Hope you can give me some comments. Thank you for your help.
Dear Jagadish
I forgot to add one more question. Hope you will reply this as well. Is it a must to send data to an i2c device? Actually sending an address is enough to detect whether there is noack. I notice that you send data of 0x10 . Thank you
Hi LayEng,
1. I notice that you didn't use interrurpt (eg nack interrupt) to check if there is nack. Instead you use polling. Is this better? It definitely breaks these 2 while loops :
In this case either way is fine i.e. interrupt or polling. If you use interrupt method, you should set a flag if ACK is not received and using that flag you can break the while loops and you can go and try second slave. And polling method also fine because after i2c start it will immediately send address and if it doesn't receive ACK then it will immediately set the NACK flag and using that flag, we can break the while loops and can try other slaves.
2. The only means to force the scl to go high is reset?
I never tested any other ways, i felt it would be a easy way to reset the i2c to bring it back to the initial state.
Is it a must to send data to an i2c device? Actually sending an address is enough to detect whether there is noack. I notice that you send data of 0x10 .
No need to send the data, you can just send address its just fine. Actually, i took one already existing example where it is sending 0x10 data also and i modified that example to your requirement so you can leave that.
--
Thanks & regards,
Jagadish.
Dear Jagadish
Thank you for your reply. I have resolved the noack and using only address without sending data. I have the following problems which I hope you can help.
1. I am very much plagued and irked by the while loop for tx, rx, stop bit. I don't know why it happens. Hope you can explain.
2. I have read somewhere in the ref manual that if I use this subroutine i2cReceive(i2c, 2, RX_Data); or i2cSend(i2c, 2, TX_Data), the length must be minimum 2?
3. I need to read data from a temperature sensor. In my first init sequence of this ic whereby there was no error detected, I was able to read the temperature value using this "bad" code. It is bad because I did not define the command byte, following the slave address. Code 1 is able to read some value without getting stuck in while loops. Code 2 has the write of command byte value 0 followed by 2 read. My code get stuck in the rx int while loop in i2cReceive. Hope you can give me a reference code for a write, followed by a read. Thank you
code 1:
for(idx = 0; idx < 2; idx++)
{
if(idx==0) bitmsk=BIT0_TEMP_IC_1;
else if(idx==1) bitmsk =BIT1_TEMP_IC_2;
u8I2cErrorBits &= ~(bitmsk); //clear i2c error for temp IC
devAddr=( idx ==0)? TCN75_1_I2C_ADDR: TCN75_2_I2C_ADDR;
printf("devAddr= 0x%2x, bitmsk=%02x \n", devAddr, bitmsk);
i2cSetMode(i2c, I2C_MASTER);
i2cSetDirection(i2c, I2C_RECEIVER);
i2cSetSlaveAdd(i2c, devAddr); // temp sensor is using i2c2
i2cSetStop(i2c);
/* Transmit Start Condition */
i2cSetStart(i2c);
//i2cSetStop(i2c);
//i2cClearSCD(i2c);
i2cSetCount(i2c, 2);
i2cReceive(i2c, 2, RX_Data);
//i2cSendByte(i2c, 0x00);
/* Wait until Bus Busy is cleared */
while(i2cIsBusBusy(i2c) == true)
{
if((i2c->STR & I2C_NACK) == I2C_NACK)
{
u8I2cErrorBits |=bitmsk;
error=1;
break; /*break while loop*/
}
}
/* Wait until Stop is detected */
while(i2cIsStopDetected(i2c) == 0)
{
if((i2c->STR & I2C_NACK) == I2C_NACK)
{
error=1;
u8I2cErrorBits |= bitmsk;
break; /*break while loop*/
}
}
/* Clear the Stop condition */
if (error)
{
error=0;
/*NACK is received due to slave not connected, So go to the next slave*/
i2c->MDR = (uint32)((uint32)0U << 5U);/** - i2c Enter reset */
i2c->MDR |= (uint32)I2C_RESET_OUT; /* i2c out of reset */
}
i2cSetStop(i2c);
i2cClearSCD(i2c);
printf("D:%d %d\r\n", RX_Data[0], RX_Data[1]);
printf("bitmsk = %02x \n", bitmsk);
bool bErrorIC= (u8I2cErrorBits & bitmsk? true:false);
printf("Temp IC %d error %d\n", idx, bErrorIC);
}
Code 2: Transmit of command byte works without getting stuck but code gets stuck in i2cReceive.
// send command byte T_AMBIENCE_REG
i2cSetSlaveAdd(i2c, devAddr);
/* Set mode as Master */
i2cSetMode(i2c, I2C_MASTER);
/* Set direction to receiver */
i2cSetDirection(i2c, I2C_TRANSMITTER);
i2cSetStop(i2c);
i2cClearSCD(i2c);
/* Transmit Start Condition */
i2cSetStart(i2c);
i2cSendByte(i2c, T_AMBIENCE_REG); // config reg set to 0.5 deg resolution
/* Wait until Bus Busy is cleared */
while(i2cIsBusBusy(i2c) == true);
/* Wait until Stop is detected */
while(i2cIsStopDetected(i2c) == 0);
i2cClearSCD(i2c);
//i2cSetStop(i2c);
/* Configure Data count */
/* Note: Optional - It is done in Init, unless user want to change */
//i2cSetMode(i2c, I2C_MASTER);
i2cSetDirection(i2c, I2C_RECEIVER);
i2cSetSlaveAdd(i2c, devAddr); // temp sensor is using i2c2
i2cSetStop(i2c);
i2cSetCount(i2c, 2);
/* Transmit Start Condition */
i2cSetStart(i2c);
//read 2 bytes from ambience register
i2cReceive(i2c, 2, RX_Data);
//i2cSendByte(i2c, 0x00);
/* Wait until Bus Busy is cleared */
while(i2cIsBusBusy(i2c) == true)
{
if((i2c->STR & I2C_NACK) == I2C_NACK)
{
u8I2cErrorBits |=bitmsk;
error=1;
break; /*break while loop*/
}
}
/* Wait until Stop is detected */
while(i2cIsStopDetected(i2c) == 0)
{
if((i2c->STR & I2C_NACK) == I2C_NACK)
{
error=1;
u8I2cErrorBits |= bitmsk;
break; /*break while loop*/
}
}
/* Clear the Stop condition */
if (error)
{
error=0;
/*NACK is received due to slave not connected, So go to the next slave*/
i2c->MDR = (uint32)((uint32)0U << 5U);/** - i2c Enter reset */
i2c->MDR |= (uint32)I2C_RESET_OUT; /* i2c out of reset */
}
i2cClearSCD(i2c);
i2cSetStop(i2c);
ret_value = (uint16_t) RX_Data[0] <<8 + (uint16_t) RX_Data[1]; // if msb is 1, number is negative
Please help. Thank you
Dear Jagadish
The write followed by a read refer to writing to a command byte followed by a read of 2 data bytes from the same slave address. I was able to get the reading if I break the sequence into into subroutines. Eg
TSS_vSetAmbienceReg(TCN75_1); // just the txmit portion
uint16_t temper= TSS_vRead(TCN75_1); // just the rx portion
If I combine these 2 functions into a single subroutine like in code 2 above, I get all kinds of overflow which I don't understand. I would very much like to know why and what is wrong with my code. FYI, for the ok state, the STR register =0x2430 . I would like to know bit NACKSNT. What is the meaning and how did it happen. Hope you can give me a reference code for a slave dev write+read combine.
Thank you
Dear Jagadish
Another instruction I don't like is:
2cClearSCD(i2c);
i2cSetStop(i2c);
I don't know what it is doing and how it affects the slave address. I read somewhere that if there is a stop bit, the slave address is gone.
Hope you can answer all my questions above. Thank you
Hi LayEng,
We have one example in our HALCoGen based on PCF8570 temperature sensor.
Did you get a chance to refer this? It might be useful for your application.
--
Thanks & regards,
Jagadish.
Dear Jagadish
Thank you for your reply. No, I have not seen this before. I just jump into the job and don't know where to get info except through you. I will look at it and ask questions after that.
How about the question about
2cClearSCD(i2c);
i2cSetStop(i2c);
Is it explained there? Thank you
Hi LayEng,
2cClearSCD(i2c);
i2cSetStop(i2c);Is it explained there?
This is fine actually, the clearSCD function will be helpful to clear already set SCD bit which is set due to a STOP condition has been sent if it is a master device.
The second function will be helpful to send a actual STOP bit over i2c line, as we cleared existing SCD flag in previous section right and this bit will now get set if the STOP condition properly generated from MASTER i2c device.
These two functions are in correct sequence, no issues.
--
Thanks & regards,
Jagadish.
Dear Jagadish
1. Thank you for your support. I have studied the example code that you recommended. I find that my problem is I must add this wait between the write command byte and read data
while(i2cIsMasterReady(i2c) != true);
2. I am also irked by this kind of while loops. They are everywhere and can hang the software because the function (eg in this case i2cIsMasterReady(i2c)) don't change state. Can you advise how best to take care of these hangs?
3. Is it compulsory to set the data count register ( i2cSetCount(i2c, 1);) ? From the specs it says
This down counter is used to generate a stop condition if a stop condition is specified (STP = 1) |
Where is the stop condition specified in this code below?
i2cSetMode(i2c, I2C_MASTER);
i2cSetDirection(i2c, I2C_TRANSMITTER);
i2cSetSlaveAdd(i2c, addr); // temp sensor is using i2c2
i2cSetCount(i2c, 1);
i2cSetStop(i2c);
/* Transmit Start Condition */
i2cSetStart(i2c);
i2cSendByte(i2c, cmd);
/* Wait until Bus Busy is cleared */
while(i2cIsBusBusy(i2c) == true)
{
delay++;
if((i2c->STR & I2C_NACK) == I2C_NACK || delay > 10000 )
{
u8I2cErrorBits |=bitmsk;
error=1;
break; /*break while loop*/
}
}
/* Wait until Stop is detected */
delay=0;
while(i2cIsStopDetected(i2c) == 0)
{
delay++;
if((i2c->STR & I2C_NACK) == I2C_NACK || delay > 10000 )
{
error=1;
u8I2cErrorBits |= bitmsk;
break; /*break while loop*/
}
}
if (error)
{
error=0;
/*NACK is received due to slave not connected, So go to the next slave*/
u16I2cSTRSave=i2c->STR;
i2c->MDR = (uint32)((uint32)0U << 5U);/** - i2c Enter reset */
i2c->MDR |= (uint32)I2C_RESET_OUT; /* i2c out of reset */
}
/* Clear the Stop condition */
i2cClearSCD(i2cREG1);
4. I have seen a code which set zero to data count.
Dear Jagadish
I have a question 6.
6. Is the order of writing this instructions before START important? Eg
i2cSetMode(i2c, I2C_MASTER);
i2cSetDirection(i2c, I2C_TRANSMITTER);
i2cSetSlaveAdd(i2c, addr); // temp sensor is using i2c2
i2cSetCount(i2c, 1);
i2cSetStop(i2c);
/* Transmit Start Condition */
i2cSetStart(i2c);
Can I write it in this order?
i2cSetStop(i2c);
i2cSetDirection(i2c, I2C_TRANSMITTER);
i2cSetSlaveAdd(i2c, addr); // temp sensor is using i2c2
i2cSetCount(i2c, 1);
i2cSetMode(i2c, I2C_MASTER);
i2cSetStart(i2c);
Hi LayEng,
1. Thank you for your support. I have studied the example code that you recommended. I find that my problem is I must add this wait between the write command byte and read data
Goot to hear that you solved the problem.
2. I am also irked by this kind of while loops. They are everywhere and can hang the software because the function (eg in this case i2cIsMasterReady(i2c)) don't change state. Can you advise how best to take care of these hangs?
I would say those delays are required for proper communication in i2c. Without delays we don't get expected behavior, so these delays are required.
3. Is it compulsory to set the data count register ( i2cSetCount(i2c, 1);) ? From the specs it says
This down counter is used to generate a stop condition if a stop condition is specified (STP = 1) Where is the stop condition specified in this code below?
Yes, it is compulsory. As a master of i2c you should generate STOP condition after transmitting required bytes or receiving some required bytes right. Using this down counter register we can do that, we will configure required number of bytes and we have to set STOP bit (note this stop condition not sent now it will get send only after down counter becomes zero). So now after start condition the master will start send or receive byte by byte and decrements the down counter after each byte and once the down counter value reaches to the zero the STOP condition will automatically be initiated to indicate slave that the transaction completed.
i2cSetStop(i2c);
5th line indicates the setting stop bit, remember setting stop bit means not sending stop, this stop condition will be sent only after down counter becomes zero.
4. I have seen a code which set zero to data count.
i2cSetCount(I2C1,0);What is the meaning of setting data count to 0?
It means there is no data bytes in the transmission, if you set stop bit and data count zero then only address will be transmitted and STOP condition will get generated after address transmission.
5. I would like to have your comments of STR register=0x1411 . What is the possible meaning of this setting?
Please go through the STR register description in section 31.6.3 in TRM
6. Is the order of writing this instructions before START important? Eg
It is not important but START condition should be at last
Can I write it in this order?
I guess you can but i never tested.
--
Thanks & regards
Jagadish.
Dear Jagadish
I find that I don't understand TI I2C so well. I find that I have intermitternt failures. I would like to upload a file with my i2c code. Can you tell me how to upload? Looking forward to your reply
Hi LayEng,
Please look at below thread
In above thread i explain how to insert a file
void i2cInit(void) { /* USER CODE BEGIN (3) */ /* USER CODE END */ /** @b initialize @b I2C1 */ /** - i2c Enter reset */ i2cREG1->MDR = (uint32)((uint32)0U << 5U); /** - set i2c mode */ i2cREG1->MDR = (uint32)((uint32)0U << 15U) /* nack mode */ | (uint32)((uint32)0U << 14U) /* free running */ | (uint32)((uint32)0U << 13U) /* start condition - master mode only */ | (uint32)((uint32)1U <<11U) /* stop condition */ | (uint32)((uint32)1U <<10U) /* Master/Slave mode */ | (uint32)((uint32)I2C_TRANSMITTER) /* Transmitter/receiver */ | (uint32)((uint32)I2C_7BIT_AMODE) /* xpanded address */ | (uint32)((uint32)0U << 7U) /* repeat mode */ | (uint32)((uint32)0U << 6U) /* digital loopback */ | (uint32)((uint32)0U << 4U) /* start byte - master only */ | (uint32)((uint32)0U << 3U) /* free data format */ | (uint32)((uint32)I2C_8_BIT); /* bit count */ /** - set i2c extended mode */ i2cREG1->EMDR = (uint32)0U << 1U; /* Ignore Nack Enable/Disable */ /** - set i2c Backward Compatibility mode */ i2cREG1->EMDR |= 0U; /** - Disable DMA */ i2cREG1->DMACR = 0x00U; /** - set i2c data count */ i2cREG1->CNT = 8U; /** - disable all interrupts */ i2cREG1->IMR = 0x00U; /** - set prescale */ i2cREG1->PSC = 8U; /** - set clock rate */ i2cREG1->CKH = 37U; i2cREG1->CKL = 37U; /** - set i2c pins functional mode */ i2cREG1->PFNC = (0U); /** - set i2c pins default output value */ i2cREG1->DOUT = (uint32)((uint32)1U << 1U) /* sda pin */ | (uint32)(1U); /* scl pin */ /** - set i2c pins output direction */ i2cREG1->DIR = (uint32)((uint32)1U << 1U) /* sda pin */ | (uint32)(1U); /* scl pin */ /** - set i2c pins open drain enable */ i2cREG1->PDR = (uint32)((uint32)0U << 1U) /* sda pin */ | (uint32)(0U); /* scl pin */ /** - set i2c pins pullup/pulldown enable */ i2cREG1->PDIS = (uint32)((uint32)1U << 1U) /* sda pin */ | (uint32)(1U); /* scl pin */ /** - set i2c pins pullup/pulldown select */ i2cREG1->PSEL = (uint32)((uint32)1U << 1U) /* sda pin */ | (uint32)(1U); /* scl pin */ /** - set interrupt enable */ i2cREG1->IMR = (uint32)((uint32)0U << 6U) /* Address as slave interrupt */ | (uint32)((uint32)0U << 5U) /* Stop Condition detect interrupt */ | (uint32)((uint32)0U << 4U) /* Transmit data ready interrupt */ | (uint32)((uint32)0U << 3U) /* Receive data ready interrupt */ | (uint32)((uint32)0U << 2U) /* Register Access ready interrupt */ | (uint32)((uint32)0U << 1U) /* No Acknowledgment interrupt */ | (uint32)((uint32)0U); /* Arbitration Lost interrupt */ i2cREG1->MDR |= (uint32)I2C_RESET_OUT; /* i2c out of reset */ /** - initialize global transfer variables */ g_i2cTransfer_t[0U].mode = (uint32)0U << 4U; g_i2cTransfer_t[0U].length = 0U; /** @b initialize @b I2C2 */ /** - i2c Enter reset */ i2cREG2->MDR = (uint32)((uint32)0U << 5U); /** - set i2c mode */ i2cREG2->MDR = (uint32)((uint32)0U << 15U) /* nack mode */ | (uint32)((uint32)0U << 14U) /* free running */ | (uint32)((uint32)0U << 13U) /* start condition - master mode only */ | (uint32)((uint32)1U <<11U) /* stop condition */ | (uint32)((uint32)1U <<10U) /* Master/Slave mode */ | (uint32)((uint32)I2C_TRANSMITTER) /* Transmitter/receiver */ | (uint32)((uint32)I2C_7BIT_AMODE) /* Expanded address */ | (uint32)((uint32)0 << 7U) /* repeat mode */ | (uint32)((uint32)0U << 6U) /* digital loopback */ | (uint32)((uint32)0U << 4U) /* start byte - master only */ | (uint32)((uint32)0U << 3U) /* free data format */ | (uint32)(I2C_8_BIT); /* bit count */ /** - set i2c extended mode */ i2cREG2->EMDR = (uint32)0U << 1U; /* Ignore Nack Enable/Disable */ /** - set i2c Backward Compatibility mode */ i2cREG2->EMDR |= 0U; /** - Disable DMA */ i2cREG2->DMACR = 0x00U; /** - set i2c data count */ i2cREG2->CNT = 8U; /** - disable all interrupts */ i2cREG2->IMR = 0x00U; /** - set prescale */ i2cREG2->PSC = 8U; /** - set clock rate */ i2cREG2->CKH = 37U; i2cREG2->CKL = 37U; /** - set i2c pins functional mode */ i2cREG2->PFNC = (0U); /** - set i2c pins default output value */ i2cREG2->DOUT = (uint32)((uint32)1U << 1U) /* sda pin */ | (uint32)(1U); /* scl pin */ /** - set i2c pins output direction */ i2cREG2->DIR = (uint32)((uint32)1U << 1U) /* sda pin */ | (uint32)(1U); /* scl pin */ /** - set i2c pins open drain enable */ i2cREG2->PDR = (uint32)((uint32)0U << 1U) /* sda pin */ | (uint32)(0U); /* scl pin */ /** - set i2c pins pullup/pulldown enable */ i2cREG2->PDIS = (uint32)((uint32)1U << 1U) /* sda pin */ | (uint32)(1U); /* scl pin */ /** - set i2c pins pullup/pulldown select */ i2cREG2->PSEL = (uint32)((uint32)1U << 1U) /* sda pin */ | (uint32)(1U); /* scl pin */ /** - set interrupt enable */ i2cREG2->IMR = (uint32)((uint32)0U << 6U) /* Address as slave interrupt */ | (uint32)((uint32)0U << 5U) /* Stop Condition detect interrupt */ | (uint32)((uint32)0U << 4U) /* Transmit data ready interrupt */ | (uint32)((uint32)0U << 3U) /* Receive data ready interrupt */ | (uint32)((uint32)0U << 2U) /* Register Access ready interrupt */ | (uint32)((uint32)0U << 1U) /* No Acknowledgment interrupt */ | (uint32)(0U); /* Arbitration Lost interrupt */ i2cREG2->MDR |= (uint32)I2C_RESET_OUT; /* i2c out of reset */ /** - initialize global transfer variables */ g_i2cTransfer_t[1U].mode = (uint32)0U << 4U; g_i2cTransfer_t[1U].length = 0U; /* USER CODE BEGIN (4) */ /* USER CODE END */ } void TSS_vInit(){ // set registers for sending to TCN75 // set slave address uint8_t idx; uint8_t devAddr=0; uint8_t RX_Data[2]={0}; uint8_t bitmsk=0; printf("TSS_vInit\n"); for(idx = 0; idx < 2; idx++) { devAddr=( idx ==0)? TCN75_1_I2C_ADDR: TCN75_2_I2C_ADDR; if(devAddr==TCN75_1_I2C_ADDR) bitmsk=BIT0_TCN75_1; else if(devAddr==TCN75_2_I2C_ADDR) bitmsk=BIT1_TCN75_2; printf("Temp sensor devAddr= 0x%2x \n", devAddr); SER_vCh2I2cRxData(devAddr,2,RX_Data); printf("D:%d %d\r\n", RX_Data[0], RX_Data[1]); bool bErrorIC= (u8I2cErrorBits & bitmsk? true:false); printf("Temp IC %d error %d\n", idx, bErrorIC); } } void SER_vCh2I2cRxData(uint8_t addr, uint8_t length, uint8_t* rxbuf){ uint8_t* RX_Data=rxbuf; i2cBASE_t *i2c=i2cREG2; uint8_t error=0; uint8_t bitmsk=0; uint32_t delay=0; if(addr==TCN75_1_I2C_ADDR) bitmsk=BIT0_TCN75_1; else if(addr==TCN75_2_I2C_ADDR) bitmsk=BIT1_TCN75_2; else if(addr==MAX5392_1_I2C_ADDR) bitmsk=BIT2_MAX5392_1; else if(addr==MAX5392_2_I2C_ADDR) bitmsk=BIT3_MAX5392_2; i2cSetMode(i2c, I2C_MASTER); i2cSetDirection(i2c, I2C_RECEIVER); i2cSetSlaveAdd(i2c, addr); // temp sensor is using i2c2 i2cSetStop(i2c); /* Transmit Start Condition */ i2cSetStart(i2c); //i2cSetStop(i2c); //i2cClearSCD(i2c); i2cSetCount(i2c, length); i2cReceive(i2c, length, RX_Data); //i2cSendByte(i2c, 0x00); /* Wait until Bus Busy is cleared */ while(i2cIsBusBusy(i2c) == true) { delay++; if((i2c->STR & I2C_NACK) == I2C_NACK || delay > 10000 ) { u8I2cErrorBits |=bitmsk; error=1; break; /*break while loop*/ } } /* Wait until Stop is detected */ delay=0; while(i2cIsStopDetected(i2c) == 0) { delay++; if((i2c->STR & I2C_NACK) == I2C_NACK || delay > 10000 ) { error=1; u8I2cErrorBits |= bitmsk; break; /*break while loop*/ } } /* Clear the Stop condition */ if (error) { error=0; /*NACK is received due to slave not connected, So go to the next slave*/ u16I2cSTRSave=i2c->STR; i2c->MDR = (uint32)((uint32)0U << 5U);/** - i2c Enter reset */ i2c->MDR |= (uint32)I2C_RESET_OUT; /* i2c out of reset */ } i2cSetStop(i2c); i2cClearSCD(i2c); printf("Data:%d %d\r\n", RX_Data[0], *(&RX_Data[1])); bool bErrorIC= (u8I2cErrorBits & bitmsk? true:false); printf("SER_vCh2I2cRxData end Error %d\n", bErrorIC); }
Dear Jagadish
Thank you for your reply. I was able to run the attached software without any problem in my hardware. However, when I remove all the printf in the file, it start to get stuck in a receive while loop. Please see capture.png. I suspect the problem is that the routine is too fast. Can you advise how I should correct my software? Thank you.
Dear Jagadish
I would like to bring to your attention about this function:
void i2cSetSlaveAdd(i2cBASE_t *i2c, uint32 sadd)
{
i2c->SAR = sadd; /* set slave address */
}
sadd is max 16bits in specs. So the wrong type is used for sadd. I have passed an 8bit address to this function and found that the address registered in SAR is 0. Please comment. Thank you
Hi LayEng
Thank you for your reply. I was able to run the attached software without any problem in my hardware. However, when I remove all the printf in the
First find out removing of which printf statement causing the issue, for this purpose comment out one by one printf statement and understand for exactly which commenting which printf statement causing the issue.
This kind of issues are due to missing of monitoring some status flags, so first find out commenting which printf statement causing the issue.
sadd is max 16bits in specs. So the wrong type is used for sadd. I have passed an 8bit address to this function and found that the address registered in SAR is 0.
It should not be possible,
See here i am passing 0x57 value as address
Now in debug you can see 0x57 at lower 7 bits of SAR register
--
Thanks & regards,
Jagadish.
Dear Jagadish
I find out the cause of the problem and it is unrelated to printf.
1. However I would like to understand more of your statement
"This kind of issues are due to missing of monitoring some status flags". I find a few flags are critical and they seem to be affected by printf. Namely, BB, TXRDY, RXRDY, SCD. Also the debugger goes to no man's land when I break to observe expressions and then hit resume. Can you advise what flags to wait after a transmit or receive before continuing? Can you advise how to best to do a good debugging. I find that my i2c ICs can fail depending on how I write my routines. This is ridiculous!
2. Does it help if I slow down i2c clock. I tried slowing down using prescaler below. But it is impossible. Can you advise how I can slow down i2c clock?
Hi LayEng,
I find a few flags are critical and they seem to be affected by printf. Namely, BB, TXRDY, RXRDY, SCD.
You are right and these are the important flags for i2c communication.
Can you advise what flags to wait after a transmit or receive before continuing?
It is simple, whenever you write some data to the i2c data register make sure you are writing only when TXRDY flag set. similarly whenever you are reading data from i2c data register make sure to read only when RXRDY flag set.
If you are using driver functions for send and receive then it is fine because the care is already taken in the driver.
For example, if you see i2cSendByte function.
You can see they are waiting until TXRDY flag set, and they are writing only after TXRDY flag set.
Similarly, if you see i2cReceiveByte function.
They are waiting until RXRDY flag to set for reading the data.
Can you advise how to best to do a good debugging
Importantly don't try to set break points or don't try to do step by step debugging in send or receive functions. I mean don't set any break points or don't do step by step debugging in between start and stop bits, only try to verify the data after sending or receiving completed that means after stop bit sent by i2c and i2c bus ideal. Once i2c bus ideal verify the receive buffer to find out whether you received intended data or not.
And make sure to turn off the optimization level for easy debugging.
Please take care of above two debugging suggestions.
Does it help if I slow down i2c clock.
I don't think it would be useful because the most of the i2c devices will support 100Khz frequency only, i think this would be the ideal frequency.
--
Thanks & regards,
Jagadish.
Dear Jagadish
Sorry I was late in reply. I was on MC due to an accident and just came back. I am back to working on this problem. Looking forward to your continued support
Dear Jagadithe sh
My problem is I am using halcogen generated functions like i2cSendByte, i2cReceiveByte and it got stuck at while loop checking, RXRDY when it enters the function, meaning I didn't receive the data. And it happens when I use i2cReceiveByte to init and check the IC. I have 4 ICs to check. It fails at the first IC, at this while loop checking RXRDY. Can you advise why it happen?
Hi LayEng,
Maybe you are not receiving any data from slave device. Make sure the following things,
1. Make sure the pull-up's are connected properly.
2. Make sure you are sending proper slave address.
3. If you have a logic analyzer please monitor SDA and SCL lines and see whether the data shifted as expected or not?
--
Thanks & regards,
Jagadish.
Dear Jagadish
That is a strong possibility. I have since used another hardware. Things improve but still a lot of problems. I have the following questions:
1. I often can't see changes in RXRDY, TXRDY, SCD which is tested in my routines and the software becomes stuck in thiese checks. Eg
while ((i2c->STR & (uint32)I2C_TX_INT) == 0U)
{
} /* Wait */
i2c->DXR = (uint32)byte;
So I enable the corresponding bits in the i2cinterrupt, hoping to force the change. Alas the values don't change. I have to use a variable instead. Please let me know why i2c->STR can't be ored with the corresponding bits.
2. What is the difference between using i2cReceiveByte(i2c) and i2cReceive(i2c, length, RX_Data) . Same for i2cSendByte(i2c, cmd) / i2cSend(i2c, length, TX_Data);
3. I would like to set breakpoint whenever a variable is written to see the cause of the random change in value of the variable. How do I go about it?
Thank you for your support
Dear Jagadish
The difference I was asking about i2cReceiveByte(i2c) and i2cReceive(i2c, length, RX_Data) is not about one being able to receive only one byte and the other is multiple bytes including 1. I have questions for eg i2CReceive.
Hi LayEng,
So I enable the corresponding bits in the i2cinterrupt, hoping to force the change.
We can't forcibly change the bits in the STR register, because they just SET based on the communication. Actually writing to these bits will clear the corresponding flags.
These bits just give the status by automatically get SET and we can clear these bits by writing one to the corresponding bit, that means a acknowledge back.
Example:
RXRDY flag in STR will get SET once a character is received to the I2CDRR register. And now we can clear this RXRDY flag by writing one to this bit and it is a acknowledge back that we aware about the new received character.
2. What is the difference between using i2cReceiveByte(i2c) and i2cReceive(i2c, length, RX_Data) . Same for i2cSendByte(i2c, cmd) / i2cSend(i2c, length, TX_Data);
i2cReceiveByte:
This function is useful to receive a single byte.
You can see here it is waiting till a new character is received into the DRR register by polling the "receive data ready" flag and once the character is received this flag will get SET right so then it will read the DRR register and returns the received character.
i2cReceive:
This function is useful to receive the multiple characters from i2c bus. Here the length parameter defines the number of characters to be received.
Here again there are two modes will be there interrupt Mode or polling mode which is decided based on the "Receive Data Ready Interrupt Enable" bit in the Interrupt Mast Register (IMR).
If it is a polling mode, then it is same process like receiving single character but here the loop will continue till the length number of characters received.
If it is a interrupt mode, then here we will just give length and destination buffer to the "g_i2cTransfer_t" structure which will be used in interrupt handler.
And now this structure is used in interrupt handler and actual data receiving will be done in interrupt handler as below
i2cSendByte:
It is used to send a single byte, which is similar to the i2cReceiveByte.
i2cSend:
It is used to send the multiple bytes, which is simlar to the i2cReceiv.
3. I would like to set breakpoint whenever a variable is written to see the cause of the random change in value of the variable. How do I go about it?
Thank you for your support
You can use Hardware watchpoints for this purpose
I tested this and they are applicable for variables but not applicable for registers. Here i added slave_number and STR register to the watchpoints, the breakpoint automatically got setting whenever slave_number changing but it is not setting when the STR register value changed.
--
Thanks & regards,
Jagadish.
Dear Jagadish
Thank you very much for your lengthy reply. Before your reply, I was using interrupt and using the polling path to envision sw flow. So my understanding seems to be wrong. As I describe earlier, I enabled interrupt for tx, rx, stp, and nak. Using the receive example, I thought that when I use
i2cReceive(i2c, length, RX_Data), I check for data receive using the while loop. I am wrong?
Btw, I don't see (uint32)I2C_RX_INT set in i2c->IMR. How is it set? Also if I use interrupt mode by enabling the interrupts in halcogen, I can't use i2cReceiveByte and i2cSendByte as they are not interrupt mode? Can polling mode routines be used in interrupt mode? Polling mode meaning you wait for the bit to be set, like stop bit, bb bit etc...
There is another flaw in the polling design. When I check whether the ic is available or working, I use i2cReceive or i2cReceiveByte . If the IC is not available or non working, it will hit the while loop
while ((i2c->STR & (uint32)I2C_TX_INT) == 0U)
Is there anyway to check the presence or functioning of an i2c ic or functioning of the i2cinterrupt without getting stuck in a while loop?
Thank you for your great support.
I am very sorry for not clicking the checkbox for this resolved my issue. I am about to be at my last question. Thank you
I would like to close this thread. The sample code is given but I still have other issues which should be under another thread