查看: 1431|回复: 1

[分享] 【LPC824lite】之USART_DMA单通道

[复制链接]
  • TA的每日心情

    2024-2-5 12:06
  • 签到天数: 627 天

    [LV.9]以坛为家II

    94

    主题

    1628

    帖子

    2

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    4429

    热心会员

    最后登录
    2024-2-5
    发表于 2020-10-10 16:21:32 | 显示全部楼层 |阅读模式
    本帖最后由 胤幻1988 于 2020-10-10 16:26 编辑

    今天弄了下LPC824的USART_DMA ,官方给的例子直接就AB乒乓链接操作了。
    乍一看,还是有的脑门疼。我这里先弄个简单的,就1路,不能循环。
    定义了userkey 中断作为DMA的触发信号。代码在上次的代码上修改,其他没变
    添加了几个函数文件。
    ////////////////////////////////////////////////
    key.c文件:
    #include "key.h"
    void PINT_Init_Key_User(void)
    {
            LPC_GPIO_PORT->DIRCLR0 = 1 << KEY_USER;         // 配置USER_KEY对应的引脚为输入
            LPC_SYSCON->PINTSEL[PINTSEL0] = KEY_USER; // USER_KEY对应对应到引脚中断0(PINTSEL0)
            LPC_PIN_INT->ISEL = 0 << PINTSEL0;                                 // 配置引脚中断0(PINTSEL0)为边沿触发
            LPC_PIN_INT->IENR = 1 << PINTSEL0;                                 // 配置引脚中断0(PINTSEL0)是上升沿触发
            LPC_PIN_INT->IENF = 0 << PINTSEL0;                                 // 配置引脚中断0(PINTSEL0)不是下降沿触发
            LPC_PIN_INT->IST = 0xFF;                                                                         // 清除所有可能的引脚中断标志
            NVIC_EnableIRQ(PININT0_IRQn);                                                 // 使能引脚中断
    }

    ////////////////////////////////////////////////
    key.h文件:

    #ifndef __KEY_H_
    #define __KEY_H_

    #include "LPC8xx.h"
    #include "lpc8xx_swm.h"
    #include "lpc8xx_syscon.h"
    #include "utilities.h"

    #define PINTSEL0 0                 // 定义引脚中断0的编号
    #define KEY_USER P0_1 // 定义按键USER_KEY的引脚

    void PINT_Init_Key_User(void);

    #endif

    ////////////////////////////////////////////////
    dma_usart0.C文件:

    #include "dma_usart0.h"

    // Instantiate the channel descriptor table, which must be 512-byte aligned (see lpc8xx_dma.h)
    ALIGN(512) DMA_CHDESC_T Chan_Desc_Table[NUM_DMA_CHANNELS];//NUM_DMA_CHANNELS=18 共18种通道源
    // Instantiate one reload descriptor. All descriptors must be 16-byte aligned (see lpc8xx_dma.h)
    ALIGN(16) DMA_RELOADDESC_T Reload_Descriptor_B;

    uint8_t DMA_IntA_Flag; // 中断A软件标志


    void DMA_USART0_Send(uint8_t *buf,uint32_t length)
    {
            uint32_t ch_cfg_val,xfercount,xfercfg;
            
            // Reset the DMA, and enable clocks to peripherals (see lpc8xx_syscon.h)
    //  LPC_SYSCON->PRESETCTRL &= (DMA_RST_N);//复位 DMA
    //  LPC_SYSCON->PRESETCTRL |= ~(DMA_RST_N);
      LPC_SYSCON->SYSAHBCLKCTRL |= (DMA | UART0);//使能模块时钟
            
            LPC_DMA->CTRL=0;//使能DMA,然后再配置
            
            LPC_DMA->SRAMBASE = (uint32_t)(&Chan_Desc_Table);//DMA控制器所有描述链头的地址
            
            xfercount=length-1;//数据块传输长度
      // Setup the channel's CFG register
      //
      // CFG1
      // PERIPREQEN   = 1  The peripheral DMA request is enabled
      // HWTRIGEN     = 0  Hardware triggering is disabled
      // TRIGPOL      = 0  Active low or falling edge hardware trigger (not used)
      // TRIGTYPE     = 0  Edge sensitive hardware trigger (not used)
      // TRIGBURST    = 0  Single transfer will be launched by each trigger
      // BURSTPOWER   = 0  Unused
      // SRCBURSTWRAP = 0  Unused
      // DSTBURSTWRAP = 0  Unused
      // CHPRIORITY   = 0  Highest priority
      ch_cfg_val  = 1<<DMA_CFG_PERIPHREQEN  |  //外设请求
                    1<<DMA_CFG_HWTRIGEN     |  //硬件触发
                    0<<DMA_CFG_TRIGPOL      |  //下降沿触发
                    0<<DMA_CFG_TRIGTYPE     |  //边沿触发
                    0<<DMA_CFG_TRIGBURST    |
                    0<<DMA_CFG_BURSTPOWER   |
                    0<<DMA_CFG_SRCBURSTWRAP |
                    0<<DMA_CFG_DSTBURSTWRAP |
                    0<<DMA_CFG_CHPRIORITY;
                                                                   
      LPC_DMA->CHANNEL[CH_USART0_TX].CFG = ch_cfg_val;//配置写入寄存器

      // Build the initial channel XFERCFG for the A sequence
      //
      // XFERCFG1
      // CFGVALID  = 1  Current channel descriptor is considered valid
      // RELOAD    = 1  Reload the control structure (the contents of this register) when the descriptor is exhausted
      // SWTRIG    = 0  Don't trigger now
      // CLRTRIG   = 0  The trigger is not cleared when this descriptor is exhausted
      // SETINTA   = 1  Set the INTA flag when this descriptor is exhausted
      // SETINTB   = 0  Don't use the INTB flag
      // WIDTH     = 0  Eight-bit transfers
      // SRCINC    = 1  Source address is incremented by 1 x WIDTH (source is buffer in memory)
      // DSTINC    = 0  Destination address is not incremented (destination is TXDAT register of UART)
      // XFERCOUNT =    Length of string (less the CR, less the LF, less the NUL terminator) minus 1

      xfercfg   = 0<<DMA_XFERCFG_CFGVALID |        //暂时设置为无效
                  0<<DMA_XFERCFG_RELOAD   | //没有下一个描述符
                  0<<DMA_XFERCFG_SWTRIG   | //没有软件触发
                  1<<DMA_XFERCFG_CLRTRIG  | //传输结束时清除触发标志
                  1<<DMA_XFERCFG_SETINTA  | //传输结束时设置INTA中断
                  0<<DMA_XFERCFG_SETINTB  |
                  0<<DMA_XFERCFG_WIDTH    | //数据宽度为8位
                  1<<DMA_XFERCFG_SRCINC   | //每次传输后源地址递增
                  0<<DMA_XFERCFG_DSTINC   | //每次传输后目标地址不递增
                  xfercount<<DMA_XFERCFG_XFERCOUNT;// 传输长度


      LPC_DMA->CHANNEL[CH_USART0_TX].XFERCFG = xfercfg;  //配置写入寄存器                                          // Initial XFERCFG
      // 填写通道描述符链头 指定存放的位置
            Chan_Desc_Table[CH_USART0_TX].source   = (uint32_t)(&buf[xfercount]);          // Initial source data end address (start address + (xfercount*srcinc))
      Chan_Desc_Table[CH_USART0_TX].dest     = (uint32_t)(&LPC_USART0->TXDAT);                       // Initial destination data end address
      Chan_Desc_Table[CH_USART0_TX].next     = (uint32_t)0L;                     // Initial next points to Reload Descriptor B


      // 使能对应通道的中断
      LPC_DMA->INTENSET0 =  1<<CH_USART0_TX;
      //使能对应的DMA通道
      LPC_DMA->ENABLESET0 = 1<<CH_USART0_TX;
            // 使能整个DMA控制器
      LPC_DMA->CTRL = 1;
            //设置传输描述符为有效
      LPC_DMA->SETVALID0 = 1<<CH_USART0_TX;
            
            //配置DMA触发源为“引脚中断0”
            LPC_DMATRIGMUX->DMA_ITRIG_INMUX1 = 0x05;
            //使能中断
            NVIC_EnableIRQ(DMA_IRQn);

    }
    ////////////////////////////////////////////////
    dma_usart0.h文件:


    #ifndef __DMA_USART0_H_
    #define __DMA_USART0_H_

    #include "lpc_types.h"
    #include "LPC8xx.h"
    #include "lpc8xx_dma.h"
    #include "lpc8xx_syscon.h"
    #include "utilities.h"

    //P93
    #define CH_USART0_RX 0 //USART0 对应DMA通道
    #define CH_USART0_TX 1 //USART0 对应DMA通道

    extern uint8_t DMA_IntA_Flag; // 中断A软件标志

    void DMA_USART0_Send(uint8_t *buf,uint32_t length);

    #endif

    ////////////////////////////////////////////////
    在中断函数main.isr里面添加KEY中断和DMA中断
    void DMA_IRQHandler(void)
    {
            //清除中断标志,同时对软件标志A计数
            if (LPC_DMA->INTA0 & (1 << CH_USART0_TX))
            {
                    LPC_DMA->INTA0 = 1 << CH_USART0_TX;
                    DMA_IntA_Flag++;
            }
            //清除可能的错误中断
            if (LPC_DMA->ERRINT0 & (1 << CH_USART0_TX))
            {
                    LPC_DMA->ERRINT0 = 1 << CH_USART0_TX;
            }
            
            //printf("IN the dma interrupt!\r\n");
    }


    void PININT0_IRQHandler(void)
    {
            if (LPC_PIN_INT->RISE & (1<<PINTSEL0))
                    LPC_PIN_INT->RISE = 1<<PINTSEL0; // 清除上升沿中断标志
            if (LPC_PIN_INT->FALL & (1<<PINTSEL0))
                    LPC_PIN_INT->FALL = 1<<PINTSEL0; // 清除下降沿中断标志
            
            //printf("IN the key interrupt!\r\n");
    }

    ////////////////////////////////////////////////
    在main函数里面修改:
    const unsigned char Hello[] = "Hello DMA World!\r\n"; // 待发送的数据串
    const unsigned char Hello1[] = "Hello1 DMA World!\r\n"; // 待发送的数据串

    int main(void)
    {        
            uint16_t i=0,length=0;
            uint8_t tmpbuf[100]={0};
            
            GPIOInit();
            USART0_Init();
            LED_Init();
            PINT_Init_Key_User();
            
            DMA_IntA_Flag = 0; // 清除DMA中断标记
            DMA_USART0_Send((uint8_t *)Hello, sizeof(Hello)-1); // 初始化DMA控制器
            do{
                            //printf("wait answer!\r\n");
                            //delay_ms(20);
            }
            while(DMA_IntA_Flag == 0);
            
            DMA_IntA_Flag = 0; // 清除DMA中断标记
            DMA_USART0_Send((uint8_t *)Hello1, sizeof(Hello1)-1);
            
            do{
                            //printf("wait answer!\r\n");
                            //delay_ms(20);
            }
            while(DMA_IntA_Flag == 0);
            
           while(1)
            {
                    if(DMA_IntA_Flag>0)
                    {
                            i++;
                            DMA_IntA_Flag=0;
                            length=sprintf(tmpbuf,"the key enter %d times!\r\n",i);
                            DMA_USART0_Send((uint8_t *)tmpbuf, length-1);

                    }
         }
    }

    ////////////////////////////////////////////////
    编译,下载
    按第1按键,串口打印出:Hello DMA World!
    按第2按键,串口打印出:Hello DMA World!
    按第3按键,串口打印出:the key enter 1 times!
    按第4按键,串口打印出:the key enter 2 times!
    按第5按键,串口打印出:the key enter 3 times!
    ...
    222.png
    整理了一边,现在看官方例子,果然好懂了。OVER!






    哎...今天够累的,签到来了~
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2024-4-10 22:38
  • 签到天数: 1335 天

    [LV.10]以坛为家III

    88

    主题

    4292

    帖子

    12

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    9049
    最后登录
    2024-4-13
    发表于 2020-10-11 17:13:30 | 显示全部楼层
    我倒是觉得LPC官方的示例帮用户考虑的太多了
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

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

    本版积分规则

    关闭

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

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

    GMT+8, 2024-4-20 12:12 , Processed in 0.115291 second(s), 20 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

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