Stm32 在DMA和HAL不工作的情况下进行I2C传输

Stm32 在DMA和HAL不工作的情况下进行I2C传输,stm32,i2c,dma,hal,Stm32,I2c,Dma,Hal,这似乎是一个比较常见的问题,但我在网上找到的任何解决方案都不成功。具体来说,我试图通过I2C/DMA和cubeIDE中生成的HAL将1024字节的缓冲区(完整的128x64像素图像)传输到SSD1306显示器。我使用的是STML432核子板。我可以在没有DMA的情况下使用HAL_I2C_Mem_Write传输缓冲区 基于我所看到的其他问题,问题在于DMA完成,而I2C总线仍在传输上工作。我只是不知道如何纠正这一点,并且给出的示例通常不使用HAL(不幸的是,尽管我做出了努力,但我自己并没有足够的能

这似乎是一个比较常见的问题,但我在网上找到的任何解决方案都不成功。具体来说,我试图通过I2C/DMA和cubeIDE中生成的HAL将1024字节的缓冲区(完整的128x64像素图像)传输到SSD1306显示器。我使用的是STML432核子板。我可以在没有DMA的情况下使用HAL_I2C_Mem_Write传输缓冲区

基于我所看到的其他问题,问题在于DMA完成,而I2C总线仍在传输上工作。我只是不知道如何纠正这一点,并且给出的示例通常不使用HAL(不幸的是,尽管我做出了努力,但我自己并没有足够的能力正确地将它们应用于HAL)。我曾尝试过在I2c和DMA中使用中断,但没有成功,只传输了大约前254个字节(屏幕上只显示了两行)

以下是我发送缓冲区的代码:

static void ssd1306_WriteMData_DMA(const uint8_t *data, uint16_t size)
{
    while(HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY);
    HAL_I2C_Mem_Write_DMA(&hi2c1, I2C_ADDR, SSD1306_REG_MDAT, 1, (uint8_t*)data, size);
}
以及每个中断处理程序的代码:

void I2C1_EV_IRQHandler(void)
{
  /* USER CODE BEGIN I2C1_EV_IRQn 0 */
    if(I2C1->ISR & I2C_ISR_TCR){
        
    I2C1->CR2 |=  (I2C_CR2_STOP);// stop i2c
    I2C1->ICR |=  (I2C_ICR_STOPCF);// Reset the ICR  flag.

    // stop DMA
    DMA1->IFCR |= DMA_IFCR_CTCIF6;
    // clear flag
    DMA1_Channel6->CCR &= ~DMA_CCR_EN;
}
  /* USER CODE END I2C1_EV_IRQn 0 */
  //HAL_I2C_EV_IRQHandler(&hi2c1);
  /* USER CODE BEGIN I2C1_EV_IRQn 1 */
 
  /* USER CODE END I2C1_EV_IRQn 1 */
}


void DMA1_Channel6_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel6_IRQn 0 */

    // stop DMA
    DMA1->IFCR |= DMA_IFCR_CTCIF6;
    // clear flag
    DMA1_Channel6->CCR &= ~DMA_CCR_EN;

  /* USER CODE END DMA1_Channel6_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_i2c1_tx);
  /* USER CODE BEGIN DMA1_Channel6_IRQn 1 */

  /* USER CODE END DMA1_Channel6_IRQn 1 */
}
我想这就是所有相关的代码,如果我还遗漏了什么,请告诉我。所有外围设备的初始化代码都是通过cubeMX完成的,但如果需要,我可以发布这些代码或设置。我觉得这是我错过的一件非常简单的事情,但老实说,这有点让我不知所措,所以我不太清楚到底发生了什么


谢谢你的帮助

您还没有说您正在使用哪个STM32。它们有不同的位定义(因为早期发布的部分中的I2C外围设备是垃圾),但看起来您使用的是后面的一个


基本上,您可以在参考手册中的I2C寄存器位定义中找到所需内容。如果您在停止完成之前设置停止,则需要查找清除的忙位或在发送停止时设置的BTF(字节传输完成)位。

Oops,我本想将其放入,现在已编辑。它是核子板上的STM32L432。我从我读过的其他一些页面中认出了BTF,你能再解释一下吗?我需要在哪个中断中等待BTF/BUSY,我告诉哪个停止(I2C或DMA)?谢谢我没有使用L4,但快速查看手册,您似乎需要使用TCIE位启用传输完整中断,但请注意,NBYTES字段仅为8位,因此您可能需要4个TC中断来传输,重新加载位集每次传输255个字节,然后再多传输一个来完成最后4个字节。在这种情况下,您可能不需要DMA完全中断。(BTF是一个在其他没有NBYTES功能的旧部件中使用的名称)。好的,我想我即将理解,我已经通过HAL_I2C_Mem_Write_DMA,它似乎在做你所说的关于设置xfermode=I2C_RELOAD_模式的事情;它在hi2c->XferCount中存储并减少字节数,似乎在XferCount为0之前都是设置为循环的,但它只运行一次,然后调用I2C1\u EV\u IRQHandler abov。在这一点上,如果我检查RESET=1和NBYTES=255。我如何让它实际循环并完成?我需要将“开始”设置为1吗?第1182页说,如果设置重置,则启动无效。。。谢谢我尝试过将START设置为1,但没有效果,如果我清除NBYTES并将其设置为255,它将清除I2C_ISR_TCR标志,但它似乎永远不会触发发送下一个字节。。。我觉得HAL应该解决这个问题,因为它似乎是在HAL_I2C_Mem_Write_DMA中这样设置的。也许我只是配置设置错误,导致它挂起?