STM32F401C - 发现板:带DMA的I2C

时间:2016-02-22 11:27:16

标签: i2c dma stm32f4discovery cortex-m

如何使用I2C从LSM303DLHC(磁力计)读取数据并通过DMA将数据存储在缓冲区中?

我尝试修改" LSM303DLHC_Read()"函数将其与DMA一起使用,但SerialChart上的输出始终为0。

你能告诉我一个带DMA的I2C的例子吗?

   uint16_t LSM303DLHC_DMA_Read(uint8_t DeviceAddr, uint8_t   RegisterAddr, uint16_t NumByteToRead)
{
  __IO uint32_t LSM303DLHC_Timeout = LSM303DLHC_LONG_TIMEOUT;
  __IO uint32_t temp;

  I2C_Initialization();
  DMA_Config();
restart:

  LSM303DLHC_Timeout = LSM303DLHC_LONG_TIMEOUT;
   /* Send START condition */
  I2C_GenerateSTART(LSM303DLHC_I2C, ENABLE);
  /* Test on EV5 and clear it */
  while (!I2C_CheckEvent(LSM303DLHC_I2C, I2C_EVENT_MASTER_MODE_SELECT))
  {
    if (LSM303DLHC_Timeout-- == 0)
      return ERROR;
  }

   /* Active the needed channel Request */
     I2C_DMACmd(I2C1, ENABLE);

  LSM303DLHC_Timeout = LSM303DLHC_LONG_TIMEOUT;
  /* Send slave address for read */
  I2C_Send7bitAddress(LSM303DLHC_I2C, DeviceAddr, I2C_Direction_Transmitter);

  while (!I2C_CheckEvent(LSM303DLHC_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
  {
    if (LSM303DLHC_Timeout-- == 0)
    {
      I2C_ClearFlag(LSM303DLHC_I2C,I2C_FLAG_BUSY|I2C_FLAG_AF);
      goto restart;
    }
  }
  /* Clear EV6 by setting again the PE bit */
  I2C_Cmd(LSM303DLHC_I2C, ENABLE);

  I2C_SendData(LSM303DLHC_I2C, RegisterAddr);

  /* Test on EV8 and clear it */
  LSM303DLHC_Timeout = LSM303DLHC_LONG_TIMEOUT;
  while (!I2C_CheckEvent(LSM303DLHC_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
  {
    if (LSM303DLHC_Timeout-- == 0)
     return ERROR;
  }

  if (NumByteToRead == 0x01)
  {
    restart3:
    /* Send START condition */
    I2C_GenerateSTART(LSM303DLHC_I2C, ENABLE);
    while (!I2C_CheckEvent(LSM303DLHC_I2C, I2C_EVENT_MASTER_MODE_SELECT));
    /* Send Slave address for read */
    I2C_Send7bitAddress(LSM303DLHC_I2C, DeviceAddr, I2C_Direction_Receiver);
    /* Wait until ADDR is set */
    LSM303DLHC_Timeout = LSM303DLHC_LONG_TIMEOUT;
    while (!I2C_GetFlagStatus(LSM303DLHC_I2C, I2C_FLAG_ADDR))
    {
      if (LSM303DLHC_Timeout-- == 0)
      {
        I2C_ClearFlag(LSM303DLHC_I2C,I2C_FLAG_BUSY|I2C_FLAG_AF);
        goto restart3;
      }
    }
    /* Clear ACK */
    I2C_AcknowledgeConfig(LSM303DLHC_I2C, DISABLE);
    I2C_NACKPositionConfig(LSM303DLHC_I2C, I2C_NACKPosition_Current);
    __disable_irq();
    /* Clear ADDR flag */
    temp = LSM303DLHC_I2C->SR2;
    /* Program the STOP */
    I2C_GenerateSTOP(LSM303DLHC_I2C, ENABLE);
    __enable_irq();
    while ((I2C_GetLastEvent(LSM303DLHC_I2C) & 0x0040) != 0x000040); /* Poll on RxNE */
    I2C_DMACmd(I2C1, DISABLE);
    /* Read the data */
    //*pBuffer = I2C_ReceiveData(LSM303DLHC_I2C);
    /* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
    while ((LSM303DLHC_I2C->CR1&0x200) == 0x200);
    /* Enable Acknowledgement to be ready for another reception */
    I2C_AcknowledgeConfig(LSM303DLHC_I2C, ENABLE);

    return SUCCESS;
  }
}

这是DMA配置:

void DMA_Config(void)
{
  DMA_InitTypeDef  DMA_InitStructure;

  /* Enable DMA clock */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

  /* Reset DMA Stream registers (for debug purpose) */
  DMA_DeInit(DMA1_Stream0);

  /* Check if the DMA Stream is disabled before enabling it.
     Note that this step is useful when the same Stream is used multiple times:
     enabled, then disabled then re-enabled... In this case, the DMA Stream disable
     will be effective only at the end of the ongoing data transfer and it will
     not be possible to re-configure it before making sure that the Enable bit
     has been cleared by hardware. If the Stream is used only once, this step might
     be bypassed. */
  while (DMA_GetCmdStatus(DMA1_Stream0) != DISABLE) {}

  /* Configure DMA Stream */
  DMA_InitStructure.DMA_Channel = DMA_Channel_1;
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C_Register_DR;
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Buffer_X;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
  DMA_InitStructure.DMA_BufferSize = 1 ;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMA1_Stream0, &DMA_InitStructure);

  /* Enable DMA Stream Transfer Complete interrupt */
  DMA_ITConfig(DMA1_Stream0, DMA_IT_TC, ENABLE);

  /* DMA Stream enable */
  DMA_Cmd(DMA1_Stream0, ENABLE);

  /* Check if the DMA Stream has been effectively enabled.
     The DMA Stream Enable bit is cleared immediately by hardware if there is an
     error in the configuration parameters and the transfer is no started (ie. when
     wrong FIFO threshold is configured ...) */
//  while ((DMA_GetCmdStatus(DMA2_Stream0) != ENABLE))
//  {  }

}

这是I2C配置:

void I2C_Initialization(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef  I2C_InitStructure;

/* Enable the I2C periph */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

/* Enable SCK and SDA GPIO clocks */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB , ENABLE);

GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_DOWN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

/* I2C SCK pin configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOB, &GPIO_InitStructure);

/* I2C SDA pin configuration */
GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_9;
GPIO_Init(GPIOB, &GPIO_InitStructure);

/* I2C configuration -------------------------------------------------------*/
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
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 = 100000;

/* Apply LSM303DLHC_I2C configuration after enabling it */
I2C_Init(I2C1, &I2C_InitStructure);

/* Active the needed channel Request */
//I2C_DMACmd(I2C1, ENABLE);

/* LSM303DLHC_I2C Peripheral Enable */
I2C_Cmd(I2C1, ENABLE);
}

2 个答案:

答案 0 :(得分:0)

我的第一个问题是为什么你在读取功能中有DMA配置和I2C初始化功能?

答案 1 :(得分:0)

我相信您错过了DMA1_Stream6的配置行。您需要更改DMA_InitStructure并初始化Tx流 - 现在您只需初始化Rx流。以下内容应该有效:

DMA_InitTypeDef  DMA_InitStructure;

DMA_DeInit(DMA1_Stream0); //reset DMA1 channe1 to default values;

DMA_InitStructure.DMA_Channel = DMA_Channel_1;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C1_DR_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)I2C_RxBuffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = 1;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream0, &DMA_InitStructure);

DMA_Cmd(DMA1_Stream0, ENABLE);
while (DMA_GetCmdStatus(DMA1_Stream6) != ENABLE);

DMA_ClearFlag(DMA1_Stream0, DMA_FLAG_TCIF0 | DMA_FLAG_FEIF0 | DMA_FLAG_DMEIF0 | \
        DMA_FLAG_TEIF0 | DMA_FLAG_HTIF0);


DMA_DeInit(DMA1_Stream6);

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)I2C_TxBuffer;
DMA_InitStructure.DMA_BufferSize = 1;

DMA_Init(DMA1_Stream6, &DMA_InitStructure);

DMA_Cmd(DMA1_Stream6, ENABLE);
while (DMA_GetCmdStatus(DMA1_Stream6) != ENABLE);

DMA_ClearFlag(DMA1_Stream6, DMA_FLAG_TCIF6 | DMA_FLAG_FEIF6 | DMA_FLAG_DMEIF6 | \
        DMA_FLAG_TEIF6 | DMA_FLAG_HTIF6);