Skip to content

Commit 3da9326

Browse files
committed
Use DMA for transfers.
1 parent 55d3e02 commit 3da9326

1 file changed

Lines changed: 58 additions & 2 deletions

File tree

firmware/hackrf_usb/usb_api_transceiver.c

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@
2626
#include <stdbool.h>
2727
#include <stddef.h>
2828

29+
#include <libopencm3/lpc43xx/m4/nvic.h>
30+
#include <libopencm3/cm3/nvic.h>
31+
2932
#include <fixed_point.h>
33+
#include <gpdma.h>
3034
#include <hackrf_core.h>
3135
#include <hackrf_ui.h>
3236
#include <m0_state.h>
@@ -75,6 +79,8 @@ typedef struct {
7579

7680
set_sample_r_params_t set_sample_r_params;
7781

82+
void transceiver_dma_setup(void);
83+
7884
usb_request_status_t usb_vendor_request_set_baseband_filter_bandwidth(
7985
usb_endpoint_t* const endpoint,
8086
const usb_transfer_stage_t stage)
@@ -347,6 +353,8 @@ void transceiver_startup(const transceiver_mode_t mode)
347353
usb_started = 0;
348354
usb_completed = 0;
349355

356+
transceiver_dma_setup();
357+
350358
radio_switch_opmode(&radio, mode);
351359

352360
hackrf_ui()->set_transceiver_mode(mode);
@@ -460,15 +468,63 @@ usb_request_status_t usb_vendor_request_get_buffer_size(
460468
return USB_REQUEST_STATUS_OK;
461469
}
462470

471+
/* clang-format off */
472+
473+
// Which GPDMA channel to use.
474+
const uint32_t DMA_CHANNEL = 1;
475+
476+
// GPDMA CCONFIG register setting.
477+
const uint32_t DMA_CONFIG =
478+
GPDMA_CCONFIG_FLOWCNTRL(0) // memory-to-memory
479+
| GPDMA_CCONFIG_IE(0) // no error interrupt
480+
| GPDMA_CCONFIG_ITC(1) // terminal count interrupt
481+
| GPDMA_CCONFIG_L(0) // do not lock
482+
| GPDMA_CCONFIG_H(0); // do not halt
483+
484+
// GPDMA CCONTROL register setting (excluding TRANSFERSIZE field).
485+
const uint32_t DMA_CONTROL =
486+
GPDMA_CCONTROL_SBSIZE(7) // 256-transfer src bursts
487+
| GPDMA_CCONTROL_DBSIZE(7) // 256-transfer dst bursts
488+
| GPDMA_CCONTROL_SWIDTH(2) // 32-bit src transfers
489+
| GPDMA_CCONTROL_DWIDTH(2) // 32-bit dst transfers
490+
| GPDMA_CCONTROL_S(0) // AHB Master 0
491+
| GPDMA_CCONTROL_D(1) // AHB Master 1
492+
| GPDMA_CCONTROL_SI(1) // increment source
493+
| GPDMA_CCONTROL_DI(1) // increment destination
494+
| GPDMA_CCONTROL_PROT1(0) // user mode
495+
| GPDMA_CCONTROL_PROT2(0) // not bufferable
496+
| GPDMA_CCONTROL_PROT3(0) // not cacheable
497+
| GPDMA_CCONTROL_I(1); // interrupt enabled
498+
499+
/* clang-format on */
500+
501+
// Called before any sequence of DMA transfers.
502+
void transceiver_dma_setup(void)
503+
{
504+
gpdma_controller_enable();
505+
GPDMA_CCONFIG(DMA_CHANNEL) = DMA_CONFIG;
506+
GPDMA_CCONTROL(DMA_CHANNEL) = DMA_CONTROL;
507+
GPDMA_CLLI(DMA_CHANNEL) = 0;
508+
GPDMA_INTTCCLEAR = (1 << DMA_CHANNEL);
509+
nvic_enable_irq(NVIC_DMA_IRQ);
510+
}
511+
512+
// Called to start each DMA transfer.
463513
void transceiver_start_dma(void* src, void* dest, size_t size)
464514
{
515+
uint32_t num_transfers = size >> 2;
516+
GPDMA_CCONTROL(DMA_CHANNEL) = DMA_CONTROL | num_transfers;
517+
GPDMA_CSRCADDR(DMA_CHANNEL) = (uint32_t) src;
518+
GPDMA_CDESTADDR(DMA_CHANNEL) = (uint32_t) dest;
465519
dma_pending = size;
466-
memcpy(dest, src, size);
467-
dma_isr();
520+
gpdma_channel_enable(DMA_CHANNEL);
468521
}
469522

523+
// Called when a DMA transfer completes.
470524
void dma_isr(void)
471525
{
526+
gpdma_channel_disable(DMA_CHANNEL);
527+
GPDMA_INTTCCLEAR = (1 << DMA_CHANNEL);
472528
m0_state.m4_count += dma_pending;
473529
dma_pending = 0;
474530
}

0 commit comments

Comments
 (0)