DMA Driver

[中文]

Overview

DMA (Direct Memory Access) driver provides high-speed data transfer between memory and peripherals without CPU intervention.

Functional Description

  • Multiple DMA channels for concurrent operations

  • Memory-to-memory transfers

  • Peripheral-to-memory transfers

  • Memory-to-peripheral transfers

  • Interrupt support for transfer completion

  • Channel allocation and management

  • Configurable transfer parameters

  • Status monitoring

  • Low power mode support

Development Guide

  1. Initialization - Call bk_dma_driver_init() before any DMA operations - Allocate channel: bk_dma_alloc(user_id) - Configure transfer: source, destination, length

  2. Basic Operations - Set addresses: bk_dma_set_src_addr(), bk_dma_set_dest_addr() - Set length: bk_dma_set_transfer_len() - Start transfer: bk_dma_start() - Wait completion: bk_dma_wait_finish()

  3. Channel Management - Allocate: bk_dma_alloc() - Free: bk_dma_free() - Check remaining: bk_dma_get_remain_len()

  4. Interrupt Handling - Register ISR: bk_dma_register_isr() - Enable interrupt: bk_dma_enable_interrupt() - Handle completion in ISR

Notes

  • Channel allocation must be in task context

  • Ensure memory alignment for transfers

  • Consider cache consistency

  • Use proper interrupt priorities

API Reference

  • bk_dma_driver_init/deinit() - Driver management

  • bk_dma_alloc/free() - Channel management

  • bk_dma_set_src_addr/dest_addr() - Address configuration

  • bk_dma_set_transfer_len() - Length configuration

  • bk_dma_start/stop() - Transfer control

  • bk_dma_get_remain_len() - Status monitoring

  • bk_dma_register_isr() - Interrupt handling

  • bk_dma_wait_finish() - Synchronous wait

Examples

Basic memory-to-memory transfer:

bk_dma_driver_init();
dma_id_t chan = bk_dma_alloc(0x1000);
if (chan >= DMA_ID_MAX) {
    printf("DMA allocation failed\n");
    return;
}

uint8_t src[1024], dst[1024];
bk_dma_set_src_addr(chan, (uint32_t)src);
bk_dma_set_dest_addr(chan, (uint32_t)dst);
bk_dma_set_transfer_len(chan, 1024);
bk_dma_start(chan);
bk_dma_wait_finish(chan);
bk_dma_free(0x1000, chan);

Interrupt-based transfer:

static void dma_isr(dma_id_t id, void *param) {
    printf("DMA channel %d complete\n", id);
    bk_dma_clear_interrupt(id);
}

dma_id_t chan = bk_dma_alloc(0x1001);
bk_dma_register_isr(chan, dma_isr, NULL);
bk_dma_enable_interrupt(chan);

uint8_t src[512], dst[512];
bk_dma_set_src_addr(chan, (uint32_t)src);
bk_dma_set_dest_addr(chan, (uint32_t)dst);
bk_dma_set_transfer_len(chan, 512);
bk_dma_start(chan);

Peripheral-to-memory transfer:

dma_id_t chan = bk_dma_alloc(0x1002);
uint8_t buffer[256];
bk_dma_set_src_addr(chan, UART0_RX_ADDR);
bk_dma_set_dest_addr(chan, (uint32_t)buffer);
bk_dma_set_transfer_len(chan, 256);
bk_dma_start(chan);

while (bk_dma_get_remain_len(chan) > 0) {
    // Wait for completion
}
printf("Received %d bytes\n", 256);
bk_dma_free(0x1002, chan);

Status monitoring:

dma_id_t chan = bk_dma_alloc(0x1003);
uint8_t src[1024], dst[1024];
bk_dma_set_src_addr(chan, (uint32_t)src);
bk_dma_set_dest_addr(chan, (uint32_t)dst);
bk_dma_set_transfer_len(chan, 1024);
bk_dma_start(chan);

while (1) {
    uint32_t remain = bk_dma_get_remain_len(chan);
    dma_status_t status = bk_dma_get_status(chan);
    printf("Remain: %d, Status: %d\n", remain, status);

    if (remain == 0) {
        printf("Transfer complete\n");
        break;
    }
    rtos_delay_milliseconds(10);
}
bk_dma_free(0x1003, chan);

FAQs

  • Channel allocation failed: Check available channels and user ID

  • Transfer failure: Verify address alignment and validity

  • Interrupt not triggered: Confirm ISR registration and enable

Error Codes

  • BK_ERR_DMA_NOT_INIT: Driver not initialized

  • BK_ERR_DMA_INVALID_ID: Invalid DMA channel ID

  • BK_ERR_DMA_CHANNEL_BUSY: Channel busy

  • BK_ERR_DMA_TRANSFER_FAIL: Transfer failed