你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

DMA+UASRT,DMA无法使能

[复制链接]
gege770 提问时间:2017-4-27 10:37 /
各位大侠,小弟遇到一个十分让人困惑的问题。在如下的main函数中将BspInit();前面的#if 0改为#if 1之后,也就是将BspInit();到main结尾部分的代码编译进来之后,串口无法正常发数,原因在于DMA使能失败;在#if 0的情况下,也就是不将BspInit();到main结尾部分的代码编译进来,则串口能够正常工作。按道理来说,后面的代码还未运行,怎么会影响到前面代码的执行呢?不应该啊。于是考虑是不是栈溢出导致的问题,然后仔细想了一下,发现说不通,栈的空间是在函数被调用的时候才会被占用,因为串口测试代码放在了main函数的最开始,而且运行到for循环的时候,栈的空间才被占用不到60个字节,在启动代码里面分配的栈的大小是1K字节。小弟我想了各种办法,做了各种尝试,试了各种初始化以及使能顺序,依然没有能够解决这个问题。想请各位前辈大侠高手们帮忙给支支招,小弟先谢谢论坛里的各位前辈大侠高手们了。
       
main函数如下
int main(void)
{
        int ret;
        struct PlcJDIRT *jdirt;
        char *memory;
        char *r_memory;               
        /*串口测试*/
        uint32_t i=0;
        uint8_t b[16] = {1,3, 0,0,0,2,0xFF,0xFF};
       
        delay_init(168);

        ret = OpenUart(PLC_STM32_UART_COM1);
        for(i=0; i<5; i++)
        {       
                        ret = WriteToUart(PLC_STM32_UART_COM1, b, 8);       
                        delay_ms(1000);               
        }
        /*串口测试*/
        /*-------------init all board device---------------*/       
               
        //NVIC config 0-15 prio       
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);       
       
#if 0       
        BspInit();

    //InitDrac200MConfig();

        ret = InitPlcSys();
    assert(ret == PLC_RTSUCCESS);

    ret = InitPSocketSystem();
    assert(ret == PLC_RTSUCCESS);

    ret = InitPlcCommonFW();
    assert(ret == PLC_RTSUCCESS);
       
        InitialDRAC200MIOBoard();
        InitialModbusSlave();
        InitialModbusMaster();

        memory = pv_EXT_PortMalloc(SIZE_OF_MEMORY);
        assert(memory != NULL);
        r_memory = pv_EXT_PortMalloc(SIZE_OF_R_MEMORY);
        assert(r_memory != NULL);

  jdirt = InitPlcJDIRT(memory, SIZE_OF_MEMORY,
         r_memory, SIZE_OF_R_MEMORY);
  assert(jdirt != NULL);
       
        xTaskCreate(led_task,"TASK_1",256,NULL,20,NULL);       
       
        xTaskCreate(StartUDPServer,"UDPServer",1000, jdirt, 5, NULL);       
       
        vTaskStartScheduler();
#endif
}

OpenUart(PLC_STM32_UART_COM1);调用顺序如下
/*Initialize UART5*/
PLC_STM32_UART_COM1_Config(PLC_UART_485, PLC_BAUDRATE_115200, PLC_PARITY_NO, PLC_DATABIT_8, PLC_STOPBIT_1);
/*Enable UART5*/                                       
/*Configure DMA1_Stream0 for UART5_RX*/
DMAConfig(DMA1_Stream0,
                  BUF_SIZE_MAX,
                  DMA_DIR_PeripheralToMemory,
                  (uint32_t)g_buf_rx[COM1],
                   DMA_Mode_Circular,
                  (uint32_t)&UART5->DR,
                  DMA_Priority_Medium);       
NVICConfig(DMA1_Stream0_IRQn, 12, 0);
/*Configure DMA1_Stream7 for UART5_TX*/
DMAConfig(DMA1_Stream7,
                  0,
                  DMA_DIR_MemoryToPeripheral,
                  (uint32_t)g_buf_tx[COM1],
                  DMA_Mode_Normal,
                  (uint32_t)&UART5->DR,
                  DMA_Priority_High);
NVICConfig(UART5_IRQn, 12, 0);                               
/*Start to receive data through COM1*/
DMAEnable(DMA1_Stream0, UART5, USART_DMAReq_Rx, BUF_SIZE_MAX);
/*Enable UART5*/
USART_Cmd(UART5, ENABLE);                                       

WriteToUart(PLC_STM32_UART_COM2, b, 8);中会调用WriteData(DMA1_Stream7, UART5, COM1, buf, length);
       
WriteData(DMA1_Stream7, UART5, COM1, buf, length);中会调用DMAEnable(DMAy_Streamx, USARTx, USART_DMAReq_Tx, (uint16_t)length);

DMAEnable(DMAy_Streamx, USARTx, USART_DMAReq_Tx, (uint16_t)length);程序如下
/*
*********************************************************************************************************
*        @brief        Enable DMA transfer
*   @param  DMAy_Streamx: where y can be 1 or 2 to select the DMA and x
*                can be 0 to 7 to select the DMA Stream.
*        @param        USARTx: where x can be 1, 2, 3, 4, 5, 6, 7 or 8 to select the USART or UART peripheral.
*        @param        USART_DMAReq: Specifies the DMA request.
*                This parameter can be any combination of the following values:
*                USART_DMAReq_Tx: USART DMA transmit request
*                USART_DMAReq_Rx: USART DMA receive request
*        @param  counter: Specifies the number of data items need to be transfered.
*        @retval None
*********************************************************************************************************
*/
static void DMAEnable(DMA_Stream_TypeDef * DMAy_Streamx, USART_TypeDef * USARTx, uint16_t USART_DMAReq, uint16_t counter)
{
        USART_DMACmd(USARTx, USART_DMAReq, DISABLE);
        DMA_Cmd(DMAy_Streamx, DISABLE);
        while (DMA_GetCmdStatus(DMAy_Streamx) != DISABLE){}
        DMA_SetCurrDataCounter(DMAy_Streamx, counter);
        USART_DMACmd(USARTx, USART_DMAReq, ENABLE);       
        DMA_Cmd(DMAy_Streamx, ENABLE);       
}

GPIO初始化代码如下
/*
*********************************************************************************************************
*        @brief        Configure the PLC_STM32_UART_COM1 according to the specified
*         parameters, referenced by SetSTM32UartConfig.
*        @param  mode: Select RS485 or RS232.
*   @param  baud: Set baud rate.
*        @param  parity: Set parity mode.
*        @param        data_bit: Set word length.
*        @param        stop_bit: Set number of stop bits.
*        @retval None
*********************************************************************************************************
*/
static void PLC_STM32_UART_COM1_Config(char mode, char baud, char parity, char data_bit, char stop_bit)
{
        GPIO_InitTypeDef GPIO_InitStructure;
       
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOG, ENABLE);//Enable clock of GPIOB, GPIOC, GPIOD, GPIOG
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);//Enable clock of UART5

        /*Alternate function PC12->UART5_TX, PD2->UART5_RX*/
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_UART5);//AF, GPIOC12->UART5
        GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_UART5);//AF, GPIOD2->UART5
       
        /*Configure Pin_12 of GPIOC as AF UART5_TX*/
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;//GPIOC12
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//Alternate function
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//Speed 50MHz
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//Push & pull
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//No pull
        GPIO_Init(GPIOC, &GPIO_InitStructure);//Initialize GPIOC
        /*Configure Pin_2 of GPIOD as AF UART5_RX*/
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;//GPIOD2
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;// Alternate function
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//Speed 50MHz
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//Push & pull
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//No pull
        GPIO_Init(GPIOD, &GPIO_InitStructure);//Initialize GPIOD                
        /*Configure Pin_5 of GPIOB to select RS232 or RS485 in main board*/  
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//GPIOB5
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//Out put
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//Speed 50MHz
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//Push & pull
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//No pull
        GPIO_Init(GPIOB, &GPIO_InitStructure);//Initialize GPIOB
        /*Configure Pin_9 of GPIOG to select RS232 or RS485 in core board*/  
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//GPIOG9
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//Out put
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//Speed 50MHz
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//Push & pull
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//No pull
        GPIO_Init(GPIOG, &GPIO_InitStructure);//Initialize GPIOG
        /*Configure Pin_7 of GPIOD to select TX or RX of RS485*/
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;//GPIOD7
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//Out put
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//Speed 50MHz
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//Push & pull
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//No pull       
        GPIO_Init(GPIOD, &GPIO_InitStructure);//Initialize GPIOD        
       
        /*Initialize UART5*/
        USART_Config(UART5, baud, parity);
       
        /*Select RS485 or RS232*/
        UART5_485OR232 = mode;//Select RS485 or RS232 in core board         
        UART5_MB485OR232 = mode;//Select RS485 or RS232 in main board
       
        /*Set default mode of RS485*/
        UART5_485 = RS485_RX_CONTROL;//Default Rx       
}       

串口初始化代码如下
/*
*********************************************************************************************************
*        @brief        Configure the USART according to the specified parameters.
*        @param  USARTx: where x can be 1, 2, 3, 4, 5, 6, 7 or 8 to select the USART or UART peripheral.
*   @param  baud: Set baud rate.
*        @param  parity: Set parity mode.
*        @retval None
*********************************************************************************************************
*/
static void USART_Config(USART_TypeDef * USARTx, char baud, char parity)
{
        USART_InitTypeDef USART_InitStructure;
       
        switch (baud){
                case PLC_BAUDRATE_300:
                        USART_InitStructure.USART_BaudRate = 300;//Set baud rate to 300
                        break;
                case PLC_BAUDRATE_9600:
                        USART_InitStructure.USART_BaudRate = 9600;//Set baud rate to 9600
                        break;                       
                case PLC_BAUDRATE_38400:
                        USART_InitStructure.USART_BaudRate = 38400;//Set baud rate to 38400
                        break;                       
                case PLC_BAUDRATE_115200:
                        USART_InitStructure.USART_BaudRate = 115200;//Set baud rate to 115200
                        break;       
        }
        switch (parity){
                case PLC_PARITY_NO:
                        USART_InitStructure.USART_Parity = USART_Parity_No;//No parity
                        USART_InitStructure.USART_WordLength = USART_WordLength_8b;//Set word length to 8
                        break;
                case PLC_PARITY_EVEN:
                        USART_InitStructure.USART_Parity = USART_Parity_Even;//Even parity
                        USART_InitStructure.USART_WordLength = USART_WordLength_9b;//Set word length to 9
                        break;                       
                case PLC_PARITY_ODD:
                        USART_InitStructure.USART_Parity = USART_Parity_Odd;//Odd parity
                        USART_InitStructure.USART_WordLength = USART_WordLength_9b;//Set word length to 9
                        break;
        }
        USART_InitStructure.USART_StopBits = USART_StopBits_1;//1 stop bit
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//No hardware control
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;        //Tx & Rx are both enabled
        USART_Init(USARTx, &USART_InitStructure);//Initialize USARTx
       
        /*Clear TC bit in USART_SR*/
        while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == SET){
                USART_ClearFlag(USARTx, USART_FLAG_TC);               
        }
       
        /*Enable transmission complete interrupt*/
        USART_ITConfig(USARTx, USART_IT_TC, ENABLE);//for test
}       

NVIC初始化代码如下
/*
*********************************************************************************************************
*        @brief        Configure DMA or USART interrupt.
*        @retval None
*********************************************************************************************************
*/
static void NVICConfig(uint8_t  NVIC_IRQChannel,
                                           uint8_t  NVIC_IRQChannelPreemptionPriority,
                                           uint8_t  NVIC_IRQChannelSubPriority)
{       
        NVIC_InitTypeDef NVIC_InitStructure;
       
        /*Enable DMA TC interrupt*/
        NVIC_InitStructure.NVIC_IRQChannel = NVIC_IRQChannel;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_IRQChannelPreemptionPriority;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_IRQChannelSubPriority;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
}

DMA初始化代码如下
/*
*********************************************************************************************************
*        @brief        Configure the DMA according to the specified parameters,
*                referenced by ReadFromUart & WriteToUart.
*   @param  DMAy_Streamx: where y can be 1 or 2 to select the DMA and x
*                can be 0 to 7 to select the DMA Stream.
*        @param        DMA_DIR: Specifies if the data will be transferred from memory to peripheral,
*                from memory to memory or from peripheral to memory.
*        @param        DMA_Memory0BaseAddr: Specifies the memory 0 base address for DMAy Streamx.
*        @param        DMA_PeripheralBaseAddr: Specifies the peripheral base address for DMAy Streamx.
*        @param        DMA_Priority: Specifies whether the Peripheral address register
*                should be incremented or not.
*        @retval None
*********************************************************************************************************
*/
static void DMAConfig( DMA_Stream_TypeDef *  DMAy_Streamx,
                                           uint32_t  DMA_BufferSize,       
                                           uint32_t  DMA_DIR,
                                           uint32_t  DMA_Memory0BaseAddr,
                                           uint32_t  Mode,       
                                           uint32_t  DMA_PeripheralBaseAddr,
                                           uint32_t  DMA_Priority )
{
        DMA_InitTypeDef  DMA_InitStructure;
        /*Enable the clock of DMA*/
        if((uint32_t)DMAy_Streamx<(uint32_t)DMA2)//Determin the current stream belongs to DMA1 or DMA2
                RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);//Enable the clock of DMA1       
        else
                RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);//Enable the clock of DMA2
        DMA_DeInit(DMAy_Streamx);
       
        /*Waiting for the EN bit in DMA_SxCR become reset*/
        DMA_Cmd(DMAy_Streamx, DISABLE);       
        while (DMA_GetCmdStatus(DMAy_Streamx) != DISABLE){}                                  
       
        /*Configure DMA stream*/               
        DMA_InitStructure.DMA_BufferSize = DMA_BufferSize;//need to be configured
        DMA_InitStructure.DMA_Channel = DMA_Channel_4;
        DMA_InitStructure.DMA_DIR = DMA_DIR;//need to be configured
        DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;//changed
        DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;       
        DMA_InitStructure.DMA_Memory0BaseAddr = DMA_Memory0BaseAddr;//need to be configured
        DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        DMA_InitStructure.DMA_Mode = Mode;//need to be configured       
        DMA_InitStructure.DMA_PeripheralBaseAddr = DMA_PeripheralBaseAddr;//need to be configured
        DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        DMA_InitStructure.DMA_Priority = DMA_Priority;//need to be configured
        DMA_Init(DMAy_Streamx, &DMA_InitStructure);       
       
        /*Enable DMA TCIF if the stream is used for receiving*/
        if((DMAy_Streamx == DMA1_Stream0) || (DMAy_Streamx == DMA1_Stream1) || (DMAy_Streamx == DMA1_Stream2))//for test       
                DMA_ITConfig(DMAy_Streamx, DMA_IT_TC, ENABLE);        
}                                               

收藏 3 评论12 发布时间:2017-4-27 10:37

举报

12个回答
gege770 回答时间:2017-6-17 14:22:31
不是堆的问题,答案已经被找到了。由于将#if 0改为#if 1之后,由于代码量变大,MDK5自动的将发送缓冲区分派到CCM上了,而CCM与DMA并未直接连接,所以会导致transfer error从而导致DMA使能失败。解决方法是用attribute指定缓冲区的位置。如果带有RTOS的环境下,如果RTOS管理的是外扩内存的话,也可以用RTOS自带的类似于malloc的函数来动态的分配缓冲区。
在这里要提醒各位使用MDK5的童鞋,这款编译器有一定的坑,特别是对于内存的分配上。有时候一不小心就会给你把缓冲区分配到一些非法地址上去,大家一定要注意。如果大家遇到什么诡异现象,无法从程序本身上去解释的话,那么建议大家从内存的角度去考虑,检查一下MDK有没有将缓冲区分配到了非法地址上。

评分

参与人数 1ST金币 +5 收起 理由
zero99 + 5 结贴奖励

查看全部评分

xmshao 回答时间:2017-4-27 15:19:29
你现在安排的堆多大?会不会是HEAP设置小了点?
arenas 回答时间:2017-6-24 09:02:07
gege770 发表于 2017-6-17 14:22
不是堆的问题,答案已经被找到了。由于将#if 0改为#if 1之后,由于代码量变大,MDK5自动的将发送缓冲区分派 ...

学习了。感谢分享。

MDK5其实总是会有一些BUG,编译和调试都如此,之前也遇到调试跳转到非指定的地址,然后优化等级越高(比如level3)有时候也会导致一些问题。
无薪税绵 回答时间:2017-6-24 11:47:18
这么快就找到解决方法了,不错。
好吃好好吃 回答时间:2017-6-24 20:41:25
这个不错,经验之谈,
风中的IT 回答时间:2017-6-24 21:04:14
学习了,这种编译器导致的问题还是很难查的
xmshao 回答时间:2017-6-25 13:34:19
gege770 发表于 2017-6-17 14:22
不是堆的问题,答案已经被找到了。由于将#if 0改为#if 1之后,由于代码量变大,MDK5自动的将发送缓冲区分派 ...

oh 谢谢反馈!赞!
shuolang126 回答时间:2017-6-26 08:56:55
恩,学习了,之前较少使用M4系列内核MCU,也没有遇到过这个问题,可以参考下面这个文档,学习CCM的用法。
http://www.stmcu.com.cn/Designre ... b7562f11b9bbd82d0df
--------------------------------------------------------
STM32家族中基于ARM Cortex M4内核的STM32F3与STM32F4系列芯片内有一块特殊的SRAM存储区---内核耦合存储器[CCM RAM],为CPU所专享访问。主要是为了实现最高系统时钟频率下执行代码,同时避免出现等待状态。因此,与从闪存里执行代码相比,就大大减少了关键任务的执行时间。

CCM RAM一般用于实时性高或计算密集型程序,比如:
* 数字电源的控制环(开关电源,照明)
* 3相矢量电机控制
* 实时DSP 任务

当程序代码位于CCM RAM且数据保存在常规SRAM时,M4内核便处于最优的哈佛结构配置,让指令零等待执行从而实现速度最大化。如果中断服务程序位于CCM RAM中,可以确保最短的时延,提高响应速度。

当CCM RAM不用来存放执行代码时,也可当做常规SRAM使用。不过它不能被DMA访问。另外,也不推荐在CCM中同时存放指令代码和数据,不然内核访问CCM里的数据和指令时可能会出现冲突,影响CPU的处理性能。
-------------------------------------------------------------
从资料看,如何使用CCM内存,需要工程做相应配置。

评分

参与人数 1ST金币 +5 收起 理由
zero99 + 5

查看全部评分

lulugl 回答时间:2017-6-26 09:21:07
除了用keil还可以用什么工具没有坑的,楼主
asmhai 回答时间:2017-6-26 23:11:36
签到签到。
sz_Dean 回答时间:2018-11-16 11:28:58
不错,学习了
pig141 回答时间:2020-6-1 09:52:22
gege770 发表于 2017-6-17 14:22
不是堆的问题,答案已经被找到了。由于将#if 0改为#if 1之后,由于代码量变大,MDK5自动的将发送缓冲区分派 ...

学习学习

所属标签

相似问题

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版