cancel
Showing results for 
Search instead for 
Did you mean: 

How do you implement an I2C Slave to look like a memory?

KiptonM
Lead

Here is what I am trying to Implement. To make the I2C Slave look like a memory to the master.

Syntax is one of two cases.

For a Write:

<Dev Add W><MemAdd MSB><MemAdd LSB><Data0><Data1>...<Data N><Stop>

For a Read:

<Dev Add W><MemAdd MSB><MemAdd LSB><Restart Dev Add R><Data0><Data1>...<Data N><Stop>

I am on the first step. I want to use DMA because I do not want interrupts firing on every byte. My processor has to do other things like data collection, and not just mind the I2C.

I think I have to use the HAL_I2C_Slave_Seq_Receive_DMA() and HAL_I2C_Slave_Seq_Transmit_DMA() routines.

There is a XferOptions parameter, and I can not figure out what to use for the initial read (from the slave point of view.) .

It does not matter which one I use, I get an error.

I am looking for one that gracefully ends with a stop or a restart. Because in the write case, they could write 2 bytes at the address, or could write 2 more bytes at the next address. I am limiting them to a total of 8 words or 16 bytes.

In the case of a read they just write the 2 address bytes then do a restart.

Is the answer to just ignore the errors and continue? I really do not like having a product with functions throwing error interrupts.

Thanks in advance.

Kip

1 ACCEPTED SOLUTION

Accepted Solutions
KnarfB
Principal III

You may check this code, but it is using _IT not _DMA.

https://gitlab.com/stm32mcu/i2c_master_and_servant.git

The changes should be straightforward modulo HAL issues.

hth

KnarfB

View solution in original post

9 REPLIES 9
KiptonM
Lead

If I tell the Slave to just read 18 bytes, the two address bytes and the maximum of 16 data bytes, and it gets a stop before the 16 bytes, it calls the HAL_I2C_ErrorCallback(). The bytes are in the buffer, but I do not know how many bytes are valid.

I suspect you'll have to dig that out of the DMA registers.

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

>  but I do not know how many bytes are valid.

Usually this can be calculated from Size and Count members of the I2C "handle" struct.

TDK
Guru

> Is the answer to just ignore the errors and continue? I really do not like having a product with functions throwing error interrupts.

NACK is classified as an error flag, even though it is used in normal communications. If the "error" is due to the master NACK to signify the end of reading data, the correct procedure would be to ignore it and return to the main loop to await the next instruction.

If you feel a post has answered your question, please click "Accept as Solution".
KnarfB
Principal III

You may check this code, but it is using _IT not _DMA.

https://gitlab.com/stm32mcu/i2c_master_and_servant.git

The changes should be straightforward modulo HAL issues.

hth

KnarfB

Thanks. I will have to check it tonight when I get home. It looks like my work computer will not allow me to access that site.

Thanks for the suggestions. I Looked at the Size and Count Members of the I2C1 handle and they are both 0; It is probably because I am using DMA.

I think I found it. I see in the buffer the 4 values I transferred, which match what I see in the Logic Analyzer.

I passed 16 for the buffer size in HAL_I2C_Slave_Seq_Receive_DMA() and looking at DMA_CNDTR3 there is a 12 in the register. The documentation says it is decremented after each transfer. so 16 - 12 = 4. The number of good bytes in the buffer,

And DMA_CNDTR3 is available through the hi2c1 structure.

hi2c1.hdmarx->Instance->CNDTR

Thanks for the code. Is the only to make this work is to do an interrupt per byte transferred? It seems very inefficient. But if that is the only way, then that is what I have to do.

KiptonM
Lead

I got my code to work thanks to your example. Thank you.