STM32F103ZET6 USART con DMA se comporta de manera diferente en la ejecución de depuración versus reinicio

Estoy usando el MCU STM32F103ZET6 y tengo un problema extraño en el que si programo y depuro o programo y restablezco mi MCU, el USART3 utilizado para comunicarse con un dispositivo esclavo no funciona. En la depuración, no hay datos USART que ingresen a la memoria desde el DMA, y tengo en un osciloscopio que el dispositivo esclavo envía datos constantemente. He comprobado:

  1. Los relojes están configurados a velocidades apropiadas.
  2. El USART sigue funcionando con USART3_getchar(0)
  3. reiniciando mi USART3.
  4. El pin BOOT0 está bajo en la depuración.
  5. El canal DMA no está siendo utilizado por nada más.

Revisé el manual de referencia y la hoja de datos del dispositivo, pero tengo problemas para depurar/verificar la configuración en el código para ver la diferencia entre la ejecución de depuración/restablecimiento.

// Local Variables
GPIO_InitTypeDef    GPIO_InitStructure;
NVIC_InitTypeDef    NVIC_InitStructure;
USART_InitTypeDef   USART_InitStructure;
USART_ClockInitTypeDef USART_ClockInitStructure;

// Code
// Configure UART
RCC_APB2PeriphClockCmd(RCC_APB1Periph_USART3 | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);     // USART3 Periph clock enable

// Configure Pins
GPIO_InitStructure.GPIO_Pin                     =  UART3_RX_PIN;
GPIO_InitStructure.GPIO_Speed                   =  GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode                    =  GPIO_Mode_IPD;
GPIO_Init(UART3_PORT, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin                     =  UART3_TX_PIN;
GPIO_InitStructure.GPIO_Speed                   =  GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode                    =  GPIO_Mode_AF_PP;
GPIO_Init(UART3_PORT, &GPIO_InitStructure);

#if(UART3_TX_FLOW_CTS_EN    == 1)                                                       
// Enable USART3 CTS pin
GPIO_InitStructure.GPIO_Pin                     =  UART3_CTS_PIN;
GPIO_InitStructure.GPIO_Speed                   =  GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode                    =  GPIO_Mode_IN_FLOATING;
GPIO_Init(UART3_PORT, &GPIO_InitStructure);
#endif

#if(UART3_RX_FLOW_RTS_EN    == 1)                                                       
// Enable USART3 RTS pin
GPIO_InitStructure.GPIO_Pin                     =  UART3_RTS_PIN;
GPIO_InitStructure.GPIO_Speed                   =  GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode                    =  GPIO_Mode_Out_PP;
GPIO_Init(UART3_PORT, &GPIO_InitStructure);

mCSP_USART3_RTS_PIN_GO;                                                             
// initialise the RTS pin as go
#endif

st_uart3_tx_glb.timeout_timer_u16               =  UART3_TX_TIMEOUT;
while(  (uart3_tx_flg                           == 0)   &&
#if(UART3_TX_FLOW_CTS_EN    == 1)

        (mCSP_USART3_CTS_READ                   == 0)   &&
#endif
        (st_uart3_tx_glb.timeout_timer_u16      >  0)   );

//Set USART3 Clock
USART_ClockStructInit(&USART_ClockInitStructure);
USART_ClockInit(USART3, &USART_ClockInitStructure);

USART_InitStructure.USART_BaudRate                  =  baud_rate_u32;
USART_InitStructure.USART_WordLength                =  USART_WordLength_8b;
USART_InitStructure.USART_StopBits                  =  USART_StopBits_1;
USART_InitStructure.USART_Parity                    =  USART_Parity_No;
#if(UART3_TX_FLOW_CTS_EN    == 1)
USART_InitStructure.USART_HardwareFlowControl       =  
USART_HardwareFlowControl_CTS;  // Enable USART3 CTS pin
#else
USART_InitStructure.USART_HardwareFlowControl       =  
USART_HardwareFlowControl_None;
#endif
USART_InitStructure.USART_Mode                      =  USART_Mode_Rx | 
USART_Mode_Tx;
USART_Init(USART3, &USART_InitStructure);

// Enable interrupts
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);

// Enable modules
USART_Cmd(USART3, ENABLE);
USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);

// Enable the UART3 Interupt
//  NVIC_InitStructure.NVIC_IRQChannel                      =  USART3_IRQn;
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=USART3_IRQ_PREM_PRI;
//  NVIC_InitStructure.NVIC_IRQChannelSubPriority   = USART3_IRQ_SUB_PRI;
//  NVIC_InitStructure.NVIC_IRQChannelCmd                   =  ENABLE;
//  NVIC_Init(&NVIC_InitStructure);

// Configure DMA
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);                                  // DMA1 Periph clock enable

st_uart3_tx_glb.cnt_u8                              =  st_uart3_tx_glb.wr_index_u8;

DMA_DeInit(DMA1_Channel2);
DMA_StructInit(&DMA_UART3_InitStructure);
DMA_UART3_InitStructure.DMA_PeripheralBaseAddr      =  (uint32_t)&USART3->DR;
DMA_UART3_InitStructure.DMA_MemoryBaseAddr          =  (uint32_t)uart3_rx_buffer_a_u8_glb;
DMA_UART3_InitStructure.DMA_DIR                     =  DMA_DIR_PeripheralSRC;
DMA_UART3_InitStructure.DMA_BufferSize              =  st_uart3_tx_glb.cnt_u8;
DMA_UART3_InitStructure.DMA_PeripheralInc           =  DMA_PeripheralInc_Disable;
DMA_UART3_InitStructure.DMA_MemoryInc               =  DMA_MemoryInc_Enable;
DMA_UART3_InitStructure.DMA_PeripheralDataSize      =  DMA_PeripheralDataSize_Byte;
DMA_UART3_InitStructure.DMA_MemoryDataSize          =  DMA_MemoryDataSize_Byte;
DMA_UART3_InitStructure.DMA_Mode                    =  DMA_Mode_Circular;
DMA_UART3_InitStructure.DMA_Priority                =  DMA_Priority_VeryHigh;
DMA_UART3_InitStructure.DMA_M2M                     =  DMA_M2M_Disable;
DMA_Init(DMA1_Channel2, &DMA_UART3_InitStructure);

// Enable the DMA complete Interupt
NVIC_InitStructure.NVIC_IRQChannel                      =  DMA1_Channel2_IRQn;
NVIC_Init(&NVIC_InitStructure);

DMA_Cmd(DMA1_Channel2, ENABLE);
El DMA y el USART no se pueden detener durante la depuración, podría perder la sincronización si pierde las interrupciones de esta manera. Consulte DBGMCU_CR.
Puedo ver la definición de bits en stm32f10x.h pero no estoy seguro, ¿necesito definir bits DBGMCU_CR específicos para que USART y DMA funcionen en la depuración? No creo que haya necesitado hacer esto antes. No detengo la CPU, simplemente espero que entre un poco en la memoria y me detengo después de eso.

Respuestas (2)

Las estructuras locales deben inicializarse; de ​​lo contrario, algunos campos pueden obtener valores impredecibles:

GPIO_InitTypeDef    GPIO_InitStructure={};
NVIC_InitTypeDef    NVIC_InitStructure={};
USART_InitTypeDef   USART_InitStructure={};
USART_ClockInitTypeDef USART_ClockInitStructure={};

mCSP_USART3_RTS_PIN_GO;¿Qué hace esta declaración? ¿Es una macro o qué?

Estas banderas deben declararse volatile, de lo contrario, puede obtener un comportamiento diferente en diferentes configuraciones de optimización:

while(  (uart3_tx_flg                           == 0)   &&
#if(UART3_TX_FLOW_CTS_EN    == 1)
    (mCSP_USART3_CTS_READ                   == 0)   &&
#endif
    (st_uart3_tx_glb.timeout_timer_u16      >  0)   );

Fue que USART3 está en APB1 y no en el reloj APB2 y, por lo tanto, no se estaba habilitando, pero en el cargador de arranque se estaba habilitando el reloj APB1 USART3.