各位大侠,小弟遇到一个十分让人困惑的问题。在如下的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); } |
在这里要提醒各位使用MDK5的童鞋,这款编译器有一定的坑,特别是对于内存的分配上。有时候一不小心就会给你把缓冲区分配到一些非法地址上去,大家一定要注意。如果大家遇到什么诡异现象,无法从程序本身上去解释的话,那么建议大家从内存的角度去考虑,检查一下MDK有没有将缓冲区分配到了非法地址上。
评分
查看全部评分
学习了。感谢分享。
MDK5其实总是会有一些BUG,编译和调试都如此,之前也遇到调试跳转到非指定的地址,然后优化等级越高(比如level3)有时候也会导致一些问题。
oh 谢谢反馈!赞!
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内存,需要工程做相应配置。
评分
查看全部评分
学习学习