UART Transmit with DMA Issues
Edit: compilable example code posted below in comments. The problem now with this code is that too many messages are being sent in addition to the wrong data being sent.
I am using VisualGDB and a STM32F303RET6.
I am having trouble trying to get the UART transmitter to work with the DMA controller. The UART transmitter works fine when I do a single transmission by manually updating the TDR. But, when I use the DMA controller, the data that is transmitted is not what is expected.
It appears to me that the data being sent is coming from a memory address other than the address that I have told the DMA controller to point to in CMAR. But, when looking at the address of the data and the address in the CMAR, it matches. So, I am not sure what the problem is but I do wonder if the problem is something I am not understanding with C and C++. Since VisualGDB operates in C++ files, I write C++ wrappers for the C functions that do the heavy lifting with modifying the registers. When, I tried using a data pointer for the memory address to read from that was compiled under the C compiler, I could not get the DMA controller to operate correctly. When I pass the DMA controller a memory address from a pointer that was compiled under the C++ compiler, it works but sends the wrong data.
Hopefully, someone can help me.
Here is my code to setup the DMA controller for UART1.
void c_uart_setup_dma(uint8_t port, uint8_t * data) { uint16_t reg; uint32_t * tmp; volatile uint32_t src_address; volatile uint32_t dest_address; DMA_TypeDef * dma; DMA_Channel_TypeDef * dma_chan; USART_TypeDef * uart; // Assign the DMA channel and DMA controller based on the UART port c_uart_setdma(port, dma, dma_chan); // Assign the pointer for the UART port based on which one we want to modify c_uart_setport(port, uart); // set the source and destination address locations tmp = (uint32_t*)&data; src_address = *(uint32_t*)tmp; dest_address = (uint32_t)&uart->TDR; // test to see if this changes the data at the correct location *data = 0; *(data + 1) = 0; *(data + 2) = 0; // configure the DMA channel // set the RCC clock for the DMA controller RCC->AHBENR |= 0x01; // enable DMA1 RCC->AHBENR |= 0x02; // enable DMA2 // set the peripheral register address data will be read from/written to dma_chan->CPAR = dest_address; // set the memory address data will be read from/written to dma_chan->CMAR = src_address; // configure the total number of data items to be transferred dma_chan->CNDTR = (uint16_t)0x03; // configure the channel priority, data transfer direction, mode, data size, and interrupt reg = DMA_CCR_PL | DMA_CCR_DIR | DMA_CCR_TEIE | DMA_CCR_TCIE | DMA_CCR_MINC; dma_chan->CCR |= reg; // activate the DMA channel dma_chan->CCR |= DMA_CCR_EN; // clear the TC flag uart->ICR |= USART_ICR_TCCF; // enable the DMA transmitter in the UART //uart->CR3 |= USART_CR3_DMAT; // enable the DMA IRQ c_uart_set_dma_irq(port); }And here is what the debug shows when stopped at the end of this setup function:
Here is the code for my transmit function:
void c_uart_transmit_dma(uint8_t port)
{ uint32_t * source; uint32_t address; USART_TypeDef * uart; DMA_TypeDef * dma; DMA_Channel_TypeDef * dma_chan; // set the UART port c_uart_setport(port, uart); // set the DMA channel c_uart_setdma(port, dma, dma_chan); // disable the DMA channel dma_chan->CCR &= ~DMA_CCR_EN; // set the number of bytes to transfer dma_chan->CNDTR |= 0x03; // activate the DMA channel dma_chan->CCR |= DMA_CCR_EN; // clear the TC flag by writing the TCCF bit in ICR uart->ICR |= USART_ICR_TCCF; // enable the DMA transmitter in the UART uart->CR3 |= USART_CR3_DMAT; }Any help would be greatly appreciated!
