2012-07-16 02:28 AM
Hi,
I am try to develop a simple I2C “receive data�? type of function; I took most of the code from the zip file that I was able to download from the st webpages.
The main function of interest getBytesI2C1DMA() sends a “0�? to the onboard LM75 and receives two bytes that contain the temperature information. I see the two temperature related bytes in the logic analyzer, but I don’t see the value getting copied into the LM75_BufferRX buffer. LM75_BufferRX[0] and LM75_BufferRX[1] are both reporting 0x0B and the final value that is stored in “tmp�? is wrong. It looks like the DMA copy is failing. I have spent hours trying to figure out whats going wrong here. Can you please point me to the flaw in this code?
Any suggestions/advice is highly appreciated.
typedef
enum { TX = 0, RX = 1 } DMADirection_TypeDef;uint16_t getBytesI2C1DMA(
intaddress,
inttotalBytes) // <---- Problem FUNCTION
{ uint8_t LM75_BufferRX[10] ={1,1,0,0,0,0,0,0,0,0}; if(totalBytes>10)
return0;
sendByteI2C1(address, 0); // Configure DMA Peripheral DMA_Config(RX, (uint8_t*)LM75_BufferRX, totalBytes); // Enable DMA NACK automatic generation I2C_DMALastTransferCmd(I2C1, ENABLE); // Send START condition a second time I2C_GenerateSTART(I2C1, ENABLE); /* Test on SB Flag */ I1C1_Timeout = FLAG_TIMEOUT; while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_SB)) {
if((I1C1_Timeout--) == 0)
return0;
} /* Send LM75 address for read */ I2C_Send7bitAddress(I2C1, address, I2C_Direction_Receiver); /* Test on ADDR Flag */ I1C1_Timeout = FLAG_TIMEOUT; while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) {
if((I1C1_Timeout--) == 0)
return0;
} // Enable I2C DMA request I2C_DMACmd(I2C1,ENABLE); // Enable DMA RX Channel DMA_Cmd(DMA1_Channel7, ENABLE); // Wait until DMA Transfer Complete I1C1_Timeout = LONG_TIMEOUT; while(!DMA_GetFlagStatus(DMA1_FLAG_TC7)) {
if((I1C1_Timeout--) == 0)
return0;
} // Send STOP Condition I2C_GenerateSTOP(I2C1, ENABLE); // Disable DMA RX Channel DMA_Cmd(DMA1_Channel7, DISABLE); // Disable I2C DMA request I2C_DMACmd(I2C1, DISABLE); // Clear DMA RX Transfer Complete Flag DMA_ClearFlag(DMA1_FLAG_TC7); //!< Store LM75_I2C received data tmp = (uint16_t)(LM75_BufferRX[0] << 8); <------- LM75_BufferRX[0] & [1] contain 0x0B which is not the value I see in the logic analyzer tmp |= LM75_BufferRX[1]; //!< Return Temperature value tmp=(uint16_t)(tmp >> 7); returntmp;
} static void DMA_Config(DMADirection_TypeDef Direction, uint8_t* buffer, uint8_t NumData) { DMA_InitTypeDef DMA_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); /* Initialize the DMA_PeripheralBaseAddr member */ DMA_InitStructure.DMA_PeripheralBaseAddr = I2C1_BASE; /* Initialize the DMA_MemoryBaseAddr member */ DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buffer; /* Initialize the DMA_PeripheralInc member */ DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; /* Initialize the DMA_MemoryInc member */ DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; /* Initialize the DMA_PeripheralDataSize member */ DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; /* Initialize the DMA_MemoryDataSize member */ DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; /* Initialize the DMA_Mode member */ DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; /* Initialize the DMA_Priority member */ DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; /* Initialize the DMA_M2M member */ DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; /* If using DMA for Reception */ if (Direction == RX) { /* Initialize the DMA_DIR member */ DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; /* Initialize the DMA_BufferSize member */ DMA_InitStructure.DMA_BufferSize = NumData; DMA_DeInit(DMA1_Channel7); DMA_Init(DMA1_Channel7, &DMA_InitStructure); } /* If using DMA for Transmission */ else if (Direction == TX) { /* Initialize the DMA_DIR member */ DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; /* Initialize the DMA_BufferSize member */ DMA_InitStructure.DMA_BufferSize = NumData; DMA_DeInit(DMA1_Channel6); DMA_Init(DMA1_Channel6, &DMA_InitStructure); } } int sendByteI2C1( int address, int byte) { /* Test on BUSY Flag */ I1C1_Timeout = LONG_TIMEOUT; while (I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY)) if ((I1C1_Timeout--) == 0) return 0; /* Enable the I2C peripheral */ I2C_GenerateSTART(I2C1, ENABLE); // Test on SB Flag I1C1_Timeout = FLAG_TIMEOUT; while (!I2C_GetFlagStatus(I2C1,I2C_FLAG_SB)) if ((I1C1_Timeout--) == 0) return 0; /* Send device address for write */ I2C_Send7bitAddress(I2C1, address, I2C_Direction_Transmitter); /* Test on ADDR Flag */ I1C1_Timeout = FLAG_TIMEOUT; while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) if ((I1C1_Timeout--) == 0) return 0; I2C_SendData(I2C1, byte); /* Test on ADDR Flag */ I1C1_Timeout = FLAG_TIMEOUT; while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)) // EV-8 if ((I1C1_Timeout--) == 0) return 0; return 1; } This is how I initialize the I2C interfacevoid
initI2C() { I2C_InitTypeDef I2C_InitStructure; //--------------------------------------------------------- //-------------- Initialize GPIO GPIO_InitTypeDef GPIO_InitStructure; /*!< I2C1 Periph clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); /*!< LM75_I2C_SCL_GPIO_CLK, LM75_I2C_SDA_GPIO_CLK and LM75_I2C_SMBUSALERT_GPIO_CLK Periph clock enable */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOB, ENABLE); /*!< Configure I2C1 pins: SCL */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_Init(GPIOB, &GPIO_InitStructure); /*!< Configure I2C1 pins: SDA */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; GPIO_Init(GPIOB, &GPIO_InitStructure); /*!< Configure I2C1 pin: SMBUS ALERT */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOB, &GPIO_InitStructure); //----------------------------------------------------------- I2C_DeInit(I2C1); /*!< I2C1 Init */ I2C_InitStructure.I2C_Mode = I2C_Mode_SMBusHost; I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStructure.I2C_OwnAddress1 = 0x00; I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_InitStructure.I2C_ClockSpeed = L2C_SPEED; I2C_Init(I2C1, &I2C_InitStructure); /*!< Enable SMBus Alert interrupt */ I2C_ITConfig(I2C1, I2C_IT_ERR, ENABLE); /*!< I2C1 Init */ I2C_Cmd(I2C1, ENABLE); } #i2c-lm75-dma #stm32-i2c-dma2012-07-29 02:34 PM
I'd like to bump this post...
Having the same problem with this code. I've modified it to be used with a MCP23 This is an I2C 16 bit port expander, but the theory is the same and very little of the code needed changes. DMA functions are returning/sending the (byte wise) MSB and dropping the LSB. I've copied the WriteReg and ReadReg functions and subsituted the DMA calls with the extra I2C_Receive() and I2C_Send calls and the functions work fine. Has anyone looked at this as of recent? Update: 7/30/2012 I've got it to work... but I don't like the fix... This code:/* Test on BUSY Flag */
MCP27XXX_Timeout = MCP27XXX_LONG_TIMEOUT;
while (I2C_GetFlagStatus(MCP27XXX_I2C,I2C_FLAG_BUSY))
{
if((MCP27XXX_Timeout--) == 0) return MCP27XXX_TIMEOUT_UserCallback();
}
/* Configure DMA Peripheral */
MCP27XXX_DMA_Config(MCP27XXX_DMA_TX, &MCP27XXX_BufferTX[0], 3);
/* Enable the I2C peripheral */
I2C_GenerateSTART(MCP27XXX_I2C, ENABLE);
gets the job done... this tells the DMA controller to send one more byte than the buffer length. I have verified that the code does wait for the TXE and BTF flags before calling GenerateSTOP() so it's not an issue of the DMA controller being cut off while transmitting the last byte. At least it doesn't seem that way.
--Dave