2019-05-24 01:43 PM
I have done some investigation and arrived that the problem is with the "DIR" bit in
the Interrupt Status register not firing to indicate whether to do a Read.
uint32_t isr_trace[64];
int isr_count = 0;
void I2C2_EV_IRQHandler(void)
{
isr_trace[isr_count++] = I2C2->ISR; /* debug to check ISR status on entry*/
if (!(I2C2->ISR & I2C_ISR_DIR_Msk)) /* Master is writing memory address.*/
{
while (!(I2C2->ISR & I2C_ISR_RXNE_Msk)) {}
RX_buffer[RX_count++] = I2C2->RXDR;
}
else /* Master is requesting data from memory. */
{
for (int i = 0; i < 4; i++)
{
while (!(I2C2->ISR & I2C_ISR_TXE_Msk)) {}
I2C2->TXDR = TX_buffer[i];
}
}
I2C2->ICR |= I2C_ICR_STOPCF;
}
However if I then set a software break point before reading the I2C2->ISR register
as shown below here.
void I2C2_EV_IRQHandler(void)
{
__BKPT(0);
isr_trace[isr_count++] = I2C2->ISR; /* debug to check ISR status on entry*/
...
}
The I2C2->ISR is updated to show the "DIR" bit correctly. Many thanks in advance.
2019-05-24 04:25 PM
Working on H743 today, IIC as Master
Try a stronger pullup, I used a 4k7 pair and still have trouble.
had to drop the speed to 40KHz, still not perfect.
It was suggested by @Community member to drop the pullup further, maybe 2k7.
2019-05-24 05:00 PM
Hi TJ thanks for your response. I have tried reducing the speed to 10KHz just to prove things but did not make a difference. I am unable to change the Pullup on the I2C master as this is a third party device that we are using to talk to other I2C devices and works fine.
One more thing I forgot to add to my initial post is that the Master I2C device does not support clock stretching.
2019-05-25 03:26 PM
You can still add a pullup on your end, without issue,
I would just try a 1K as an extreme then you will know if it helps.
if 10KHz does not work then add extra pullups are unlikely to fix it, I would test it. its the SDA pin that needs it.
otherwise , looks like a coding issue.
you could try using the DMA transfer, slightly different coding/delays, may give a different result.
2019-05-26 11:47 AM
Hi TJ, Thank for your response once again. I am not sure that this is a data transfer issue due to the I2C bus. It might be a code issue like you suggested. As I mentioned in my first email I can perform a write from the I2C master (Electric Imp 005) and read all the data sent correctly by the I2C Slave (Stm32H743) .
The problem I am experiencing is related to when I perform an I2C read from the master. There is meant to be a flag in the I2C ISR register known as the "DIR" bit.
This flag should be set on entry to the I2C2_EV_IRQHandler(void) but what I observed that this bit is never set unless a breakpoint is SET in the ISR.
2019-05-28 02:38 PM
Hi All,
Just in case someone has a similar issue, please find below a solution that I derive. Note that the RX_buffer, TX_buffer and their respective counters are defined as follows.
// ------------------- main.c ----------------------------
#define MAX_BUF 128
volatile uint8_t RX_buffer[MAX_BUF];
volatile uint8_t TX_buffer[MAX_BUF];
volatile int RX_count = 0;
volatile int TX_count = 0;
void main()
{
...
MX_I2C2_Init();
...
HAL_I2C_EnableListen_IT(&hi2c2);
while(1)
{
}
}
// ---------------------------------stm32h7xx_it.c ----------------------------------
extern uint8_t TX_buffer[MAX_BUF];
extern uint8_t RX_buffer[MAX_BUF];
extern uint8_t RX_count;
extern uint8_t TX_count;
void I2C2_EV_IRQHandler(void)
{
/* USER CODE BEGIN I2C2_EV_IRQn 0 */
uint32_t isr = I2C2->ISR;
if (( isr & I2C_ISR_TXE) == I2C_ISR_TXE )
{
I2C2->TXDR = TX_buffer[TX_count++];
}
if (( isr & I2C_ISR_RXNE) == I2C_ISR_RXNE )
{
RX_buffer[RX_count++] = I2C2->RXDR;
}
if (( isr & I2C_ISR_NACKF) == I2C_ISR_NACKF )
{
TX_count = RX_count = 0;
I2C2->ICR |= I2C_ICR_ADDRCF; // clear flag only once after receiving nack.
I2C2->ISR |= I2C_ISR_TXE; // flush txdr to avoid residue in buffer
I2C2->ICR |= I2C_ICR_NACKCF;
}
if (( isr & I2C_ISR_STOPF) == I2C_ISR_STOPF )
{
I2C2->ICR |= I2C_ICR_STOPCF;
}
if (( isr & I2C_ISR_OVR) == I2C_ISR_OVR )
{
I2C2->ICR |= I2C_ICR_OVRCF;
}
/* USER CODE END I2C2_EV_IRQn 0 */
}