Gorgon_Meducer 发表于 2013-11-6 18:07:28

[交流][拍砖]新版驱动接口风格调查(二):DMA

本帖最后由 Gorgon_Meducer 于 2013-11-13 17:37 编辑

说在前面的话
    感谢上次大家关于IO口配置的踊跃发言,使我们能够远离闭门造车和自我感觉良好的状态,如大家所见,现在两个帖子
都做了更新,根据大家的意见修正了风格。这次展示的是DMA的接口风格,希望大家踊跃拍砖。
   
   说起DMA,本质来说就是替代内核去完成 存储器之间,存储器与外设之间,外设与外设之间的数据搬运。这里面涉及到
地址的问题,数据大小的问题,大小端的问题,等等原本简单的工作一下就复杂起来了。我们试图在两个层面上提供一个比
较容易使用的接口:从灵活性上说,如果你是DMA的使用高手,那么我们的接口不应该限制你的发挥;如果你是DMA的普通
使用者,虽然不太熟悉,但是对这种“高上大”的“新事物”还是有几分向往的,我们希望为你们提供套餐式的服务,比如
后面例子展示的4种常见套餐:存储器到存储器,外设到存储器,存储器到外设和外设到外设。
   另外,得益于DMA的强大,它提供一种叫做链表的模式,就是DMA的传输控制是像普通节点一样保存在SRAM里的,这个
节点实际上是一个结构体,结构体有一个NEXT指针,也就是说DMA允许你把一系列想做的操作都通过这样一个链表记录下来
然后他会勤勤恳恳的替你一个一个的完成而基本不用干预——想到能做什么了吧?是的,DMA甚至可以帮你完成12864的数据
刷新,你只要在SRAM里面保存一个显存,然后你用链表描述好IO操作的过程,剩下就什么都不用管了,是不是很方便,很强
大?一般来说,普通外设的寄存器设置和数据搬运都不在话下。

   说了这么多,主要还是想让大家从如何简化DMA操作的接口出发来吐槽。来吧,让搬砖拍的更猛烈吧!



    这是新版本编码规范的一个范例代码,包含对应的驱动模型和接口规范,我希望在不提供进一步解说的情况下听听大家
的意见,并提供以下信息:
1、第一眼给你的感受,是喜欢 恐惧 还是 茫然无措
2、顺次阅读代码后,代码要表达的意思你是否已经了解大概,表意是否清晰
3、有什么你觉得疑惑的地方?
4、有什么改进意见?
5、任何批评意见都是非常欢迎的

如果可能,希望大家能在回帖中描述下你理解的代码的行为。

这个库的目标就是要让代码使用起来简单,不仅仅要屏蔽底层的寄存器操作,还要做到功能和意义一目了然。
参与的人,即便自觉是菜鸟,也不用觉得自己水平不够之类的,因为你们就是最终的用户,你们是最有发言权的!
非常感谢大家的参与。


P.S: 这个库将是未来一个实质性的半导体产品的系统库。



范例一:Memory 到 Memory的数据搬运
    static volatile uint8_t chSource[]= {               //!< 测试用的数据源 source data
      MREPEAT(TEST_COUNT, SOURCE_DATA, 0)
    };   
    static volatile uint8_t chTarget[] = {                  //!< 测试用的目标地址 destination data
      MREPEAT(TEST_COUNT, TARGET_DATA, 0)
    };   
            
    DMA_CHN_CFG(
      DMA_CHANNEL0,                                       //!< channel 0
      
      DMA_TSF_CFG(
            DMA_MANUAL_TRIGGER_NEXT,                        //!< 手动触发 Manual Trigger next block
            DMA_MODE_MEMORY_TO_MEMORY,                      //!< 使用Memory到Memory传输的模板 momory to momory mode
            DMA_DATA_BITS_8,                              //!< 要传输数据的数据类型 data bits size

            UBOUND(chSource),                               //!< 要传输多少个数据 data size
            &chSource,                                 //!< 源数据地址 source address
            &chTarget                                    //!< 目标地址 destination address
      ),
    );

    DMA0.Trigger(DMA_CHANNEL0_MASK);                        //!< 触发传输 set trigger

    //! 等待传输完成
    while (!DMA_IS_CHN_TSF_CPL(DMA_CHANNEL0));         
范例二:外设到 存储器 的数据搬运
    static volatile uint32_t wTarget;         //!< 目标缓冲区 destination data
            
    DMA_CHN_CFG(
      DMA_CHANNEL1,                                       //!< channel 1
      
      DMA_TSF_CFG(
            DMA_MANUAL_TRIGGER_NEXT,                        //!< 手动触发模式 Manual Trigger next block
            DMA_MODE_PERIPHRAL_TO_MEMORY,                   //!< 使用从外设搬运数据到存储器的模板 peripheral to memory mode
            DMA_DATA_BITS_32,                               //!< 数据类型 data bits size

            TEST_COUNT,                                     //!< 要传输多少个数据 data size
            &XXX_USART0.RBR_THR_DLL.RBR.Value,            //!< 源寄存器的地址 source address
            &wTarget                                     //!< 目标缓冲区的地址 destination address
      ),
    );

    DMA0.Trigger(DMA_CHANNEL1_MASK);                        //!< set trigger
    while (DMA0.GetChannelState(DMA_CHANNEL1, STATE_TIRG));
范例五:单通道链表模式
static volatile uint32_t wMemory0[] @0x20004200ul = {   //!< source of first
      MREPEAT(TEST_COUNT, MEMORY0_DATA, 0)
    };   
    static volatile uint32_t wMemory1[] @0x20004300ul = {   //!< destination of first and source of second
      MREPEAT(TEST_COUNT, MEMORY1_DATA, 0)
    };   
    static volatile uint32_t wMemory2[] @0x20004400ul = {   //!< destination of second
      MREPEAT(TEST_COUNT, MEMORY2_DATA, 0)
    };   
            
    DMA_CHN_CFG(
      DMA_CHANNEL0,                                       //!< channel 0
      
      DMA_TSF_LIST(
            TSF_ITEM (
                DMA_MODE_MEMORY_TO_MEMORY    |                  //!< memory to memory mode
                DMA_DATA_BITS_32,                               //!< data bits size

                TEST_COUNT,                                     //!< data size
                &wMemory0,                                 //!< source address
                &wMemory1                                    //!< destination address
            ),
      
            TSF_ITEM (
                DMA_MODE_MEMORY_TO_PERIPHRAL    |               //!< memory to peripheral mode
                DMA_DATA_BITS_32,                               //!< data bits size
                TEST_COUNT,                                     //!< data size
                &wMemory1,                                 //!< source address      
                &GSP_USART0.RBR_THR_DLL.THR.Value               //!< destination address
            ),
      
            TSF_ITEM (
                DMA_MODE_PERIPHRAL_TO_PERIPHRAL    |            //!< peripheral to peripheral mode
                DMA_DATA_BITS_32,                               //!< data bits size
                TEST_COUNT,                                     //!< data size
                &GSP_USART1.RBR_THR_DLL.RBR.Value,            //!< source address      
                &GSP_USART1.RBR_THR_DLL.THR.Value               //!< destination address
            ),      
      
            TSF_ITEM (
                DMA_MANUAL_TRIGGER_NEXT    |                  //!< Manual Trigger next block
                DMA_MODE_PERIPHRAL_TO_MEMORY    |               //!< peripheral to memory mode
                DMA_DATA_BITS_32,                               //!< data bits size
                TEST_COUNT,                                     //!< data size
                &GSP_USART0.RBR_THR_DLL.RBR.Value,            //!< source address      
                &wMemory2                                    //!< destination address
            )   
      )
      
    );

    DMA0.Trigger(DMA_CHANNEL0_MASK);                        //!< set trigger
    delay(0x120);                                           //!< wait usart0 send complete
    DMA0.Trigger(DMA_CHANNEL0_MASK);                        //!< set trigger
    delay(0x120);                                           //!< wait usart1 send complete
    DMA0.Trigger(DMA_CHANNEL0_MASK);                        //!< set trigger

Gorgon_Meducer 发表于 2013-11-6 18:08:59

本帖最后由 Gorgon_Meducer 于 2013-12-31 11:17 编辑

Sensor Hub 硬件触发的例子
应用场景描述:
    我们来用DMA配合信号系统来构建一个芯片梦游的例子。是的,梦游,整个过程中,CPU都处于休眠状态。
应用是这个样子的:
    a. CPU完成最初DMA和信号网络的配置以后就进入休眠模式并不再唤醒。
    b. 假设外部有一个传感器,该传感器通过SPI从机模式与芯片通信,当传感器完成数据采样后,会拉高信号
      线EXT_REQ(熟悉手机内部应用的人都很清楚这种结构,一般也把这根信号叫做中断信号) 。
    c. 芯片在EXT_REQ的上升沿回复系统时钟,但并不唤醒内核,随后该信号触发DMA完成一次数据传送,
      用以开启SPI的时钟。
    d. 当SPI时钟开启后,由于发送缓冲中(TX_FIFO)预先填充了7个字节的数据,通信立即开始。
    e. 在SPI通信的过程中,由于接受缓冲不为空,RX_FIFO_DAVL(RX FIFO Data Available)信号为高,该
      信号持续触发DMA及时的将SPI接受缓冲中的数据搬运到指定的SRAM缓冲区内
    f. 当SPI通信结束后,帧结束信号FRM_EXCHANGE将触发 DMA将 SPI的时钟关闭,并在关闭时钟后,预先
       填充下一次通讯所需的7个字节的数据到SPI的发送缓冲中。由于SPI时钟已经关闭,FIFO仍然能操作,
       但是数据却要等到下一次时钟恢复时才能发送了。
    g. 当所有外设完成工作后,系统重新进入休眠模式。

    可以看到,整个过程中内核并未参与。如果不需要数据处理,芯片只是采集传感器信息,集中后,以固定
的频率(比如100Hz)发送给主控芯片,那么仍然不需要涉及到内核。如果需要简单的数据处理,那么内核
可以在必要的时候唤醒,快速完成功能后重新进入休眠。这种思想,就是我在另外一个帖子里面提到的脉冲
工作模式。





void dma_cfg(void)
{
    static uint32_t wSrc0 @0x20008004 = 0;
    static uint32_t wSrc1 @0x20008008 = 1;
    static uint32_t wOutputBuffer    @0x2000800C = {0xAC,0,1,2,3,4,5};
    static uint32_t wInputBuffer   @0x20008104 ;

    //!< init dma
    DMA_CHN_CFG(
      DMA_CHANNEL0,                                           //!< channel0                     
      DMA_CHN_TRIG_RISING_EDGE_SENSITIVE,

      //!Open SPI0 P_CLK
      DMA_TSF_CFG(
            DMA_TSF_MODE_MEMORY_TO_PERIPHRAL    |
            DMA_TSF_MANUAL_TRIGGER_NEXT         |
            DMA_TSF_DATA_BITS_32                ,
            1                                 ,
            &wSrc1                              ,
            &GSP_CMC.PCLKDIV.Value
      ),
    );      

   
    DMA_CHN_CFG(
      DMA_CHANNEL1,                                           //!< channel1         
      DMA_CHN_TRIG_RISING_EDGE_SENSITIVE      |
      DMA_CHN_BURST_TRANSFER                  |
      DMA_CHN_BURST_SIZE_1                  ,

      //! read spi data CMD(Ignored) + 6 Bytes
      DMA_TSF_CFG(
            DMA_TSF_MODE_PERIPHRAL_TO_MEMORY    |
            DMA_TSF_MANUAL_TRIGGER_NEXT         |
            DMA_TSF_DATA_BITS_32                ,
            7                                 ,
            &GSP_SPI0.DR.Value                  ,
            wInputBuffer
      ),
    );


    //!< init dma
    DMA_CHN_CFG(
      DMA_CHANNEL2,                                           //!< channel2                        
      DMA_CHN_TRIG_RISING_EDGE_SENSITIVE      ,

      //! disable SPI P_CLK
      DMA_TSF_CFG(
            DMA_TSF_MODE_MEMORY_TO_PERIPHRAL    |
            DMA_TSF_AUTO_TRIGGER_NEXT         |
            DMA_TSF_DATA_BITS_32                ,
            1                                 ,
            &wSrc0                              ,
            &GSP_CMC.PCLKDIV.Value
      ),

      //! fill spi fifo with CMD + 6 Bytes(Dummy write for spi read)
      DMA_TSF_CFG(
            DMA_TSF_MODE_MEMORY_TO_PERIPHRAL    |
            DMA_TSF_MANUAL_TRIGGER_NEXT         |
            DMA_TSF_DATA_BITS_32                ,
            7                                 ,
            wOutputBuffer                     ,
            &GSP_SPI0.DR.Value
      ),
    );
}

void spi_dma_test_init(void)
{
    ...

    // enable dma
    PM_AHB_CLK_ENABLE(AHBCLK_DMA);

    IO_CFG(
      {PA7, IO_WORKS_AS_APIO0,      IO_PULL_UP},
      {PA1, IO_WORKS_AS_SPI0_SCK,   IO_PULL_UP},
      {PA2, IO_WORKS_AS_SPI0_MISO,    IO_PULL_UP},
      {PA3, IO_WORKS_AS_SPI0_MOSI,    IO_PULL_UP},
      {PA4, IO_WORKS_AS_SPI0_CS,      IO_PULL_UP},
    );
   
    SPI_CFG(
      SPI0,
      SPI_MODE_MASTER             |
      SPI_MODE_FORMAT_SPI         |
      SPI_MODE_CLK_IDLE_LOW       |
      SPI_MODE_SAMP_SECOND_EDGE,
      SPI_MODE_DATASIZE_8,
      SPI_PCLK_DIV_1
    );
    SPI0.Open();                        //!< enable spi0
    PM_PCLK_SET(PCLK_SPI0,0);         //!< disable P_CLK for SPI manually
   
    //! fill spi fifo with CMD + 6 Bytes(Dummy write for spi read)
    SPI0.Write(0xAC);
    SPI0.Write(0x00);
    SPI0.Write(0x01);
    SPI0.Write(0x02);
    SPI0.Write(0x03);
    SPI0.Write(0x04);
    SPI0.Write(0x05);
   
    //! signal connection
    SIGNAL_CFG(
    /*----------------------------------------------------------------------------------------------*
   *    SIGNAL    Source Signal         Usage                   Digtal Filter                   *
   *----------------------------------------------------------------------------------------------*/

      /*! \note Use the raising edge of APIO0 to trigger DMA Channel0, the APIO0 is connected to
         *      PA7 in IO_CFG(). It is the trigger signal called EXT_REQ in the wave form.
         */
      { SIGNAL0,USE_SIGNAL_APIO0,       TO_TRIGGER_DMA0_CHN0,   ON_RAISING_EDGE               },

      /*! \note When there are any data available in SPI0 RX FIFO (signal gose high), general pulse
         *      to trigger DMA channel2 to fetch data from spi. Here EVERY_5_TIMES is the pulses
         *      prescaler, which means the pulse frequency is the 1/5 of the system clock.
         */
      { SIGNAL1,USE_SPI0_RX_FIFO_DAVL,TO_TRIGGER_DMA0_CHN1,   ON_HIGH_LEVEL | EVERY_5_TIMES   },

      /*! \note When SPI Frame complete, trigger the dma channel3 transfer
         */
      { SIGNAL2,USE_SPI0_FRM_EXCHANGED, TO_TRIGGER_DMA0_CHN2,                                 },
    );
   
    //! configure DMA
    dma_cfg();

    //! fall in sleep and NEVER wake up.
    PM_SLEEP(DEEP_SLEEP);
}


Robin_King 发表于 2013-11-6 18:10:30

先顶一下。。。。

catwill 发表于 2013-11-7 13:51:53

DMA_CHN_CFG(
      ......
      DMA_TSF_CFG(
                ......
      ),
);

那个拖尾的逗号是必须的吗?
如果不是,我觉得应该去掉。
“如果在其他由逗号分隔的列表(如枚举声明、单行多变量声明等)中也允许使用,那还说得过去,可惜事实并非如此。”

Gorgon_Meducer 发表于 2013-11-7 16:38:03

catwill 发表于 2013-11-7 13:51 static/image/common/back.gif
DMA_CHN_CFG(
      ......
      DMA_TSF_CFG(


这不是多余的……因为在链表模式下……允许有多个Transfer,也就是多个DMA_TSF_CFG,不过删除也可以的

Gorgon_Meducer 发表于 2013-11-7 17:11:40

更新了链式传输——使用单通道完成四次不同类型的传输,传输之间既有自动切换,也有手动触发切换
这里,需要手动触发的地方,可以是硬件触发,也可以是例子中的软件触发。

renjun_EMbest 发表于 2013-11-7 17:50:47

小白求指点:

1:看不懂下面的含义 Memory repeat 函数,后两个参数是神马意思?
   MREPEAT(TEST_COUNT, SOURCE_DATA, 0)
2:DMA_CHN_CFG 里面为什么包含DMA_TSF_CFG函数?分成两个不好?
3:UBOUND(chSource),是神马意思
4:DMA_IS_CHN_TSF_CPL名字有待考究 CPL complete
5:DMA_MANUAL_TRIGGER_NEXT, 建议去掉NEXT,多余
6:最后一个链表的例子有意思,想知道DMA_CHN_CFG的实现方式,可变宏?
7:CHANNEL_BLOCK0_ADDR, 啥意思?

laipi 发表于 2013-11-7 18:14:59

版主你好 yg?

sunliezhi 发表于 2013-11-7 18:56:58

还是不习惯太多的大写{:lol:}

canspider 发表于 2013-11-7 20:42:50

不明觉厉

eduhf_123 发表于 2013-11-7 21:27:50

顶个帖。

sbk100 发表于 2013-11-8 11:49:13

MREPEAT(TEST_COUNT, SOURCE_DATA, 0)是啥东东,函数么?怎么后面又没有分号呢?看着很蛋疼

STM32_Study 发表于 2013-11-8 12:04:16

{:cry:}说好的展开风格呢?

滴答滴答下雨啦 发表于 2013-11-8 12:15:58

帮顶……

Gorgon_Meducer 发表于 2013-11-8 22:22:20

STM32_Study 发表于 2013-11-8 12:04 static/image/common/back.gif
说好的展开风格呢?

DMA太复杂了,展开会死人的……真的……相信我……

Gorgon_Meducer 发表于 2013-11-8 22:22:59

sbk100 发表于 2013-11-8 11:49 static/image/common/back.gif
MREPEAT(TEST_COUNT, SOURCE_DATA, 0)是啥东东,函数么?怎么后面又没有分号呢?看着很蛋疼 ...

这个其实无关紧要……只是用来做数据填充的,真不是这个例子的一部分……

meirenai 发表于 2013-11-8 23:33:32

内部的宏不知道什么意思。
依楼主上一个模版来看,上面的几个例子,应该是主程序把。
说实话我还是比较喜欢一条一条的配置外设,这样封装的太厉害,有点摸不着北。

Gorgon_Meducer 发表于 2013-11-9 09:37:47

meirenai 发表于 2013-11-8 23:33 static/image/common/back.gif
内部的宏不知道什么意思。
依楼主上一个模版来看,上面的几个例子,应该是主程序把。
说实话我还是比较喜欢 ...

作为一种讨论,你是不是平时不太喜欢使用黑盒子呢?

enovo2468 发表于 2013-11-9 14:54:05

学习一下{:biggrin:}{:smile:}

eduhf_123 发表于 2013-11-12 21:26:54

忍不住吐个槽

现在的经济环境真的已经差到这种程度了么?还是说现在的人心已经浮躁到没人愿意搞技术的程度了?

傻孩子才刚发出来的技术帖,竟然3天没有人回复、竟然6天里只有不到20个回复,不可思议。

Gorgon_Meducer 发表于 2013-11-13 09:54:54

eduhf_123 发表于 2013-11-12 21:26 static/image/common/back.gif
忍不住吐个槽

现在的经济环境真的已经差到这种程度了么?还是说现在的人心已经浮躁到没人愿意搞技术的程度 ...

只能说用DMA的环境和场合不多,大家也就凑合着搬运版运数据而已。过几天我放出来中断系统的接口,
一定砖头多的能盖房子了。

jm2011 发表于 2013-11-13 11:20:25

这个结构体定义的有点太偏底层了,可能和DMA的设计是一一对应的(看到你的定义,我就想起了DMA的实现);
建议封装的靠上层一点(个人感觉,就是软件使用者不太需要了解太多的底层);

另外,增加异步回调机制是不是会好点;这样在发出DMA后,不需要那个WHILE了;

可以简化单次和链表,统一一种模式(越简单越好),功能都是可以实现的;

Gorgon_Meducer 发表于 2013-11-13 12:10:35

本帖最后由 Gorgon_Meducer 于 2013-11-13 12:13 编辑

jm2011 发表于 2013-11-13 11:20 static/image/common/back.gif
这个结构体定义的有点太偏底层了,可能和DMA的设计是一一对应的(看到你的定义,我就想起了DMA的实现);
建 ...

其实这个已经比较高层了,更底层的部分已经屏蔽了。回调机制其实是有的,是基于硬件中断的,
由于中断系统的架构还在改进,所以暂时只能使用查询来展示接口。

另外,你仔细看,单次和链表实际上是一样的啊,DMA_TSF_CFG() 块只有一个,就是单次的,
有多个就是链表。

关于你说的希望更高层一点,能否给出一点例子呢?

jm2011 发表于 2013-11-13 13:32:29

恩,个人考虑,可以给当前的通道单独提炼一个cfg的函数,来设置一些公共的属性;
像参数DMA_MANUAL_TRIGGER_NEXT, DMA_MODE_PERIPHRAL_TO_MEMORY等用户不用知道这些,这些在内部自己处理;
参数DMA_DATA_BITS_32也不用每次都设置,直接设置当前channel一次就可以;

另外就是关于LIST的最好再细化一下,可以细化为:Element 和 List结构;
如果是当前DMA就一次那么就只有一个Element,多个块就有多个Element;
至于上面的一些DMA的参数,放在另外的结构体里保存;

这样比较符合程序员的思维,一人之言,如有不周,敬请谅解:)

Gorgon_Meducer 发表于 2013-11-13 17:15:24

本帖最后由 Gorgon_Meducer 于 2013-11-13 17:39 编辑

jm2011 发表于 2013-11-13 13:32 static/image/common/back.gif
恩,个人考虑,可以给当前的通道单独提炼一个cfg的函数,来设置一些公共的属性;
像参数DMA_MANUAL_TRIGGER ...


恩,个人考虑,可以给当前的通道单独提炼一个cfg的函数,来设置一些公共的属性;

答:如果单独提炼一个CFG函数,会破坏一致性,而且实际上,对一个通道来说,其实没有公共属性。


像参数DMA_MANUAL_TRIGGER_NEXT, DMA_MODE_PERIPHRAL_TO_MEMORY等用户不用知道这些,这些在内部自己处理;

DMA_MANUAL_TRIGGER_NEXT, DMA_MODE_PERIPHRAL_TO_MEMORY 这些是用户必须指定的信息,对驱动来说,这些信息
是无法确定的,必须要用户指定,其实类似 DMA_MODE_PERIPHRAL_TO_MEMORY 这样的宏,已经是进行封装以后的结果了,
它规定了数据传输时候源地址和目标地址的指针处理方式(是否自动加,加多少之类的),对于这种已经可以确定的逻辑,我们
是可以封装成模板的(DMA_MODE_PERIPHRAL_TO_MEMORY就是模板),但是对于只有用户知道的信息,而驱动无法确定的
信息,我们是无法进行信息封装的。


参数DMA_DATA_BITS_32也不用每次都设置,直接设置当前channel一次就可以;

DMA_DATA_BITS_32 不是公共信息,因为每次传输的数据类型都不同,如果非要实现你说的这种功能,恐怕只有使用C++这种
天然支持类的语言,通过基类的方式来实现了。你说的很有道理,但目前用的是C语言,要实现这个功能,同事又不增加太多代码
的复杂度,难度有点大,不过既然需求提出来了,我会认真考虑实现方式的。


另外就是关于LIST的最好再细化一下,可以细化为:Element 和 List结构;
如果是当前DMA就一次那么就只有一个Element,多个块就有多个Element;
至于上面的一些DMA的参数,放在另外的结构体里保存;

这个是可以修改的,目前实际上DMA_TSF_CFG就是一个Element,但即便这么做了未必讨好,因为很多嵌入式开发人员并不熟悉
这种链表结构,对他们来说Transfer也许更直接一点,这一点我再仔细考虑下。


这样比较符合程序员的思维,一人之言,如有不周,敬请谅解:)

非常感谢你的反馈,我希望针对我的回复,我们能有更多的讨论。请看看新的Chain List风格如何?




我们现在尝试减少参数的数量,并把每一次传输触发下一次传输的方式的设定改为默认是自动的,可以通过特殊指定的方式将其
改为手动。过一会儿将更新新的接口。

NR小高 发表于 2013-11-13 17:29:00

我觉得一个东西最难的地方,就是用自己的表达方式来完全描述它,最起码,这点,我要向楼主学习,DMA既然高级,难学,但更应该去掌握,顶楼主!

zhexuejia 发表于 2013-11-15 14:55:01

Robin_King 发表于 2013-11-6 18:10 static/image/common/back.gif
先顶一下。。。。

这位的头像要不要这么销魂啊

xjtyOnly51 发表于 2013-11-29 11:49:04

mark{:smile:}

wazhiyi 发表于 2013-12-18 10:23:34

正在mark中。。。。。

wazhiyi 发表于 2013-12-18 10:24:05

楼主能否给点完整的代码,我等入门的人可以先在系统上跑起来

Gorgon_Meducer 发表于 2013-12-18 10:32:19

wazhiyi 发表于 2013-12-18 10:24
楼主能否给点完整的代码,我等入门的人可以先在系统上跑起来

这目前只是风格调查,还没有办法针对其它家芯片做出驱动。以后我们的开源团队会尝试补对其他它家的芯片支持。
另外,对目前的DMA接口风格,有什么看法么?随便说说都没关系。

wazhiyi 发表于 2013-12-18 10:51:38

Gorgon_Meducer 发表于 2013-12-18 10:32
这目前只是风格调查,还没有办法针对其它家芯片做出驱动。以后我们的开源团队会尝试补对其他它家的芯片支 ...

我想现在我的STM32系统上跑起来在看看有没有不妥的地方,光看代码,好抽象,可能太菜了

Gorgon_Meducer 发表于 2013-12-18 12:15:25

本帖最后由 Gorgon_Meducer 于 2013-12-18 16:44 编辑

wazhiyi 发表于 2013-12-18 10:51
我想现在我的STM32系统上跑起来在看看有没有不妥的地方,光看代码,好抽象,可能太菜了 ...

目前还不支持STM32,主要看DMA的特性,不一定能封装出相同的功能,可能更强,也可能更弱。这里只是从
接口的角度来征求风格以及使用便利性上的意见。

Gorgon_Meducer 发表于 2013-12-31 11:17:58

在二楼更新使用DMA配合信号网络系统通过梦游模式实现传感器数据读取的例子。

brentcao 发表于 2014-7-21 22:23:59

个人喜欢把左括号另起一行,呵呵,各人风格不一样的啦

miight 发表于 2015-5-5 22:37:37

自己太菜了,有点看不懂啊!
页: [1]
查看完整版本: [交流][拍砖]新版驱动接口风格调查(二):DMA