cancel
Showing results for 
Search instead for 
Did you mean: 

In my I2C Slave program the Callbacks are not being called.

KiptonM
Lead

I am using HAL_I2C_Slave_Receive_DMA() function and am putting flags in each of the Callbacks which I have redefined in my code from the weak ones in stm32g0xx_hal_i2c.c.

I have also tried putting breakpoints in the callback functions to see if it foes there.

There is no indication that it is.

My HAL_UART_Transmit_DMA() function is working. And it is calling the HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) function.

So I know interrupts are turned on. I did not have to enable anything in the interrupts the HAL took care of that.

I went into stm32g0xx_hal_conf.c and modified the line

#define USE_HAL_I2C_REGISTER_CALLBACKS  1u

So it used all the callbacks.

Looking at the hi2c1 structure, there are valid addresses in each of the callback pointers. Right now I cannot verify whether they are using the default weak ones or mine. But according to the documentation if I define them they should override the weak ones.

When I use the HAL_I2C_Mem_Write_DMA() in the master STM32G031K8 the data shows up correctly in the slave, but I cannot see that any of the callbacks were executed.

When I use the HAL_I2C_Mem_Read_DMA() in the master the written data shows up correctly in the slave buffer until after the restart, where it hangs because I have no indication from any callback that I need to do anything, like read the data and write back the results.

That tells me that the I2C device is enabled. But nothing is happening.

With the UART I did not have to go into the configuration register and enable the individual interrupts, the HAL did that. Is that not the case for the I2C?

I am using the HAL_Delay() function. So I made the UART, and I2C interrupts level 3 priority.

I made the DMA interrupts level 2 priority.

I made the sys_tick interrupt level 1.

The rest are left at the defaut 0.

I am only using the UART and I2C at present. No ADC and no timers. No other peripheral interrupts.

On Page 341/2202 of UM2319 Rev 2 it says "Configure the priority and enable the NVIC for the transfer complete interrupt on the DMA Tx or Rx Channel. "

I set the priorities, as I mentioned above. I enabled the interrupts and set the priorities in the MX program. Do I have to do something else? The documentation is very sparse about the details.

Is the HAL_I2C_Slave_Receive_DMA() function the one I should be using while waiting for data with my device address to show up on the bus? Or Should I be using HAL_I2C_Slave_Seq_Receive_DMA()? The documentation is not very clear the plusses and minuses of either function.

While searching for how to fix this, I found another example that used the AddrCallback() to see if the device was accessed. Then they did something based on the address and the direction. Mine is simpler. In most cases it looks like a 16-bit memory location they send a 16-bit address, and get a 16-bit response. So I know they will always send me at least two bytes. And if it is a write it could be 2 more. If it is a read, then they will send a restart, and the address with a read. What interrupt should happen then to let me know I should send something?

Back to the original question, what could I be missing to prevent the callbacks from being executed?

Thanks,

Kip

1 ACCEPTED SOLUTION

Accepted Solutions
KiptonM
Lead

The callbacks seem to be working. Just not how I expected.

This image is what the logic analyzer sees. The Master is doing a HAL_I2C_Mem_Write_DMA() with 2 address bits and 2 data bits. This is exactly what I want to see.

I have been using HAL_I2C_Slave_Receive_DMA() to get it. And when I have the characters receive greater than 4 bytes (to receive) I do not get the HAL_I2C_SlaveRxCpltCallback() but I just discovered I get the HAL_I2C_ErrorCallback() and the values in the receive buffer are correct. HAL_I2C_AddrCallback() was never called.

When the HAL_I2C_Slave_Receive_DMA() is exactly 4 bytes I get the HAL_I2C_SlaveRxCpltCallback(). And the values in the receive buffer are correct. HAL_I2C_AddrCallback() was never called.

When the HAL_I2C_Slave_Receive_DMA() is exactly 2 bytes I do not get any callback.

My problem is that I do not know whether a read or a write is coming in so I do not know how many bytes to read. The I2C_TwoBoards_ComDMA is a bad example to use for communicating with two boards. It is not realistic.

It appears you have to know how much data is coming before you read.

View solution in original post

11 REPLIES 11
KiptonM
Lead

Here is a screenshot showing the debugger with the Callback pointers in the hi2c1 structure.

KnarfB
Principal III

When you set USE_HAL_I2C_REGISTER_CALLBACKS  to 1, the callbacks must be registered via HAL_I2C_RegisterCallback. In this case, the callbacks are true C function pointers. No linker magic/weak involved.

If you leave it at 0, the weak functions are called unless you implement your own functions with the exact same names. The linker resolves this in favor of the non-weak function definition.

To verify, set a breakpoint at the real interrupt handler in stm32g0xx_it.c and follow the path into HAL code where you find pattern like:

#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1)
          hi2c->AddrCallback(hi2c, transferdirection, slaveaddrcode);
#else
          HAL_I2C_AddrCallback(hi2c, transferdirection, slaveaddrcode);
#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */

hth

KnarfB

KiptonM
Lead

Looking at the I2C_CR1 register in the Debugger it has a value of 0x80B9

In the code it is in the middle of the HAL_I2C_Slave_Receive_DMA() just after the restart. It looks like there is no restart interrupt. So how do I know if there is a restart? And I am guessing the RXIE and TXIE are not set because the DMA is handling the individual byte transfers.

KiptonM
Lead

I think the HAL_I2C_AddrCallback() is called when the start bit sends an address and it is received correctly. So that is the ADDRIE and that is 1, but HAL_I2C_AddrCallback() was not called.

KiptonM
Lead

It has to be something stupid I am missing, but I do not see it.

KiptonM
Lead

So it appears that the HAL_I2C_ErrorCallback() is called according to my flags, but no other callback ever.

Watch that things are not blocking or held up in HAL_Delay(), or other loops depending on the clock advancing.

SysTick really should have the highest priority.

Callbacks are called under interrupt context, via HAL call-ins from the IRQ Handlers.

Looking at peripheral registers in the debugger can also be invasive. Be especially wary of registers that clear on read, and FIFO / data registers.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
KiptonM
Lead

The callbacks seem to be working. Just not how I expected.

This image is what the logic analyzer sees. The Master is doing a HAL_I2C_Mem_Write_DMA() with 2 address bits and 2 data bits. This is exactly what I want to see.

I have been using HAL_I2C_Slave_Receive_DMA() to get it. And when I have the characters receive greater than 4 bytes (to receive) I do not get the HAL_I2C_SlaveRxCpltCallback() but I just discovered I get the HAL_I2C_ErrorCallback() and the values in the receive buffer are correct. HAL_I2C_AddrCallback() was never called.

When the HAL_I2C_Slave_Receive_DMA() is exactly 4 bytes I get the HAL_I2C_SlaveRxCpltCallback(). And the values in the receive buffer are correct. HAL_I2C_AddrCallback() was never called.

When the HAL_I2C_Slave_Receive_DMA() is exactly 2 bytes I do not get any callback.

My problem is that I do not know whether a read or a write is coming in so I do not know how many bytes to read. The I2C_TwoBoards_ComDMA is a bad example to use for communicating with two boards. It is not realistic.

It appears you have to know how much data is coming before you read.

Sys_clock interrupt is 1, which is higher priority than any other interrupt I am using. In ST lower number is higher. priority.