Issue 1: Unexpected Data Transmission with DMA
#include "stm32f10x.h"
#include "Delay.h"
#include "DMA.h"
#include "Serial.h"
uint8_t dataBuffer[3];
int main(void)
{
/* Module initialization */
OLED_Init();
Key_Init();
Serial_Init();
MyDMA_TX_Init(DMA1_Channel4, (uint32_t)&USART1->DR, (uint32_t)dataBuffer, 3);
dataBuffer[0] = 0x01;
dataBuffer[1] = 0xFA;
dataBuffer[2] = 0x02;
SRAM_USART1_Transfer();
dataBuffer[0] = 0x03;
dataBuffer[1] = 0xFB;
dataBuffer[2] = 0x04;
SRAM_USART1_Transfer();
}
#include "DMA.h"
uint16_t transferSize;
void MyDMA_TX_Init(DMA_Channel_TypeDef* DMA_CHx, uint32_t peripheralAddr, uint32_t memoryAddr, uint16_t size)
{
transferSize = size;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = peripheralAddr;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryBaseAddr = memoryAddr;
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_BufferSize = size;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_Init(DMA_CHx, &DMA_InitStructure);
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
}
void SRAM_USART1_Transfer(void)
{
DMA_Cmd(DMA1_Channel4, DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel4, transferSize);
DMA_Cmd(DMA1_Channel4, ENABLE);
while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET);
DMA_ClearFlag(DMA1_FLAG_TC4);
}
When the DMA initialization function includes enabling the DMA channel immediately, unexpected null bytes (0x00) appear in the transmission. This occurs because enabling the DMA channel before setting up the data buffer can trigger premature transfers with uninitialized data.
Issue 2: DMA Transmission Failure with Immediate Serial Writes
Serial_SendByte(0x01);
dataBuffer[0] = 0xFA;
SRAM_USART1_Transfer();
Serial_SendByte(0x02);
When sending data via DMA immediately followed by a direct write to the USART data register, the DMA transmission fails to complete properly. This happens because DMA doesn't transfer data instantaneously - it requires time to process the transfer. When the CPU immediately writes to the USART data register after initiating a DMA transfer, it creates a conflict where both the DMA controller and CPU are trying to access the same peripheral register.
Issue 3: USART Idle Interrupt Timing Issues
Problem 3.1: Required Delay in USART Idle Interrupt
void USART3_IRQHandler(void)
{
uint8_t clear = clear;
if (USART_GetITStatus(USART3, USART_IT_IDLE) != RESET)
{
Delay_ms(40);
SRAM_USART1_Transfer((uint32_t)USART3_RX_BUF, 40);
DMA_Cmd(DMA1_Channel3, DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel3, 200);
DMA_Cmd(DMA1_Channel3, ENABLE);
clear = USART3->SR;
clear = USART3->DR;
}
}
Without a delay of approximately 40ms in the USART idle interrupt handler, the received data is corrupted. This suggests that the DMA transfer is still in progress when the idle interrupt occurs, and the delay provides time for the DMA to complete its operation.
Problem 3.2: DMA Transfer Count Dependency on Delay
Delay_ms(500);
USART3_RX_LEN = USART3_MAX_RECV_LEN - DMA1_Channel3->CNDTR;
if(USART3_RX_BUF[0] == 0xFF)
{
u1_printf("%d\r\n", USART3_RX_LEN);
}
When transmitting 81 bytes to the gateway (20 four-byte values plus a one-byte header), with a 500ms delay, the DMA transfer counter correctly decrements by 81, and all data is received. However, with only a 40ms delay, the transfer counter only decrements by 41, resulting in only 10 data values being received. This indicates that the DMA transfer hasn't completed when the USART idle interrupt is triggered, and the delay is simply waiting for the transfer to finish. Based on Issue 2, it appears that when USART3 receives data, the RXNE flag is set, but if the DMA doesn't promptly move the data, a bus idle condition occurs, triggering the USART idle interrupt prematurely.