STM32H7 CPU Cache 与MDMA冲突问题

关于最近使用STM32H743+SDMMC+QSPI+MDMA+FATFS读写SD卡与SPI FLASH时的问题:

注:以下修改适用于你使用了STM32H743+SDMMC+QSPI+MDMA+FATFS+Cache缓存的情况。

  • 在读写SD卡时,发现f_write函数返回FR_INT_ERR,然后打断点调试发现底层函数返回值没有问题:
    - ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/a1a6d9fede0849b18788f643673b9164.png)

    使用读卡器发现数据实际已经写入;这让我百思不得其解,怀疑是什么原因导致数据没有同步;于是想到了会不会是STM32H7的Cache缓存的问题,然后上网找资料,看到了一篇文章:文章链接在这里插入图片描述
    经过这篇文章提示,于是看了代码,确实开启了Cache;尝试关闭后:
    在这里插入图片描述
    果然写入返回错误的问题解决了:
    在这里插入图片描述
    关闭Cacheh后,SDRAM的内存映射读写也变慢了,影响了其他模块性能,问题还未完全解决。
    于是想办法在不关闭缓存机制的情况下,能够保证数据的一致性了,然后根据SCB_EnableDCache这个函数跳转,发现了一个SCB_CleanDCache函数,该函数是清除数据Cache的,然后尝试使用了一下,在DMA读写之前调用,重写了下面函数:在这里插入图片描述
    测试发现也是可以的,其他模块也没有受到影响,到此,问题全部解决。

  • QSPI FALSH读写也是一样,也是MDMA与Cache数据不一致导致的,解决方法可以参考上面SD卡。
    修改读写部分函数(底层驱动基于野火开发板例程修改):
    在这里插入图片描述
    在这里插入图片描述
    参照SDMMC的磁盘读写(sd_diskio.c文件),完成以下修改:
    在这里插入图片描述
    在这里插入图片描述

  • 最后注意时钟树的选择:
    DTCM内存池,DTCM共128KB,此部分内存仅CPU和MDMA(通过AHBS)可以访问!!!

    ITCM内存池,DTCM共64 KB,此部分内存仅CPU和MDMA(通过AHBS)可以访问!!!
    在这里插入图片描述
    之前我QSPI 时钟选择是HCLK3,所以 QSPI按照SD卡改了也不行,更改时钟选择就行了。

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是在Linux环境下使用DMA输出频率的STM32MP157 DAC例程: 1. 首先,需要在设备树中启用DAC和DMA: ``` &dac { status = "okay"; dmas = <&mdma1 0 0>, <&mdma1 1 0>; dma-names = "tx", "rx"; #address-cells = <1>; #size-cells = <0>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_dac>; clock-names = "kernel", "pll3_p_ck"; clocks = <&rcc SCK_DAC>, <&rcc SCK_PLL3_Q>; }; &mdma1 { status = "okay"; }; ``` 这里我们使用了mdma1作为DMA控制器,同时启用了DAC和DMA。 2. 在Linux驱动程序中初始化DAC和DMA: ``` static int stm32_dac_probe(struct platform_device *pdev) { struct stm32_dac *dac; struct resource *res; int ret; dac = devm_kzalloc(&pdev->dev, sizeof(*dac), GFP_KERNEL); if (!dac) return -ENOMEM; /* 获取DAC的资源 */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); dac->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(dac->base)) return PTR_ERR(dac->base); /* 获取DMA的资源 */ dac->dma_tx = of_dma_request_slave_channel(pdev->dev.of_node, 0); if (!dac->dma_tx) { dev_err(&pdev->dev, "No Tx DMA channel\n"); return -ENODEV; } /* 初始化DAC */ ret = stm32_dac_hw_init(dac); if (ret) { dev_err(&pdev->dev, "Failed to initialize DAC\n"); return ret; } /* 初始化DMA */ ret = stm32_dac_dma_init(dac); if (ret) { dev_err(&pdev->dev, "Failed to initialize DMA\n"); return ret; } platform_set_drvdata(pdev, dac); return 0; } static int stm32_dac_hw_init(struct stm32_dac *dac) { /* 使能DAC时钟 */ clk_prepare_enable(dac->clk); /* 初始化DAC */ writel(DAC_CR_EN1 | DAC_CR_TSEL1(7), dac->base + DAC_CR); writel(DAC_DHR12R1(0x800), dac->base + DAC_DHR12R1); return 0; } static int stm32_dac_dma_init(struct stm32_dac *dac) { /* 初始化DMA */ dac->dma_tx_desc = dmaengine_prep_slave_sg(dac->dma_tx, dac->sg_tx, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); if (!dac->dma_tx_desc) { dev_err(dac->dev, "Failed to prepare Tx DMA descriptor\n"); return -EINVAL; } return 0; } ``` 在probe函数中,我们首先获取DAC和DMA的资源,然后分别调用`stm32_dac_hw_init`和`stm32_dac_dma_init`函数进行初始化。 在`stm32_dac_hw_init`函数中,我们使能DAC时钟,初始化DAC,并将DAC的输出信号设置为定时器7的触发信号。 在`stm32_dac_dma_init`函数中,我们初始化DMA,并为DMA分配一个描述符。 3. 在驱动程序中添加输出函数`stm32_dac_output`: ``` static ssize_t stm32_dac_output(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct stm32_dac *dac = dev_get_drvdata(dev); int ret; /* 将数据写入DMA缓冲区 */ ret = kstrtoint(buf, 10, &dac->value); if (ret) return ret; dac->buf[0] = dac->value; /* 启动DMA */ dmaengine_submit(dac->dma_tx_desc); dma_async_issue_pending(dac->dma_tx); return count; } static DEVICE_ATTR(output, S_IWUSR, NULL, stm32_dac_output); ``` `stm32_dac_output`函数将用户传入的数据写入DMA缓冲区,并启动DMA传输。 4. 在设备树中添加属性节点`output`: ``` &dac { ... output { compatible = "sysfs"; type = "int"; mode = "w"; }; }; ``` 这里我们使用sysfs节点来进行属性传输。 5. 在用户空间中通过sysfs节点来向DAC写入数据: ``` #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #define SYSFS_DAC "/sys/devices/platform/ff0c0000.dac/output" int main(int argc, char *argv[]) { int fd; char buf[16]; int value; if (argc < 2) { printf("Usage: %s <value>\n", argv[0]); return 0; } value = atoi(argv[1]); snprintf(buf, sizeof(buf), "%d", value); fd = open(SYSFS_DAC, O_WRONLY); if (fd < 0) { perror("open"); return -1; } if (write(fd, buf, strlen(buf)) < 0) { perror("write"); close(fd); return -1; } close(fd); return 0; } ``` 这里我们通过sysfs节点向DAC写入数据。 以上就是在Linux环境下使用DMA输出频率的STM32MP157 DAC例程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值