2009-06-16 01:14 AM
DMA + I2C losing one byte?
2011-05-17 04:13 AM
I've got a strange problem with I2C with DMA transfers.
If I'm transmitting to a slave, on the DMA_InitStructure.DMA_BufferSize, I have to put always a value 1byte higher than what I want to write. This doesn't happen if receiving from slave. It's wierd because it's like DMA1_FLAG_TC4 is set before transfer is complete, or something similar.. So, for example, if I set DMA_InitStructure4.DMA_BufferSize = 5, it will only read 4 bytes (checked on the oscilloscope). Does somebody know a reason for this? I'm having problems accessing an EEPROM, and this behavior is related somehow. Following you will find the code I'm using. -> command I2C2_Master_BufferWrite(Buffer, TxLgth); void I2C2_Master_BufferWrite(u8* pBuffer, u8 NumByteToWrite){ I2C2_TXOK = false; DMA_InitStructure4.DMA_MemoryBaseAddr = (u32)pBuffer; DMA_InitStructure4.DMA_BufferSize = (u32)NumByteToWrite+1; KERN_DMAChannel4Configuration(); I2C_ITConfig(I2C2, I2C_IT_EVT | I2C_IT_ERR, ENABLE); I2C_DMACmd(I2C2, ENABLE); /* Enable the DMA Channel4 Transfer Complete IT */ DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE); /* Generate the START */ I2C_GenerateSTART(I2C2, ENABLE); } void I2C2_Master_BufferRead(u8* pBuffer, u8 NumByteToRead){ I2C2_RXOK = false; DMA_InitStructure5.DMA_MemoryBaseAddr = (u32)pBuffer; DMA_InitStructure5.DMA_BufferSize = (u32)NumByteToRead; KERN_DMAChannel5Configuration(); I2C_ITConfig(I2C2, I2C_IT_EVT | I2C_IT_ERR, ENABLE); /* Set Last bit to have a NACK on the last received byte */ I2C_DMALastTransferCmd(I2C2, ENABLE); I2C_DMACmd(I2C2, ENABLE); /* Enable the DMA Channel5 Transfer Complete IT */ DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE); /* Generate the START */ I2C_GenerateSTART(I2C2, ENABLE); } Interrupt servicing : void DMA1_Channel4_IRQHandler(void) { /* I2C2 TX */ DMA_Cmd(DMA1_Channel4, DISABLE); DMA_ClearFlag(DMA1_FLAG_TC4); I2C_GenerateSTOP(I2C2, ENABLE); I2C2_TXOK = true; } Thanks! J [ This message was edited by: jvaque on 03-06-2009 09:53 ]2011-05-17 04:13 AM
I was trying to write subroutines for reading/writing EEPROM. I was not manage to do that.
I do it using I2C interrupts only. Your problem is probably related to the fact that you have to set STOP bit before sending or receiving last byte. It is rather difficult with DMA. Let me know how did you solve the problem.2011-05-17 04:13 AM
I started with I2C interrupts, but I found this method to be too tedious. There's also the bug you say, having to set STOP before the last transfer, but according to the last errata sheet (
) , to avoid this, they recommend to use DMA transfers, but there's not a lot of examples. I'll keep investigating and keep you posted.2011-05-17 04:13 AM
Thanks to ST support, I've solved the problem I had, it appears that I was issuing a Stop condition when the DMA had finished transfering data to the I2C registers, but before these were transmitted by the I2C peripheal.Now I2C with DMA runs smooth, both in Master and Slave.
2011-05-17 04:13 AM
I'm interested in how exactly you solved you problem. Indeed, I quit on using DMA because of one extra byte 0xFF (the contrary of you), it appears only on the first execution of reading on the SMBus. After that, everything is normal (except that without stopping the transfer before the last byte a NACK cannot be sent) but because of it, as my DMA use circular memory, I have a TC IT before the last byte. It happens only when I'm a slave receiving data from a master. I tried not to use circular memory but did not find how to reset the destination address. I tried to reput the address as I do during initialization but it weirdly does not work. I now use interrupts but your thread gave me desire for solving the problem. Can you please tell me how you configure your DMA. I have read the AN on DMA, RM0008 for DMA and I2C but if you have some other useful documentations can you please tell me ?