const struct spi_comm_packet *spi_master_wait_response_done(void) { const struct spi_comm_packet *resp = (const struct spi_comm_packet *)in_msg; stm32_spi_regs_t *spi = STM32_SPI1_REGS; if (dma_wait(STM32_DMAC_SPI1_TX) || dma_wait(STM32_DMAC_SPI1_RX)) { debug_printf("SPI: Incomplete response\n"); goto err_wait_response_done; } if (spi->sr & STM32_SPI_SR_CRCERR) { debug_printf("SPI: CRC mismatch\n"); goto err_wait_response_done; } if (resp->cmd_sts != EC_SUCCESS) { debug_printf("SPI: Slave error\n"); goto err_wait_response_done; } exit_wait_response_done: dma_disable(STM32_DMAC_SPI1_TX); dma_disable(STM32_DMAC_SPI1_RX); dma_clear_isr(STM32_DMAC_SPI1_TX); dma_clear_isr(STM32_DMAC_SPI1_RX); /* Set CS1 (slave SPI_NSS) to high */ STM32_GPIO_BSRR(GPIO_A) = 1 << 6; return resp; err_wait_response_done: resp = NULL; goto exit_wait_response_done; }
/** * \brief 32-bit checksum of DMA transfer data * * This test sets up DMA to do a data block transfer, and sets up * the CRC module to do a 32 bit checksum on the data. The checksum * will then be added to another buffer, the same procedure is setup * with this new buffer which should result in a checksum = 0. * * \param test Current test case */ static void run_32bit_dma_test(const struct test_case *test) { uint32_t checksum; bool success; uint8_t data_buf_8bit[LENGTH(data_8bit) + sizeof(uint32_t)]; uint8_t data_8bit_cpy[LENGTH(data_8bit) + sizeof(uint32_t)]; setup_dma_channel(LENGTH(data_8bit), (uint8_t *)data_8bit, data_buf_8bit); crc_dma_checksum_start(CONF_TEST_DMACH, CRC_32BIT); dma_channel_trigger_block_transfer(CONF_TEST_DMACH); success = wait_for_dma_transfer(test); dma_channel_disable(CONF_TEST_DMACH); dma_disable(); checksum = crc_dma_checksum_stop(); if (!success) { return; } test_assert_true(test, checksum == CRC_CHECKSUM_32BIT, "Checksum mismatch on DMA CRC-32 test"); memcpy(data_8bit_cpy, data_8bit, LENGTH(data_8bit)); crc32_append_value(checksum, &data_8bit_cpy[LENGTH(data_8bit_cpy) - sizeof(uint32_t)]); setup_dma_channel(LENGTH(data_8bit_cpy), (uint8_t *)data_8bit_cpy, data_buf_8bit); crc_dma_checksum_start(CONF_TEST_DMACH, CRC_32BIT); dma_channel_trigger_block_transfer(CONF_TEST_DMACH); success = wait_for_dma_transfer(test); dma_channel_disable(CONF_TEST_DMACH); dma_disable(); checksum = crc_dma_checksum_stop(); if (!success) { return; } test_assert_true(test, checksum == 0, "Checksum fail check failed on DMA CRC-16 test"); }
/* DMA1 Channel7 Interrupt Handler gets executed once the complete framebuffer has been transmitted to the LEDs */ void DMA1_Channel7_IRQHandler(void) { // clear DMA7 transfer complete interrupt flag dma_clear_isr_bits(DMA1, DMA_CH7); // enable TIM2 Update interrupt to append 50us dead period timer_enable_irq(TIMER2, TIMER_UPDATE_INTERRUPT); // disable the DMA channels dma_disable(DMA1, DMA_CH2); dma_disable(DMA1, DMA_CH5); dma_disable(DMA1, DMA_CH7); // IMPORTANT: disable the DMA requests, too! timer_dma_disable_req(TIMER2, 1); timer_dma_disable_req(TIMER2, 2); timer_dma_disable_req(TIMER2, 0); /* TIM_DMA_Update */ }
int spi_slave_send_response_flush(void) { int ret; ret = dma_wait(STM32_DMAC_SPI1_TX); ret |= dma_wait(STM32_DMAC_SPI1_RX); dma_disable(STM32_DMAC_SPI1_TX); dma_disable(STM32_DMAC_SPI1_RX); dma_clear_isr(STM32_DMAC_SPI1_TX); dma_clear_isr(STM32_DMAC_SPI1_RX); /* Set N_CHG (master SPI_NSS) to low */ STM32_GPIO_BSRR(GPIO_A) = 1 << (1 + 16); return ret; }
//------------------------------------------------------------------------------ // send one block of data for write block or write multiple blocks uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) { #ifdef SPI_DMA dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, (uint8_t *)src, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT | DMA_TRNS_ERR)); dma_attach_interrupt(DMA1, DMA_CH3, DMAEvent); dma_set_priority(DMA1, DMA_CH3, DMA_PRIORITY_VERY_HIGH); dma_set_num_transfers(DMA1, DMA_CH3, 512); dmaActive = true; dma_enable(DMA1, DMA_CH3); while(dmaActive) delayMicroseconds(1); dma_disable(DMA1, DMA_CH3); #else // SPI_DMA spiSend(token); for (uint16_t i = 0; i < 512; i++) { spiSend(src[i]); } #endif // OPTIMIZE_HARDWARE_SPI spiSend(0xff); // dummy crc spiSend(0xff); // dummy crc status_ = spiRec(); if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) { error(SD_CARD_ERROR_WRITE); chipSelectHigh(); Serial.println("Error: Write"); Serial.println("Error: Sd2Card::writeData()"); return false; } return true; }
/** * \brief Access AES module with DMA support * * \note Read STATE using DMA channel 0. * Check DMA driver example for more information about DMA usage. * */ static void aes_dma_output(void) { // Make sure config is all zeroed out so we don't get any stray bits memset(&config, 0, sizeof(config)); dma_enable(); dma_channel_set_burst_length(&config, DMA_CH_BURSTLEN_1BYTE_gc); dma_channel_set_transfer_count(&config, BLOCK_LENGTH); dma_channel_set_src_reload_mode(&config, DMA_CH_SRCRELOAD_NONE_gc); dma_channel_set_dest_reload_mode(&config, DMA_CH_DESTRELOAD_NONE_gc); dma_channel_set_src_dir_mode(&config, DMA_CH_SRCDIR_FIXED_gc); dma_channel_set_dest_dir_mode(&config, DMA_CH_DESTDIR_INC_gc); dma_channel_set_source_address(&config, (uint16_t)(uintptr_t)&AES_STATE); dma_channel_set_destination_address(&config, (uint16_t)(uintptr_t)single_ans); dma_channel_write_config(DMA_CHANNEL_N, &config); // Use the configuration above by enabling the DMA channel in use. dma_channel_enable(DMA_CHANNEL_N); /* * Trigger a manual start since there is no trigger sources used in * this example. */ dma_channel_trigger_block_transfer(DMA_CHANNEL_N); while (!(DMA_CH0_CTRLB & DMA_CH_TRNIF_bm)); DMA_CH0_CTRLB |= DMA_CH_TRNIF_bm; dma_disable(); }
/** * @brief Discover the reason why a DMA interrupt was called. * * You may only call this function within an attached interrupt * handler for the given channel. * * This function resets the internal DMA register state which encodes * the cause of the interrupt; consequently, it can only be called * once per interrupt handler invocation. * * @brief dev DMA device * @brief channel Channel whose interrupt is being handled. * @return Reason why the interrupt fired. * @sideeffect Clears channel status flags in dev->regs->ISR. * @see dma_attach_interrupt() * @see dma_irq_cause */ dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel) { uint8 status_bits = dma_get_isr_bits(dev, channel); /* If the channel global interrupt flag is cleared, then * something's very wrong. */ ASSERT(status_bits & BIT(0)); dma_clear_isr_bits(dev, channel); /* ISR flags get set even if the corresponding interrupt enable * bits in the channel's configuration register are cleared, so we * can't use a switch here. * * Don't change the order of these if statements. */ if (status_bits & BIT(3)) { return DMA_TRANSFER_ERROR; } else if (status_bits & BIT(1)) { return DMA_TRANSFER_COMPLETE; } else if (status_bits & BIT(2)) { return DMA_TRANSFER_HALF_COMPLETE; } else if (status_bits & BIT(0)) { /* Shouldn't happen (unless someone messed up an IFCR write). */ throb(); } #if DEBUG_LEVEL < DEBUG_ALL else { /* We shouldn't have been called, but the debug level is too * low for the above ASSERT() to have had any effect. In * order to fail fast, mimic the DMA controller's behavior * when an error occurs. */ dma_disable(dev, channel); } #endif return DMA_TRANSFER_ERROR; }
int dma_tube_cfg(dma_dev *dev, dma_channel channel, dma_tube_config *cfg) { dma_tube_reg_map *chregs; int ret = preconfig_check(dev, channel, cfg); if (ret < 0) { return ret; } dma_disable(dev, channel); /* Must disable before reconfiguring */ dma_clear_isr_bits(dev, channel); /* For sanity and consistency * with STM32F2. */ chregs = dma_tube_regs(dev, channel); switch (_dma_addr_type(cfg->tube_dst)) { case DMA_ATYPE_PER: ret = config_to_per(chregs, cfg); break; case DMA_ATYPE_MEM: ret = config_to_mem(chregs, cfg); break; default: /* Can't happen */ ASSERT(0); return -DMA_TUBE_CFG_ECFG; } if (ret < 0) { return ret; } chregs->CNDTR = cfg->tube_nr_xfers; return DMA_TUBE_CFG_SUCCESS; }
void dma_disable_all(void) { int ch; for (ch = 0; ch < STM32_DMAS_TOTAL_COUNT; ch++) dma_disable(ch); }
dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel) { /* Grab and clear the ISR bits. */ uint8 status_bits = dma_get_isr_bits(dev, channel); dma_clear_isr_bits(dev, channel); /* If the channel global interrupt flag is cleared, then * something's very wrong. */ ASSERT(status_bits & 0x1); /* If GIF is set, then some other flag should be set, barring * something unexpected (e.g. the user making an unforeseen IFCR * write). */ ASSERT(status_bits != 0x1); /* ISR flags get set even if the corresponding interrupt enable * bits in the channel's configuration register are cleared, so we * can't use a switch here. * * Don't change the order of these if statements. */ if (status_bits & 0x8) { return DMA_TRANSFER_ERROR; } else if (status_bits & 0x2) { return DMA_TRANSFER_COMPLETE; } else if (status_bits & 0x4) { return DMA_TRANSFER_HALF_COMPLETE; } /* If we get here, one of our assumptions has been violated, but * the debug level is too low for the above ASSERTs() to have had * any effect. In order to fail fast, mimic the DMA controller's * behavior when an error occurs. */ dma_disable(dev, channel); return DMA_TRANSFER_ERROR; }
static int spi_master_read_write_byte(uint8_t *in_buf, uint8_t *out_buf, int sz) { int ret; dma_start_rx(&dma_rx_option, sz, in_buf); dma_prepare_tx(&dma_tx_option, sz, out_buf); dma_go(dma_get_channel(STM32_DMAC_SPI1_TX)); ret = dma_wait(STM32_DMAC_SPI1_TX); ret |= dma_wait(STM32_DMAC_SPI1_RX); dma_disable(STM32_DMAC_SPI1_TX); dma_disable(STM32_DMAC_SPI1_RX); dma_clear_isr(STM32_DMAC_SPI1_TX); dma_clear_isr(STM32_DMAC_SPI1_RX); return ret; }
static void serial_received(struct serial *serial) { dma_disable(DMA1, serial->channel); usart_tcie(serial->port->c_dev()->regs, 0); serial->dmaEvent = false; serial->txComplete = true; receiveMode(serial); serial->syncReadStart = syncReadTimer.getCount(); }
static int dm_test_dma_rx(struct unit_test_state *uts) { struct udevice *dev; struct dma dma_tx, dma_rx; u8 src_buf[512]; u8 dst_buf[512]; void *dst_ptr; size_t len = 512; u32 meta1, meta2; int i; ut_assertok(uclass_get_device_by_name(UCLASS_DMA, "dma", &dev)); ut_assertok(dma_get_by_name(dev, "tx0", &dma_tx)); ut_assertok(dma_get_by_name(dev, "rx0", &dma_rx)); ut_assertok(dma_enable(&dma_tx)); ut_assertok(dma_enable(&dma_rx)); memset(dst_buf, 0, len); for (i = 0; i < len; i++) src_buf[i] = i; meta1 = 0xADADDEAD; meta2 = 0; dst_ptr = NULL; ut_assertok(dma_prepare_rcv_buf(&dma_tx, dst_buf, len)); ut_assertok(dma_send(&dma_tx, src_buf, len, &meta1)); ut_asserteq(len, dma_receive(&dma_rx, &dst_ptr, &meta2)); ut_asserteq(0xADADDEAD, meta2); ut_asserteq_ptr(dst_buf, dst_ptr); ut_assertok(dma_disable(&dma_tx)); ut_assertok(dma_disable(&dma_rx)); ut_assertok(dma_free(&dma_tx)); ut_assertok(dma_free(&dma_rx)); ut_assertok(memcmp(src_buf, dst_buf, len)); return 0; }
static void i2c_event_handler(int port) { /* save and clear status */ i2c_sr1[port] = STM32_I2C_SR1(port); STM32_I2C_SR1(port) = 0; /* Confirm that you are not in master mode */ if (STM32_I2C_SR2(port) & (1 << 0)) { CPRINTS("slave ISR triggered in master mode, ignoring"); return; } /* transfer matched our slave address */ if (i2c_sr1[port] & (1 << 1)) { /* If it's a receiver slave */ if (!(STM32_I2C_SR2(port) & (1 << 2))) { dma_start_rx(dma_rx_option + port, sizeof(host_buffer), host_buffer); STM32_I2C_CR2(port) |= (1 << 11); rx_pending = 1; } /* cleared by reading SR1 followed by reading SR2 */ STM32_I2C_SR1(port); STM32_I2C_SR2(port); } else if (i2c_sr1[port] & (1 << 4)) { /* If it's a receiver slave */ if (!(STM32_I2C_SR2(port) & (1 << 2))) { /* Disable, and clear the DMA transfer complete flag */ dma_disable(DMAC_SLAVE_RX); dma_clear_isr(DMAC_SLAVE_RX); /* Turn off i2c's DMA flag */ STM32_I2C_CR2(port) &= ~(1 << 11); } /* clear STOPF bit by reading SR1 and then writing CR1 */ STM32_I2C_SR1(port); STM32_I2C_CR1(port) = STM32_I2C_CR1(port); } /* TxE event */ if (i2c_sr1[port] & (1 << 7)) { if (port == I2C2) { /* AP is waiting for EC response */ if (rx_pending) { i2c_process_command(); /* reset host buffer after end of transfer */ rx_pending = 0; } else { /* spurious read : return dummy value */ STM32_I2C_DR(port) = 0xec; } } } }
void ppm_timeout_isr() { // This failure mode indicates we lost comm with // the transmitter //TODO: re-initialize the dma and wait for ppm signal //re-initializing should ensure that the ppm signal // is captured on the sync pulse. ppm_timeout=1; dma_disable(DMA1, DMA_CH1); init_ppm_dma_transfer(); }
/** * @brief Set up a DMA transfer. * * The channel will be disabled before being reconfigured. The * transfer will have low priority by default. You may choose another * priority before the transfer begins using dma_set_priority(), as * well as performing any other configuration you desire. When the * channel is configured to your liking, enable it using dma_enable(). * * @param dev DMA device. * @param channel DMA channel. * @param peripheral_address Base address of peripheral data register * involved in the transfer. * @param peripheral_size Peripheral data transfer size. * @param memory_address Base memory address involved in the transfer. * @param memory_size Memory data transfer size. * @param mode Logical OR of dma_mode_flags * @sideeffect Disables the given DMA channel. * @see dma_xfer_size * @see dma_mode_flags * @see dma_set_num_transfers() * @see dma_set_priority() * @see dma_attach_interrupt() * @see dma_enable() */ void dma_setup_transfer(dma_dev *dev, dma_channel channel, __io void *peripheral_address, dma_xfer_size peripheral_size, __io void *memory_address, dma_xfer_size memory_size, uint32 mode) { dma_channel_reg_map *channel_regs = dma_channel_regs(dev, channel); dma_disable(dev, channel); /* can't write to CMAR/CPAR otherwise */ channel_regs->CCR = (memory_size << 10) | (peripheral_size << 8) | mode; channel_regs->CMAR = (uint32)memory_address; channel_regs->CPAR = (uint32)peripheral_address; }
void dma_start(dma_buffer * buffer, unsigned long count, unsigned char mode) { /* Disable interrupts */ int old_ints = disable(); dma_disable(buffer->channel); dma_set_mode(buffer->channel, mode); dma_clear_ff(buffer->channel); dma_set_addr(buffer->channel, buffer->physical); dma_clear_ff(buffer->channel); dma_set_count(buffer->channel, count); dma_enable(buffer->channel); /* Re-enable interrupts */ if (old_ints) enable(); }
int adc_read_all_channels(int *data) { int i; int16_t raw_data[ADC_CH_COUNT]; const struct adc_t *adc; int restore_watchdog = 0; int ret = EC_SUCCESS; if (!adc_powered()) return EC_ERROR_UNKNOWN; mutex_lock(&adc_lock); if (adc_watchdog_enabled()) { restore_watchdog = 1; adc_disable_watchdog_no_lock(); } adc_configure_all(); dma_clear_isr(STM32_DMAC_ADC); dma_start_rx(&dma_adc_option, ADC_CH_COUNT, raw_data); /* Start conversion */ STM32_ADC_CR2 |= (1 << 0); /* ADON */ if (dma_wait(STM32_DMAC_ADC)) { ret = EC_ERROR_UNKNOWN; goto exit_all_channels; } for (i = 0; i < ADC_CH_COUNT; ++i) { adc = adc_channels + i; data[i] = raw_data[i] * adc->factor_mul / adc->factor_div + adc->shift; } exit_all_channels: dma_disable(STM32_DMAC_ADC); if (restore_watchdog) adc_enable_watchdog_no_lock(); mutex_unlock(&adc_lock); return ret; }
/** * \brief Test the error handling of the module * * \note Test error handling by disabling a channel which is in use * * \param test Current test */ static void run_dma_error_handling_test(const struct test_case *test) { /* Enable DMA */ dma_enable(); /* Reset the channel */ dma_channel_reset(DMA_CHANNEL_0); /* Set up channel 0 to do some work, check that is it busy, * change some settings and verify a transfer error */ dma_channel_write_burst_length(DMA_CHANNEL_0, DMA_CH_BURSTLEN_1BYTE_gc); dma_channel_write_transfer_count(DMA_CHANNEL_0, MEMORY_BLOCK_SIZE); dma_channel_write_source(DMA_CHANNEL_0, (uint16_t)(uintptr_t)memory_block_src); dma_channel_write_destination(DMA_CHANNEL_0, (uint16_t)(uintptr_t)memory_block_dest); /* Enable the channel */ dma_channel_enable(DMA_CHANNEL_0); /* Start a block transfer */ dma_channel_trigger_block_transfer(DMA_CHANNEL_0); /* Wait for the channel to become busy */ while (!dma_channel_is_busy(DMA_CHANNEL_0)) { /* Intentionally left empty */ } /* Disable the channel while it is busy */ if (dma_channel_is_busy(DMA_CHANNEL_0)) { dma_channel_disable(DMA_CHANNEL_0); } /* Test whether the channel is in error */ test_assert_true(test, dma_get_channel_status( DMA_CHANNEL_0) == DMA_CH_TRANSFER_ERROR, "DMA channel not in error after disabling during transfer" " write"); dma_disable(); }
static int i2c_write_raw_slave(int port, void *buf, int len) { stm32_dma_chan_t *chan; int rv; /* we don't want to race with TxE interrupt event */ disable_i2c_interrupt(port); /* Configuring DMA1 channel DMAC_SLAVE_TX */ enable_ack(port); chan = dma_get_channel(DMAC_SLAVE_TX); dma_prepare_tx(dma_tx_option + port, len, buf); /* Start the DMA */ dma_go(chan); /* Configuring i2c to use DMA */ STM32_I2C_CR2(port) |= (1 << 11); if (in_interrupt_context()) { /* Poll for the transmission complete flag */ dma_wait(DMAC_SLAVE_TX); dma_clear_isr(DMAC_SLAVE_TX); } else { /* Wait for the transmission complete Interrupt */ dma_enable_tc_interrupt(DMAC_SLAVE_TX); rv = task_wait_event(DMA_TRANSFER_TIMEOUT_US); dma_disable_tc_interrupt(DMAC_SLAVE_TX); if (!(rv & TASK_EVENT_WAKE)) { CPRINTS("Slave timeout, resetting i2c"); i2c_init_port(port); } } dma_disable(DMAC_SLAVE_TX); STM32_I2C_CR2(port) &= ~(1 << 11); enable_i2c_interrupt(port); return len; }
/** * Prepare a stream for use and start it * * @param stream stream to read * @param count Number of bytes to transfer * @param periph Pointer to peripheral data register * @param memory Pointer to memory address for receive/transmit * @param flags DMA flags for the control register. */ static void prepare_stream(enum dma_channel stream, unsigned count, void *periph, void *memory, unsigned flags) { stm32_dma_stream_t *dma_stream = dma_get_channel(stream); uint32_t ccr = STM32_DMA_CCR_PL_VERY_HIGH; dma_disable(stream); dma_clear_isr(stream); /* Following the order in DocID026448 Rev 1 (RM0383) p181 */ dma_stream->spar = (uint32_t)periph; dma_stream->sm0ar = (uint32_t)memory; dma_stream->sndtr = count; dma_stream->scr = ccr; ccr |= flags & STM32_DMA_CCR_CHANNEL_MASK; dma_stream->scr = ccr; dma_stream->sfcr &= ~STM32_DMA_SFCR_DMDIS; ccr |= flags; dma_stream->scr = ccr; }
static void usb_reset(void) { /* Disable TIM7. */ tim_disable_counter(TIM7); /* Disable DMA. */ dma_disable(DMA_TIM7_UP); /* Clear queue. */ head = tail = 0; /* Set endpoint type and address. */ usbdevfs_setup_endpoint(0, USBDEVFS_CONTROL, 0); usbdevfs_setup_endpoint(1, USBDEVFS_ISOCHRONOUS, AS_ENUM); /* Set default address. */ usbdevfs_set_device_address(0); /* Reset control transfer state. */ control_reset(); }
/** Skip remaining data in a block when in partial block read mode. */ void Sd2Card::readEnd(void) { if (inBlock_) { // skip data and crc #ifdef SPI_DMA dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, ack, DMA_SIZE_8BITS, (/*DMA_MINC_MODE | DMA_CIRC_MODE |*/ DMA_FROM_MEM | DMA_TRNS_CMPLT | DMA_TRNS_ERR)); dma_attach_interrupt(DMA1, DMA_CH3, DMAEvent); dma_set_priority(DMA1, DMA_CH3, DMA_PRIORITY_VERY_HIGH); dma_set_num_transfers(DMA1, DMA_CH3, SPI_BUFF_SIZE + 1 - offset_); dmaActive = true; dma_enable(DMA1, DMA_CH3); while(dmaActive)delayMicroseconds(1); dma_disable(DMA1, DMA_CH3); #else // SPI_DMA while (offset_++ < 514) spiRec(); #endif // SPI_DMA chipSelectHigh(); inBlock_ = 0; } }
/* DMA1 (channel3) interrupt */ void dma_tim7_up_isr(void) { /* Interrupt mask */ if (!dma_get_interrupt_mask(DMA_TIM7_UP, DMA_COMPLETE)) return; /* Interrupt status */ if (dma_get_interrupt_status(DMA_TIM7_UP, DMA_GLOBAL | DMA_COMPLETE) != (DMA_GLOBAL | DMA_COMPLETE)) return; /* Disable TIM7. */ tim_disable_counter(TIM7); /* Disable DMA. */ dma_disable(DMA_TIM7_UP); /* Dequeue. */ head = (head + 1) % QUEUESIZE; /* Clear interrupt. */ dma_clear_interrupt(DMA_TIM7_UP, DMA_COMPLETE | DMA_GLOBAL); }
/** * Get ready to receive a message from the master. * * Set up our RX DMA and disable our TX DMA. Set up the data output so that * we will send preamble bytes. */ static void setup_for_transaction(void) { stm32_spi_regs_t *spi = STM32_SPI1_REGS; volatile uint8_t dummy __attribute__((unused)); /* clear this as soon as possible */ setup_transaction_later = 0; /* Not ready to receive yet */ tx_status(EC_SPI_NOT_READY); /* We are no longer actively processing a transaction */ state = SPI_STATE_PREPARE_RX; /* Stop sending response, if any */ dma_disable(STM32_DMAC_SPI1_TX); /* * Read dummy bytes in case there are some pending; this prevents the * receive DMA from getting that byte right when we start it. */ dummy = spi->dr; #ifdef CHIP_FAMILY_STM32F0 /* 4 Bytes makes sure the RX FIFO on the F0 is empty as well. */ dummy = spi->dr; dummy = spi->dr; dummy = spi->dr; #endif /* Start DMA */ dma_start_rx(&dma_rx_option, sizeof(in_msg), in_msg); /* Ready to receive */ state = SPI_STATE_READY_TO_RX; tx_status(EC_SPI_OLD_READY); }
/** * \brief Test read from fixed location, trigger from timer and callback * * \note This test sets up a timer to trigger the DMA module, * which in turn reads the timer_overflow_counter variable and writes * it to memory sequentially. It then checks to see that the memory block * written is sequential according to the overflow count. * * \param test Current test */ static void run_dma_triggered_with_callback(const struct test_case *test) { struct dma_channel_config config_params; bool success; /* Null the buffer */ set_buffer(dest_block_tc, 0x0000); /* Null out the config parameter struct */ memset(&config_params, 0, sizeof(config_params)); /* * Enable the timer, and set it to count up. * When it overflows, it triggers the DMA to * read timer_overflow_counter. */ tc_enable(&TIMER); tc_set_direction(&TIMER, TC_UP); tc_write_period(&TIMER, TIMER_PERIOD); tc_set_resolution(&TIMER, TIMER_RESOLUTION); tc_set_overflow_interrupt_level(&TIMER, PMIC_LVL_LOW); tc_set_overflow_interrupt_callback(&TIMER, timer_overflow_callback); /* Enable the DMA module */ dma_enable(); /* Set callback for transfer done */ dma_set_callback(DMA_CHANNEL_0, dma_transfer_is_complete); /* Set low interrupt level */ dma_channel_set_interrupt_level(&config_params, PMIC_LVL_LOW); /* Set up the DMA to read the timer value * * - Single shot transfer mode * - Two byte (16-bit) burst length * - Increment on source and destination * - Reload on burst for source * - No reload for destination */ dma_channel_set_single_shot(&config_params); dma_channel_set_burst_length(&config_params, DMA_CH_BURSTLEN_1BYTE_gc); dma_channel_set_src_reload_mode(&config_params, DMA_CH_SRCRELOAD_BURST_gc); dma_channel_set_src_dir_mode(&config_params, DMA_CH_SRCDIR_FIXED_gc); dma_channel_set_dest_reload_mode(&config_params, DMA_CH_DESTRELOAD_NONE_gc); dma_channel_set_dest_dir_mode(&config_params, DMA_CH_DESTDIR_INC_gc); /* Set trigger source to TCC0's overflow */ dma_channel_set_trigger_source(&config_params, DMA_CH_TRIGSRC_TCC0_OVF_gc); /* Transfer DEST_BLOCK_TC_SIZE bytes */ dma_channel_set_transfer_count(&config_params, DEST_BLOCK_TC_SIZE); /* Set address */ dma_channel_set_source_address(&config_params, (uint16_t)(uintptr_t)&timer_overflow_counter); dma_channel_set_destination_address(&config_params, (uint16_t)(uintptr_t)dest_block_tc); /* Reset the channel */ dma_channel_reset(DMA_CHANNEL_0); /* Write the config */ dma_channel_write_config(DMA_CHANNEL_0, &config_params); /* Enable the channel */ dma_channel_enable(DMA_CHANNEL_0); /* Wait for transfer to finish */ while (!dma_has_completed) { /* Intentionally left empty */ } /* Disable DMA */ dma_disable(); /* Verify that the result is as expected */ success = block_compare(dest_block_tc, expected_result_tc, DEST_BLOCK_TC_SIZE); test_assert_true(test, success, "Result is not as expected"); }
/** * * \brief Set DMA configuration, and read it back * * \note This function writes a configuration to the DMA * controller, and reads it back to verify settings have * been correctly set. * * \param test Current test case */ static void run_dma_config_interface_test(const struct test_case *test) { struct dma_channel_config config_params; struct dma_channel_config read_config; const uint16_t transfer_count = 1024; const uint8_t repeats = 64; uint8_t channel_index; #ifdef CONFIG_HAVE_HUGEMEM hugemem_ptr_t dest_huge_addr = HUGEMEM_NULL; hugemem_ptr_t src_huge_addr = HUGEMEM_NULL; hugemem_write32(dest_huge_addr, 0xABCD1234); hugemem_write32(src_huge_addr, 0xAAAABBBB); #else const uint16_t dest_addr = 0xBEEF; const uint16_t src_addr = 0xABCD; #endif memset(&config_params, 0, sizeof(config_params)); dma_enable(); /* Apply some parameters */ dma_channel_set_burst_length(&config_params, DMA_CH_BURSTLEN_4BYTE_gc); dma_channel_set_single_shot(&config_params); dma_channel_set_interrupt_level(&config_params, PMIC_LVL_HIGH); dma_channel_set_src_reload_mode(&config_params, DMA_CH_SRCRELOAD_BLOCK_gc); dma_channel_set_dest_reload_mode(&config_params, DMA_CH_DESTRELOAD_BURST_gc); dma_channel_set_src_dir_mode(&config_params, DMA_CH_SRCDIR_DEC_gc); dma_channel_set_dest_dir_mode(&config_params, DMA_CH_DESTDIR_DEC_gc); dma_channel_set_trigger_source(&config_params, DMA_CH_TRIGSRC_TCC0_CCA_gc); dma_channel_set_transfer_count(&config_params, transfer_count); dma_channel_set_repeats(&config_params, repeats); #ifdef CONFIG_HAVE_HUGEMEM dma_channel_set_destination_hugemem(&config_params, dest_huge_addr); dma_channel_set_source_hugemem(&config_params, src_huge_addr); #else dma_channel_set_destination_address(&config_params, dest_addr); dma_channel_set_source_address(&config_params, src_addr); #endif /* Loop through all channels, read back config from them, and verify */ for (channel_index = 0; channel_index < DMA_NUMBER_OF_CHANNELS; channel_index++) { dma_channel_write_config(channel_index, &config_params); /* Null out the read_config struct */ memset(&read_config, 0, sizeof(read_config)); /* Read the config back from the module */ dma_channel_read_config(channel_index, &read_config); test_assert_true(test, read_config.addrctrl == config_params.addrctrl, "CH %d: Address control register does not match configuration", channel_index); test_assert_true(test, read_config.ctrla == config_params.ctrla, "CH %d: Control register A does not match configuration", channel_index); test_assert_true(test, read_config.repcnt == config_params.repcnt, "CH %d: Repeat counter register does not match configuration", channel_index); test_assert_true(test, read_config.trfcnt == config_params.trfcnt, "CH %d: Transfer counter register does not" " match configuration", channel_index); test_assert_true(test, read_config.trigsrc == config_params.trigsrc, "CH %d: Trigger source register does not match configuration", channel_index); #ifdef CONFIG_HAVE_HUGEMEM test_assert_true(test, read_config.destaddr == config_params.destaddr, "CH %d: Destination address register does not" " match configuration", channel_index); test_assert_true(test, read_config.srcaddr == config_params.srcaddr, "CH %d: Source address register does not match configuration", channel_index); #else test_assert_true(test, read_config.destaddr16 == config_params.destaddr16, "CH %d: DESTADDR16 does not match configuration", channel_index); test_assert_true(test, read_config.srcaddr16 == config_params.srcaddr16, "CH %d: SRCADDR16 does not match configuration"); #endif } /* Reset the channel */ dma_channel_reset(DMA_CHANNEL_0); /* Check set and unset single shot */ memset(&config_params, 0, sizeof(config_params)); memset(&read_config, 0, sizeof(read_config)); dma_channel_set_single_shot(&config_params); dma_channel_write_config(DMA_CHANNEL_0, &config_params); dma_channel_read_config(DMA_CHANNEL_0, &read_config); test_assert_true(test, read_config.ctrla == config_params.ctrla, "Single shot mode not set correctly"); memset(&config_params, 0, sizeof(config_params)); dma_channel_unset_single_shot(&config_params); dma_channel_write_config(DMA_CHANNEL_0, &config_params); dma_channel_read_config(DMA_CHANNEL_0, &read_config); test_assert_true(test, read_config.ctrla == config_params.ctrla, "Single shot mode not unset correctly"); /* Reset it again, and test the direct configuration functions */ memset(&read_config, 0, sizeof(read_config)); dma_channel_write_burst_length(DMA_CHANNEL_0, DMA_CH_BURSTLEN_4BYTE_gc); dma_channel_write_transfer_count(DMA_CHANNEL_0, transfer_count); dma_channel_write_repeats(DMA_CHANNEL_0, repeats); #ifdef CONFIG_HAVE_HUGEMEM dma_channel_write_source_hugemem(DMA_CHANNEL_0, src_huge_addr); dma_channel_write_destination_hugemem(DMA_CHANNEL_0, dest_huge_addr); #else dma_channel_write_source(DMA_CHANNEL_0, src_addr); dma_channel_write_destination(DMA_CHANNEL_0, dest_addr); #endif /* Verify that settings have been set correctly */ dma_channel_read_config(DMA_CHANNEL_0, &read_config); test_assert_true(test, (read_config.ctrla & DMA_CH_BURSTLEN_gm) == DMA_CH_BURSTLEN_4BYTE_gc, "Read burst length does not match configuration"); test_assert_true(test, read_config.trfcnt == transfer_count, "Read transfer count does not match configuration"); test_assert_true(test, read_config.repcnt == repeats, "Read repeat value does not match configuration"); #ifdef CONFIG_HAVE_HUGEMEM test_assert_true(test, read_config.srcaddr == src_huge_addr, "Read source address does not match configuration"); test_assert_true(test, read_config.destaddr == dest_huge_addr, "Read destination address does not match configuration"); #else test_assert_true(test, read_config.srcaddr16 == src_addr, "Read source address does not match configuration"); test_assert_true(test, read_config.destaddr16 == dest_addr, "Read destination address does not match configuration"); #endif dma_disable(); }
/** * \brief Test different directions on all channels * * \note This test copies the source memory block into the destination block * in different ways. * * \param test Current test */ static void run_dma_direction_test(const struct test_case *test) { struct dma_channel_config config_params; uint8_t channel_index; bool success = true; /* Assume everything goes well */ /* Fill the source block with our known pattern */ set_buffer(memory_block_src, 0x00); block_fill(memory_block_src, MEMORY_BLOCK_SIZE); /* Null out the config params */ memset(&config_params, 0, sizeof(config_params)); /* Enable DMA */ dma_enable(); /* No reload on source and destination */ dma_channel_set_src_reload_mode(&config_params, DMA_CH_SRCRELOAD_NONE_gc); dma_channel_set_dest_reload_mode(&config_params, DMA_CH_DESTRELOAD_NONE_gc); dma_channel_set_transfer_count(&config_params, MEMORY_BLOCK_SIZE); dma_channel_set_burst_length(&config_params, DMA_CH_BURSTLEN_1BYTE_gc); /* Test a memory transfer on all channels */ for (channel_index = 0; channel_index < DMA_NUMBER_OF_CHANNELS; channel_index++) { /* Reset channel and write the configuration */ dma_channel_reset(channel_index); /* Increment source, increment destination */ dma_channel_set_src_dir_mode(&config_params, DMA_CH_SRCDIR_INC_gc); dma_channel_set_dest_dir_mode(&config_params, DMA_CH_DESTDIR_INC_gc); /* Data starts from the first byte */ dma_channel_set_source_address(&config_params, (uint16_t)(uintptr_t)memory_block_src); dma_channel_set_destination_address(&config_params, (uint16_t)(uintptr_t)memory_block_dest); /* Write the config */ dma_channel_write_config(channel_index, &config_params); /* Clear destination */ set_buffer(memory_block_dest, 0x00); /* Enable channel, transfer, and disable it */ dma_channel_enable(channel_index); dma_transfer_block(channel_index); dma_channel_disable(channel_index); /* Check that source and destination are equal */ success = block_compare(memory_block_src, memory_block_dest, MEMORY_BLOCK_SIZE); if (!success) { break; } /* Reset channel and write the configuration */ dma_channel_reset(channel_index); /* Decrement source, increment destination */ dma_channel_set_src_dir_mode(&config_params, DMA_CH_SRCDIR_DEC_gc); dma_channel_set_dest_dir_mode(&config_params, DMA_CH_DESTDIR_INC_gc); /* Data starts from the first byte */ dma_channel_set_source_address(&config_params, (uint16_t)(uintptr_t) (memory_block_src + MEMORY_BLOCK_SIZE - 1)); dma_channel_set_destination_address(&config_params, (uint16_t)(uintptr_t)memory_block_dest); /* Write the config */ dma_channel_write_config(channel_index, &config_params); /* Clear destination */ set_buffer(memory_block_dest, 0x00); /* Enable channel, transfer, and disable it */ dma_channel_enable(channel_index); dma_transfer_block(channel_index); dma_channel_disable(channel_index); /* Check that destination is the reverse of source */ success = block_compare_reverse(memory_block_src, memory_block_dest, MEMORY_BLOCK_SIZE); if (!success) { break; } /* Reset channel and write the configuration */ dma_channel_reset(channel_index); /* Decrement source, increment destination */ dma_channel_set_src_dir_mode(&config_params, DMA_CH_SRCDIR_INC_gc); dma_channel_set_dest_dir_mode(&config_params, DMA_CH_DESTDIR_DEC_gc); /* Data starts from the first byte */ dma_channel_set_source_address(&config_params, (uint16_t)(uintptr_t)memory_block_src); dma_channel_set_destination_address(&config_params, (uint16_t)(uintptr_t) (memory_block_dest + MEMORY_BLOCK_SIZE - 1)); /* Write the config */ dma_channel_write_config(channel_index, &config_params); /* Clear destination */ set_buffer(memory_block_dest, 0x00); /* Enable channel, transfer, and disable it */ dma_channel_enable(channel_index); dma_transfer_block(channel_index); dma_channel_disable(channel_index); /* Check that destination is the reverse of source */ success = block_compare_reverse(memory_block_src, memory_block_dest, MEMORY_BLOCK_SIZE); if (!success) { break; } /* Reset channel and write the configuration */ dma_channel_reset(channel_index); /* Decrement source, Decrement destination */ dma_channel_set_src_dir_mode(&config_params, DMA_CH_SRCDIR_DEC_gc); dma_channel_set_dest_dir_mode(&config_params, DMA_CH_DESTDIR_DEC_gc); /* Data starts from the first byte */ dma_channel_set_source_address(&config_params, (uint16_t)(uintptr_t) (memory_block_src + MEMORY_BLOCK_SIZE - 1)); dma_channel_set_destination_address(&config_params, (uint16_t)(uintptr_t) (memory_block_dest + MEMORY_BLOCK_SIZE - 1)); /* Write the config */ dma_channel_write_config(channel_index, &config_params); /* Clear destination */ set_buffer(memory_block_dest, 0x00); /* Enable channel, transfer, and disable it */ dma_channel_enable(channel_index); dma_transfer_block(channel_index); dma_channel_disable(channel_index); /* Check that source and destination are equal */ success = block_compare(memory_block_src, memory_block_dest, MEMORY_BLOCK_SIZE); if (!success) { break; } } /* Disable DMA */ dma_disable(); test_assert_true(test, success, "DMA direction copy test failed on channel %d", channel_index); }
static boolean __wss_detect() { /* First find the port number */ if (!wss.port) { static unsigned int wss_ports[] = { 0x32c, 0x530, 0x604, 0xE80, 0xF40 }; int i; for (i = 0; i < 5; i++) { wss.port = wss_ports[i]; if (__wss_ping()) break; } if (i < 0) { wss.port = 0; return FALSE; } } /* Now disable output */ wss_output(FALSE); /* Detect the DMA channel */ if (!wss.dma) { static int __dma[] = { 0, 1, 3 }; int i; /* Enable playback IRQ */ __wss_regbit_set(WSSR_PIN_CTRL, WSSM_IRQ_ENABLE); __wss_outreg(WSSR_IRQ_STATUS, WSSM_PLAYBACK_IRQ); /* Start a short DMA transfer and check if DMA count is zero */ for (i = 0; i < 3; i++) { unsigned int timer, status, freq = 44100; wss.dma = __dma[i]; dma_disable(wss.dma); dma_set_mode(wss.dma, DMA_MODE_WRITE); dma_clear_ff(wss.dma); dma_set_count(wss.dma, 10); dma_enable(wss.dma); /* Clear IRQ status */ outportb(WSS_STATUS, 0); __wss_setformat(__wss_getrate(&freq)); __wss_outreg(WSSR_COUNT_LOW, 1); __wss_outreg(WSSR_COUNT_HIGH, 0); /* Tell codec to start transfer */ __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE); _farsetsel(_dos_ds); timer = _farnspeekl(0x46c); while (_farnspeekl(0x46c) - timer <= 2) if (dma_get_count(wss.dma) == 0) break; __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE); dma_disable(wss.dma); /* Now check if DMA transfer count is zero and an IRQ is pending */ status = inportb(WSS_STATUS); outportb(WSS_STATUS, 0); if ((dma_get_count(wss.dma) == 0) && (status & WSSM_INT)) break; wss.dma = 0; } if (!wss.dma) return FALSE; } /* Now detect the IRQ number */ if (!wss.irq) { unsigned int i, irqmask, freq = 5510; unsigned long timer, delta = 0x7fffffff; /* IRQ can be one of 2,3,5,7,10 */ irq_detect_start(0x04ac, __wss_irq_irqdetect); dma_disable(wss.dma); dma_set_mode(wss.dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT); dma_clear_ff(wss.dma); dma_set_count(wss.dma, 1); dma_enable(wss.dma); __wss_setformat(__wss_getrate(&freq)); /* Clear IRQ status */ outportb(WSS_STATUS, 0); __wss_outreg(WSSR_COUNT_LOW, 0); __wss_outreg(WSSR_COUNT_HIGH, 0); /* Prepare timeout counter */ _farsetsel(_dos_ds); timer = _farnspeekl(0x46c); while (timer == _farnspeekl(0x46c)); timer = _farnspeekl(0x46c); /* Reset all IRQ counters */ irq_detect_clear(); /* Tell codec to start transfer */ __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE); /* Now wait 1/18 seconds */ while (timer == _farnspeekl(0x46c)); __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE); dma_disable(wss.dma); /* Given frequency 5510Hz, a buffer size of 1 byte and a time interval of 1/18.2 second, we should have received about 302 interrupts */ for (i = 2; i <= 10; i++) { int count = abs(302 - irq_detect_get(i, &irqmask)); if (count < delta) wss.irq = i, delta = count; } if (delta > 150) wss.irq = 0; irq_detect_end(); if (!wss.irq) return FALSE; } return TRUE; }
/** * Read part of a 512 byte block from an SD card. * * \param[in] block Logical block to be read. * \param[in] offset Number of bytes to skip at start of block * \param[out] dst Pointer to the location that will receive the data. * \param[in] count Number of bytes to read * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ uint8_t Sd2Card::readData(uint32_t block, uint16_t offset, uint16_t count, uint8_t* dst) { //uint16_t n; if (count == 0) return true; if ((count + offset) > 512) { goto fail; } if (!inBlock_ || block != block_ || offset < offset_) { block_ = block; // use address if not SDHC card if (type()!= SD_CARD_TYPE_SDHC) block <<= 9; if (cardCommand(CMD17, block)) { error(SD_CARD_ERROR_CMD17); Serial.println("Error: CMD17"); goto fail; } if (!waitStartBlock()) { goto fail; } offset_ = 0; inBlock_ = 1; } #ifdef SPI_DMA // skip data before offset if(offset_ < offset){ dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, ack, DMA_SIZE_8BITS, (/*DMA_MINC_MODE | DMA_CIRC_MODE |*/ DMA_FROM_MEM | DMA_TRNS_CMPLT | DMA_TRNS_ERR)); dma_attach_interrupt(DMA1, DMA_CH3, DMAEvent); dma_set_priority(DMA1, DMA_CH3, DMA_PRIORITY_VERY_HIGH); dma_set_num_transfers(DMA1, DMA_CH3, offset - offset_); dmaActive = true; dma_enable(DMA1, DMA_CH3); while(dmaActive) delayMicroseconds(1); dma_disable(DMA1, DMA_CH3); } offset_ = offset; // transfer data dma_setup_transfer(DMA1, DMA_CH2, &SPI1->regs->DR, DMA_SIZE_8BITS, dst, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT | DMA_TRNS_ERR)); dma_attach_interrupt(DMA1, DMA_CH2, DMAEvent); dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, ack, DMA_SIZE_8BITS, (/*DMA_MINC_MODE | DMA_CIRC_MODE |*/ DMA_FROM_MEM)); dma_set_priority(DMA1, DMA_CH2, DMA_PRIORITY_VERY_HIGH); dma_set_priority(DMA1, DMA_CH3, DMA_PRIORITY_VERY_HIGH); dma_set_num_transfers(DMA1, DMA_CH2, count); dma_set_num_transfers(DMA1, DMA_CH3, count); dmaActive = true; dma_enable(DMA1, DMA_CH3); dma_enable(DMA1, DMA_CH2); while(dmaActive) delayMicroseconds(1); dma_disable(DMA1, DMA_CH3); dma_disable(DMA1, DMA_CH2); offset_ += count; if (!partialBlockRead_ || offset_ >= SPI_BUFF_SIZE) { readEnd(); } #else // skip data before offset for (;offset_ < offset; offset_++) { spiRec(); } // transfer data for (uint16_t i = 0; i < count; i++) { dst[i] = spiRec(); } offset_ += count; if (!partialBlockRead_ || offset_ >= 512) { // read rest of data, checksum and set chip select high readEnd(); } #endif return true; fail: chipSelectHigh(); Serial.println("Error: Sd2Card::readData()"); return false; }