2024-07-31 11:32 AM
Hello I need to send a string via USART every 500ms. I tried to use DMA that seems to be easy to configure. USART transfer works but only without DMA (test in while main cycle). I do not see any problem in DMA configuration. Can you tell me it there is something that I do not set?
I start DMA transfer in Systick cycle.
Thank you
#include "main.h"
#include "stm32g0xx.h"
#include <stdint.h>
#define BAUD_RATE 9600
#define SYS_CLK 64000000
const char message[] = "Hello, world!\r\n";
void DMA_Init(void) {
// Enable DMA clock
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
// Configure DMA for USART1 TX (DMA1 Channel 1)
DMA1_Channel1->CPAR = (uint32_t)&USART1->TDR;
DMA1_Channel1->CMAR = (uint32_t)message;
DMA1_Channel1->CNDTR = sizeof(message) - 1;
DMA1_Channel1->CCR = DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE;
// Enable DMA1 interrupt
NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
void USART1_Init(void) {
// Enable clocks
RCC->IOPENR |= RCC_IOPENR_GPIOBEN; // Enable GPIOB clock
RCC->APBENR2 |= RCC_APBENR2_USART1EN; // Enable USART1 clock
// Configure PB6 as USART1_TX and PB7 as USART1_RX
GPIOB->MODER &= ~(GPIO_MODER_MODE6_Msk | GPIO_MODER_MODE7_Msk);
GPIOB->MODER |= (0x2 << GPIO_MODER_MODE6_Pos) | (0x2 << GPIO_MODER_MODE7_Pos); // Set PB6 and PB7 to AF mode
GPIOB->AFR[0] |= (0x0 << GPIO_AFRL_AFSEL6_Pos) | (0x0 << GPIO_AFRL_AFSEL7_Pos); // Set AF0 (USART1)
// Configure USART1
USART1->BRR = SYS_CLK / BAUD_RATE; // Set baud rate
USART1->CR3 |= USART_CR3_DMAT; // Enable DMA for transmitter - TOTO JE NAVIC
USART1->CR1 |= USART_CR1_TE; // Enable transmitter
USART1->CR1 |= USART_CR1_UE; // Enable USART
}
void DMA1_Channel1_IRQHandler(void) {
if (DMA1->ISR & DMA_ISR_TCIF1) {
// Clear the transfer complete interrupt flag
DMA1->IFCR |= DMA_IFCR_CTCIF1;
// Optional: Disable DMA channel if needed, and re-enable if you need to prepare for the next transfer
DMA1_Channel1->CCR &= ~DMA_CCR_EN; // Disable DMA channel
DMA1_Channel1->CNDTR = sizeof(message) - 1;//1; // Reset number of data to transfer
DMA1_Channel1->CCR |= DMA_CCR_EN; // Re-enable DMA channel
}
}
void SysTick_Handler(void)
{
SysTickCounter++;
if (SysTickCounter>500) {
DMA1_Channel1->CCR |= DMA_CCR_EN;
SysTickCounter = 0;
}
}
void USART1_SendString(const char *str) {
while (*str) {
while (!(USART1->ISR & USART_ISR_TXE_TXFNF_Msk)); // Wait until TX buffer is empty
USART1->TDR = *str++; // Transmit character
}
}
int main(void)
{
CLK_Config();
GPIO_Init();
SysTick_Init();
DMA_Init();
USART1_Init();
while (1)
{
//USART1_SendString(message); - THIS WORKS, BUT NOT WITH DMA
//for (volatile int i = 0; i < 1000000; i++);
}
}