/* Disable and reset the SPI peripheral using the procedure outlined in the * STM32F302 Reference Manual (section 28.5.8 pg. 815) without blocking. * This function assumes that a transaction isn't currently in progress. */ static void disable_and_reset_spi_properly(void){ dma_disable_channel(DMA1, DMA_CHANNEL3); dma_disable_channel(DMA1, DMA_CHANNEL2); spi_disable(SPI3); rcc_periph_reset_pulse(RST_SPI3); DmaCleanupNeeded = false; TxSpi = false; }
// for the STM32F0, interrupts for DMA_CH4 and DMA_CH5 are combined void dma1_channel4_5_isr(void) { usart_disable_tx_dma(USART2); usart_disable_rx_dma(USART2); dma_clear_interrupt_flags(DMA1, DMA_CHANNEL4, DMA_TCIF); dma_clear_interrupt_flags(DMA1, DMA_CHANNEL5, DMA_TCIF); dma_disable_channel(DMA1, DMA_CHANNEL4); dma_disable_channel(DMA1, DMA_CHANNEL5); }
/// Processing done after rx completes. void process_rx_dma_interrupt(struct spi_periph *periph) { struct spi_periph_dma *dma = periph->init_struct; struct spi_transaction *trans = periph->trans[periph->trans_extract_idx]; /* Disable DMA Channel */ dma_disable_transfer_complete_interrupt(dma->dma, dma->rx_chan); /* Disable SPI Rx request */ spi_disable_rx_dma((uint32_t)periph->reg_addr); /* Disable DMA rx channel */ dma_disable_channel(dma->dma, dma->rx_chan); if (dma->rx_extra_dummy_dma) { /* * We are finished the first part of the receive with real data, * but still need to run the dummy to get a transfer complete interrupt * after the complete transaction is done. */ /* Reset the flag so this only happens once in a transaction */ dma->rx_extra_dummy_dma = FALSE; /* Use the difference in length between rx and tx */ uint16_t len_remaining = trans->output_length - trans->input_length; spi_configure_dma(dma->dma, dma->rx_chan, (uint32_t)dma->spidr, (uint32_t)&(dma->rx_dummy_buf), len_remaining, trans->dss, FALSE); dma_set_read_from_peripheral(dma->dma, dma->rx_chan); dma_set_priority(dma->dma, dma->rx_chan, DMA_CCR_PL_HIGH); /* Enable DMA transfer complete interrupts. */ dma_enable_transfer_complete_interrupt(dma->dma, dma->rx_chan); /* Enable DMA channels */ dma_enable_channel(dma->dma, dma->rx_chan); /* Enable SPI transfers via DMA */ spi_enable_rx_dma((uint32_t)periph->reg_addr); } else { /* * Since the receive DMA is always run until the very end * and this interrupt is triggered after the last data word was read, * we now know that this transaction is finished. */ /* Run the callback */ trans->status = SPITransSuccess; if (trans->after_cb != 0) { trans->after_cb(trans); } /* AFTER the callback, then unselect the slave if required */ if (trans->select == SPISelectUnselect || trans->select == SPIUnselect) { SpiSlaveUnselect(trans->slave_idx); } spi_next_transaction(periph); } }
/** @brief DMA2,3 callback * * callback function for DMA transfer */ void dma1_channel2_3_isr( void ) { /* after DMA transfer completed enable timer 3 overflow */ dma_clear_interrupt_flags(DMA1, DMA_CHANNEL2, DMA_TCIF); timer_enable_irq(TIM3, TIM_DIER_UIE); dma_disable_channel( DMA1, DMA_CHANNEL2); dma_disable_channel( DMA1, DMA_CHANNEL3); dma_disable_channel( DMA1, DMA_CHANNEL4); timer_disable_irq( TIM3, TIM_DIER_CC1DE); timer_disable_irq( TIM3, TIM_DIER_CC3DE); timer_disable_irq( TIM3, TIM_DIER_UDE); }
// DMA1_CHANNEL2 UART3_TX void dma1_channel2_isr(void) { if ((DMA1_ISR & DMA_ISR_TCIF2) != 0) { DMA1_IFCR |= DMA_IFCR_CTCIF2; dma_disable_transfer_complete_interrupt(DMA1, DMA_CHANNEL2); usart_disable_tx_dma(USART3); dma_disable_channel(DMA1, DMA_CHANNEL2); (*tx_done_handler)(); } }
void _USART_DMA_ISR(void) { DMA_IFCR(_USART_DMA) |= DMA_IFCR_CTCIF(_USART_DMA_CHANNEL); dma_disable_transfer_complete_interrupt(_USART_DMA, _USART_DMA_CHANNEL); usart_disable_tx_dma(_USART); dma_disable_channel(_USART_DMA, _USART_DMA_CHANNEL); busy = 0; }
void acq_pause() { gpio_clear(BANK_LED, GPIO_LED); spi_disable(SPI_C1); spi_disable_rx_dma(SPI_C1); dma_disable_transfer_complete_interrupt(DMA1, DMA_CHANNEL2); dma_disable_half_transfer_interrupt(DMA1, DMA_CHANNEL2); dma_disable_channel(DMA1, DMA_CHANNEL2); nvic_disable_irq(NVIC_DMA1_CHANNEL2_IRQ); }
/* Receive data using DMA. */ void rx_spi(void *data, uint16_t size){ if(DmaCleanupNeeded)cleanup_dma_spi(); /* This byte is sent continuously when rx_spi() receives data. */ static const uint8_t RxSpiDummyByte = 0x00; spi_enable_rx_dma(SPI3); dma_channel_reset(DMA1, DMA_CHANNEL2); dma_disable_channel(DMA1, DMA_CHANNEL2); dma_set_peripheral_address(DMA1, DMA_CHANNEL2, (uint32_t) &(SPI_DR(SPI3))); dma_set_memory_address(DMA1, DMA_CHANNEL2, (uint32_t) data); dma_set_number_of_data(DMA1, DMA_CHANNEL2, size); dma_set_priority(DMA1, DMA_CHANNEL2, DMA_CCR_PL_HIGH); dma_set_memory_size(DMA1, DMA_CHANNEL2, DMA_CCR_MSIZE_8BIT); dma_set_peripheral_size(DMA1, DMA_CHANNEL2, DMA_CCR_PSIZE_8BIT); dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL2); dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL2); dma_set_read_from_peripheral(DMA1, DMA_CHANNEL2); dma_enable_channel(DMA1, DMA_CHANNEL2); /* The SPI peripheral is driven by transmitted bytes, so dummy bytes * must be sent in order to receive data. This is accomplished with DMA * by simply not incrementing the memory address. */ dma_channel_reset(DMA1, DMA_CHANNEL3); dma_disable_channel(DMA1, DMA_CHANNEL3); dma_set_peripheral_address(DMA1, DMA_CHANNEL3, (uint32_t) &(SPI_DR(SPI3))); dma_set_memory_address(DMA1, DMA_CHANNEL3, (uint32_t) &RxSpiDummyByte); dma_set_number_of_data(DMA1, DMA_CHANNEL3, size); dma_set_priority(DMA1, DMA_CHANNEL3, DMA_CCR_PL_HIGH); dma_set_memory_size(DMA1, DMA_CHANNEL3, DMA_CCR_MSIZE_8BIT); dma_set_peripheral_size(DMA1, DMA_CHANNEL3, DMA_CCR_PSIZE_8BIT); dma_disable_memory_increment_mode(DMA1, DMA_CHANNEL3); dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL3); dma_set_read_from_memory(DMA1, DMA_CHANNEL3); dma_enable_channel(DMA1, DMA_CHANNEL3); spi_enable_tx_dma(SPI3); spi_enable(SPI3); DmaCleanupNeeded = true; }
/* Cleanup between DMA transfers. */ static void cleanup_dma_spi(void){ /* Disable SPI without resetting the peripheral. */ dma_disable_channel(DMA1, DMA_CHANNEL3); dma_disable_channel(DMA1, DMA_CHANNEL2); spi_disable(SPI3); if(TxSpi){ /* After tx_spi() completes there will be several nonsense bytes * in the RXFIFO. They must be cleared out so that they don't * corrupt a subsequent SPI read. */ uint8_t throwaway; throwaway = SPI_DR(SPI3); throwaway = SPI_DR(SPI3); throwaway = SPI_DR(SPI3); throwaway = SPI_DR(SPI3); throwaway = throwaway; /* Suppress compiler warnings. */ TxSpi = false; } spi_disable_tx_dma(SPI3); spi_disable_rx_dma(SPI3); DmaCleanupNeeded = false; }
// DMA1_CHANNEL2 UART3_RX void dma1_channel3_isr(void){ if ((DMA1_ISR & DMA_ISR_TCIF3) != 0) { DMA1_IFCR |= DMA_IFCR_CTCIF3; dma_disable_transfer_complete_interrupt(DMA1, DMA_CHANNEL3); usart_disable_rx_dma(USART3); dma_disable_channel(DMA1, DMA_CHANNEL3); gpio_set(GPIOB, GPIO_DEBUG_1); // hal_uart_manual_rts_set(); (*rx_done_handler)(); } }
/* Simultaneously transmit and receive data using DMA. */ void rxtx_spi(void *rxdata, const void *txdata, uint16_t size){ if(DmaCleanupNeeded)cleanup_dma_spi(); spi_enable_rx_dma(SPI3); dma_channel_reset(DMA1, DMA_CHANNEL2); dma_disable_channel(DMA1, DMA_CHANNEL2); dma_set_peripheral_address(DMA1, DMA_CHANNEL2, (uint32_t) &(SPI_DR(SPI3))); dma_set_memory_address(DMA1, DMA_CHANNEL2, (uint32_t) rxdata); dma_set_number_of_data(DMA1, DMA_CHANNEL2, size); dma_set_priority(DMA1, DMA_CHANNEL2, DMA_CCR_PL_HIGH); dma_set_memory_size(DMA1, DMA_CHANNEL2, DMA_CCR_MSIZE_8BIT); dma_set_peripheral_size(DMA1, DMA_CHANNEL2, DMA_CCR_PSIZE_8BIT); dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL2); dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL2); dma_set_read_from_peripheral(DMA1, DMA_CHANNEL2); dma_enable_channel(DMA1, DMA_CHANNEL2); dma_channel_reset(DMA1, DMA_CHANNEL3); dma_disable_channel(DMA1, DMA_CHANNEL3); dma_set_peripheral_address(DMA1, DMA_CHANNEL3, (uint32_t) &(SPI_DR(SPI3))); dma_set_memory_address(DMA1, DMA_CHANNEL3, (uint32_t) txdata); dma_set_number_of_data(DMA1, DMA_CHANNEL3, size); dma_set_priority(DMA1, DMA_CHANNEL3, DMA_CCR_PL_HIGH); dma_set_memory_size(DMA1, DMA_CHANNEL3, DMA_CCR_MSIZE_8BIT); dma_set_peripheral_size(DMA1, DMA_CHANNEL3, DMA_CCR_PSIZE_8BIT); dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL3); dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL3); dma_set_read_from_memory(DMA1, DMA_CHANNEL3); dma_enable_channel(DMA1, DMA_CHANNEL3); spi_enable_tx_dma(SPI3); spi_enable(SPI3); DmaCleanupNeeded = true; }
/* SPI receive completed with DMA */ void dma1_channel2_isr(void) { gpio_set(GPIOA,GPIO4); if ((DMA1_ISR &DMA_ISR_TCIF2) != 0) { DMA1_IFCR |= DMA_IFCR_CTCIF2; } dma_disable_transfer_complete_interrupt(DMA1, DMA_CHANNEL2); spi_disable_rx_dma(SPI1); dma_disable_channel(DMA1, DMA_CHANNEL2); /* Increment the status to indicate one of the transfers is complete */ transceive_status++; gpio_clear(GPIOA,GPIO4); }
/* SPI transmit completed with DMA */ void dma1_channel3_isr(void) { gpio_set(GPIOB,GPIO1); if ((DMA1_ISR &DMA_ISR_TCIF3) != 0) { DMA1_IFCR |= DMA_IFCR_CTCIF3; } dma_disable_transfer_complete_interrupt(DMA1, DMA_CHANNEL3); spi_disable_tx_dma(SPI1); dma_disable_channel(DMA1, DMA_CHANNEL3); /* If tx_len < rx_len, create a dummy transfer to clock in the remaining * rx data */ if (rx_buf_remainder > 0) { dma_channel_reset(DMA1, DMA_CHANNEL3); dma_set_peripheral_address(DMA1, DMA_CHANNEL3, (uint32_t)&SPI1_DR); dma_set_memory_address(DMA1, DMA_CHANNEL3, (uint32_t)(&dummy_tx_buf)); // Change here dma_set_number_of_data(DMA1, DMA_CHANNEL3, rx_buf_remainder); // Change here dma_set_read_from_memory(DMA1, DMA_CHANNEL3); dma_disable_memory_increment_mode(DMA1, DMA_CHANNEL3); // Change here #if USE_16BIT_TRANSFERS dma_set_peripheral_size(DMA1, DMA_CHANNEL3, DMA_CCR_PSIZE_16BIT); dma_set_memory_size(DMA1, DMA_CHANNEL3, DMA_CCR_MSIZE_16BIT); #else dma_set_peripheral_size(DMA1, DMA_CHANNEL3, DMA_CCR_PSIZE_8BIT); dma_set_memory_size(DMA1, DMA_CHANNEL3, DMA_CCR_MSIZE_8BIT); #endif dma_set_priority(DMA1, DMA_CHANNEL3, DMA_CCR_PL_HIGH); rx_buf_remainder = 0; // Clear the buffer remainder to disable this section later dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL3); dma_enable_channel(DMA1, DMA_CHANNEL3); spi_enable_tx_dma(SPI1); } else { /* Increment the status to indicate one of the transfers is complete */ transceive_status++; } gpio_clear(GPIOB,GPIO1); }
void dma_enable_channel(int channel, struct dma_request *request) { struct dma_channel_regs *regs = dma_regs [channel]; /* TODO - transfer sizes (assumes word) */ if (DMA_GET_SRC(request->source_map, channel) == DMA_INVALID) panicf ("DMA: invalid channel"); /* setup a transfer on specified channel */ dma_disable_channel (channel); if((unsigned long)request->source_addr < UNCACHED_BASE_ADDR) regs->disrc = (unsigned long)request->source_addr + UNCACHED_BASE_ADDR; else regs->disrc = (unsigned long)request->source_addr; regs->disrcc = request->source_control; if((unsigned long)request->dest_addr < UNCACHED_BASE_ADDR) regs->didst = (unsigned long)request->dest_addr + UNCACHED_BASE_ADDR; else regs->didst = (unsigned long)request->dest_addr; regs->didstc = request->dest_control; regs->dcon = request->control | request->count | DMA_GET_SRC(request->source_map, channel) * DCON_HWSRCSEL; dma_state [channel].callback = request->callback; /* Activate the channel */ invalidate_dcache_range((void *)request->dest_addr, request->count * 4); dma_state [channel].status |= STATUS_CHANNEL_ACTIVE; regs->dmasktrig = DMASKTRIG_ON; if ((request->control & DCON_HW_SEL) == 0) { /* Start DMA */ regs->dmasktrig |= DMASKTRIG_SW_TRIG; } }
void pcm_play_dma_stop(void) { is_playing = false; dma_disable_channel(0); /* Ensure byte counts read back 0 */ DMAC_CH_SRC_ADDR(0) = 0; dma_start_addr = NULL; dma_start_size = 0; dma_rem_size = 0; dma_release(); #ifdef HAVE_RECORDING if (!is_recording) bitclr32(&CGU_AUDIO, (1<<11)); #endif play_callback_pending = false; }
/// Processing done after tx completes void process_tx_dma_interrupt(struct spi_periph *periph) { struct spi_periph_dma *dma = periph->init_struct; struct spi_transaction *trans = periph->trans[periph->trans_extract_idx]; /* Disable DMA Channel */ dma_disable_transfer_complete_interrupt(dma->dma, dma->tx_chan); /* Disable SPI TX request */ spi_disable_tx_dma((uint32_t)periph->reg_addr); /* Disable DMA tx channel */ dma_disable_channel(dma->dma, dma->tx_chan); if (dma->tx_extra_dummy_dma) { /* * We are finished the first part of the transmit with real data, * but still need to clock in the rest of the receive data. * Set up a dummy dma transmit transfer to accomplish this. */ /* Reset the flag so this only happens once in a transaction */ dma->tx_extra_dummy_dma = FALSE; /* Use the difference in length between tx and rx */ uint16_t len_remaining = trans->input_length - trans->output_length; spi_configure_dma(dma->dma, dma->tx_chan, (uint32_t)dma->spidr, (uint32_t)&(dma->tx_dummy_buf), len_remaining, trans->dss, FALSE); dma_set_read_from_memory(dma->dma, dma->tx_chan); dma_set_priority(dma->dma, dma->tx_chan, DMA_CCR_PL_MEDIUM); /* Enable DMA transfer complete interrupts. */ dma_enable_transfer_complete_interrupt(dma->dma, dma->tx_chan); /* Enable DMA channels */ dma_enable_channel(dma->dma, dma->tx_chan); /* Enable SPI transfers via DMA */ spi_enable_tx_dma((uint32_t)periph->reg_addr); } }
void acq_init() { /* Initialize amplifier control GPIO */ gpio_mode_setup(BANK_AMP, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_AMP); gpio_clear(BANK_AMP, GPIO_AMP); gpio_mode_setup(BANK_LED, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_LED); gpio_clear(BANK_LED, GPIO_LED); /* Initialize SPI GPIOs */ gpio_mode_setup(BANK_CS, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_CS); gpio_mode_setup(BANK_SCLK, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_SCLK); gpio_mode_setup(BANK_DOUT, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_DOUT); gpio_set_af(BANK_CS, GPIO_AF6, GPIO_CS); gpio_set_af(BANK_SCLK, GPIO_AF6, GPIO_SCLK); gpio_set_af(BANK_DOUT, GPIO_AF6, GPIO_DOUT); rcc_periph_clock_enable(RCC_SPI3); acq_spi_init(SPI_C1); rcc_periph_clock_enable(RCC_DMA1); dma_channel_reset(DMA1, DMA_CHANNEL2); dma_disable_channel(DMA1, DMA_CHANNEL2); dma_set_peripheral_address(DMA1, DMA_CHANNEL2, (uint32_t)&SPI_DR(SPI_C1)); dma_set_memory_address(DMA1, DMA_CHANNEL2, (uint32_t)&acq_channel.buff); dma_set_number_of_data(DMA1, DMA_CHANNEL2, BUFFER_SIZE); dma_set_priority(DMA1, DMA_CHANNEL2, DMA_CCR_PL_MEDIUM); dma_set_memory_size(DMA1, DMA_CHANNEL2, DMA_CCR_MSIZE_16BIT); dma_set_peripheral_size(DMA1, DMA_CHANNEL2, DMA_CCR_PSIZE_16BIT); dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL2); dma_set_read_from_peripheral(DMA1, DMA_CHANNEL2); dma_enable_circular_mode(DMA1, DMA_CHANNEL2); nvic_set_priority(NVIC_DMA1_CHANNEL2_IRQ, PRIO_ACQ); }
static void ResetDMA() { dma_disable_channel(DMA1, TERM_USART_DMACHAN); dma_set_number_of_data(DMA1, TERM_USART_DMACHAN, TERM_BUFSIZE); dma_enable_channel(DMA1, TERM_USART_DMACHAN); }
int main(void) { /* Exactly 20 bytes including '0' at the end. We want to transfer 32bit * 5 so it should fit */ char s1[20] = "Hello STM MEM2MEM\r\n"; char s2[20]; rcc_clock_setup_in_hse_16mhz_out_72mhz(); gpio_setup(); usart_setup(); gpio_clear(GPIOB, GPIO7); /* LED1 on */ gpio_set(GPIOB, GPIO6); /* LED2 off */ my_usart_print_string(USART1, "s1 "); my_usart_print_string(USART1, s1); rcc_peripheral_enable_clock(&RCC_AHBENR, RCC_AHBENR_DMA1EN); /* MEM2MEM mode for channel 1. */ dma_enable_mem2mem_mode(DMA1, DMA_CHANNEL1); /* Highest priority. */ dma_set_priority(DMA1, DMA_CHANNEL1, DMA_CCR1_PL_VERY_HIGH); /* 32Bit wide transfer for source and destination. */ dma_set_memory_size(DMA1, DMA_CHANNEL1, DMA_CCR1_MSIZE_32BIT); dma_set_peripheral_size(DMA1, DMA_CHANNEL1, DMA_CCR1_PSIZE_32BIT); /* After each 32Bit we have to increase the addres because we use RAM. */ dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL1); dma_enable_peripheral_increment_mode(DMA1, DMA_CHANNEL1); /* We define the source as peripheral. */ dma_set_read_from_peripheral(DMA1, DMA_CHANNEL1); /* We want to transfer string s1. */ dma_set_peripheral_address(DMA1, DMA_CHANNEL1, (u32) &s1); /* Destination should be string s2. */ dma_set_memory_address(DMA1, DMA_CHANNEL1, (u32) &s2); /* Set number of DATA to transfer. Remember that this means not necessary bytes but MSIZE or PSIZE depending from your source device. */ dma_set_number_of_data(DMA1, DMA_CHANNEL1, 5); /* Start DMA transfer. */ dma_enable_channel(DMA1, DMA_CHANNEL1); /* TODO: write a function to get the interrupt flags. */ while(!(DMA_ISR(DMA1) & 0x0000001)) { } dma_disable_channel(DMA1, DMA_CHANNEL1); /* String s1 should now already be transferred to s2. */ my_usart_print_string(USART1, "s2 "); my_usart_print_string(USART1, s2); gpio_clear(GPIOB, GPIO6); /* LED2 on */ while(1); /* Halt. */ return 0; }