linux stm32mp157 DAC使用DMA输出频率例程
时间: 2024-01-30 13:04:28 浏览: 211
以下是在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例程。
阅读全文