void dma_stream_reset(u32 dma, u8 stream) { /* Disable stream (must be done before register is otherwise changed). */ DMA_SCR(dma, stream) &= ~DMA_SxCR_EN; /* Reset all config bits. */ DMA_SCR(dma, stream) = 0; /* Reset data transfer number. */ DMA_SNDTR(dma, stream) = 0; /* Reset peripheral and memory addresses. */ DMA_SPAR(dma, stream) = 0; DMA_SM0AR(dma, stream) = 0; DMA_SM1AR(dma, stream) = 0; /* This is the default setting */ DMA_SFCR(dma, stream) = 0x21; /* Reset all stream interrupt flags using the interrupt flag clear register. */ u32 mask = DMA_ISR_MASK(stream); if (stream < 4) { DMA_LIFCR(dma) |= mask; } else { DMA_HIFCR(dma) |= mask; } }
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)); }
/** 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)); }
void dma_set_peripheral_address(u32 dma, u8 stream, u32 address) { if (!(DMA_SCR(dma, stream) & DMA_SxCR_EN)) DMA_SPAR(dma, stream) = (u32 *) address; }
/******************************************************************************* * int bsp_uart_dma_init(u32 iuart, u32 baud, u32 rxbuffsize, u32 txbuffsize, u32 dmastreamrx, u32 dmastreamtx, u32 dma_tx_int_priority); * @brief : Initialize USART/UART for DMA transfers * @param : iuart: pointer to UART base, e.g. 'USART1' * @param : baud: name says it all, e.g. '921600' * @param : rxbuffsize: number of bytes in a circular tx buffer * @param : txbuffsize" number of bytes in a circular rx buffer * @param : dmastreamrx: DMA stream number for RX (0 - 7) * @param : dmastreamtx: DMA stream number for TX (0 - 7) * @param : dma_tx_int_priority: interrupt priority, (0x00 - 0xf0) e.g. 0xc0, low 4 bits zero * @return : 0 = success; fail traps to 'panic_leds' *******************************************************************************/ int bsp_uart_dma_init(u32 iuart, u32 baud, u32 rxbuffsize, u32 txbuffsize, u32 dmastreamrx, u32 dmastreamtx, u32 dma_tx_int_priority) { u32 cb_Idx; // Used "everywhere" to index into the control block array int tmp; struct UARTPINS uartpins; struct IRQNUM dma_irq_number_tx; struct IRQNUM dma_irq_number_rx; u32 dma_x; u32 dma_channel_number_rx = 4; // Initialize to prevent compiler warning u32 dma_channel_number_tx = 5; /* Be sure arguments passed are within range */ if (dmastreamrx > 7) bsp_panic(-1); if (dmastreamtx > 7) bsp_panic(-2); if ((dma_tx_int_priority & 0xffffff0f) != 0) bsp_panic(-3); // Bogus priority cb_Idx = mapindex(iuart); // Map usart/uart register base to control block index /* Convert dma stream to dma base and irq number */ dma_irq_number_tx = irq_given_datastream(iuart, dmastreamtx); // TX dma_irq_number_rx = irq_given_datastream(iuart, dmastreamrx); // RX /* The DMA determined should be the same...mostly a debugging issue. */ if (dma_irq_number_tx.dma != dma_irq_number_rx.dma) bsp_panic(-333); dma_x = dma_irq_number_tx.dma; // Lazy way of dealing with it later /* Set dma stream interrupt to revector to this routine; check if dma is in use. */ tmp = nvic_dma_stream_vector_add( (void(*)(u32*))&DMA_UART_IRQHandler, (u32*)&cb_uart[cb_Idx], dma_irq_number_tx.num, dmastreamtx); if (tmp != 0) bsp_panic(-30 + tmp); /* RX doesn't interrupt, but we need to show that the stream has been taken */ tmp = nvic_dma_stream_vector_add( (void(*)(u32*))&DMA_UART_IRQHandler, (u32*)&cb_uart[cb_Idx], dma_irq_number_rx.num, dmastreamrx); if (tmp != 0) bsp_panic(-130 + tmp); /* Load some parameters that might be important. */ cb_uart[cb_Idx].idma = dma_x; // Save dma register base address cb_uart[cb_Idx].rxdma_stream = dmastreamrx; // Save stream number cb_uart[cb_Idx].txdma_stream = dmastreamtx; // Save stream number cb_uart[cb_Idx].iuart = iuart; // Save uart register base address cb_uart[cb_Idx].flag = 2; // Show this setup for dma driven /* Find DMA channel numbers for RX and TX, given stream number */ switch (dma_x) { case DMA1_BASE: if (dma1_rxstreamtbl_4[dmastreamrx & 0x7] == iuart) {dma_channel_number_rx = 4; break;} if (dma1_rxstreamtbl_5[dmastreamrx & 0x7] == iuart) {dma_channel_number_rx = 5; break;} bsp_panic(-6); // RX stream specified is not compatible with UART/DMA1 case DMA2_BASE: if (dma2_rxstreamtbl_4[dmastreamrx & 0x7] == iuart) {dma_channel_number_rx = 4; break;} if (dma2_rxstreamtbl_5[dmastreamrx & 0x7] == iuart) {dma_channel_number_rx = 5; break;} bsp_panic(-7); // RX stream specified is not compatible with UART/DMA2 default: bsp_panic(-8); // Something seriously wrong here! } switch (dma_x) { case DMA1_BASE: if (dma1_txstreamtbl_4[dmastreamtx & 0x7] == iuart) {dma_channel_number_tx = 4; break;} if (dma1_txstreamtbl_5[dmastreamtx & 0x7] == iuart) {dma_channel_number_tx = 5; break;} if (dma1_txstreamtbl_7[dmastreamtx & 0x7] == iuart) {dma_channel_number_tx = 7; break;} bsp_panic(-9); // TX stream specified is not compatible with UART/DMA1 case DMA2_BASE: if (dma2_txstreamtbl_4[dmastreamtx & 0x7] == iuart) {dma_channel_number_tx = 4; break;} if (dma2_txstreamtbl_5[dmastreamtx & 0x7] == iuart) {dma_channel_number_tx = 5; break;} bsp_panic(-10); // TX stream specified is not compatible with UART/DMA2 default: bsp_panic(-11); // Something seriously wrong here! } static u32 qqq; qqq = dma_channel_number_rx; /* At this point we (should!) have a good DMA channel and stream that associates with the UART. */ /* Set up UART pins, port & uart clockings. THIS IS BOARD SPECIFIC */ if (uart_pins(iuart, &uartpins) != 0) bsp_panic(-15); /* Setup baud rate */ usartx_setbaud (iuart, uartpins.pclk, baud); /* Obtain some buffer space */ getbuff(cb_Idx, rxbuffsize, txbuffsize); /* ---------- Set up UART ----------------------------------------------------------------------------------- */ /* Set up CR1 ---------------------------------------------------- */ USART_CR1(iuart) |= (1<<13) | (1<<3) | (1<<2);// Set Usart enable, tx enable, rx enable /* Hook up usart tx and rx to dma channels */ USART_CR3(iuart) |= (1<<7) | (1<<6); /* Setup CR2 ------------------------------------------------------------------- */ /* After reset CR2 is 0x0000 and this is just fine */ /* --------- Set up the DMA channels ------------------------------------------------------------------------ */ /* Set peripheral address for RX */ DMA_SPAR(dma_x,dmastreamrx) = (u32*)(iuart + 0x04); // Address of uart DR register /* Set peripheral address for TX */ DMA_SPAR(dma_x,dmastreamtx) = (u32*)(iuart + 0x04); // Address of uart DR register /* DMA stream configuration register--RX p 325 */ // Channel number | MINC | CIRC | Per->Mem DMA_SCR(dma_x,dmastreamrx) = ( (dma_channel_number_rx<< 25) | (1<<10) | (1<<8) | (0x0<<6) ); /* DMA stream configuration register--TX */ // Channel number | MINC | CIRC | Mem->per | priority DMA_SCR(dma_x,dmastreamtx) = ( (dma_channel_number_tx<< 25) | (1<<10) | (0<<8) | (0x1<<6) | (1<<16)); /* Set RX memory address (stays forever) */ DMA_SM0AR(dma_x,dmastreamrx) = cb_uart[cb_Idx].rxbuff_base; /* Set the number of bytes in the RX buff */ DMA_SNDTR(dma_x,dmastreamrx) = cb_uart[cb_Idx].rxbuff_size; /* DMA for TX interrupts */ NVICIPR (dma_irq_number_tx.num,dma_tx_int_priority); // Set dma interrupt priority (tx) NVICISER(dma_irq_number_tx.num); // Enable dma interrupt (tx) /* Final enabling of DMA */ DMA_SCR(dma_x,dmastreamrx) |= (0x1); // Enable rx stream DMA_SCR(dma_x,dmastreamtx) |= ((1<<4)); // TCIE (xfer complete interrupt), not enable stream return 0; // SUCCESS! }