void TBlockingSpiDmaJob::Run() { TaskId = TScheduler::GetCurrentTaskId(); CurrentJob = this; const uint32_t spi = FLASH_SPI_CHANNEL; const uint32_t dma = DMA1; assert(SPI_SR(spi) & SPI_SR_TXE); assert(~SPI_SR(spi) & SPI_SR_BSY); assert(!(SPI_SR(spi) & SPI_SR_RXNE)); { const uint32_t channel = FLASH_DMA_TX_CHANNEL; dma_channel_reset(dma, channel); dma_set_peripheral_address(dma, channel, reinterpret_cast<uint32_t>(&SPI_DR(spi))); dma_set_memory_address(dma, channel, reinterpret_cast<uint32_t>(Out)); dma_set_number_of_data(dma, channel, Len); dma_set_read_from_memory(dma, channel); dma_enable_memory_increment_mode(dma, channel); dma_set_peripheral_size(dma, channel, DMA_CCR_PSIZE_8BIT); dma_set_memory_size(dma, channel, DMA_CCR_MSIZE_8BIT); dma_set_priority(dma, channel, DMA_CCR_PL_LOW); // dma_enable_transfer_complete_interrupt(dma, channel); dma_enable_channel(dma, channel); } { const uint32_t channel = FLASH_DMA_RX_CHANNEL; dma_channel_reset(dma, channel); dma_set_peripheral_address(dma, channel, reinterpret_cast<uint32_t>(&SPI_DR(spi))); dma_set_number_of_data(dma, channel, Len); if (In != 0) { dma_set_memory_address(dma, channel, reinterpret_cast<uint32_t>(In)); dma_enable_memory_increment_mode(dma, channel); } else { dma_set_memory_address(dma, channel, reinterpret_cast<uint32_t>(&DummyPosition)); } dma_set_peripheral_size(dma, channel, DMA_CCR_PSIZE_8BIT); dma_set_memory_size(dma, channel, DMA_CCR_MSIZE_8BIT); dma_set_priority(dma, channel, DMA_CCR_PL_LOW); dma_enable_transfer_complete_interrupt(dma, channel); dma_enable_channel(dma, channel); } // Kick off the transfer spi_enable_rx_dma(spi); spi_enable_tx_dma(spi); // Wait for completion TScheduler::BlockUntil(&Finished); }
void spi_start(void) { /* Reset flash chip */ gpio_clear(GPIOD, BL_SPI2_RST); wait(10); gpio_set(GPIOD, BL_SPI2_RST); wait(10); gpio_set(GPIOD, BL_SPI2_WP); /* No WriteProtect, Set Chip select to 1(no select) */ gpio_set(GPIOB, BL_SPI2_NSS); /* Reset and disable SPI */ spi_reset(SPI2); /* Disable I2S */ SPI2_I2SCFGR = 0; /* CR1 */ spi_set_clock_phase_0(SPI2); /* CPHA = 0 */ spi_set_clock_polarity_0(SPI2); /* CPOL = 0 */ spi_send_msb_first(SPI2); /* LSB = 0 */ spi_set_full_duplex_mode(SPI2); /* RXONLY = 0 */ spi_set_unidirectional_mode(SPI2); /* BIDI = 0 */ spi_enable_software_slave_management(SPI2); /* SSM = 1 */ spi_set_nss_high(SPI2); /* SSI = 1 */ spi_set_master_mode(SPI2); /* MSTR = 1 */ spi_set_dff_8bit(SPI2); /* DFf = 8 bit */ // spi_enable_crc(SPI2); /* XXX: Too fast? Maybe DIV_4 will be better? */ spi_set_baudrate_prescaler(SPI2, SPI_CR1_BR_FPCLK_DIV_2); /* CR2 */ spi_enable_ss_output(SPI2); /* SSOE = 1 */ /* Disable regular interrupt flags */ spi_disable_tx_buffer_empty_interrupt(SPI2); spi_disable_rx_buffer_not_empty_interrupt(SPI2); spi_disable_error_interrupt(SPI2); /* Enabling RX/TX DMA flags */ spi_enable_tx_dma(SPI2); spi_enable_rx_dma(SPI2); d_print("REG: %lu:%lu\r\n", SPI_CR1(SPI2), SPI_CR2(SPI2)); spi_enable(SPI2); }
/* 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); }
/* 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; }
/// 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); } }
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)); }
/* Transmit data using DMA. */ void tx_spi(const void *data, uint16_t size){ if(DmaCleanupNeeded)cleanup_dma_spi(); 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) data); 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); TxSpi = true; DmaCleanupNeeded = true; }
void tim4_isr() { timer_clear_flag(TIM4, TIM_SR_UIF); cm3_assert(state == IDLE); state = READING; select_slave(); dma_clear_interrupt_flags(DMA1, DMA_CHANNEL1, 0xf); dma_clear_interrupt_flags(DMA1, DMA_CHANNEL2, 0xf); dma_set_memory_address(DMA1, DMA_CHANNEL1, (uint32_t) txstr); dma_set_number_of_data(DMA1, DMA_CHANNEL1, 10); dma_set_memory_address(DMA1, DMA_CHANNEL2, (uint32_t) rxbuf); dma_set_number_of_data(DMA1, DMA_CHANNEL2, 10); spi_enable_tx_dma(SPI2); spi_enable_rx_dma(SPI2); dma_enable_channel(DMA1, DMA_CHANNEL1); dma_enable_channel(DMA1, DMA_CHANNEL2); }
/** * Start a new transaction with DMA. */ static void spi_start_dma_transaction(struct spi_periph* periph, struct spi_transaction* trans) { struct spi_periph_dma *dma; uint8_t sig = 0x00; /* Store local copy to notify of the results */ trans->status = SPITransRunning; periph->status = SPIRunning; dma = periph->init_struct; /* * Check if we need to reconfigure the spi peripheral for this transaction */ sig = get_transaction_signature(trans); if (sig != dma->comm_sig) { /* A different config is required in this transaction... */ set_comm_from_transaction(&(dma->comm), trans); /* remember the new conf signature */ dma->comm_sig = sig; /* apply the new configuration */ spi_disable((uint32_t)periph->reg_addr); spi_init_master((uint32_t)periph->reg_addr, dma->comm.br, dma->comm.cpol, dma->comm.cpha, dma->comm.dff, dma->comm.lsbfirst); spi_enable_software_slave_management((uint32_t)periph->reg_addr); spi_set_nss_high((uint32_t)periph->reg_addr); spi_enable((uint32_t)periph->reg_addr); } /* * Select the slave after reconfiguration of the peripheral */ if (trans->select == SPISelectUnselect || trans->select == SPISelect) { SpiSlaveSelect(trans->slave_idx); } /* Run the callback AFTER selecting the slave */ if (trans->before_cb != 0) { trans->before_cb(trans); } /* * Receive DMA channel configuration ---------------------------------------- * * We always run the receive DMA until the very end! * This is done so we can use the transfer complete interrupt * of the RX DMA to signal the end of the transaction. * * If we want to receive less than we transmit, a dummy buffer * for the rx DMA is used after for the remaining data. * * In the transmit only case (input_length == 0), * the dummy is used right from the start. */ if (trans->input_length == 0) { /* run the dummy rx dma for the complete transaction length */ spi_configure_dma(dma->dma, dma->rx_chan, (uint32_t)dma->spidr, (uint32_t)&(dma->rx_dummy_buf), trans->output_length, trans->dss, FALSE); } else { /* run the real rx dma for input_length */ spi_configure_dma(dma->dma, dma->rx_chan, (uint32_t)dma->spidr, (uint32_t)trans->input_buf, trans->input_length, trans->dss, TRUE); /* use dummy rx dma for the rest */ if (trans->output_length > trans->input_length) { /* Enable use of second dma transfer with dummy buffer (cleared in ISR) */ dma->rx_extra_dummy_dma = TRUE; } } dma_set_read_from_peripheral(dma->dma, dma->rx_chan); dma_set_priority(dma->dma, dma->rx_chan, DMA_CCR_PL_VERY_HIGH); /* * Transmit DMA channel configuration --------------------------------------- * * We always run the transmit DMA! * To receive data, the clock must run, so something has to be transmitted. * If needed, use a dummy DMA transmitting zeros for the remaining length. * * In the reveive only case (output_length == 0), * the dummy is used right from the start. */ if (trans->output_length == 0) { spi_configure_dma(dma->dma, dma->tx_chan, (uint32_t)dma->spidr, (uint32_t)&(dma->tx_dummy_buf), trans->input_length, trans->dss, FALSE); } else { spi_configure_dma(dma->dma, dma->tx_chan, (uint32_t)dma->spidr, (uint32_t)trans->output_buf, trans->output_length, trans->dss, TRUE); if (trans->input_length > trans->output_length) { /* Enable use of second dma transfer with dummy buffer (cleared in ISR) */ dma->tx_extra_dummy_dma = TRUE; } } 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->rx_chan); dma_enable_transfer_complete_interrupt(dma->dma, dma->tx_chan); /* Enable DMA channels */ dma_enable_channel(dma->dma, dma->rx_chan); dma_enable_channel(dma->dma, dma->tx_chan); /* Enable SPI transfers via DMA */ spi_enable_rx_dma((uint32_t)periph->reg_addr); spi_enable_tx_dma((uint32_t)periph->reg_addr); }
void codecInit(void) { memset(adcBuffer, 0xaa, sizeof(adcBuffer)); // I2S2 alternate function mapping gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO12 | GPIO13 | GPIO14 | GPIO15); gpio_set_af(GPIOB, GPIO_AF5, GPIO12 | GPIO13 | GPIO15); gpio_set_af(GPIOB, GPIO_AF6, GPIO14); // I2S2ext_SD (I2S receive) gpio_mode_setup(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO6); gpio_set_af(GPIOC, GPIO_AF5, GPIO6); // MCLK gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO12 | GPIO13 | GPIO15); gpio_set_output_options(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, GPIO6); // Set up SPI1 spi_reset(SPI1); spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_256, SPI_CR1_CPOL_CLK_TO_1_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_2, SPI_CR1_DFF_16BIT, SPI_CR1_MSBFIRST); spi_set_nss_high(SPI1); spi_enable_software_slave_management(SPI1); spi_enable(SPI1); // SPI1 alternate function mapping, set CSB signal high output gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO5 | GPIO7); gpio_set_af(GPIOA, GPIO_AF5, GPIO5 | GPIO7); gpio_set(GPIOA, GPIO4); gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO4); codecConfig(); // Set up I2S for 48kHz 16-bit stereo. // The input to the PLLI2S is 1MHz. Division factors are from // table 126 in the data sheet. // // This gives us 1.536MHz SCLK = 16 bits * 2 channels * 48000 Hz // and 12.288 MHz MCLK = 256 * 48000 Hz. // With this PLL configuration the actual sampling frequency // is nominally 47991 Hz. spi_reset(SPI2); RCC_PLLI2SCFGR = (3 << 28) | (258 << 6); RCC_CR |= RCC_CR_PLLI2SON; while (!(RCC_CR & RCC_CR_PLLI2SRDY)); const unsigned i2sdiv = 3; SPI_I2SPR(SPI2) = SPI_I2SPR_MCKOE | SPI_I2SPR_ODD | i2sdiv; SPI_I2SCFGR(SPI2) |= SPI_I2SCFGR_I2SMOD | SPI_I2SCFGR_I2SE | (SPI_I2SCFGR_I2SCFG_MASTER_TRANSMIT << SPI_I2SCFGR_I2SCFG_LSB); SPI_I2SCFGR(I2S2_EXT_BASE) = SPI_I2SCFGR_I2SMOD | SPI_I2SCFGR_I2SE | (SPI_I2SCFGR_I2SCFG_SLAVE_RECEIVE << SPI_I2SCFGR_I2SCFG_LSB); // Configure the DMA engine to stream data to the DAC. dma_stream_reset(DMA1, DAC_DMA_STREAM); dma_set_peripheral_address(DMA1, DAC_DMA_STREAM, (intptr_t)&SPI_DR(SPI2)); dma_set_memory_address(DMA1, DAC_DMA_STREAM, (intptr_t)dacBuffer[0]); dma_set_memory_address_1(DMA1, DAC_DMA_STREAM, (intptr_t)dacBuffer[1]); dma_set_number_of_data(DMA1, DAC_DMA_STREAM, BUFFER_SAMPLES); dma_channel_select(DMA1, DAC_DMA_STREAM, DAC_DMA_CHANNEL); dma_set_transfer_mode(DMA1, DAC_DMA_STREAM, DMA_SxCR_DIR_MEM_TO_PERIPHERAL); dma_set_memory_size(DMA1, DAC_DMA_STREAM, DMA_SxCR_MSIZE_16BIT); dma_set_peripheral_size(DMA1, DAC_DMA_STREAM, DMA_SxCR_PSIZE_16BIT); dma_enable_memory_increment_mode(DMA1, DAC_DMA_STREAM); dma_enable_double_buffer_mode(DMA1, DAC_DMA_STREAM); dma_enable_stream(DMA1, DAC_DMA_STREAM); // Configure the DMA engine to stream data from the ADC. dma_stream_reset(DMA1, ADC_DMA_STREAM); dma_set_peripheral_address(DMA1, ADC_DMA_STREAM, (intptr_t)&SPI_DR(I2S2_EXT_BASE)); dma_set_memory_address(DMA1, ADC_DMA_STREAM, (intptr_t)adcBuffer[0]); dma_set_memory_address_1(DMA1, ADC_DMA_STREAM, (intptr_t)adcBuffer[1]); dma_set_number_of_data(DMA1, ADC_DMA_STREAM, BUFFER_SAMPLES); dma_channel_select(DMA1, ADC_DMA_STREAM, ADC_DMA_CHANNEL); dma_set_transfer_mode(DMA1, ADC_DMA_STREAM, DMA_SxCR_DIR_PERIPHERAL_TO_MEM); dma_set_memory_size(DMA1, ADC_DMA_STREAM, DMA_SxCR_MSIZE_16BIT); dma_set_peripheral_size(DMA1, ADC_DMA_STREAM, DMA_SxCR_PSIZE_16BIT); dma_enable_memory_increment_mode(DMA1, ADC_DMA_STREAM); dma_enable_double_buffer_mode(DMA1, ADC_DMA_STREAM); dma_enable_stream(DMA1, ADC_DMA_STREAM); dma_enable_transfer_complete_interrupt(DMA1, ADC_DMA_STREAM); nvic_enable_irq(NVIC_DMA1_STREAM3_IRQ); nvic_set_priority(NVIC_DMA1_STREAM3_IRQ, 0x80); // 0 is most urgent // Start transmitting data spi_enable_rx_dma(I2S2_EXT_BASE); spi_enable_tx_dma(SPI2); }
static int spi_dma_transceive(uint8_t *tx_buf, int tx_len, uint8_t *rx_buf, int rx_len) #endif { /* Check for 0 length in both tx and rx */ if ((rx_len < 1) && (tx_len < 1)) { /* return -1 as error */ return -1; } /* Reset DMA channels*/ dma_channel_reset(DMA1, DMA_CHANNEL4); dma_channel_reset(DMA1, DMA_CHANNEL5); /* Reset SPI data and status registers. * Here we assume that the SPI peripheral is NOT * busy any longer, i.e. the last activity was verified * complete elsewhere in the program. */ volatile uint8_t temp_data __attribute__ ((unused)); while (SPI_SR(SPI2) & (SPI_SR_RXNE | SPI_SR_OVR)) { temp_data = SPI_DR(SPI2); } /* Reset status flag appropriately (both 0 case caught above) */ transceive_status = NONE; if (rx_len < 1) { transceive_status = ONE; } if (tx_len < 1) { transceive_status = ONE; } /* Set up rx dma, note it has higher priority to avoid overrun */ if (rx_len > 0) { dma_set_peripheral_address(DMA1, DMA_CHANNEL4, (uint32_t)&SPI2_DR); dma_set_memory_address(DMA1, DMA_CHANNEL4, (uint32_t)rx_buf); dma_set_number_of_data(DMA1, DMA_CHANNEL4, rx_len); dma_set_read_from_peripheral(DMA1, DMA_CHANNEL4); dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL4); #if USE_16BIT_TRANSFERS dma_set_peripheral_size(DMA1, DMA_CHANNEL4, DMA_CCR_PSIZE_16BIT); dma_set_memory_size(DMA1, DMA_CHANNEL4, DMA_CCR_MSIZE_16BIT); #else dma_set_peripheral_size(DMA1, DMA_CHANNEL4, DMA_CCR_PSIZE_8BIT); dma_set_memory_size(DMA1, DMA_CHANNEL4, DMA_CCR_MSIZE_8BIT); #endif dma_set_priority(DMA1, DMA_CHANNEL4, DMA_CCR_PL_VERY_HIGH); } /* Set up tx dma */ if (tx_len > 0) { dma_set_peripheral_address(DMA1, DMA_CHANNEL5, (uint32_t)&SPI2_DR); dma_set_memory_address(DMA1, DMA_CHANNEL5, (uint32_t)tx_buf); dma_set_number_of_data(DMA1, DMA_CHANNEL5, tx_len); dma_set_read_from_memory(DMA1, DMA_CHANNEL5); dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL5); #if USE_16BIT_TRANSFERS dma_set_peripheral_size(DMA1, DMA_CHANNEL5, DMA_CCR_PSIZE_16BIT); dma_set_memory_size(DMA1, DMA_CHANNEL5, DMA_CCR_MSIZE_16BIT); #else dma_set_peripheral_size(DMA1, DMA_CHANNEL5, DMA_CCR_PSIZE_8BIT); dma_set_memory_size(DMA1, DMA_CHANNEL5, DMA_CCR_MSIZE_8BIT); #endif dma_set_priority(DMA1, DMA_CHANNEL5, DMA_CCR_PL_HIGH); } /* Enable dma transfer complete interrupts */ if (rx_len > 0) { dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL4); } if (tx_len > 0) { dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL5); } /* Activate dma channels */ if (rx_len > 0) { dma_enable_channel(DMA1, DMA_CHANNEL4); } if (tx_len > 0) { dma_enable_channel(DMA1, DMA_CHANNEL5); } /* Enable the spi transfer via dma * This will immediately start the transmission, * after which when the receive is complete, the * receive dma will activate */ if (rx_len > 0) { spi_enable_rx_dma(SPI2); } if (tx_len > 0) { spi_enable_tx_dma(SPI2); } return 0; }
static int spi_dma_transceive(uint8_t *tx_buf, int tx_len, uint8_t *rx_buf, int rx_len) #endif { /* Check for 0 length in both tx and rx */ if ((rx_len < 1) && (tx_len < 1)) { /* return -1 as error */ return -1; } /* Reset DMA channels*/ dma_channel_reset(DMA1, DMA_CHANNEL2); dma_channel_reset(DMA1, DMA_CHANNEL3); /* Reset SPI data and status registers. * Here we assume that the SPI peripheral is NOT * busy any longer, i.e. the last activity was verified * complete elsewhere in the program. */ volatile uint8_t temp_data __attribute__ ((unused)); while (SPI_SR(SPI1) & (SPI_SR_RXNE | SPI_SR_OVR)) { temp_data = SPI_DR(SPI1); } /* Reset status flag appropriately (both 0 case caught above) */ transceive_status = NONE; if (rx_len < 1) { transceive_status = ONE; } /* Determine tx length case to change behaviour * If tx_len >= rx_len, then normal case, run both DMAs with normal settings * If rx_len == 0, just don't run the rx DMA at all * If tx_len == 0, use a dummy buf and set the tx dma to transfer the same * amount as the rx_len, to ensure everything is clocked in * If 0 < tx_len < rx_len, first do a normal case, then on the tx finished * interrupt, set up a new dummyy buf tx dma transfer for the remaining * required clock cycles (handled in tx dma complete interrupt) */ if ((tx_len > 0) && (tx_len < rx_len)) { rx_buf_remainder = rx_len - tx_len; } /* Set up rx dma, note it has higher priority to avoid overrun */ if (rx_len > 0) { dma_set_peripheral_address(DMA1, DMA_CHANNEL2, (uint32_t)&SPI1_DR); dma_set_memory_address(DMA1, DMA_CHANNEL2, (uint32_t)rx_buf); dma_set_number_of_data(DMA1, DMA_CHANNEL2, rx_len); dma_set_read_from_peripheral(DMA1, DMA_CHANNEL2); dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL2); #if USE_16BIT_TRANSFERS dma_set_peripheral_size(DMA1, DMA_CHANNEL2, DMA_CCR_PSIZE_16BIT); dma_set_memory_size(DMA1, DMA_CHANNEL2, DMA_CCR_MSIZE_16BIT); #else dma_set_peripheral_size(DMA1, DMA_CHANNEL2, DMA_CCR_PSIZE_8BIT); dma_set_memory_size(DMA1, DMA_CHANNEL2, DMA_CCR_MSIZE_8BIT); #endif dma_set_priority(DMA1, DMA_CHANNEL2, DMA_CCR_PL_VERY_HIGH); } /* Set up tx dma (must always run tx to get clock signal) */ if (tx_len > 0) { /* Here we have a regular tx transfer */ dma_set_peripheral_address(DMA1, DMA_CHANNEL3, (uint32_t)&SPI1_DR); dma_set_memory_address(DMA1, DMA_CHANNEL3, (uint32_t)tx_buf); dma_set_number_of_data(DMA1, DMA_CHANNEL3, tx_len); dma_set_read_from_memory(DMA1, DMA_CHANNEL3); dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL3); #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); } else { /* Here we aren't transmitting any real data, use the dummy buffer * and set the length to the rx_len to get all rx data in, while * not incrementing the memory pointer */ 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_len); // 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); } /* Enable dma transfer complete interrupts */ if (rx_len > 0) { dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL2); } dma_enable_transfer_complete_interrupt(DMA1, DMA_CHANNEL3); /* Activate dma channels */ if (rx_len > 0) { dma_enable_channel(DMA1, DMA_CHANNEL2); } dma_enable_channel(DMA1, DMA_CHANNEL3); /* Enable the spi transfer via dma * This will immediately start the transmission, * after which when the receive is complete, the * receive dma will activate */ if (rx_len > 0) { spi_enable_rx_dma(SPI1); } spi_enable_tx_dma(SPI1); return 0; }
bool TSpiDmaQueue::TryStartJob() { // Start the next DMA job in the queue if the SPI interface is // available (TXE=1 and BSY=0) // We treat both SPI busses (flash and display) as one, so no concurrent jobs // are allowed. const uint32_t spi = LCD_SPI_CHANNEL; if ((SPI_SR(spi) & SPI_SR_TXE) && (~SPI_SR(spi) & SPI_SR_BSY)) { if (Jobs.Empty()) { return false; } const TSpiDmaJob& job = Jobs.First(); const TBuffer& buffer = job.GetBuffer(); // SPI receive register should be empty here! assert(!(SPI_SR(spi) & SPI_SR_RXNE)); const uint32_t dma = DMA1; { const uint32_t channel = (job.GetChip() == TSpiDmaJob::CS_LCD) ? LCD_DMA_TX_CHANNEL : FLASH_DMA_TX_CHANNEL; dma_channel_reset(dma, channel); dma_set_peripheral_address(dma, channel, reinterpret_cast<uint32_t>(&SPI_DR(spi))); dma_set_memory_address(dma, channel, reinterpret_cast<uint32_t>(buffer.GetData())); dma_set_number_of_data(dma, channel, buffer.GetLength()); dma_set_read_from_memory(dma, channel); dma_enable_memory_increment_mode(dma, channel); dma_set_peripheral_size(dma, channel, DMA_CCR_PSIZE_8BIT); dma_set_memory_size(dma, channel, DMA_CCR_MSIZE_8BIT); dma_set_priority(dma, channel, DMA_CCR_PL_LOW); //dma_enable_transfer_complete_interrupt(dma, channel); dma_enable_channel(dma, channel); } { const uint32_t channel = (job.GetChip() == TSpiDmaJob::CS_LCD) ? LCD_DMA_RX_CHANNEL : FLASH_DMA_RX_CHANNEL; dma_channel_reset(dma, channel); dma_set_peripheral_address(dma, channel, reinterpret_cast<uint32_t>(&SPI_DR(spi))); dma_set_memory_address(dma, channel, reinterpret_cast<uint32_t>(buffer.GetData())); dma_set_number_of_data(dma, channel, buffer.GetLength()); dma_enable_memory_increment_mode(dma, channel); dma_set_peripheral_size(dma, channel, DMA_CCR_PSIZE_8BIT); dma_set_memory_size(dma, channel, DMA_CCR_MSIZE_8BIT); dma_set_priority(dma, channel, DMA_CCR_PL_LOW); dma_enable_transfer_complete_interrupt(dma, channel); dma_enable_channel(dma, channel); } // Set CS and LCD_A0 lines Pin_lcd_cs.Clear(); if (job.GetLcdData()) { Pin_lcd_a0.Set(); } else { Pin_lcd_a0.Clear(); } // Kick off the transfer spi_enable_rx_dma(spi); spi_enable_tx_dma(spi); return true; } return false; }