查看: 3455|回复: 9

[已解决] K60 DMA SPI2

[复制链接]

该用户从未签到

4

主题

22

帖子

0

注册会员

Rank: 2

积分
180
最后登录
2019-12-27
发表于 2017-4-27 19:23:28 | 显示全部楼层 |阅读模式
本帖最后由 andyxu 于 2017-4-27 19:23 编辑

最近想用DMA来获取SPI2中的数据,发现不成功。芯片是MK60DN512ZVLQ10。
现在我基本实现的是:
1.SPI2的轮训读数据;
2.DMA 内存到内存之间的拷贝。

但是就是无法实现利用DMA来读取SPI2中的(POPR)的数据。

  1. void SPI_Init(SPI_InitTypeDef * SPI_InitStruct)
  2. {
  3.     SPI_Type *SPIx;
  4.    
  5.     SPIx = SPI_InstanceTable[SPI_InitStruct->instance];
  6.    
  7.     /* Enable clock gate */
  8.     *(uint32_t*)SIM_SPIClockGateTable[SPI_InitStruct->instance].addr |= SIM_SPIClockGateTable[SPI_InitStruct->instance].mask;
  9.    
  10.         /* Clear all flags */
  11.     SPIx->SR = 0xFFFFFFFF;

  12.     /* Halt: stop SPI */
  13.     SPIx->MCR |= SPI_MCR_HALT_MASK;
  14.    
  15.     /* master or slave */
  16.     switch(SPI_InitStruct->mode)
  17.     {
  18.         case kSPI_Master:
  19.             SPIx->MCR |= SPI_MCR_MSTR_MASK;
  20.             break;
  21.         case kSPI_Slave:
  22.             SPIx->MCR &= ~SPI_MCR_MSTR_MASK;
  23.             break;
  24.         default:
  25.             break;
  26.     }
  27.    
  28.     /* enable SPI clock */
  29.     SPIx->MCR &= ~SPI_MCR_MDIS_MASK;
  30.    
  31.     /* disable FIFO and clear FIFO flag */
  32.     SPIx->MCR |=
  33.         SPI_MCR_PCSIS_MASK |
  34.         SPI_MCR_HALT_MASK  |
  35.         SPI_MCR_CLR_TXF_MASK|
  36.        // SPI_MCR_MTFE_MASK   |
  37.         SPI_MCR_CLR_RXF_MASK
  38. //        SPI_MCR_DIS_RXF_MASK|
  39. //        SPI_MCR_DIS_TXF_MASK
  40.         ;
  41.    
  42.     /* config frame format */
  43.     SPI_CTARConfig(SPI_InitStruct->instance, SPI_InitStruct->ctar, SPI_InitStruct->frameFormat, SPI_InitStruct->dataSize, SPI_InitStruct->bitOrder, SPI_InitStruct->baudrate);
  44.    
  45. //    /* DMA configuration related with SPI2 */
  46.         SPI_ITDMAConfig(HW_SPI2, kSPI_DMA_RFDF, true);

  47.         /* launch */
  48.     SPIx->MCR &= ~SPI_MCR_HALT_MASK;
  49. }
复制代码

  1. /* DMA configuration related with eDMA */
  2.         DMA_InitTypeDef DMA_InitStruct1         = {0};
  3.     DMA_InitStruct1.chl                                 = 15;
  4.     DMA_InitStruct1.chlTriggerSource         = SPI2_REV_DMAREQ;
  5.     DMA_InitStruct1.triggerSourceMode         = kDMA_TriggerSource_Normal;
  6.     DMA_InitStruct1.minorLoopByteCnt         = 4;
  7.     DMA_InitStruct1.majorLoopCnt                 = 1;
  8.    
  9.     DMA_InitStruct1.sAddr                                 = (uint32_t)((void*)&SPI2->POPR);
  10.     DMA_InitStruct1.sLastAddrAdj                 = 0;
  11.     DMA_InitStruct1.sAddrOffset                 = 0;
  12.     DMA_InitStruct1.sDataWidth                         = kDMA_DataWidthBit_32;
  13.     DMA_InitStruct1.sMod                                 = kDMA_ModuloDisable;
  14.    
  15.     DMA_InitStruct1.dAddr                                 = (uint32_t)(&recvData);
  16.     DMA_InitStruct1.dLastAddrAdj                 = 0;
  17.     DMA_InitStruct1.dAddrOffset                 = 0;
  18.     DMA_InitStruct1.dDataWidth                         = kDMA_DataWidthBit_32;
  19.     DMA_InitStruct1.dMod                                 = kDMA_ModuloDisable;
  20.     DMA_Init(&DMA_InitStruct1);
复制代码
  1. uint32_t DMA_Init(DMA_InitTypeDef *DMA_InitStruct)
  2. {
  3.     uint8_t chl;
  4.    
  5.         /* enable DMA and DMAMUX clock */
  6. #if defined(DMAMUX0)  
  7.     SIM->SCGC6 |= SIM_SCGC6_DMAMUX0_MASK;
  8. #endif
  9. #if  defined(DMAMUX1)
  10.     SIM->SCGC6 |= SIM_SCGC6_DMAMUX1_MASK;
  11. #endif
  12. #if  defined(DMAMUX)
  13.     SIM->SCGC6 |= SIM_SCGC6_DMAMUX_MASK;
  14. #endif
  15.         
  16.         SIM->SCGC7 |= SIM_SCGC7_DMA_MASK;
  17.    
  18.     chl = DMA_InitStruct->chl;
  19. //        printf("Node2: chl = %d\r\n", chl);
  20.     /* disable chl first */
  21.     DMA0->ERQ &= ~(1<<(chl));
  22.     /* dma chl source config */
  23.     DMAMUX_InstanceTable[0]->CHCFG[chl] = DMAMUX_CHCFG_SOURCE(DMA_InitStruct->chlTriggerSource);
  24. //        printf("Node2: chl = %d\r\n", DMAMUX_InstanceTable[0]->CHCFG[chl]);

  25.     /* trigger mode */
  26.     switch(DMA_InitStruct->triggerSourceMode)
  27.     {
  28.         case kDMA_TriggerSource_Normal:
  29.             DMAMUX_InstanceTable[0]->CHCFG[chl] &= ~DMAMUX_CHCFG_TRIG_MASK;
  30.             break;
  31.         case kDMA_TriggerSource_Periodic:
  32.             DMAMUX_InstanceTable[0]->CHCFG[chl] |= DMAMUX_CHCFG_TRIG_MASK;
  33.             break;
  34.         default:
  35.             break;
  36.     }
  37.     /* clear some register */
  38.     DMA0->TCD[chl].ATTR  = 0;
  39.     DMA0->TCD[chl].CSR   = 0; // control and state register
  40.     /* minor loop cnt */
  41.     DMA0->TCD[chl].NBYTES_MLNO = DMA_NBYTES_MLNO_NBYTES(DMA_InitStruct->minorLoopByteCnt);
  42.     /* major loop cnt */
  43.         DMA0->TCD[chl].CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(DMA_InitStruct->majorLoopCnt);
  44.         DMA0->TCD[chl].BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(DMA_InitStruct->majorLoopCnt);
  45.     /* source config */
  46.     DMA0->TCD[chl].SADDR = DMA_InitStruct->sAddr;
  47.     DMA0->TCD[chl].SOFF = DMA_InitStruct->sAddrOffset;
  48.     DMA0->TCD[chl].ATTR |= DMA_ATTR_SSIZE(DMA_InitStruct->sDataWidth);
  49.     DMA0->TCD[chl].ATTR |= DMA_ATTR_SMOD(DMA_InitStruct->sMod);
  50.     DMA0->TCD[chl].SLAST = DMA_SLAST_SLAST(DMA_InitStruct->sLastAddrAdj);
  51.     /* destation config */
  52.     DMA0->TCD[chl].DADDR = DMA_InitStruct->dAddr;
  53.     DMA0->TCD[chl].DOFF = DMA_InitStruct->dAddrOffset;
  54.     DMA0->TCD[chl].ATTR |= DMA_ATTR_DSIZE(DMA_InitStruct->dDataWidth);
  55.     DMA0->TCD[chl].ATTR |= DMA_ATTR_DMOD(DMA_InitStruct->dMod);
  56.     DMA0->TCD[chl].DLAST_SGA = DMA_DLAST_SGA_DLASTSGA(DMA_InitStruct->dLastAddrAdj);
  57.     /* auto close enable(disable req on major loop complete)*/
  58.     DMA0->TCD[chl].CSR |= DMA_CSR_DREQ_MASK;
  59.         /* enable DMAMUX */
  60.         DMAMUX_InstanceTable[0]->CHCFG[chl] |= DMAMUX_CHCFG_ENBL_MASK;
  61.    
  62.     return chl;
  63. }
复制代码


最后是DMA0->SERQ = DMA_SERQ_SERQ(chl);使能对应通道的触发源请求。但是if(DMA0->TCD[chl].CSR & DMA_CSR_DONE_MASK)标识位一直是未完成。

我查看数据手册,难道SPI2是没有触发源的,为什么手册中是空白的。还望大神指点一二。
微信截图_20170427192235.png

最佳答案

楼主,以我对NXP的DSPI了解,提醒楼主在使用DSPI的EDMA传输时要注意的地方: DSPI的PUSHR寄存器低16位为数据,高16位为控制区; 请楼主确认下该款芯片是否支持PUSHR寄存器的byte 或者 halfword写入。 如果不支持,那 ...
回复

使用道具 举报

该用户从未签到

4

主题

22

帖子

0

注册会员

Rank: 2

积分
180
最后登录
2019-12-27
 楼主| 发表于 2017-4-27 19:51:21 | 显示全部楼层
我还有几个小小的疑问:
1.轮训模式下,是不是在SPI为非Halt之后,一旦命令和数据写入PUSHR,SPI就开始通信了?
2.轮训模式下,是不是只有在写入PUSHR之后,等完成通信,才可能有POPR的数据?也就是不存在直接单纯读POPR的可能?

那么,DMA模式下,如果仅给出Rx的request 信号,能读取SPI的数据吗?
回复 支持 反对

使用道具 举报

  • TA的每日心情

    2019-9-17 13:22
  • 签到天数: 238 天

    连续签到: 1 天

    [LV.7]常住居民III

    30

    主题

    905

    帖子

    6

    金牌会员

    Rank: 6Rank: 6

    积分
    2251
    最后登录
    2024-10-8
    发表于 2017-4-28 08:30:38 | 显示全部楼层
    没有尝试过,据FAE介绍过一次,有点小复杂
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    4

    主题

    22

    帖子

    0

    注册会员

    Rank: 2

    积分
    180
    最后登录
    2019-12-27
     楼主| 发表于 2017-4-28 09:54:05 | 显示全部楼层
    very333 发表于 2017-4-28 08:30
    没有尝试过,据FAE介绍过一次,有点小复杂

    今天早上我尝试了一下我昨天的猜想,发现我的猜想是对的,总结如下:
    1.不论是轮训还是DMA,在SPI为非Halt的状态下,只要往PUSHR寄存器中写入,那么SPI的传输此刻就开始了;
    2.手册上虽然没有写SPI2的DMA触发源,但实际上都是可能用的,分别指的是20 和21号;
    3.如果没有发送,即向PUSHR寄存器中写数据,是没有数据返回的。

    当然,这一切应该都跟我主机是 Mater 有关。
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    712

    主题

    6371

    帖子

    0

    超级版主

    Rank: 8Rank: 8

    积分
    24871
    最后登录
    2025-7-18
    发表于 2017-4-28 10:40:06 | 显示全部楼层
    楼主你好!
    关于DMA SPI的例程,建议你参考这个帖子,里么有官方同事分享的参考代码,你可以参考代码之后理解下:
    http://community.nxp.com/docs/DOC-94082
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2019-7-4 09:29
  • 签到天数: 7 天

    连续签到: 1 天

    [LV.3]偶尔看看II

    1

    主题

    48

    帖子

    10

    中级会员

    Rank: 3Rank: 3

    积分
    257
    最后登录
    2019-12-23
    发表于 2017-4-28 11:04:00 | 显示全部楼层
    楼主,以我对NXP的DSPI了解,提醒楼主在使用DSPI的EDMA传输时要注意的地方:
    DSPI的PUSHR寄存器低16位为数据,高16位为控制区;
    请楼主确认下该款芯片是否支持PUSHR寄存器的byte 或者 halfword写入。
    如果不支持,那么就是每次EDMA的传输宽度必须是word(32bit),否则EDMA传输失败。
    如果楼主数据是uint8_t类型,那么就需要3channel进行数据传输了,这个解释起来就麻烦了。
    楼主可以去参考NXP的官方SDK2.0 .DSPI的这个PUSHR寄存器写入方法还是比较恶心的,估计后面新的版本肯定会支持PUSHR寄存器byte和halfword写入的。
    个人的一点经验,希望对楼主有帮助。
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    4

    主题

    22

    帖子

    0

    注册会员

    Rank: 2

    积分
    180
    最后登录
    2019-12-27
     楼主| 发表于 2017-4-28 12:43:51 | 显示全部楼层
    小恩GG 发表于 2017-4-28 10:40
    楼主你好!
    关于DMA SPI的例程,建议你参考这个帖子,里么有官方同事分享的参考代码,你可以参考代码之后理 ...

    微信截图_20170428124300.png
    貌似我登录了我的账号之后,我是没有权限查看?
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    4

    主题

    22

    帖子

    0

    注册会员

    Rank: 2

    积分
    180
    最后登录
    2019-12-27
     楼主| 发表于 2017-4-28 12:44:31 | 显示全部楼层
    疯狂的大石头 发表于 2017-4-28 11:04
    楼主,以我对NXP的DSPI了解,提醒楼主在使用DSPI的EDMA传输时要注意的地方:
    DSPI的PUSHR寄存器低16位为数 ...

    谢谢你的分享,我会好好研究下的。
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    712

    主题

    6371

    帖子

    0

    超级版主

    Rank: 8Rank: 8

    积分
    24871
    最后登录
    2025-7-18
    发表于 2017-4-28 12:49:49 | 显示全部楼层
    andyxu 发表于 2017-4-28 12:43
    貌似我登录了我的账号之后,我是没有权限查看?

    dspi.c.zip (2.98 KB, 下载次数: 22)
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    4

    主题

    22

    帖子

    0

    注册会员

    Rank: 2

    积分
    180
    最后登录
    2019-12-27
     楼主| 发表于 2017-4-29 08:35:54 | 显示全部楼层
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-7-19 15:47 , Processed in 0.245828 second(s), 32 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表