/** * \brief DMAC tx channel configuration. */ static void configure_dmac_tx(void) { uint32_t ul_cfg; dma_transfer_descriptor_t dmac_trans; ul_cfg = 0; ul_cfg |= DMAC_CFG_DST_PER(USART_TX_IDX) | DMAC_CFG_DST_H2SEL | DMAC_CFG_SOD_ENABLE | DMAC_CFG_FIFOCFG_ALAP_CFG; dmac_channel_set_configuration(DMAC, BOARD_USART_DMAC_TX_CH, ul_cfg); dmac_channel_disable(DMAC, BOARD_USART_DMAC_TX_CH); dmac_trans.ul_source_addr = (uint32_t) gs_puc_buffer; dmac_trans.ul_destination_addr = (uint32_t) & BOARD_USART->US_THR; dmac_trans.ul_ctrlA = DMAC_CTRLA_BTSIZE(BUFFER_SIZE) | DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE; dmac_trans.ul_ctrlB = DMAC_CTRLB_SRC_DSCR | DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_MEM2PER_DMA_FC | DMAC_CTRLB_SRC_INCR_INCREMENTING | DMAC_CTRLB_DST_INCR_FIXED; dmac_trans.ul_descriptor_addr = 0; dmac_channel_single_buf_transfer_init(DMAC, BOARD_USART_DMAC_TX_CH, &dmac_trans); dmac_channel_enable(DMAC, BOARD_USART_DMAC_TX_CH); }
/** * \brief Start DMA sending data. * * \param p_buffer Pointer to the data to be transmitted. * \param us_size Size of the data to be transmitted. */ static void ssc_dma(void *p_buffer, uint16_t us_size) { dma_transfer_descriptor_t desc; desc.ul_source_addr = (uint32_t)p_buffer; desc.ul_destination_addr = (uint32_t)(&SSC->SSC_THR); desc.ul_ctrlA = DMAC_CTRLA_BTSIZE(us_size) | DMAC_CTRLA_SRC_WIDTH_HALF_WORD | DMAC_CTRLA_DST_WIDTH_HALF_WORD; desc.ul_ctrlB = DMAC_CTRLB_SRC_DSCR_FETCH_DISABLE | DMAC_CTRLB_DST_DSCR_FETCH_DISABLE | DMAC_CTRLB_FC_MEM2PER_DMA_FC | DMAC_CTRLB_SRC_INCR_INCREMENTING | DMAC_CTRLB_DST_INCR_FIXED | DMAC_CTRLB_IEN; desc.ul_descriptor_addr = NULL; dmac_channel_single_buf_transfer_init(DMAC, DMA_CH, &desc); /* Start DMA transfer */ dmac_channel_enable(DMAC, DMA_CH); /* Enable SSC transmitter */ ssc_enable_tx(SSC); }
/** * \brief Set DMAC buffer transfer size used by a DMAC channel. * * \param pDmac Pointer to the DMAC peripheral. * \param channel Particular channel number. * \param bsize number of transfers to be performed. */ void DMAC_SetBufferSize( Dmac *pDmac, uint8_t channel, uint16_t bsize) { assert(pDmac); assert(channel < DMAC_CHANNEL_NUM); pDmac->DMAC_CH_NUM[channel].DMAC_CTRLA &= ~DMAC_CTRLA_BTSIZE_Msk; pDmac->DMAC_CH_NUM[channel].DMAC_CTRLA |= DMAC_CTRLA_BTSIZE( bsize ); }
/** * \brief Test DMA single buffer transfer with polling mode. * * \param test Current test case. */ static void run_single_buf_xfer_test(const struct test_case *test) { uint32_t i; uint32_t cfg; dma_transfer_descriptor_t desc; /* Initialize DMA buffer */ for (i = 0; i < DMA_BUF_SIZE; i++) { g_dma_buf[0][i] = i; g_dma_buf[1][i] = 0; } /* Initialize and enable DMA controller */ pmc_enable_periph_clk(ID_DMAC); dmac_init(DMAC); dmac_set_priority_mode(DMAC, DMAC_PRIORITY_ROUND_ROBIN); dmac_enable(DMAC); /* Set for channel configuration register */ cfg = DMAC_CFG_SOD_ENABLE | /* Enable stop on done */ DMAC_CFG_AHB_PROT(1) | /* Set AHB Protection */ DMAC_CFG_FIFOCFG_ALAP_CFG; /* FIFO Configuration */ dmac_channel_set_configuration(DMAC, DMA_CH, cfg); /* Initialize single buffer transfer: buffer 0 -> buffer 1 */ desc.ul_source_addr = (uint32_t) g_dma_buf[0]; desc.ul_destination_addr = (uint32_t) g_dma_buf[1]; desc.ul_ctrlA = DMAC_CTRLA_BTSIZE(DMA_BUF_SIZE) | /* Set Buffer Transfer Size */ DMAC_CTRLA_SRC_WIDTH_WORD | /* Source transfer size is set to 32-bit width */ DMAC_CTRLA_DST_WIDTH_WORD; /* Destination transfer size is set to 32-bit width */ desc.ul_ctrlB = DMAC_CTRLB_SRC_DSCR_FETCH_DISABLE | /* Buffer Descriptor Fetch operation is disabled for the source */ DMAC_CTRLB_DST_DSCR_FETCH_DISABLE | /* Buffer Descriptor Fetch operation is disabled for the destination */ DMAC_CTRLB_FC_MEM2MEM_DMA_FC | /* Memory-to-Memory Transfer */ DMAC_CTRLB_SRC_INCR_INCREMENTING | /* The source address is incremented */ DMAC_CTRLB_DST_INCR_INCREMENTING; /* The destination address is incremented */ desc.ul_descriptor_addr = 0; /* No descriptor for single transfer */ dmac_channel_single_buf_transfer_init(DMAC, DMA_CH, &desc); /* Start DMA transfer and wait for finish */ dmac_channel_enable(DMAC, DMA_CH); while (!dmac_channel_is_transfer_done(DMAC, DMA_CH)) { } /* Verify the transferred data */ for (i = 0; i < DMA_BUF_SIZE; i++) { test_assert_true(test, g_dma_buf[0][i] == g_dma_buf[1][i], "Data comparison failed."); } }
void spi_start_transmit_dma(Dmac *p_dmac, Spi *p_spi, uint32_t ul_num, const void *src, uint32_t nb_bytes) { static uint8_t ff = 0xFF; uint32_t cfg, src_incr = DMAC_CTRLB_SRC_INCR_INCREMENTING; dma_transfer_descriptor_t desc; // Send 0xFF repeatedly if src is NULL if (!src) { src = &ff; src_incr = DMAC_CTRLB_SRC_INCR_FIXED; } // Disable the DMA channel prior to configuring dmac_enable(p_dmac); dmac_channel_disable(p_dmac, ul_num); cfg = DMAC_CFG_SOD | DMAC_CFG_DST_H2SEL | DMAC_CFG_DST_PER(SPI_TX_IDX) | DMAC_CFG_FIFOCFG_ALAP_CFG; dmac_channel_set_configuration(p_dmac, ul_num, cfg); // Prepare DMA transfer desc.ul_source_addr = (uint32_t)src; desc.ul_destination_addr = (uint32_t)&(p_spi->SPI_TDR); desc.ul_ctrlA = DMAC_CTRLA_BTSIZE(nb_bytes) | DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE; desc.ul_ctrlB = DMAC_CTRLB_SRC_DSCR | DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_MEM2PER_DMA_FC | src_incr | DMAC_CTRLB_DST_INCR_FIXED; // Next field is ignored, but set it anyway desc.ul_descriptor_addr = (uint32_t)NULL; // Finish configuring the transfer dmac_channel_single_buf_transfer_init(p_dmac, ul_num, &desc); // And now start the DMA transfer dmac_channel_enable(p_dmac, ul_num); }
void spi_start_receive_dma(Dmac *p_dmac, Spi *p_spi, uint32_t ul_num, const void *dest, uint32_t nb_bytes) { uint32_t cfg; dma_transfer_descriptor_t desc; // clear any potential overrun error cfg = p_spi->SPI_SR; // Turn the DMA channel off before configuring dmac_enable(p_dmac); dmac_channel_disable(p_dmac, ul_num); cfg = DMAC_CFG_SOD | DMAC_CFG_SRC_H2SEL | DMAC_CFG_SRC_PER(SPI_RX_IDX) | DMAC_CFG_FIFOCFG_ASAP_CFG; dmac_channel_set_configuration(p_dmac, ul_num, cfg); // Prepare DMA transfer desc.ul_source_addr = (uint32_t)&(p_spi->SPI_RDR); desc.ul_destination_addr = (uint32_t)dest; desc.ul_ctrlA = DMAC_CTRLA_BTSIZE(nb_bytes) | DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE; desc.ul_ctrlB = DMAC_CTRLB_SRC_DSCR | DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_PER2MEM_DMA_FC | DMAC_CTRLB_SRC_INCR_FIXED | DMAC_CTRLB_DST_INCR_INCREMENTING; // This next field is ignored but set it anyway desc.ul_descriptor_addr = (uint32_t)NULL; // Finish configuring the DMA transfer dmac_channel_single_buf_transfer_init(p_dmac, ul_num, &desc); // And now allow the DMA transfer to begin dmac_channel_enable(p_dmac, ul_num); }
void ledUpdate(void){ volatile uint16_t* row_data; unsigned i; gpioSetVal(blanks[row], 1); if(++row == NUM_ROWS) row = 0; row_data = led_buffer + XFERS_PER_ROW * row; DMAC->DMAC_CH_NUM[DMA_CHANNEL_LEDS].DMAC_SADDR = (uint32_t)row_data; DMAC->DMAC_CH_NUM[DMA_CHANNEL_LEDS].DMAC_DADDR = (uint32_t)&SPI0->SPI_TDR; DMAC->DMAC_CH_NUM[DMA_CHANNEL_LEDS].DMAC_DSCR = 0; DMAC->DMAC_CH_NUM[DMA_CHANNEL_LEDS].DMAC_CTRLA = DMAC_CTRLA_BTSIZE(XFERS_PER_ROW) | DMAC_CTRLA_SCSIZE_CHK_16 | DMAC_CTRLA_DCSIZE_CHK_1 | DMAC_CTRLA_SRC_WIDTH_HALF_WORD | DMAC_CTRLA_DST_WIDTH_HALF_WORD; DMAC->DMAC_CH_NUM[DMA_CHANNEL_LEDS].DMAC_CTRLB = DMAC_CTRLB_FC_MEM2PER_DMA_FC | DMAC_CTRLB_SRC_INCR_INCREMENTING | DMAC_CTRLB_DST_INCR_FIXED; DMAC->DMAC_CH_NUM[DMA_CHANNEL_LEDS].DMAC_CFG = DMAC_CFG_DST_PER(1) | DMAC_CFG_SRC_PER(1) | DMAC_CFG_DST_H2SEL_HW | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ALAP_CFG; DMAC->DMAC_CHER = (1 << DMA_CHANNEL_LEDS); //wait for transfer to start while(SPI0->SPI_SR & SPI_SR_TXEMPTY); SPI0->SPI_IER = SPI_IER_TXEMPTY; }
/** * \brief Test DMA single buffer transfer with polling mode. */ static void test_single_buf_xfer(void) { //! [dmac_define_vars] uint32_t i; uint32_t cfg; dma_transfer_descriptor_t desc; //! [dmac_define_vars] printf("\n\rTest single buffer transfer...\n\r"); //! [dmac_define_prepare_buffer] /** Initialize DMA buffer */ for (i = 0; i < DMA_BUF_SIZE; i++) { g_dma_buf[0][i] = i; g_dma_buf[1][i] = 0; } //! [dmac_define_prepare_buffer] /* Initialize and enable DMA controller */ //! [dmac_init_clock] pmc_enable_periph_clk(ID_DMAC); //! [dmac_init_clock] //! [dmac_init_module] dmac_init(DMAC); //! [dmac_init_module] //! [dmac_set_priority] dmac_set_priority_mode(DMAC, DMAC_PRIORITY_ROUND_ROBIN); //! [dmac_set_priority] //! [dmac_enable_module] dmac_enable(DMAC); //! [dmac_enable_module] //! [dmac_configure_channel] /** Set for channel configuration register */ cfg = DMAC_CFG_SOD_ENABLE | /** Enable stop on done */ DMAC_CFG_AHB_PROT(1) | /** Set AHB Protection */ DMAC_CFG_FIFOCFG_ALAP_CFG; /** FIFO Configuration */ dmac_channel_set_configuration(DMAC, DMA_CH, cfg); //! [dmac_configure_channel] //! [dmac_configure_for_single_transfer_1] /** Initialize single buffer transfer: buffer 0 -> buffer 1 */ desc.ul_source_addr = (uint32_t) g_dma_buf[0]; desc.ul_destination_addr = (uint32_t) g_dma_buf[1]; //! [dmac_configure_for_single_transfer_1] /* * Set DMA CTRLA: * - Set Buffer Transfer Size * - Source transfer size is set to 32-bit width * - Destination transfer size is set to 32-bit width */ //! [dmac_configure_for_single_transfer_2] desc.ul_ctrlA = DMAC_CTRLA_BTSIZE(DMA_BUF_SIZE) | DMAC_CTRLA_SRC_WIDTH_WORD | DMAC_CTRLA_DST_WIDTH_WORD; //! [dmac_configure_for_single_transfer_2] /* * Set DMA CTRLB: * - Buffer Descriptor Fetch operation is disabled for the source * - Buffer Descriptor Fetch operation is disabled for the destination * - Memory-to-Memory Transfer * - The source address is incremented * - The destination address is incremented */ //! [dmac_configure_for_single_transfer_3] desc.ul_ctrlB = DMAC_CTRLB_SRC_DSCR_FETCH_DISABLE | DMAC_CTRLB_DST_DSCR_FETCH_DISABLE | DMAC_CTRLB_FC_MEM2MEM_DMA_FC | DMAC_CTRLB_SRC_INCR_INCREMENTING | DMAC_CTRLB_DST_INCR_INCREMENTING; //! [dmac_configure_for_single_transfer_3] /* No descriptor for single transfer */ //! [dmac_configure_for_single_transfer_4] desc.ul_descriptor_addr = 0; dmac_channel_single_buf_transfer_init(DMAC, DMA_CH, &desc); //! [dmac_configure_for_single_transfer_4] /* Start DMA transfer and wait for finish */ //! [dmac_start_transfer] dmac_channel_enable(DMAC, DMA_CH); //! [dmac_start_transfer] //! [dmac_wait_for_done] while (!dmac_channel_is_transfer_done(DMAC, DMA_CH)) { } //! [dmac_wait_for_done] /* Verify the transferred data */ for (i = 0; i < DMA_BUF_SIZE; i++) { if (g_dma_buf[0][i] != g_dma_buf[1][i]) { printf("> Test NG.\n\r"); while (1) { } } } printf("> Test OK\n\r"); }
/** * \brief Test DMA multiple buffer transfer with interrupt mode. */ static void test_multi_buf_xfer(void) { uint32_t i; uint32_t cfg; dma_transfer_descriptor_t desc[3]; printf("\n\rTest multiple buffer transfer...\n\r"); /* Initialize DMA buffer */ for (i = 0; i < DMA_BUF_SIZE; i++) { g_dma_buf[0][i] = i; g_dma_buf[1][i] = i + 10; g_dma_buf[2][i] = i + 20; g_dma_buf[3][i] = 0; g_dma_buf[4][i] = 0; g_dma_buf[5][i] = 0; } /* Initialize and enable DMA controller */ pmc_enable_periph_clk(ID_DMAC); dmac_init(DMAC); dmac_set_priority_mode(DMAC, DMAC_PRIORITY_ROUND_ROBIN); dmac_enable(DMAC); /* Set for channel configuration register */ cfg = DMAC_CFG_SOD_DISABLE | /* Disable stop on done */ DMAC_CFG_AHB_PROT(1) | /* Set AHB Protection */ DMAC_CFG_FIFOCFG_ALAP_CFG; /* FIFO Configuration */ dmac_channel_set_configuration(DMAC, 0, cfg); /* Initialize multiple buffer transfer (LLI) : * buffer 0 -> buffer 3 * buffer 1 -> buffer 4 * buffer 2 -> buffer 5 */ desc[0].ul_source_addr = (uint32_t) g_dma_buf[0]; desc[0].ul_destination_addr = (uint32_t) g_dma_buf[3]; /* * Set DMA CTRLA: * - Set Buffer Transfer Size * - Source transfer size is set to 32-bit width * - Destination transfer size is set to 32-bit width */ desc[0].ul_ctrlA = DMAC_CTRLA_BTSIZE(DMA_BUF_SIZE) | DMAC_CTRLA_SRC_WIDTH_WORD | DMAC_CTRLA_DST_WIDTH_WORD; /* * Set DMA CTRLB: * - Descriptor is fetched from the memory * - Descriptor is fetched from the memory * - Memory-to-Memory Transfer * - The source address is incremented * - The destination address is incremented */ desc[0].ul_ctrlB = DMAC_CTRLB_SRC_DSCR_FETCH_FROM_MEM | DMAC_CTRLB_DST_DSCR_FETCH_FROM_MEM | DMAC_CTRLB_FC_MEM2MEM_DMA_FC | DMAC_CTRLB_SRC_INCR_INCREMENTING | DMAC_CTRLB_DST_INCR_INCREMENTING; /* Pointer to next descriptor */ desc[0].ul_descriptor_addr = (uint32_t) &desc[1]; desc[1].ul_source_addr = (uint32_t) g_dma_buf[1]; desc[1].ul_destination_addr = (uint32_t) g_dma_buf[4]; /* * Set DMA CTRLA: * - Set Buffer Transfer Size * - Source transfer size is set to 32-bit width * - Destination transfer size is set to 32-bit width */ desc[1].ul_ctrlA = DMAC_CTRLA_BTSIZE(DMA_BUF_SIZE) | DMAC_CTRLA_SRC_WIDTH_WORD | DMAC_CTRLA_DST_WIDTH_WORD; /* * Set DMA CTRLB: * - Source descriptor is fetched from the memory * - Destination descriptor is fetched from the memory * - Memory-to-Memory Transfer * - The source address is incremented * - The destination address is incremented */ desc[1].ul_ctrlB = DMAC_CTRLB_SRC_DSCR_FETCH_FROM_MEM | DMAC_CTRLB_DST_DSCR_FETCH_FROM_MEM | DMAC_CTRLB_FC_MEM2MEM_DMA_FC | DMAC_CTRLB_SRC_INCR_INCREMENTING | DMAC_CTRLB_DST_INCR_INCREMENTING; /* Pointer to next descriptor */ desc[1].ul_descriptor_addr = (uint32_t) &desc[2]; desc[2].ul_source_addr = (uint32_t) g_dma_buf[2]; desc[2].ul_destination_addr = (uint32_t) g_dma_buf[5]; /* * Set Buffer Transfer Size * Source transfer size is set to 32-bit width * Destination transfer size is set to 32-bit width */ desc[2].ul_ctrlA = DMAC_CTRLA_BTSIZE(DMA_BUF_SIZE) | DMAC_CTRLA_SRC_WIDTH_WORD | DMAC_CTRLA_DST_WIDTH_WORD; /* * Set DMA CTRLB: * - Source descriptor is fetched from the memory * - Destination descriptor is fetched from the memory * - Memory-to-Memory Transfer * - The source address is incremented * - The destination address is incremented */ desc[2].ul_ctrlB = DMAC_CTRLB_SRC_DSCR_FETCH_FROM_MEM | DMAC_CTRLB_DST_DSCR_FETCH_FROM_MEM | DMAC_CTRLB_FC_MEM2MEM_DMA_FC | DMAC_CTRLB_SRC_INCR_INCREMENTING | DMAC_CTRLB_DST_INCR_INCREMENTING; /* The end of LLI */ desc[2].ul_descriptor_addr = 0; dmac_channel_multi_buf_transfer_init(DMAC, DMA_CH, &desc[0]); /* Set interrupt */ NVIC_EnableIRQ(DMAC_IRQn); dmac_enable_interrupt(DMAC, (DMAC_EBCIER_CBTC0 << DMA_CH)); /* Start DMA transfer and wait for finish */ g_xfer_done = 0; dmac_channel_enable(DMAC, DMA_CH); while (!g_xfer_done) { } /* Verify the transferred data */ for (i = 0; i < DMA_BUF_SIZE; i++) { if ((g_dma_buf[0][i] != g_dma_buf[3][i]) || (g_dma_buf[1][i] != g_dma_buf[4][i]) || (g_dma_buf[2][i] != g_dma_buf[5][i])) { printf("> Test NG.\n\r"); while (1) { } } } printf("> Test OK.\n\r"); }