打印
[技术问答]

关于华大MCU DMA收发串口问题

[复制链接]
8514|26
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
nczywq|  楼主 | 2021-10-1 16:08 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我参考usart例程中的DMA收发方式,修改成了DMA只收数据,然后用作finsh的通信端口USART1,完全正常,然后我又使能了一个USART4做为485收发,参考UART1的代码拷贝了一个,关键代码如下:
#define USART4_CH                                 (M4_USART4)
#define USART4_BAUDRATE   (115200ul)
#define USART4_RX_PORT    (PortB)
#define USART4_RX_PIN     (Pin04)
#define USART4_RX_FUNC    (Func_Usart4_Rx)
#define USART4_TX_PORT    (PortB)
#define USART4_TX_PIN     (Pin05)
#define USART4_TX_FUNC    (Func_Usart4_Tx)
#define USART4_EI_NUM     (INT_USART4_EI)
#define USART4_EI_IRQn    (Int003_IRQn)
extern uint8_t Uart4_Rx;                                //串口4接收缓存
extern uint8_t Uart4_Buffer[];        //串口4接收到的数据
extern uint8_t Uart4_Count;
void Uart4_Init(void)
{
        en_result_t enRet = Ok;
    stc_irq_regi_conf_t stcIrqRegiCfg;
    uint32_t u32Fcg1Periph = PWC_FCG1_PERIPH_USART1 | PWC_FCG1_PERIPH_USART2 | \
                             PWC_FCG1_PERIPH_USART3 | PWC_FCG1_PERIPH_USART4;
                /* Enable peripheral clock */
    PWC_Fcg1PeriphClockCmd(u32Fcg1Periph, Enable);
       
    const stc_usart_uart_init_t stcInitCfg = {
        UsartIntClkCkNoOutput,
        UsartClkDiv_1,
        UsartDataBits8,
        UsartDataLsbFirst,
        UsartOneStopBit,
        UsartParityNone,
        UsartSamleBit8,
        UsartStartBitFallEdge,
        UsartRtsEnable,
    };
                 /* Initialize USART IO */
    PORT_SetFunc(USART4_RX_PORT, USART4_RX_PIN, USART4_RX_FUNC, Disable);
    PORT_SetFunc(USART4_TX_PORT, USART4_TX_PIN, USART4_TX_FUNC, Disable);

    /* Initialize USART */
    enRet = USART_UART_Init(USART4_CH, &stcInitCfg);
    if (enRet != Ok)
    {
        while (1)
        {
        }
    }
    else
    {
    }

    /* Set baudrate */
    enRet = USART_SetBaudrate(USART4_CH, USART4_BAUDRATE);
    if (enRet != Ok)
    {
        while (1)
        {
        }
    }
    else
    {
    }

    /* Set USART RX error IRQ */
                MEM_ZERO_STRUCT(stcIrqRegiCfg);
    stcIrqRegiCfg.enIRQn = USART4_EI_IRQn;
    stcIrqRegiCfg.pfnCallback = &Usart4ErrIrqCallback;
    stcIrqRegiCfg.enIntSrc = USART4_EI_NUM;
    enIrqRegistration(&stcIrqRegiCfg);
    NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
    NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
    NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);

    /*Enable TX && RX && RX interrupt function*/
    USART_FuncCmd(USART4_CH, UsartTx, Enable);
    USART_FuncCmd(USART4_CH, UsartRx, Enable);
    USART_FuncCmd(USART4_CH, UsartRxInt, Enable);
}
下面是DMA初始化函数
/* DMAC */
#define DMA1CH1_UNIT                        (M4_DMA1)
#define DMA1_CH1                            (DmaCh1)
#define DMA1CH1_TRG_SEL                     (EVT_USART4_RI)



/* DMA block transfer complete interrupt */
#define DMA1CH1_BTC_INT_NUM                 (INT_DMA1_BTC1)
#define DMA1CH1_BTC_INT_IRQn                (Int004_IRQn)
void Dma1Ch1Init(void)
{
        stc_dma_config_t stcDmaInit;
    stc_irq_regi_conf_t stcIrqRegiCfg;
                MEM_ZERO_STRUCT(stcDmaInit);

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

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

    /* Initialize DMA. */
    MEM_ZERO_STRUCT(stcDmaInit);
    stcDmaInit.u16BlockSize = 1u; /* 1 block */
    stcDmaInit.u32SrcAddr = ((uint32_t)(&USART4_CH->DR)+2ul); /* Set source address. */
    stcDmaInit.u32DesAddr = (uint32_t)(&Uart4_Rx);     /* Set destination address. */
    stcDmaInit.stcDmaChCfg.enSrcInc = AddressFix;  /* 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(DMA1CH1_UNIT, DMA1_CH1, &stcDmaInit);
               
               

    /* Enable the specified DMA channel. */
    DMA_ChannelCmd(DMA1CH1_UNIT, DMA1_CH1, Enable);

    /* Clear DMA flag. */
    DMA_ClearIrqFlag(DMA1CH1_UNIT, DMA1_CH1, TrnCpltIrq);

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

    /* Set DMA trigger source. */
    DMA_SetTriggerSrc(DMA1CH1_UNIT, DMA1_CH1, DMA1CH1_TRG_SEL);

    /* Set DMA block transfer complete IRQ */
                MEM_ZERO_STRUCT(stcIrqRegiCfg);
    stcIrqRegiCfg.enIRQn = DMA1CH1_BTC_INT_IRQn;
    stcIrqRegiCfg.pfnCallback = &Dma1ch1BtcIrqCallback;
    stcIrqRegiCfg.enIntSrc = DMA1CH1_BTC_INT_NUM;
    enIrqRegistration(&stcIrqRegiCfg);
    NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
    NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
    NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
}
static void Dma1ch1BtcIrqCallback(void)
{
                RS485CS(1); //准备发送
    DMA_ClearIrqFlag(DMA1CH1_UNIT, DMA1_CH1, BlkTrnCpltIrq);
                Uart4_Buffer[Uart4_Count++] = Uart4_Rx;
                USART_SendData(USART4_CH,(uint16_t)Uart4_Rx);
                while (Reset == USART_GetStatus(USART4_CH, UsartTxComplete));
                RS485CS(0); //准备发送
       
        /*        if(Uart4_Count >= 10)
                {
                        RS485CS(1); //准备发送
                        for(int i = 0 ; i < 10 ; i += 1)
                        {
                                USART_SendData(USART4_CH,(uint16_t)Uart4_Buffer[i]);
                                while (Reset == USART_GetStatus(USART4_CH, UsartTxComplete));
       
                        }
                        Uart4_Count = 0 ;
                        RS485CS(0); //准备发送
                }*/
}
串口1使用的Int001_IRQn
DMA1CH0使用的Int002_IRQn
串口4使用的Int003_IRQn
DMA1CH1使用的Int004_IRQn

USART1,用在finsh就完全正常的,可以正常收发;
USART4,就是无法收到电脑发送的数据,没有进入中断,但是单片机发数据电脑能收到。
我是从STM32转到华大MCU的,这是第一次使用华大MCU做的板子,也是第一次使用rt-thread,这是公司第一次使用国产的芯片和rt-thread,这次公司的测量项目,我直接从,芯片选型,全部转为国产,到ORCAD画图,allegro画PCB,打样,自己做SMT,经历了1个多月,现在板子终于出成品了,就开始了漫长的代码移植,STM32我是一直在MAC上开发的,遗憾的是华大没有官方的GCC移植代码,我发现IAR里面有GCC,的S和linker,我自己就手动写了,makefile,直到编译,解决了无数个坑,最后编译终于没有问题了,可是华大的没有openocd的cfg文件,我用仿真器下载不上去,由于项目没有时间了,暂时放弃了linux和MAC下的编译了,回到Keil了,如果论坛里有人要我GCC makefile文件,留言,我把源码发给你,可以一直研究openocd 怎么把编译后的文件下载到MCU。
项目完成后,我会把我STM32转向华大的MCU,做的教学视频,从ORCAD画原理图,到allegro布线,到打样,到做钢网,到贴片。到移植官方的代码,到移植rt-thread,最后在到移植finsh.
现在就是遇到了,单片机收不到电脑数据,可能是我不熟悉华大MCU的原因,还希望论坛大佬,能指点我一下。谢谢大家

使用特权

评论回复
沙发
nczywq|  楼主 | 2021-10-5 15:27 | 只看该作者
,哎,搞了几天了,还是没有进展。

使用特权

评论回复
板凳
zchong| | 2021-10-8 07:47 | 只看该作者
慢慢来,仔细核对代码

使用特权

评论回复
地板
nczywq|  楼主 | 2021-10-8 14:33 | 只看该作者
zchong 发表于 2021-10-8 07:47
慢慢来,仔细核对代码

我使用逻辑分析仪分析了我发的数据,发现是能够正常解码的,我看了华大官方的管脚,PB4/NJTRST,这个脚,带多功能,虽然写了fun_grp2,但是直接改代码,是不能收到数据的,我在家又鬼使神差的跳线方式到B3/JTDO_TRACESWO,还是不行,我当时就怀疑我板子设计是不是有问题,原理图,PCB布局全部核对了一次,发送接收线,差分走线,走的没问题。我就直接怀疑了是不是管脚有多功能的时候,不能在华大官方的代码上改端口,我尝试把接收口改到PB9,板子上飞线到PB9,发现居然能正常收到数据了,我只能说华大官方的也很坑,不知道,有没有这方面的说明,还是他们自己都不知道这个问题?哎,板子要重新设计了,还是官方例子,115200波特率,改成57600没问题,再改就会报,参数错误,真的很不想去研究误码率,可是官方代码又不兼容其他波特率,,,国产之路,用着真的心累

使用特权

评论回复
评论
nczywq 2021-10-11 14:22 回复TA
@wubangmi :我一个月前才在网上买的你们的MCU,做板子,加焊接,加移植代码,一共才一个多月,9月中旬才开始搞代码的,所以对你们的MCU还是有很多不熟悉的地方,这个管脚被用成了JTAG,也完全是靠以前的经验得出来的,- - ,你们这个管脚配置这个功能,比ST的强太多了,他们的管脚是固定了那几个口,用着真好 
wubangmi 2021-10-9 17:12 回复TA
PB4/NJTRST,你都知道这是个复用的IO口,你要先把这个口子设置成GPIO功能,再设置为你需要的UART口,不然他还是JTAG的NJRST功能。 PORT_DebugPortSetting(TDO_SWO|TDI|TRST,Disable);这个函数是吧JTAG的几个口子配置成IO的,你先调用一次这玩意 
5
asmine| | 2021-10-9 16:27 | 只看该作者
finish指的是什么

使用特权

评论回复
6
nczywq|  楼主 | 2021-10-10 10:28 | 只看该作者
asmine 发表于 2021-10-9 16:27
finish指的是什么

就是shell窗口,像ubuntu一样,用命令行控制板子

使用特权

评论回复
7
两只袜子| | 2021-10-10 17:17 | 只看该作者
唉,都是st缺货惹的祸

使用特权

评论回复
8
martinhu| | 2021-10-11 09:18 | 只看该作者
nczywq 发表于 2021-10-8 14:33
我使用逻辑分析仪分析了我发的数据,发现是能够正常解码的,我看了华大官方的管脚,PB4/NJTRST,这个脚, ...

PB4/NJTRST,B3/JTDO_TRACESWO,这两个都是JTAG接口的特殊功能脚,上电后默认是JTAG功能,不是GPIO,所以不能像其他IO一样设置func序号就可以,需要先调用GPIO的PSPCR寄存器disable特殊功能(GPIO的库函数有封装),然后再初始化IO。

使用特权

评论回复
9
nczywq|  楼主 | 2021-10-11 13:45 | 只看该作者
martinhu 发表于 2021-10-11 09:18
PB4/NJTRST,B3/JTDO_TRACESWO,这两个都是JTAG接口的特殊功能脚,上电后默认是JTAG功能,不是GPIO,所以 ...

非常谢谢你,函数我已经找到,因为我使用的是swd,所以我使用了下面的代码来关闭了相关端口的功能
PORT_DebugPortSetting(TDO_SWO,Disable);                        //关闭DEBUG端口功能
        PORT_DebugPortSetting(TDI,Disable);                                //关闭DEBUG端口功能
        PORT_DebugPortSetting(TRST,Disable);                        //关闭DEBUG端口功能

,再次感谢

使用特权

评论回复
10
martinhu| | 2021-10-11 15:20 | 只看该作者
nczywq 发表于 2021-10-11 13:45
非常谢谢你,函数我已经找到,因为我使用的是swd,所以我使用了下面的代码来关闭了相关端口的功能

,再 ...

“115200波特率,改成57600没问题,再改就会报,参数错误,”
至于波特率的问题,你要注意串口的时钟频率,还有波特率寄存器是8bit的,所以如果时钟频率太高,而波特率低的话,会导致波特率寄存器溢出,在库函数里面会返回错误,如果是调用库函数设置,可以查看返回值判断,建议使用的时候结合使用的波特率,用UART自带的时钟分频,将时钟分频到与波特率合适的频率

使用特权

评论回复
11
nczywq|  楼主 | 2021-10-11 15:37 | 只看该作者
martinhu 发表于 2021-10-11 15:20
“115200波特率,改成57600没问题,再改就会报,参数错误,”
至于波特率的问题,你要注意串口的时钟频率 ...

这个分频我做好了,总线我分成了50MHZ,串口再分成4,12.5mhz,的时候,9600到115200,测试都还蛮稳定的

使用特权

评论回复
12
nczywq|  楼主 | 2021-10-13 11:36 | 只看该作者
martinhu 发表于 2021-10-11 15:20
“115200波特率,改成57600没问题,再改就会报,参数错误,”
至于波特率的问题,你要注意串口的时钟频率 ...

哥,你们这个MCU定时器中断是怎么回事,我串口收到数据,打开计时,只要在时间内,再次收到数据我清空了TMR0_UNIT->CNTBR = 0ul ;TIM0CHB的计数值,但是这个值很飘忽不定啊,我清空了,他还是按照上一次的中断,提前进入中断了,导致我这数据还没收完,就提前收到结束信号了

使用特权

评论回复
评论
nczywq 2021-10-19 13:51 回复TA
@wubangmi :感谢,感觉这款MCU越调越顺利了 
wubangmi 2021-10-14 16:39 回复TA
@nczywq :华大的UART例程里timerout和UART配合超时中断的例程 
nczywq 2021-10-14 15:19 回复TA
@martinhu :串口还可以空闲中断?因为ModbusRTU结束符号是3个字符时间,我就用的定时器,来计算的结束符,不知道你讲的串口空闲中断是怎么用的?我TIM0我停止后再清除计数,也不行,并没有重新计数 
martinhu 2021-10-14 11:30 回复TA
你用手动清零?timer0和uart可以自动做空闲中断吧? 如果手动清零,试试先停止再清零。 
13
labasi| | 2021-11-4 10:52 | 只看该作者
为什么要手动清零呢

使用特权

评论回复
14
wowu| | 2021-11-4 11:44 | 只看该作者
什么叫空闲中断呢

使用特权

评论回复
15
xiaoqizi| | 2021-11-4 11:46 | 只看该作者
不支持低速吗

使用特权

评论回复
评论
nczywq 2021-11-15 16:37 回复TA
都支持的 
16
木木guainv| | 2021-11-4 11:59 | 只看该作者
计数值为什么会变化呢

使用特权

评论回复
评论
nczywq 2021-11-15 16:38 回复TA
计数值读取到的并不太准确,好像不是实时的 
17
paotangsan| | 2021-11-4 12:01 | 只看该作者
都有多少分频呀

使用特权

评论回复
评论
nczywq 2021-11-15 16:38 回复TA
分频,你在华大库文件里面,有一个结构体里面写了有多少分频的 
18
nczywq|  楼主 | 2021-11-15 16:36 | 只看该作者
labasi 发表于 2021-11-4 10:52
为什么要手动清零呢

因为我是想收到数据后,重置定时器,所 以想用手动

使用特权

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

本版积分规则

12

主题

60

帖子

2

粉丝