/** Setup the USART for recieve with DMA. This function sets up the DMA * controller and additional USART parameters for DMA receive. The USART must * first be configured using \ref usart_setup_common. */ void usart_rx_dma_setup(void) { /* Set up the USART1 RX DMA and interrupts. */ /* Enable clock to DMA peripheral. */ RCC_AHB1ENR |= RCC_AHB1ENR_DMA2EN; /* Enable RX DMA on the USART. */ usart_enable_rx_dma(USART1); /* USART1 RX - DMA2, stream 5, channel 4. */ /* Make sure stream is disabled to start. */ DMA2_S5CR &= ~DMA_SxCR_EN; DMA2_S5CR = 0; /* Configure the DMA controller. */ /* Error interrupts. */ DMA2_S5CR = DMA_SxCR_DMEIE | DMA_SxCR_TEIE | /* Transfer complete interrupt. */ DMA_SxCR_TCIE | /* Enable circular buffer mode. */ DMA_SxCR_CIRC | DMA_SxCR_DIR_PERIPHERAL_TO_MEM | /* Increment the memory address after each transfer. */ DMA_SxCR_MINC | /* 8 bit transfers from USART peripheral. */ DMA_SxCR_PSIZE_8BIT | /* and to memory. */ DMA_SxCR_MSIZE_8BIT | /* Low priority. */ DMA_SxCR_PL_LOW | /* The channel selects which request line will trigger a * transfer. In this case, channel 4 = UART1_RX * (see CD00225773.pdf Table 23). */ DMA_SxCR_CHSEL(4); /* Transfer up the the length of the buffer. */ DMA2_S5NDTR = USART_RX_BUFFER_LEN; DMA2_S5PAR = &USART1_DR; /* DMA from the USART1 data register. */ DMA2_S5M0AR = rx_buff; /* to the rx_buff. */ // TODO: Investigate more about the best FIFO settings. DMA2_S5FCR = DMA_SxFCR_DMDIS | /* Enable DMA stream FIFO. */ DMA_SxFCR_FTH_2_4_FULL | /* Trigger level 1/2 full. */ DMA_SxFCR_FEIE; /* Enable FIFO error interrupt. */ rx_rd = 0; /* Buffer is empty to begin with. */ rd_wraps = wr_wraps = 0; /* Enable DMA2 Stream 5 (RX) interrupts with the NVIC. */ nvic_enable_irq(NVIC_DMA2_STREAM5_IRQ); /* Enable the DMA channel. */ DMA2_S5CR |= DMA_SxCR_EN; }
/** Setup the USART for transmission with DMA. This function sets up the DMA * controller and additional USART parameters for DMA transmission. The USART * must first be configured using \ref usart_setup_common. */ void usart_tx_dma_setup(void) { /* Set up the USART1 TX DMA and interrupts. */ /* Enable clock to DMA peripheral. */ RCC_AHB1ENR |= RCC_AHB1ENR_DMA2EN; /* Enable TX DMA on the USART. */ usart_enable_tx_dma(USART1); /* USART1 TX - DMA2, stream 7, channel 4 */ /* Make sure stream is disabled to start. */ DMA2_S7CR &= ~DMA_SxCR_EN; DMA2_S7CR = 0; /* Configure the DMA controller. */ /* Error interrupts. */ DMA2_S7CR = DMA_SxCR_DMEIE | DMA_SxCR_TEIE | /* Transfer complete interrupt. */ DMA_SxCR_TCIE | DMA_SxCR_DIR_MEM_TO_PERIPHERAL | /* Increment the memory address after each transfer. */ DMA_SxCR_MINC | /* 8 bit transfers to USART peripheral. */ DMA_SxCR_PSIZE_8BIT | /* and from memory. */ DMA_SxCR_MSIZE_8BIT | /* Low priority. */ DMA_SxCR_PL_LOW | /* The channel selects which request line will trigger a * transfer. In this case, channel 4 = UART1_TX * (see CD00225773.pdf Table 23). */ DMA_SxCR_CHSEL(4); /* For now, don't transfer any number of datas (will be set in the initiating * function). */ DMA2_S7NDTR = 0; DMA2_S7PAR = &USART1_DR; /* DMA into the USART1 data register. */ DMA2_S7M0AR = buff; /* from the buff. */ /* TODO: Investigate more about the best FIFO settings. */ DMA2_S7FCR = DMA_SxFCR_DMDIS | /* Enable DMA stream FIFO. */ DMA_SxFCR_FTH_2_4_FULL | /* Trigger level 1/2 full. */ DMA_SxFCR_FEIE; /* Enable FIFO error interrupt. */ wr = rd = 0; /* Buffer is empty to begin with. */ /* Enable DMA2 Stream 7 (TX) interrupts with the NVIC. */ nvic_enable_irq(NVIC_DMA2_STREAM7_IRQ); }
static void spi_dma_setup_rx(uint32_t spi, uint32_t dma, u8 stream, u8 channel) { spi_enable_rx_dma(spi); /* Make sure stream is disabled to start. */ DMA_SCR(dma, stream) &= ~DMA_SxCR_EN; /* RM0090 - 9.3.17 : Supposed to wait until enable bit reads '0' before we * write to registers. */ while (DMA_SCR(dma, stream) & DMA_SxCR_EN) ; /* RM0090 - 9.3.17 : Supposed to clear any interrupts in DMA status register * before we reconfigure registers. */ dma_clear_interrupt_flags(dma, stream, DMA_ISR_FLAGS); /* Configure the DMA controller. */ DMA_SCR(dma, stream) = 0; DMA_SCR(dma, stream) = /* Error interrupts. */ DMA_SxCR_DMEIE | DMA_SxCR_TEIE | DMA_SxCR_DIR_PERIPHERAL_TO_MEM | /* Enable DMA transfer complete interrupt */ DMA_SxCR_TCIE | /* Increment the memory address after each transfer. */ DMA_SxCR_MINC | /* 8 bit transfers from SPI peripheral. */ DMA_SxCR_PSIZE_8BIT | /* and to memory. */ DMA_SxCR_MSIZE_8BIT | /* Low priority. */ DMA_SxCR_PL_VERY_HIGH | /* The channel selects which request line will trigger a transfer. * (see CD00225773.pdf Table 23). */ DMA_SxCR_CHSEL(channel); /* Transfer up to the length of the buffer. */ DMA_SNDTR(dma, stream) = 0; /* DMA from the SPI data register... */ DMA_SPAR(dma, stream) = &SPI_DR(spi); /* Enable DMA interrupts for this stream with the NVIC. */ if (dma == DMA1) nvicEnableVector(dma_irq_lookup[0][stream], CORTEX_PRIORITY_MASK(CORTEX_MAX_KERNEL_PRIORITY+2)); else if (dma == DMA2) nvicEnableVector(dma_irq_lookup[1][stream], CORTEX_PRIORITY_MASK(CORTEX_MAX_KERNEL_PRIORITY+2)); }
static void spi_dma_setup_tx(uint32_t spi, uint32_t dma, u8 stream, u8 channel) { spi_enable_tx_dma(spi); /* Make sure stream is disabled to start. */ DMA_SCR(dma, stream) &= ~DMA_SxCR_EN; /* Configure the DMA controller. */ DMA_SCR(dma, stream) = 0; DMA_SCR(dma, stream) = /* Error interrupts. */ DMA_SxCR_DMEIE | DMA_SxCR_TEIE | DMA_SxCR_DIR_MEM_TO_PERIPHERAL | /* Increment the memory address after each transfer. */ DMA_SxCR_MINC | /* 8 bit transfers from SPI peripheral. */ DMA_SxCR_PSIZE_8BIT | /* and to memory. */ DMA_SxCR_MSIZE_8BIT | /* Low priority. */ DMA_SxCR_PL_VERY_HIGH | /* The channel selects which request line will trigger a transfer. * (see CD00225773.pdf Table 23). */ DMA_SxCR_CHSEL(channel); /* Transfer up to the length of the buffer. */ DMA_SNDTR(dma, stream) = 0; /* DMA from the SPI data register... */ DMA_SPAR(dma, stream) = &SPI_DR(spi); /* Enable DMA interrupts for this stream with the NVIC. */ if (dma == DMA1) nvicEnableVector(dma_irq_lookup[0][stream], CORTEX_PRIORITY_MASK(CORTEX_MAX_KERNEL_PRIORITY+2)); else if (dma == DMA2) nvicEnableVector(dma_irq_lookup[1][stream], CORTEX_PRIORITY_MASK(CORTEX_MAX_KERNEL_PRIORITY+2)); }
void init_usart(void) { usart_t *usart1 = get_usart(1); *RCC_APB2ENR |= RCC_APB2ENR_USART1EN; /* Enable USART1 Clock */ *RCC_AHB1ENR |= RCC_AHB1ENR_GPIOBEN; /* Enable GPIOB Clock */ /* Set PB6 and PB7 to alternative function USART * See stm32f4_ref.pdf pg 141 and stm32f407.pdf pg 51 */ /* PB6 */ gpio_moder(GPIOB, 6, GPIO_MODER_ALT); gpio_afr(GPIOB, 6, GPIO_AF_USART13); gpio_otyper(GPIOB, 6, GPIO_OTYPER_PP); gpio_pupdr(GPIOB, 6, GPIO_PUPDR_NONE); gpio_ospeedr(GPIOB, 6, GPIO_OSPEEDR_50M); /* PB7 */ gpio_moder(GPIOB, 7, GPIO_MODER_ALT); gpio_afr(GPIOB, 7, GPIO_AF_USART13); gpio_otyper(GPIOB, 7, GPIO_OTYPER_PP); gpio_pupdr(GPIOB, 7, GPIO_PUPDR_NONE); gpio_ospeedr(GPIOB, 7, GPIO_OSPEEDR_50M); /* Enable USART1 */ usart1->CR1 |= USART_CR1_UE; /* 8 data bits */ usart1->CR1 &= ~(1 << 12); /* 1 stop bit */ usart1->CR2 &= ~(3 << 12); /** DMA set up **/ /* DMA2, Stream 2, Channel 4 is USART1_RX * DMA2, Stream 7, Channel 4 is USART1_TX */ usart1->CR3 |= USART_CR3_DMAR | USART_CR3_DMAT; /* Enable DMA2 clock */ *RCC_AHB1ENR |= RCC_AHB1ENR_DMA2EN; *RCC_AHB1ENR |= RCC_AHB1ENR_DMA1EN; /* Clear configuration registers enable bits and wait for them to be ready */ *DMA2_CR_S(2) &= ~(DMA_SxCR_EN); *DMA2_CR_S(7) &= ~(DMA_SxCR_EN); while ( (*DMA2_CR_S(2) & DMA_SxCR_EN) || (*DMA2_CR_S(7) & DMA_SxCR_EN) ); /* Select channel 4 */ *DMA2_CR_S(2) |= DMA_SxCR_CHSEL(4); *DMA2_CR_S(7) |= DMA_SxCR_CHSEL(4); /* Peripheral address - Both use USART data register */ *DMA2_PAR_S(2) = (uint32_t) &usart1->DR; /* RX */ *DMA2_PAR_S(7) = (uint32_t) &usart1->DR; /* TX */ /* * Allocate buffer memory. * This must be allocated because static data goes into * CCMRAM on STM32F4 implementation, and the bus matrix * does not connect CCMRAM to the DMA engine. Thus, it * is allocated from user heap to ensure it is accessible * by DMA */ usart_rx_buf = (char *) malloc(USART_DMA_MSIZE); usart_tx_buf = (char *) malloc(USART_DMA_MSIZE); if ((usart_rx_buf == NULL) || (usart_tx_buf == NULL)) { panic(); } else { /* Clear buffers */ memset(usart_rx_buf, 0, USART_DMA_MSIZE); memset(usart_tx_buf, 0, USART_DMA_MSIZE); *DMA2_M0AR_S(2) = (uint32_t) usart_rx_buf; *DMA2_M0AR_S(7) = (uint32_t) usart_tx_buf; } /* Number of data items to be transferred */ *DMA2_NDTR_S(2) = (uint16_t) USART_DMA_MSIZE; /* FIFO setup */ *DMA2_FCR_S(7) |= DMA_SxFCR_FTH_4 | DMA_SxFCR_DMDIS; /* Data direct, memory increment, high priority, memory burst */ *DMA2_CR_S(2) |= DMA_SxCR_DIR_PM | DMA_SxCR_MINC | DMA_SxCR_PL_HIGH | DMA_SxCR_CIRC; *DMA2_CR_S(7) |= DMA_SxCR_DIR_MP | DMA_SxCR_MINC | DMA_SxCR_PL_HIGH | DMA_SxCR_MBURST_4; /* Enable DMAs */ *DMA2_CR_S(2) |= DMA_SxCR_EN; /** DMA End **/ /* Set baud rate */ usart1->BRR = usart_baud(115200); /* Enable reciever and transmitter */ usart1->CR1 |= USART_CR1_RE; usart1->CR1 |= USART_CR1_TE; usart_ready = 1; }
/** Setup the USART for receive with DMA. * This function sets up the DMA controller and additional USART parameters for * DMA receive. The USART must already be configured for normal operation. * * \param s The USART DMA state structure. * \oaram usart The USART base address. * \param dma The DMA controller base address. * \param stream The DMA stream number to use. * \param channel The DMA channel to use. The stream and channel must * correspond to a USART RX channel. */ void usart_rx_dma_setup(usart_rx_dma_state* s, u32 usart, u32 dma, u8 stream, u8 channel) { s->dma = dma; s->usart = usart; s->stream = stream; s->channel = channel; chBSemInit(&s->ready_sem, TRUE); s->byte_counter = 0; s->last_byte_ticks = chTimeNow(); /* Enable clock to DMA peripheral. */ if (dma == DMA1) RCC_AHB1ENR |= RCC_AHB1ENR_DMA1EN; else if (dma == DMA2) RCC_AHB1ENR |= RCC_AHB1ENR_DMA2EN; /* Enable RX DMA on the USART. */ usart_enable_rx_dma(usart); /* Make sure stream is disabled to start. */ DMA_SCR(dma, stream) &= ~DMA_SxCR_EN; /* RM0090 - 9.3.17 : Supposed to wait until enable bit reads '0' before we * write to registers. */ while (DMA_SCR(dma, stream) & DMA_SxCR_EN) ; /* RM0090 - 9.3.17 : Supposed to clear any interrupts in DMA status register * before we reconfigure registers. */ dma_clear_interrupt_flags(dma, stream, DMA_ISR_FLAGS); /* Configure the DMA controller. */ DMA_SCR(dma, stream) = 0; DMA_SCR(dma, stream) = /* Error interrupts. */ DMA_SxCR_DMEIE | DMA_SxCR_TEIE | /* Transfer complete interrupt. */ DMA_SxCR_TCIE | /* Enable circular buffer mode. */ DMA_SxCR_CIRC | DMA_SxCR_DIR_PERIPHERAL_TO_MEM | /* Increment the memory address after each transfer. */ DMA_SxCR_MINC | /* 8 bit transfers from USART peripheral. */ DMA_SxCR_PSIZE_8BIT | /* and to memory. */ DMA_SxCR_MSIZE_8BIT | /* Low priority. */ DMA_SxCR_PL_LOW | /* The channel selects which request line will trigger a transfer. * (see CD00225773.pdf Table 23). */ DMA_SxCR_CHSEL(channel); /* Transfer up to the length of the buffer. */ DMA_SNDTR(dma, stream) = USART_RX_BUFFER_LEN; /* DMA from the USART data register... */ DMA_SPAR(dma, stream) = &USART_DR(usart); /* ...to the RX buffer. */ DMA_SM0AR(dma, stream) = s->buff; /* Buffer is empty to begin with. */ s->rd = 0; s->rd_wraps = s->wr_wraps = 0; /* Enable DMA interrupts for this stream with the NVIC. */ if (dma == DMA1) nvicEnableVector(dma_irq_lookup[0][stream], CORTEX_PRIORITY_MASK(USART_DMA_ISR_PRIORITY)); else if (dma == DMA2) nvicEnableVector(dma_irq_lookup[1][stream], CORTEX_PRIORITY_MASK(USART_DMA_ISR_PRIORITY)); /* These reads clear error flags before enabling DMA */ (void)USART_SR(usart); (void)USART_DR(usart); /* Enable the DMA channel. */ DMA_SCR(dma, stream) |= DMA_SxCR_EN; }
/** Setup the USART for transmission with DMA. * This function sets up the DMA controller and additional USART parameters for * DMA transmit. The USART must already be configured for normal operation. * * \param s The USART DMA state structure. * \oaram usart The USART base address. * \param dma The DMA controller base address. * \param stream The DMA stream number to use. * \param channel The DMA channel to use. The stream and channel must * correspond to a USART RX channel. */ void usart_tx_dma_setup(usart_tx_dma_state* s, u32 usart, u32 dma, u8 stream, u8 channel) { s->dma = dma; s->usart = usart; s->stream = stream; s->channel = channel; s->byte_counter = 0; s->last_byte_ticks = chTimeNow(); /* Enable clock to DMA peripheral. */ if (dma == DMA1) RCC_AHB1ENR |= RCC_AHB1ENR_DMA1EN; else if (dma == DMA2) RCC_AHB1ENR |= RCC_AHB1ENR_DMA2EN; /* Enable TX DMA on the USART. */ usart_enable_tx_dma(usart); /* Make sure stream is disabled to start. */ DMA_SCR(dma, stream) &= ~DMA_SxCR_EN; /* Configure the DMA controller. */ DMA_SCR(dma, stream) = 0; DMA_SCR(dma, stream) = /* Error interrupts. */ DMA_SxCR_DMEIE | DMA_SxCR_TEIE | /* Transfer complete interrupt. */ DMA_SxCR_TCIE | DMA_SxCR_DIR_MEM_TO_PERIPHERAL | /* Increment the memory address after each transfer. */ DMA_SxCR_MINC | /* 4 bytes written to the FIFO from memory at a time */ DMA_SxCR_MBURST_INCR4 | /* 8 bit transfers from USART peripheral. */ DMA_SxCR_PSIZE_8BIT | /* and to memory. */ DMA_SxCR_MSIZE_8BIT | /* TODO: what priority level is necessary? */ /* Very high priority. */ DMA_SxCR_PL_VERY_HIGH | /* The channel selects which request line will trigger a transfer. * (see CD00225773.pdf Table 23). */ DMA_SxCR_CHSEL(channel); /* For now, don't transfer any number of datas * (will be set in the initiating function). */ DMA_SNDTR(dma, stream) = 0; /* DMA into the USART data register... */ DMA_SPAR(dma, stream) = &USART_DR(usart); /* ...from the TX buffer. */ DMA_SM0AR(dma, stream) = s->buff; /* TODO: Investigate more about the best FIFO settings. */ DMA_SFCR(dma, stream) = DMA_SxFCR_DMDIS | /* Enable DMA stream FIFO. */ DMA_SxFCR_FTH_2_4_FULL | /* Trigger level 2/4 full. */ DMA_SxFCR_FEIE; /* Enable FIFO error interrupt. */ s->wr = s->rd = 0; /* Buffer is empty to begin with. */ /* Enable DMA interrupts for this stream with the NVIC. */ if (dma == DMA1) nvicEnableVector(dma_irq_lookup[0][stream], CORTEX_PRIORITY_MASK(USART_DMA_ISR_PRIORITY)); else if (dma == DMA2) nvicEnableVector(dma_irq_lookup[1][stream], CORTEX_PRIORITY_MASK(USART_DMA_ISR_PRIORITY)); }