/* p13_1.c Send a string to USART2 by DMA * * USART2 transmit is on DMA Channel 4. * See Reference manual Table 28 RM0360 April 2017. * * USART2 Tx signal is connected to pin PA2. To see the output of USART2 * on a PC, you need to use a USB-serial module. Connect the Rx pin of * the module to the PA2 pin of the STM32F030 Nucleo board. Make sure * the USB-serial module you use has a 3.3V interface. * * By default, the system clock is running at 8 MHz. * The UART is configured for 9600 Baud. * PA2 - USART2 TX (AF1) * * This program was tested with Keil uVision v5.24a with DFP v2.11.0 */ #include "stm32F0xx.h" void USART2_init(void); void DMA1_init(void); void DMA1_channel4_setup(unsigned int src, unsigned int dst, int len); int done = 1; int main(void) { char alphabets[] = "abcdefghijklmnopqrstuvwxyz\n"; char message[80]; int i; int size = sizeof(alphabets)-1; USART2_init(); DMA1_init(); while (1) { /* prepare the message for transfer */ for (i = 0; i < size; i++) message[i] = alphabets[i]; /* send the message out by USART2 using DMA */ while (done == 0) { } /* wait until DMA data transfer is done */ done = 0; /* clear done flag */ DMA1_channel4_setup((unsigned int)message, (unsigned int)&USART2->TDR, size); } } /* Initialize UART pins, Baudrate The USART2 is configured to send output to pin PA2 at 9600 Baud. */ void USART2_init(void) { RCC->AHBENR |= 0x00020000; /* enable GPIOA clock */ RCC->APB1ENR |= 0x00020000; /* enable USART2 clock */ /* Configure PA2 for USART2_TX */ GPIOA->AFR[0] &= ~0x0F00; GPIOA->AFR[0] |= 0x0100; /* alt7 for USART2 */ GPIOA->MODER &= ~0x0030; GPIOA->MODER |= 0x0020; /* enable alternate function for PA2 */ USART2->BRR = 0x0341; /* 9600 baud @ 8 MHz */ USART2->CR1 = 0x0008; /* enable Tx, 8-bit data */ USART2->CR2 = 0x0000; /* 1 stop bit */ USART2->CR3 = 0x0000; /* no flow control */ USART2->CR1 |= 0x0001; /* enable USART2 */ USART2->ICR = 0x0040; /* clear TC flag */ USART2->CR1 |= 0x0040; /* enable transmit complete interrupt */ NVIC_EnableIRQ(USART2_IRQn); /* USART2 interrupt enable at NVIC */ } /* Initialize DMA1 controller * DMA1 controller's clock is enabled and also the DMA interrupt is * enabled in NVIC. */ void DMA1_init(void) { RCC->AHBENR |= 0x00000001; /* DMA controller clock enable */ DMA1->IFCR = 0x0000F000; /* clear all interrupt flags of Channel 4 */ NVIC_EnableIRQ(DMA1_Ch4_7_DMA2_Ch3_5_IRQn); /* DMA interrupt enable at NVIC */ } /* Set up a DMA transfer for USART2 * The USART2 is connected to DMA1 Channel 4. This function sets up the * peripheral register address, memory address, number of transfers, * data size, transfer direction, and DMA interrupts are enabled. * At the end, the DMA controller is enabled and the USART2 transmit * DMA is enabled. */ void DMA1_channel4_setup(unsigned int src, unsigned int dst, int len) { DMA1_Channel4->CCR &= ~1; /* disable DMA1 Channel 4 */ while (DMA1_Channel4->CCR & 1) {} /* wait until DMA1 Channel 4 is disabled */ DMA1->IFCR = 0x0000F000; /* clear all interrupt flags of Channel 4 */ DMA1_Channel4->CPAR = dst; DMA1_Channel4->CMAR = src; DMA1_Channel4->CNDTR = len; DMA1_Channel4->CCR = 0x00000090; /* data size byte, mem incr, mem-to-peripheral */ DMA1_Channel4->CCR |= 0x0000000A; /* enable interrupts DMA_IT_TC | DMA_IT_TE */ DMA1_Channel4->CCR |= 0x00000001; /* enable DMA1 Channel 4 */ USART2->ICR = 0x0040; /* clear UART transmit complete interrupt flag */ USART2->CR3 |= 0x80; /* enable USART2 transmitter DMA */ } /* DMA1 Channel 4-5-6-7 interrupt handler This function handles the interrupts from the DMA1 controller Channel4-5-6-7. The error interrupts have a placeholder for error handling code. If the interrupt is from DMA data transfer complete, the DMA controller is disabled, the interrupt flags are cleared. */ void DMA1_Channel4_5_6_7_IRQHandler(void) { if (DMA1->ISR & 0x00008000) /* if an error occurred */ while (1) {} /* substitute this by error handling */ if(DMA1->ISR & 0x0002000){ /* if channel 4 DMA completed */ DMA1->IFCR = 0x0000F000; /* clear all interrupt flags of Channel 4 */ DMA1_Channel4->CCR &= ~0x2; /* disable DMA1 Channel 1 TCIE */ } } /* USART2 interrupt handler * USART2 transmit complete interrupt is used to set the done flag to signal * the other part of the program that the data transfer is done. */ void USART2_IRQHandler(void) { USART2->ICR = 0x0040; /* clear transmit complete interrupt flag */ done = 1; /* set the done flag */ }