#include #include #include #include static const struct device * dma_dev; static int dma_chan; static struct dma_config dma_cfg; static struct dma_block_config dma_block_cfg; static K_SEM_DEFINE(dma_sem, 0, 1); static void dma_complete_callback(const struct device *dev, void *user_data, uint32_t channel, int status) { k_sem_give(&dma_sem); } static int dma_transfer_init(void) { if (dma_dev) { return 0; } dma_dev = device_get_binding(CONFIG_DMA_0_NAME); if (dma_dev == NULL) { SYS_LOG_ERR(CONFIG_DMA_0_NAME " not found"); return -ENODEV; } dma_chan = dma_request(dma_dev, 0xFF); if (dma_chan < 0) { SYS_LOG_ERR("dma_request failed"); dma_dev = NULL; return -ENODEV; } dma_cfg.complete_callback_en = 1; dma_cfg.dma_callback = dma_complete_callback; dma_cfg.dma_slot = 0; dma_cfg.dest_data_size = 4; dma_cfg.block_count = 1; dma_cfg.head_block = &dma_block_cfg; return 0; } static int _memset32(void * buf, uint32_t c32, size_t n) { static uint32_t dma_c32 __in_section_unique(ram.noinit); if (ui_memsetcpy_wait_finish(5000)) { k_sem_reset(&dma_sem); } dma_c32 = c32; dma_cfg.channel_direction = PERIPHERAL_TO_MEMORY; dma_block_cfg.block_size = n; dma_block_cfg.source_address = (uint32_t)&dma_c32; dma_block_cfg.dest_address = (uint32_t)buf; if (dma_config(dma_dev, dma_chan, &dma_cfg)) { SYS_LOG_ERR("dma%d config error\n", dma_chan); dma_block_cfg.block_size = 0; return -1; } if (dma_start(dma_dev, dma_chan)) { SYS_LOG_ERR("dma%d start error\n", dma_chan); dma_block_cfg.block_size = 0; return -1; } return 0; } void ui_memset(void * buf, uint8_t c, size_t n) { if (((uintptr_t)buf & 0x3) || (n & 0x3)) { memset(buf, c, n); return; } if (dma_transfer_init()) { memset(buf, c, n); return; } uint32_t c32 = c | ((uint32_t)c << 8) | ((uint32_t)c << 16) | ((uint32_t)c << 24); if (_memset32(buf, c32, n)) { memset(buf, c, n); } } int ui_memset16(void * buf, uint16_t c16, size_t n16) { if (((uintptr_t)buf & 0x3) || (n16 & 0x1)) { return -EINVAL; } if (dma_transfer_init()) { return -EINVAL; } uint32_t c32 = c16 | ((uint32_t)c16 << 16); return _memset32(buf, c32, n16 * 2); } int ui_memset32(void * buf, uint32_t c32, size_t n32) { if ((uintptr_t)buf & 0x3) { return -EINVAL; } if (dma_transfer_init()) { return -EINVAL; } return _memset32(buf, c32, n32 * 4); } void ui_memcpy(void * dest, const void * src, size_t n) { if (((uintptr_t)dest & 0x3) || ((uintptr_t)src & 0x3) || (n & 0x3)) { memcpy(dest, src, n); return; } if (dma_transfer_init()) { memcpy(dest, src, n); return; } if (ui_memsetcpy_wait_finish(5000)) { k_sem_reset(&dma_sem); } dma_cfg.channel_direction = MEMORY_TO_MEMORY; dma_block_cfg.block_size = n; dma_block_cfg.source_address = (uint32_t)src; dma_block_cfg.dest_address = (uint32_t)dest; if (dma_config(dma_dev, dma_chan, &dma_cfg)) { SYS_LOG_ERR("dma%d config error\n", dma_chan); dma_block_cfg.block_size = 0; memcpy(dest, src, n); return; } if (dma_start(dma_dev, dma_chan)) { SYS_LOG_ERR("dma%d start error\n", dma_chan); dma_block_cfg.block_size = 0; memcpy(dest, src, n); return; } } int ui_memsetcpy_wait_finish(int timeout_ms) { int res = 0; if (dma_dev == NULL) { return 0; } if (dma_block_cfg.block_size > 0) { if (timeout_ms < 0) { res = k_sem_take(&dma_sem, K_FOREVER); } else { res = k_sem_take(&dma_sem, K_MSEC(timeout_ms)); } if (res == 0) { dma_block_cfg.block_size = 0; } } return res; }