小小豆芽菜丶 2023-08-31 17:24 采纳率: 50%
浏览 16
已结题

32单片机hal库I2C+DMA读写AT24C02问题

我用的单片机型号是STM32G030C8T6,环境使用CUBEMX生成的代码,采用硬件I2C方式。
问题:
我想用I2C+DMA的方式去读写AT24C02,往里面写入0~0xff,然后读取出来。但是写入不了,调试的时候发现设备状态一直是繁忙,不会返回应答。

img

img

img


/* USER CODE BEGIN PV */
#define PAGE_SIZE_24CXX    8
#define PAGE_NUM_24CXX     32
#define ADDR_24CXX         0xA0
#define I2C_24CXX          hi2c1
#define ADD_SIZE_24CXX     I2C_MEMADD_SIZE_8BIT
int i;
uint8_t WriteBuffer[PAGE_SIZE_24CXX*PAGE_NUM_24CXX] = {0};
uint8_t ReadBuffer[PAGE_SIZE_24CXX*PAGE_NUM_24CXX]  = {0};
/* USER CODE END PV */

/* USER CODE BEGIN 0 */
HAL_StatusTypeDef I2C_WaitUntilDeviceReady(I2C_HandleTypeDef *hi2c,uint16_t DevAddress,uint32_t Timeout){
    uint32_t tickstart = HAL_GetTick();                 //获取当前时间
    while(HAL_GetTick()-tickstart <= Timeout){          //如果没有超时就一直尝试
        if(HAL_I2C_IsDeviceReady(hi2c, DevAddress,1, Timeout) == HAL_OK){   //如果准备好了就return
            return HAL_OK;
        }
    }
    return HAL_TIMEOUT;                                 //否则return一个错误
}
/* USER CODE END 0 */

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  MX_I2C1_Init();
  /* USER CODE BEGIN 2 */

  int e;
  for(i=0; i < PAGE_SIZE_24CXX*PAGE_NUM_24CXX; i++) {WriteBuffer[i] = i;}    //初始化要写入的数组

  uint32_t TickStart=HAL_GetTick();       //获取当前时间戳
  for (int j=0; j < PAGE_NUM_24CXX; j++)//页写入
  {
      I2C_WaitUntilDeviceReady(&I2C_24CXX, ADDR_24CXX, 10);//自己写的等待函数
      e = HAL_I2C_Mem_Write_DMA(&I2C_24CXX, ADDR_24CXX, PAGE_SIZE_24CXX*j, \
      ADD_SIZE_24CXX, WriteBuffer+PAGE_SIZE_24CXX*j, PAGE_SIZE_24CXX);//向每一页都写入数据
      if (e == HAL_OK) {
          printf("第%d页已写入,time=%lu ms\r\n", j,HAL_GetTick());//输出页写时间
      } else {
          printf("EEPROM写入出错 ,j=%d,error=%d\r\n", j, e);
      }
  }
  printf("%d次页写共用时%lu ms\r\n",PAGE_NUM_24CXX, HAL_GetTick() - TickStart);//输出总用时

  I2C_WaitUntilDeviceReady(&I2C_24CXX, ADDR_24CXX, 20);
  e = HAL_I2C_Mem_Read_DMA(&I2C_24CXX, ADDR_24CXX, 0, ADD_SIZE_24CXX,\
  ReadBuffer, PAGE_SIZE_24CXX*PAGE_NUM_24CXX);//读取数据
  if(e==HAL_ERROR)
    printf("EEPROM读取出错 %d\r\n",e);
  else
    for(i=0; i<PAGE_NUM_24CXX; i++){
      for(int j=0; j<PAGE_SIZE_24CXX; j++){
        printf("%2x ", ReadBuffer[i*8+j]);
      }
      printf("\r\n");
    }
    
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

img

但是我不用DMA的方式,直接用轮询就没问题,代码也就只改了写入和读取的函数。

int e;
  for(i=0; i < PAGE_SIZE_24CXX*PAGE_NUM_24CXX; i++) {WriteBuffer[i] = i;}    //初始化要写入的数组

  uint32_t TickStart=HAL_GetTick();       //获取当前时间戳
  for (int j=0; j < PAGE_NUM_24CXX; j++)//页写入
  {
      I2C_WaitUntilDeviceReady(&I2C_24CXX, ADDR_24CXX, 10);//自己写的等待函数
      e = HAL_I2C_Mem_Write(&I2C_24CXX, ADDR_24CXX, PAGE_SIZE_24CXX*j, \
      ADD_SIZE_24CXX, WriteBuffer+PAGE_SIZE_24CXX*j, PAGE_SIZE_24CXX, 1000);//向每一页都写入数据
      if (e == HAL_OK) {
          printf("第%d页已写入,time=%lu ms\r\n", j,HAL_GetTick());//输出页写时间
      } else {
          printf("EEPROM写入出错 ,j=%d,error=%d\r\n", j, e);
      }
  }
  printf("%d次页写共用时%lu ms\r\n",PAGE_NUM_24CXX, HAL_GetTick() - TickStart);//输出总用时

  I2C_WaitUntilDeviceReady(&I2C_24CXX, ADDR_24CXX, 20);
  e = HAL_I2C_Mem_Read(&I2C_24CXX, ADDR_24CXX, 0, ADD_SIZE_24CXX,\
  ReadBuffer, PAGE_SIZE_24CXX*PAGE_NUM_24CXX, 1000);//读取数据
  if(e==HAL_ERROR)
    printf("EEPROM读取出错 %d\r\n",e);
  else
    for(i=0; i<PAGE_NUM_24CXX; i++){
      for(int j=0; j<PAGE_SIZE_24CXX; j++){
        printf("%2x ", ReadBuffer[i*8+j]);
      }
      printf("\r\n");
    }

img

  • 写回答

1条回答 默认 最新

  • 比特流1024 2023-08-31 17:34
    关注

    参考gpt:
    结合自己分析给你如下建议:

    
    检查你的DMA通道是否正确配置,是否与I2C匹配。你可以参考1中的例子(https://blog.csdn.net/qq_45396672/article/details/117253441) ,看看他是如何配置DMA通道的。
    检查你的I2C初始化函数是否正确设置了DMA模式。你需要在HAL_I2C_Init函数中设置hdma_i2c_tx和hdma_i2c_rx两个成员,指向你的DMA句柄。你可以参考2中的例子(https://cloud.tencent.com/developer/article/2030809)  ,看看他是如何设置I2C初始化函数的。
    检查你的I2C读写函数是否正确使用了DMA模式。你需要使用HAL_I2C_Mem_Read_DMA和HAL_I2C_Mem_Write_DMA两个函数,而不是HAL_I2C_Mem_Read和HAL_I2C_Mem_Write。你可以参考3中的例子 (https://zhuanlan.zhihu.com/p/624105226)   ,看看他是如何使用I2C读写函数的。
    
    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 8月31日
  • 创建了问题 8月31日

悬赏问题

  • ¥15 编辑cmake lists 明明写了project项目名,但是还是报错怎么回事
  • ¥15 关于#计算机视觉#的问题:求一份高质量桥梁多病害数据集
  • ¥15 特定网页无法访问,已排除网页问题
  • ¥50 如何将脑的图像投影到颅骨上
  • ¥15 提问一个关于vscode相关的环境配置问题,就是输入中文但是显示不出来,代码在idea可以显示中文,但在vscode不行,不知道怎么配置环境
  • ¥15 netcore使用PuppeteerSharp截图
  • ¥20 这张图页头,页脚具体代码该怎么写?
  • ¥15 关于#sql#的问题,请各位专家解答!
  • ¥20 WPF MVVM模式 handycontrol 框架, hc:SearchBar 控件 Text="{Binding NavMenusKeyWords}" 绑定取不到值
  • ¥15 需要手写数字信号处理Dsp三个简单题 不用太复杂