[方案相关]

华大MCU之 HC32F460 的 DMA 串口发送

[复制链接]
5350|8
手机看帖
扫描二维码
随时随地手机跟帖
pzljun|  楼主 | 2021-4-13 16:51 | 显示全部楼层 |阅读模式
本帖最后由 pzljun 于 2021-4-14 02:02 编辑

#技术资源# #申请原创# 此码来自官方例程,clk_sync_dma_tx.
源同步初使化发送错误,故改成异步发送。经修改,已能实现功能。其官方例程写了很多误导人的东西
微信图片编辑_20210413164602.jpg 2770260755a8e31aa3.png 3255260755adbb58c5.png 105660755b6914661.png

/*******************************************************************************
* Copyright (C) 2016, Huada Semiconductor Co., Ltd. All rights reserved.
*
* This software is owned and published by:
* Huada Semiconductor Co., Ltd. ("HDSC").
*
* BY DOWNLOADING, INSTALLING OR USING THIS SOFTWARE, YOU AGREE TO BE BOUND
* BY ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT.
*
* This software contains source code for use with HDSC
* components. This software is licensed by HDSC to be adapted only
* for use in systems utilizing HDSC components. HDSC shall not be
* responsible for misuse or illegal use of this software for devices not
* supported herein. HDSC is providing this software "AS IS" and will
* not be responsible for issues arising from incorrect user implementation
* of the software.
*
* Disclaimer:
* HDSC MAKES NO WARRANTY, EXPRESS OR IMPLIED, ARISING BY LAW OR OTHERWISE,
* REGARDING THE SOFTWARE (INCLUDING ANY ACCOMPANYING WRITTEN MATERIALS),
* ITS PERFORMANCE OR SUITABILITY FOR YOUR INTENDED USE, INCLUDING,
* WITHOUT LIMITATION, THE IMPLIED WARRANTY OF MERCHANTABILITY, THE IMPLIED
* WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE OR USE, AND THE IMPLIED
* WARRANTY OF NONINFRINGEMENT.
* HDSC SHALL HAVE NO LIABILITY (WHETHER IN CONTRACT, WARRANTY, TORT,
* NEGLIGENCE OR OTHERWISE) FOR ANY DAMAGES WHATSOEVER (INCLUDING, WITHOUT
* LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION,
* LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) ARISING FROM USE OR
* INABILITY TO USE THE SOFTWARE, INCLUDING, WITHOUT LIMITATION, ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOSS OF DATA,
* SAVINGS OR PROFITS,
* EVEN IF Disclaimer HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* YOU ASSUME ALL RESPONSIBILITIES FOR SELECTION OF THE SOFTWARE TO ACHIEVE YOUR
* INTENDED RESULTS, AND FOR THE INSTALLATION OF, USE OF, AND RESULTS OBTAINED
* FROM, THE SOFTWARE.
*
* This software may be replicated in part or whole for the licensed use,
* with the restriction that this Disclaimer and Copyright notice must be
* included with each copy of this software, whether used in part or whole,
* at all times.
*/
/******************************************************************************/
/** \file main.c
**
** \brief This sample demonstrates clock sync data receive and transfer by DMA.
**
**   - 2018-11-27  1.0  Hongjh First version for Device Driver Library of USART
**
******************************************************************************/

/*******************************************************************************
* Include files
******************************************************************************/
#include "hc32_ddl.h"

/*******************************************************************************
* Local type definitions ('typedef')
******************************************************************************/
/**
*******************************************************************************
** \brief buffer handle
**
******************************************************************************/
typedef struct stc_buf_handle
{
    uint8_t u8Size;
    uint8_t au8Buf[200];
} stc_buf_handle_t;

/*******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/
/* DMAC */
#define DMA_UNIT                        (M4_DMA1)
#define DMA_CH                          (DmaCh0)
#define DMA_TRG_SEL                     (EVT_USART3_TI)        //此处修为3,根据硬件来的

/* USART channel definition */
#define USART_CH                        (M4_USART3)                //此处修为3,根据硬件来的

/* USART baudrate definition */
#define USART_BAUDRATE                  (256000ul)        //此处修为25600,串口助手没300000

/* USART TX Port/Pin definition */
#define USART_TX_PORT                   (PortH)
#define USART_TX_PIN                    (Pin02)                                        //此处修为H2,根据硬件来的
#define USART_TX_FUNC                   (Func_Usart3_Tx)

/* USART CK Port/Pin definition */
#define USART_CK_PORT                   (PortD)
#define USART_CK_PIN                    (Pin07)                        
#define USART_CK_FUNC                   (Func_Usart_Ck)

/* DMA block transfer complete interrupt */
#define DMA_BTC_INT_NUM                 (INT_DMA1_TC0)        //此处要修改
#define DMA_BTC_INT_IRQn                (Int002_IRQn)

/* LED(D26: green color) Port/Pin definition */
#define LED_PORT                        (PortA)                                
#define LED_PIN                         (Pin07)

/* LED operation */
#define LED_ON()                        (PORT_SetBits(LED_PORT, LED_PIN))
#define LED_OFF()                       (PORT_ResetBits(LED_PORT, LED_PIN))

/* User key:SW2 Port/Pin definition */
#define KEY_PORT                        (PortD)
#define KEY_PIN                         (Pin03)

/*******************************************************************************
* Global variable definitions (declared in header file with 'extern')
******************************************************************************/

/*******************************************************************************
* Local function prototypes ('static')
******************************************************************************/
static void ClkInit(void);
static void LedInit(void);
static void DmaInit(void);
static void DmaBtcIrqCallback(void);

/*******************************************************************************
* Local variable definitions ('static')
******************************************************************************/
static stc_buf_handle_t m_stcTxBufHanlde;

/*******************************************************************************
* Function implementation - global ('extern') and local ('static')
******************************************************************************/
/**
*******************************************************************************
** \brief Initialize Clock.
**
** \param [in] None
**
** \retval None
**
******************************************************************************/
static void ClkInit(void)
{
    stc_clk_xtal_cfg_t   stcXtalCfg;
    stc_clk_mpll_cfg_t   stcMpllCfg;
    en_clk_sys_source_t  enSysClkSrc;
    stc_clk_sysclk_cfg_t stcSysClkCfg;

    MEM_ZERO_STRUCT(enSysClkSrc);
    MEM_ZERO_STRUCT(stcSysClkCfg);
    MEM_ZERO_STRUCT(stcXtalCfg);
    MEM_ZERO_STRUCT(stcMpllCfg);

    /* Set bus clk div. */
    stcSysClkCfg.enHclkDiv  = ClkSysclkDiv1;
    stcSysClkCfg.enExclkDiv = ClkSysclkDiv2;
    stcSysClkCfg.enPclk0Div = ClkSysclkDiv1;
    stcSysClkCfg.enPclk1Div = ClkSysclkDiv2;
    stcSysClkCfg.enPclk2Div = ClkSysclkDiv4;
    stcSysClkCfg.enPclk3Div = ClkSysclkDiv4;
    stcSysClkCfg.enPclk4Div = ClkSysclkDiv2;
    CLK_SysClkConfig(&stcSysClkCfg);

    /* Switch system clock source to MPLL. */
    /* Use Xtal as MPLL source. */
    stcXtalCfg.enMode = ClkXtalModeOsc;
    stcXtalCfg.enDrv = ClkXtalLowDrv;
    stcXtalCfg.enFastStartup = Enable;
    CLK_XtalConfig(&stcXtalCfg);
    CLK_XtalCmd(Enable);

    /* MPLL config. */
    stcMpllCfg.pllmDiv = 1u; /* XTAL 8M / 1 */
    stcMpllCfg.plln = 50u;   /* 8M*50 = 400M */
    stcMpllCfg.PllpDiv = 4u; /* MLLP = 100M */
    stcMpllCfg.PllqDiv = 4u; /* MLLQ = 100M */
    stcMpllCfg.PllrDiv = 4u; /* MLLR = 100M */
    CLK_SetPllSource(ClkPllSrcXTAL);
    CLK_MpllConfig(&stcMpllCfg);

    /* flash read wait cycle setting */
    EFM_Unlock();
    EFM_SetLatency(EFM_LATENCY_4);
    EFM_Lock();

    /* Enable MPLL. */
    CLK_MpllCmd(Enable);

    /* Wait MPLL ready. */
    while (Set != CLK_GetFlagStatus(ClkFlagMPLLRdy))
    {
    }

    /* Switch system clock source to MPLL. */
    CLK_SetSysClkSource(CLKSysSrcMPLL);
}

/**
*******************************************************************************
** \brief Initialize LED.
**
** \param [in] None
**
** \retval None
**
******************************************************************************/
static void LedInit(void)
{
    stc_port_init_t stcPortInit;

    LED_OFF();

    /* LED Port/Pin initialization */
    MEM_ZERO_STRUCT(stcPortInit);
    stcPortInit.enPinMode = Pin_Mode_Out;
    stcPortInit.enExInt = Enable;
    stcPortInit.enPullUp = Enable;
    PORT_Init(LED_PORT, LED_PIN, &stcPortInit);
}

/**
*******************************************************************************
** \brief Initialize DMA.
**
** \param [in] None
**
** \retval None
**
******************************************************************************/
static void DmaInit(void)
{
    stc_dma_config_t stcDmaInit;
    stc_irq_regi_conf_t stcIrqRegiCfg;

    /* Enable peripheral clock */
    PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_DMA1 | PWC_FCG0_PERIPH_DMA2,Enable);

    /* Enable DMA. */
    DMA_Cmd(DMA_UNIT,Enable);

    /* Initialize DMA. */
    MEM_ZERO_STRUCT(stcDmaInit);
    stcDmaInit.u16BlockSize = 1u; /* 1 block */
    stcDmaInit.u16TransferCnt = 10;//(uint16_t)m_stcTxBufHanlde.u8Size;/* Transfer count */
                                                                                                                                                /*此为修改语句,一次就发10个*/
    stcDmaInit.u32SrcAddr = (uint32_t)(m_stcTxBufHanlde.au8Buf);  /* Set source address. */
    stcDmaInit.u32DesAddr = (uint32_t)(&USART_CH->DR);   /* Set destination address. */
    stcDmaInit.stcDmaChCfg.enSrcInc = AddressIncrease;   /* Set source address mode. */
    stcDmaInit.stcDmaChCfg.enDesInc = AddressFix;        /* Set destination address mode. */
    stcDmaInit.stcDmaChCfg.enIntEn = Enable;             /* Enable interrupt. */
    stcDmaInit.stcDmaChCfg.enTrnWidth = Dma8Bit;         /* Set data width 8bit. */
    DMA_InitChannel(DMA_UNIT, DMA_CH, &stcDmaInit);

    /* Enable the specified DMA channel. */
    DMA_ChannelCmd(DMA_UNIT, DMA_CH, Enable);

    /* Clear DMA flag. */
    DMA_ClearIrqFlag(DMA_UNIT, DMA_CH, TrnCpltIrq);

    /* Enable peripheral circuit trigger function. */
    PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS,Enable);

    /* Set DMA trigger source. */
    DMA_SetTriggerSrc(DMA_UNIT, DMA_CH, DMA_TRG_SEL);

    /* Set DMA block transfer complete IRQ */
    stcIrqRegiCfg.enIRQn = DMA_BTC_INT_IRQn;
    stcIrqRegiCfg.pfnCallback = &DmaBtcIrqCallback;
    stcIrqRegiCfg.enIntSrc = DMA_BTC_INT_NUM;
    enIrqRegistration(&stcIrqRegiCfg);
    NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
    NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
    NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
}

/**
*******************************************************************************
** \brief DMA block transfer complete irq callback function.
**
** \param [in] None
**
** \retval None
**
******************************************************************************/
volatile const uint8_t BT1[10]={0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9};
volatile const uint8_t BT2[10]={0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9};
volatile const uint8_t BT3[10]={0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9};
volatile  uint8_t **;
static void DmaBtcIrqCallback(void)
{
    DMA_ClearIrqFlag(DMA_UNIT, DMA_CH, TrnCpltIrq);                        //此处要修改
                ** = 0;                                /*此为增加语句*/
}
void DmaTest(uint8_t ch)
{        uint8_t i;
        while(1)
        {        if(**==0)break;

        };                        //只有标志位改成0才会写下一条
        if(**==0)
        {        //DMA发送会自动使能清0  DMA_ChannelCmd(DMA_UNIT, DMA_CH, Disable);
                ** = 1;
                DMA_SetSrcAddress(DMA_UNIT, DMA_CH,(uint32_t)(m_stcTxBufHanlde.au8Buf));
                DMA_SetTransferCnt(DMA_UNIT, DMA_CH,10);
        //        DMA_ChannelCmd(DMA_UNIT, DMA_CH, Enable);
                        if(ch==0)
                        {        for(i=0;i<10;i++){m_stcTxBufHanlde.au8Buf = BT1;}
                        }
                        if(ch==1)
                        {        for(i=0;i<10;i++){m_stcTxBufHanlde.au8Buf = BT2;}
                        }
                        if(ch==2)
                        {        for(i=0;i<10;i++){m_stcTxBufHanlde.au8Buf = BT3;}
                        }
        //        DMA_SetSrcAddress(DMA_UNIT, DMA_CH,(uint32_t)(m_stcTxBufHanlde.au8Buf));
        //        DMA_SetTransferCnt(DMA_UNIT, DMA_CH,10);
                DMA_ChannelCmd(DMA_UNIT, DMA_CH, Enable);
                        if(ch==0)        USART_SendData(M4_USART3,BT1[0]);                                                        //触发发送2
                        if(ch==1)        USART_SendData(M4_USART3,BT2[0]);                                                        //触发发送3
                        if(ch==2)        USART_SendData(M4_USART3,BT3[0]);                                                        //触发发送1,不写不会发送
        }
}
/**
*******************************************************************************
** \brief  Main function of project
**
** \param  None
**
** \retval int32_t return value, if needed
**
******************************************************************************/
int32_t main(void)
{
    uint8_t i;
    en_result_t enRet = Ok;
    uint32_t u32Fcg1Periph = PWC_FCG1_PERIPH_USART1 | PWC_FCG1_PERIPH_USART2 | \
                             PWC_FCG1_PERIPH_USART3 | PWC_FCG1_PERIPH_USART4;
/*   const stc_usart_clksync_init_t stcInitCfg = {
        UsartIntClkCkOutput,
        UsartClkDiv_1,
        UsartDataLsbFirst,
        UsartRtsEnable,
    };                原程序不能用,否则串口输出值不正确
*/  
  const stc_usart_uart_init_t stcInitCfg = {
        UsartIntClkCkNoOutput,
        UsartClkDiv_1,
        UsartDataBits8,
        UsartDataLsbFirst,
        UsartOneStopBit,
        UsartParityNone,
        UsartSamleBit8,
        UsartStartBitFallEdge,
        UsartRtsEnable,
    };

    enRet = USART_UART_Init(USART_CH, &stcInitCfg);

    /* Initialize buffer */
    m_stcTxBufHanlde.u8Size = (uint8_t)sizeof(m_stcTxBufHanlde.au8Buf);
    for (i = 0u; i < m_stcTxBufHanlde.u8Size; i++)
    {
        m_stcTxBufHanlde.au8Buf = i;
    }

    /* Initialize Clock */
    ClkInit();

    /* Initialize LED */
    LedInit();

    /* Initialize DMA */
    DmaInit();

    /* Enable peripheral clock */
    PWC_Fcg1PeriphClockCmd(u32Fcg1Periph, Enable);

    /* Initialize USART IO */
    PORT_SetFunc(USART_CK_PORT, USART_CK_PIN, USART_CK_FUNC, Disable);
    PORT_SetFunc(USART_TX_PORT, USART_TX_PIN, USART_TX_FUNC, Disable);

    /* Initialize Clock sync */
/*原程序不能用*///  enRet = USART_CLKSYNC_Init(USART_CH, &stcInitCfg);
    if (enRet != Ok)
    {
        while (1)
        {
        }
    }

    /* Set baudrate */
    enRet = USART_SetBaudrate(USART_CH, USART_BAUDRATE);
    if (enRet != Ok)
    {
        while (1)
        {
        }
    }

    /* User key : SW2 */
    while (Reset != PORT_GetBit(KEY_PORT, KEY_PIN))
    {
    }

    /*Enable TX interupt function*/
    USART_FuncCmd(USART_CH, UsartTxAndTxEmptyInt, Enable);

    while (1)
    {
        if (Set == DMA_GetIrqFlag(DMA_UNIT, DMA_CH, TrnCpltIrq))
        {
            LED_ON();  /* Send completely */
        }
                        DmaTest(0);
                        DmaTest(1);
                        DmaTest(2);
    }
}

/*******************************************************************************
* EOF (not truncated)
******************************************************************************/


4292160755a1e25523.png

使用特权

评论回复
评论
h32446975 2021-7-31 12:21 回复TA
验证了一下代码,确实可以。但是第一 个字节会发送2次。修改DMA源地址从数组的buf[1]开始,并且DMA传输长度减1,发送就正常了。 
KingKongHJG| | 2021-4-14 00:29 | 显示全部楼层
华大的M4内核MCU很难用,这个是事实,如果原厂当真不关注MCU用户的诉求,很快就会被口水淹没。

使用特权

评论回复
hiasme| | 2021-6-20 01:24 | 显示全部楼层
兄弟HC32F460串口DMA接收调通了吗?
我参照芯片自带例程配合网上帖子,用那个timer0串口接收超时中断配合DMA做的串口接收,倒是能收到数,串口接收超时中断也能进去,但是有个巨大的问题就是从芯片收一包数据到响应超时中断,居然要2.5ms,,并且我怎么调整那个Timer0定时器这个延时都不会变小(可以变得更长),我简直要吐了,我460800的波特率,一包数据8个byte,总公共的发送耗时也就才不到200us,然后你芯片响应个超时中断要2.5ms,这让我怎么接收数据?如果数据发快了完全就不行啊。
搞了好几天,斗都大了

使用特权

评论回复
评论
pzljun 2021-7-27 21:46 回复TA
那个超时中断不好用,因为是低速时钟做的分频 
huiscii| | 2021-6-23 14:07 | 显示全部楼层
有没有调好的? 我用DMA+串口,正常收发几小时后,DMA_DTCTLx->CNT 自减到0后,就会不停的发送是,而不是停止DMA,FAQ告诉我说是数组溢出或堆栈溢出,我想不通数组溢出或堆栈溢出怎么会影响到CNT==0,不停止DMA,DMA停止发送不是DMA根据CNT数量自己控制的么?

使用特权

评论回复
huiscii| | 2021-6-23 14:10 | 显示全部楼层
官网给的用例基本上都不实用.文档也是春秋笔法,如果能弄到别的芯片,呵呵

使用特权

评论回复
liangzhou1988| | 2021-7-28 16:07 | 显示全部楼层
huiscii 发表于 2021-6-23 14:10
官网给的用例基本上都不实用.文档也是春秋笔法,如果能弄到别的芯片,呵呵

看兄台好像对华大F460有意见,具体问题,代码发出来看看

使用特权

评论回复
woai32lala| | 2021-7-28 16:32 | 显示全部楼层
请问DMA发送怎么设置为软件触发

使用特权

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

本版积分规则

2

主题

36

帖子

0

粉丝