打印
[技术问答]

SPI DMA怎么配置?

[复制链接]
1848|14
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
pq113_6|  楼主 | 2019-10-21 14:18 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
现在用的是SPI2,RX和TX都打开DMA通道,配置结果如下:
**************DMA RX**************
STATUS:0
INTEN:1
RST:0
STOP:0
CONFIG:86
LENGTH:4
MEM_START:20007fec
MEM_END:20007ff0
PERIPH_ADDR:4000d010
ENABLE:1
TRANS_NUM:0
LEFT_NUM:0
**************DMA TX**************
STATUS:0
INTEN:1
RST:0
STOP:0
CONFIG:486
LENGTH:4
MEM_START:20007fe8
MEM_END:20007fec
PERIPH_ADDR:4000d010
ENABLE:1
TRANS_NUM:0
LEFT_NUM:10

目前有3个问题,
1. RX部分虽然配置了长度为4字节,但是LEFT_NUM一直为0,而TX同样是配置4字节长度,LEFT_NUM却是0x10
2. LENGTH对应的是4字节长度?LENGTH = 1表示4字节吗?也就是说读写长度必须4字节的整数倍?
3. TRANS_NUM一直为0,意味着SPI并没有通信,配置还有什么错误?

使用特权

评论回复

相关帖子

沙发
TechHolder| | 2019-10-21 17:29 | 只看该作者
pq113_6 发表于 2019-10-21 15:21
SPI通信已经OK,现在是配置DMA有问题。

SPI例程里面有使用DMA传输SPI数据例程。

使用特权

评论回复
板凳
TechHolder| | 2019-10-21 17:33 | 只看该作者
pq113_6 发表于 2019-10-21 15:47
好坑,文档《AC781X DMA模块应用笔记》里面SPI对应的DMA通道是错误的,

感谢提出,会进行更新。

使用特权

评论回复
地板
pq113_6|  楼主 | 2019-10-21 17:56 | 只看该作者
TechHolder 发表于 2019-10-21 17:29
SPI例程里面有使用DMA传输SPI数据例程。

参考例程已经可以了,有个问题,DMA的速度怎么比非DMA的方式还要慢呢?有地方可以优化吗?

使用特权

评论回复
5
AutochipsMCU| | 2019-10-22 09:57 | 只看该作者
pq113_6 发表于 2019-10-21 17:56
参考例程已经可以了,有个问题,DMA的速度怎么比非DMA的方式还要慢呢?有地方可以优化吗? ...

是否方便贴上程序瞧瞧

使用特权

评论回复
6
pq113_6|  楼主 | 2019-10-22 11:10 | 只看该作者
AutochipsMCU 发表于 2019-10-22 09:57
是否方便贴上程序瞧瞧

奇葩的是今天的代码跑不通了,不知道为什么,还在查

使用特权

评论回复
7
pq113_6|  楼主 | 2019-10-23 17:11 | 只看该作者
AutochipsMCU 发表于 2019-10-22 09:57
是否方便贴上程序瞧瞧

现在有点眉目,我的代码给你看看,看一下有什么问题。
1. 改了一下寄存器的定义,不使用库的bit写法
typedef struct {
    __IO uint32_t CHANNELx_STATUS;
    __IO uint32_t CHANNELx_INTEN;
    __IO uint32_t CHANNELx_RST;
    __IO uint32_t CHANNELx_STOP;
    __IO uint32_t CHANNELx_CONFIG;
    __IO uint32_t CHANNELx_CHAN_LENGTH;
    __IO uint32_t CHANNELx_MEM_START_ADDR;
    __IO uint32_t CHANNELx_MEM_END_ADDR;
    __IO uint32_t CHANNELx_PERIPH_ADDR;
    __IO uint32_t CHANNELx_CHAN_ENABLE;
    __IO uint32_t CHANNELx_DATA_TRANS_NUM;
    __IO uint32_t CHANNELx_INTER_FIFO_DATA_LEFT_NUM;
} DMA_Type_B;
2. DMA初始化:DMA_Type_B *dmaChannel[] =
    {
        (DMA_Type_B *)DMA2, (DMA_Type_B *)DMA3,
        (DMA_Type_B *)DMA4, (DMA_Type_B *)DMA5,
    };
    CKGEN_Enable(CLK_DMA_AHB,1);        /* Enable DMA AHB clock */
    CKGEN_Enable(CLK_DMA_APB,1);        /* Enable DMA APB clock */
    CKGEN_SoftReset(SRST_DMA_AHB,1);    /* Inactive DMA_AHB reset */
    CKGEN_SoftReset(SRST_DMA_APB,1);    /* Inactive DMA_APB reset */
    dmaChannel[2 * port]->CHANNELx_RST = 1 << 1; //HARD_RST
    dmaChannel[2 * port]->CHANNELx_RST = 0;
    dmaChannel[2 * port + 1]->CHANNELx_RST = 1 << 1; //HARD_RST
    dmaChannel[2 * port + 1]->CHANNELx_RST = 0;

3. SPI双工接口函数:
void spimTransferBytes(uint8_t port, uint8_t* wrBuf, uint8_t* rdBuf, uint16_t len)
{
    SPI_Type* SPIx;
    uint32_t spiBuf;
    //uint8_t spiBuf[] = {0xaa, 0x55};
    uint8_t dmaIndex = 0;
    DMA_Type_B *dmaChannel[] =
    {
        (DMA_Type_B *)DMA2, (DMA_Type_B *)DMA3,
        (DMA_Type_B *)DMA4, (DMA_Type_B *)DMA5,
    };
    if(len == 0 || port > 1)
        return;

    SPIx = spimGroup[port];
    if(SPIx == SPI2)
        dmaIndex = 2;

    SPI_Disable(SPIx);

    dmaChannel[dmaIndex]->CHANNELx_STATUS = 0;
    dmaChannel[dmaIndex]->CHANNELx_INTEN = 0;
    dmaChannel[dmaIndex]->CHANNELx_CONFIG =
        (0 << 0) | //MEM2MEM 1bit
        (3 << 1) | //CHAN_PRIORITY 2bit
        (0 << 3) | //MEM_SIZE 2bit
        (0 << 5) | //PERIPH_SIZE 2bit
        (1 << 7) | //MEM_INCREAMENT 1bit
        (0 << 8) | //PERIPH_INCREAMENT 1bit
        (0 << 9) | //CHAN_CIRCULAR 1bit
        (0 << 10) | //CH_DIR 1bit
        (0 << 11); //MEM_BYTE_MODE 2bit
    dmaChannel[dmaIndex]->CHANNELx_CHAN_LENGTH = len;
    if(rdBuf == NULL)
    {
        dmaChannel[dmaIndex]->CHANNELx_MEM_START_ADDR = (uint32_t)(&spiBuf);
        dmaChannel[dmaIndex]->CHANNELx_MEM_END_ADDR = (uint32_t)(&spiBuf);
    }
    else
    {
        dmaChannel[dmaIndex]->CHANNELx_MEM_START_ADDR = (uint32_t)(rdBuf);
        dmaChannel[dmaIndex]->CHANNELx_MEM_END_ADDR = (uint32_t)rdBuf + len;
    }
    dmaChannel[dmaIndex]->CHANNELx_PERIPH_ADDR = (uint32_t)&(SPIx->DATA);
    dmaChannel[dmaIndex]->CHANNELx_CHAN_ENABLE = 1;

    dmaChannel[dmaIndex + 1]->CHANNELx_STATUS = 0;
    dmaChannel[dmaIndex + 1]->CHANNELx_INTEN = 0;
    dmaChannel[dmaIndex + 1]->CHANNELx_CONFIG =
        (0 << 0) | //MEM2MEM 1bit
        (3 << 1) | //CHAN_PRIORITY 2bit
        (0 << 3) | //MEM_SIZE 2bit
        (0 << 5) | //PERIPH_SIZE 2bit
        (1 << 7) | //MEM_INCREAMENT 1bit
        (0 << 8) | //PERIPH_INCREAMENT 1bit
        (0 << 9) | //CHAN_CIRCULAR 1bit
        (1 << 10) | //CH_DIR 1bit
        (0 << 11); //MEM_BYTE_MODE 2bit
    dmaChannel[dmaIndex + 1]->CHANNELx_CHAN_LENGTH = len;
    if(wrBuf == NULL)
    {
        dmaChannel[dmaIndex + 1]->CHANNELx_MEM_START_ADDR = (uint32_t)(&spiBuf);
        dmaChannel[dmaIndex + 1]->CHANNELx_MEM_END_ADDR = (uint32_t)(&spiBuf);
    }
    else
    {
        dmaChannel[dmaIndex + 1]->CHANNELx_MEM_START_ADDR = (uint32_t)(wrBuf);
        dmaChannel[dmaIndex + 1]->CHANNELx_MEM_END_ADDR = (uint32_t)wrBuf + len;
    }
    dmaChannel[dmaIndex + 1]->CHANNELx_PERIPH_ADDR = (uint32_t)&(SPIx->DATA);
    dmaChannel[dmaIndex + 1]->CHANNELx_CHAN_ENABLE = 1;

    //Printf("DMA RX Config: %x\n", dmaChannel[dmaIndex]->CHANNELx_CONFIG);
    //Printf("DMA TX Config: %x\n", dmaChannel[dmaIndex + 1]->CHANNELx_CONFIG);

    SPI_Enable(SPIx);

    //wait for finish
    while((dmaChannel[dmaIndex + 1]->CHANNELx_STATUS & 0x01) == 0);

    //disable DMA
    dmaChannel[dmaIndex]->CHANNELx_CHAN_ENABLE = 0;
    dmaChannel[dmaIndex + 1]->CHANNELx_CHAN_ENABLE = 0;
}

如果CHANNELx_CONFIG是上面的配置,SPI通信不通,如果改成MEM_SIZE = 2,MEM_BYTE_MODE = 3,前面的SPI通信正常,但是写入数据的顺序似乎有错误,因为我这边接的SPI设备是彩屏驱动,我刷全屏为绿色,显示是另外的颜色。

使用特权

评论回复
8
TechHolder| | 2019-10-24 17:44 | 只看该作者
pq113_6 发表于 2019-10-23 17:11
现在有点眉目,我的代码给你看看,看一下有什么问题。
1. 改了一下寄存器的定义,不使用库的bit写法
type ...

这个DMA数据宽度,传输模式设置,参考AC781X参考手册20.5.3.5小节。

使用特权

评论回复
9
pq113_6|  楼主 | 2019-10-25 11:04 | 只看该作者
TechHolder 发表于 2019-10-24 17:44
这个DMA数据宽度,传输模式设置,参考AC781X参考手册20.5.3.5小节。

有点看不懂,不过是不是发送的时候MEMSIZE必须是32,我看代码里面也说了必须是4字节对齐,如果是这样我这边就没必要看了,DMA通用性就受限制了

使用特权

评论回复
10
JasonLee27| | 2019-10-25 11:53 | 只看该作者
pq113_6 发表于 2019-10-25 11:04
有点看不懂,不过是不是发送的时候MEMSIZE必须是32,我看代码里面也说了必须是4字节对齐,如果是这样我这 ...

DMA通信主要是首地址要求是要4字节对齐,但通信长度不一定要求4字节对齐,所以你定义DMA发送buffer的时候,使用uint8_t的数组建议增加__align__(4)对齐

使用特权

评论回复
11
pq113_6|  楼主 | 2019-10-25 12:13 | 只看该作者
JasonLee27 发表于 2019-10-25 11:53
DMA通信主要是首地址要求是要4字节对齐,但通信长度不一定要求4字节对齐,所以你定义DMA发送buffer的时候 ...

了解,我的整个程序构架没法设定这个,你看接口函数buf不可能设定4字节对齐,上层发数据是用app层决定的,所以只能弃用DMA了。这个规格定义肯定有一定的局限性,建议以后的芯片能改正。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

36

主题

284

帖子

2

粉丝