手把手教你如何配置DMA[共享]

嵌入式雷达系统DMA配置实战:从原理到TI芯片应用详解 在嵌入式系统与实时信号处理领域,直接内存访问(DMA)是一项核心的硬件加速技术。其基本原理是通过独立的控制器,在内存与外围设备之间直接搬运数据,无需CPU频繁介入,从而将CPU从繁重的数据搬运任务中解放出来,专注于计算密集型算法。这项技术的核心价值在于显著提升系统吞吐量、降低CPU负载并保障实时性,尤其适用于数据流密集的应用场景,如通信、音视频处理和传感器数据采集。本文聚焦于嵌入式雷达这一典型的高性能信号处理系统,深入剖析DMA在其中的关键作用。文章以德州仪器毫米波雷达芯片为具体案例,详细解读其DMA控制器 阅读详情
AI摘要

本文详细介绍了DMA(直接内存访问)技术的基本原理及其在嵌入式系统中的应用。内容覆盖了DMA控制器的工作方式、DMA寄存器配置、DMA传输例程等关键知识点,并通过一个具体的DMA演示案例帮助读者掌握DMA的使用技巧。

如果你还没有看过《嵌入式内功.葵花宝典》,那么在阅读本这篇推荐的文章之前有必要先去看看吧,你会有新的体会的。

Direct Memory Access

  • DMA...que?           /*到底啥是DMA*/
  • DMA registers      /*DMA寄存器*/
  • Some DMA routines   /*DMA的驱动*/
  • DMA demo       /*DMA的实例*/

1. DMA … que?

Direct Memory Access (DMA) is fast way of copying data from one place to another. Or, rather, a way of transferring data fast; as it can be used for copying data, but also filling memory. When you activate DMA the so-called DMA controller basically takes over the hardware (the CPU is actually halted), does the desired transfer and hands control back to the CPU before you even knew it was missing.

There are 4 DMA channels. Channel 0 has the highest priority. It is used for time-critical operations and can only be used with internal RAM. Channels 1 and 2 are used to transfer sound data to the right sound buffers for playback. The lowest priority channel, channel 3, is for general purpose copies. One of the primary uses for this channel is loading in new bitmap or tile data.

2. DMA registers

Every kind of transfer routine needs 3 things: a source, a destination and the amount of data to copy. The whence, whither and how much. For DMA, the source address is put into REG_DMAxSAD and destination address into REG_DMAxDAD. A third register, REG_DMAxCNT, not only indicates the amount to transfer, but also controls other features possible for DMA, like when it should start the transfer, chunk-size, and how the source and destination addresses should be updated after each individual chunk of data. All the DMA registers are 32bits in length, though they can be divided into two 16bit registers if so desired. Those of channel 0 start at0400:00B0h; subsequent channels start at an offset of 12 (see table 1).

Table 1: DMA register addresses
reg function address
REG_DMAxSAD source 0400:00B0h + 0Ch·x
REG_DMAxDAD destination 0400:00B4h + 0Ch·x
REG_DMAxCNT control 0400:00B8h + 0Ch·x

2.1. DMA controls

The use of the source and destination registers should be obvious. The control register needs some explaining. Although the REG_DMAxCNT registers themselves are 32bits, they are often split into two separate registers: one for the count, and one for the actual control bits.

REG_DMAxCNT @ 0400:00B8+12 x
1F 1E 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 F E D C B A 9 8 7 6 5 4 3 2 1 0
En I TM - CS R SA DA - N

bits name define description
00-0F N  Number of transfers.
15-16 DA _DMA_DST_INC, DMA_DST_DEC, DMA_DST_FIXED, DMA_DST_RESET Destination adjustment.
  • 00: increment after each transfer (default)
  • 01: decrement after each transfer
  • 10: none; address is fixed
  • 11: haven't used it yet, but apparently this will increment the destination during the transfer, and reset it to the original value when it's done.
17-18 SA _DMA_SRC_INC, DMA_SRC_DEC, DMA_SRC_FIXED, Source Adjustment. Works just like the two bits for the destination. Note that there is no DMA_SRC_RESET; code 3 for source is forbidden.
19 R DMA_REPEAT Repeats the copy at each VBlank or HBlank if the DMA timing has been set to those modes.
1A CS _DMA_16, DMA_32 Chunk Size. Sets DMA to copy by halfword (if clear) or word (if set).
1C-1D TM _DMA_NOW, DMA_AT_VBLANK, DMA_AT_HBLANK, DMA_AT_REFRESH Timing Mode. Specifies when the transfer should start.
  • 00: start immediately.
  • 01: start at VBlank.
  • 10: start at HBlank.
  • 11: Never used it so far, but here's how I gather it works. For DMA1 and DMA2 it'll refill the FIFO when it has been emptied. Count and size are forced to 1 and 32bit, respectively. For DMA3 it will start the copy at the start of each rendering line, but with a 2 scanline delay.
1E I DMA_IRQ Interrupt request. Raise an interrupt when finished.
1F En DMA_ON Enable the DMA transfer for this channel.

2.2. Source and destination addresses

The registers for source and destination addresses work just as you'd expect: just put in the proper addresses. Oh, I should tell you that the sizes for the source and destination addresses are 28 and 27 bits wide, respectively, and not the full 32. This is nothing to worry about though: you can't access addresses above 1000:0000h anyway. For destination addresses you can't use the section above 0800:0000h. But then, being able to copy to ROM would be kind of strange, wouldn't it?


2.3. DMA flags

The REG_DMAxCNT registers can be split in two parts: one with actual flags, and one for the number of copies to do. Either way will work but you must be careful how the flags are defined: using 32-bit #defines for 16-bit registers or vice versa is not a good idea.

There are options to control what will be the next source and destination addresses when one chunk has been transferred. By default, both will increment so that it works as a copier. But you could also keep the source constant so that it'd work more as a memory fill.

What goes into the lower half of REG_DMAxCNT is the number of transfers. This is the number of chunks, not bytes! Best be careful when using sizeof() or something similar here, missing a factor 2 or 4 is very easy. A chunk can be either 16 or 32 bit, depending on bit 26.


2.4. More on DMA timing

What the immediate DMA does is easy to imagine: it works as soon as you enable the DMA. Well actually it takes 2 cycles before it'll set in basically it'll work immediately. The other timing settings aren't that more difficult conceptually, but there is one point of confusion.

Consider the following situation: you want to do something cool to your otherwise standard backgrounds; specifically, you want to do something that requires the background registers to be updated every scanline. I just said that you can copy data at every HBlank (via the DMA_AT_HBLANK timing flag), which seems perfect for the job. If you think about it for a minute, however, you may ask yourself the following question:

When you set the timing to, say, DMA_AT_HBLANK, does it do all the N copies at the next HBlank, of one copy at each HBlank until the list is done?

There is a crucial difference between the two. The first option seems pointless because all copied would be done at once; if your destination is fixed (like they are for background registers) all copies except the last would be lost. In the case of the second one, how would you do more than one copy per HBlank? Clearly, something's amiss here. There is, on two counts.

For the record, I'm not 100% sure about what I'm going to say here, but I think it's pretty close to what's actually going on. The main thing to realize is that as long as the channel is not enabled (REG_DMAxCNT{1f} is cleared), that channel won't do squat; only after REG_DMAxCNT{1f} has been set will the DMA process be initiated. At the appropriate time (determined by the timing bits) DMA will do all N copies and then shut itself off again.

Unless, that is, the repeat-bit (REG_DMAxCNT{19}) is set. In that case it will keep doing the copies at the right time until you disable the channel yourself.

3. Some DMA routines

While it's not that much trouble to set the three registers manually, it is preferable to hide the direct interaction in subroutines. For example, you could make something like this:

// Plz don't do this
void dma_copy(int 
  ch, void* src, 
 void* dest, u32 count, u32 mode)
{
    switch(ch)
    {
    case 0:
        // set DMA 0
    case 1:
        // set DMA 1
... // etc
    }
}

You might find this in older code, but it is a bad way of coding. I mean, a function with 5 arguments and a switch block to fill 3 registers while the whole point of DMA is about speed? This isn't just bad, it's downright perverse. There are several simple and not so simple ways to improve such a function in every aspect.

The first order of business: get rid of the switch-block. As a basic rule: if your cases differ only by a single number (or variable), you're doing something wrong. There are a number of ways of fixing this, but the easiest is by mapping a struct array over the DMA registers, similar to what I did for tile memory. After that, you can just select the channel with the channel variable and simply fill in the addresses and flags.

typedef struct tagDMAREC
{
    const void *src;
    void *dst;
    u32 cnt;
} DMAREC;

#define dma_mem ((volatile DMAREC*)0x040000b0)

The following are my three of my DMA routines. First the DMA_TRANSER() macro, which is the overall macro that can be used for anything. Then two routines for general memory copies and fills using 32bit transfers with DMA 3.

// in core.h
#define DMA_TRANSFER(_dst, _src, _count, 
 _ch, _mode)    /
do {                                            /
    dma_mem[_ch].cnt= 0;                        /
    dma_mem[_ch].src= (const void*)(_src);      /
    dma_mem[_ch].dst= (void*)(_dst);            /
    dma_mem[_ch].cnt= (_count) | (_mode);       /
} while(0)

// in core.c
void dma_memcpy(void *dst, const void *src, u16 count)
{
    dma_mem[3].cnt = 0; // shut off any previous transfer
    dma_mem[3].src = src;
    dma_mem[3].dst = dst;
    dma_mem[3].cnt = count | DMA_32NOW;
}

void dma_memset(void *dst, volatile u32 src, u16 count)
{
    dma_mem[3].cnt = 0; // shut off any previous transfer
    dma_mem[3].src = (const void*)&src;
    dma_mem[3].dst = dst;
    dma_mem[3].cnt = count | DMA_32NOW | DMA_SRC_FIX;
}

In all cases, I disable any previously operating transfers first. After that it's simply a matter of filling the registers. Now, it so happens that there is a 2 cycle delay before any transfer really begins. This means that you could lose a transfer if you ask for transfers in immediate succession. That's why I'm using functions here rather than macros or inlines: returning from the function takes enough time to allow the transfer to begin. I somewhat doubt that this whole thing would ever become a problem, but by adding the delay we can be absolutely sure of it.


I used to have the following macro for my transfers. It use one of the more exotic capabilities of the preprocessor: the merging-operator ‘##’, which allows you to create symbol names at compile-time. It's scary, totally unsafe and generally unruly, but it does work. The other macro I gave is better, but I still like this thing too.

#define 
 DMA_TRANSFER(_dst, _src, _count, _ch, _mode)  /
    REG_DMA##_ch##SAD = (u32)(_src),                  /
    REG_DMA##_ch##DAD = (u32)(_dst),                  /
    REG_DMA##_ch##CNT = (_count) | (_mode)            /

As long as you are using a literal number for _ch it'll form the correct register names. And yes, those comma operators between the statements actually work. They keep the statements separate, and also guard against wrongful nesting just like the do{} while(0) construct does.

3.1. On DMA fills

DMA can be used to fill memory, but there are two problems that you need to be aware of before you try it. The first can be caught by simply paying attention. DMA fills don't work quite in the same way as memset() does. What you put into REG_DMAxSAD isn't the value you want to fill with, but its address!

“Very well, I'll put the value in a variable and put use its address.” Yes, and that brings us to our second problem, a bug which is almost impossible to find. If you try this, you'll find that it doesn't work. Well it fills with something, but usually not what you wanted to fill with. The full explanation is somewhat technical, but basically because you're probably only using the variable's address and not its value, the optimizer doesn't ever initialize it. There is a simple solution, one that we've seen before, make it volatile. Or you can use a (inline) function like dma_memset(), which has its source argument set as volatile so you can just insert a number just as you'd expect. Note that if you remove the volatile keyword there, it'll fail again.


In short: DMA fills need addresses, not direct values. Globals will always work, but if you use local variables or arguments you'll need to make them volatile. Note that the same thing holds true for the BIOS call CpuFastSet().


3.2. DMA; don't wear it out

DMA is fast, there's no question about that. It can be up to ten times as fast as array copies. However, think twice about using it for every copy. First of all, while it is fast, it doesn't quite blow ever other transfer routine out of the water. CpuFastSet() comes within 10% of it for copies and is actually 10% faster for fills. The speed gain isn't that big a deal. Another problem is that it stops the CPU, which can screw up interrupts, causing seemingly random bugs. It does have its specific uses, usually in conjunction with timers or interrupts, but for general copies, you might consider other things as well. CpuFastSet() is a good routine, but tonclib also comes with memcpy16()/32() and memset16()/32() routines that are safer than that, and less restrictions. They are assembly routines, though, so you'll need to know how to assembly, or use libraries.

4. DMA demo

Fig 1: dma_demo palette
Fig 1: palette for dma_demo.

Actually, I've been using dma_memcpy in most of the demos so far, so check out any of them to see how to use it. On second thought, never mind that; I will do a demo because there may be some confusion about how DMA timing and repeat works. In this demo I'm going to update the transparent background color (pal_bg_mem[0]) at every HBlank. Unfortunately, I should point out that the demo is slightly ruined by the fact that I screwed up the defines when I first made it (I had a DMA_SRC_RESET that had the settings belonging to DMA_DST_RESET, but the results are still interesting.

First, we make a palette for every scanline (shown on the right). This is the DMA source. the primary destination is pal_bg_mem[0]. We do 16-bit copies at an HBlank and repeat for each HBlank. The basic flag is

#define DMA_DEMO (DMA_ON | DMA_REPEAT | 
 DMA_AT_HBLANK | _DMA_SRC_INC | DMA_16)

I'm going to do something special with the count and destination stuff, so I left those out. The code for the main loop is:

while(1)
{
    key_poll();

    // A: 1 copy, dst fixed
    if(KEY_DOWN_NOW(KEY_A))
        DMA_TRANSFER(pal_bg_mem, pal, 1, 
 3, DMA_DEMO | DMA_DST_FIX)
    // B: 1 copy, dst reset
    if(KEY_DOWN_NOW(KEY_B))
        DMA_TRANSFER(pal_bg_mem, pal, 1, 
 3, DMA_DEMO | DMA_DST_RESET)
    // L: double copy on HBLANK, dst fixed
    else if(KEY_DOWN_NOW(KEY_L))
        DMA_TRANSFER(pal_bg_mem, pal, 2, 
 3, DMA_DEMO | DMA_DST_FIX)
    // R: double copy on HBlank; dst reset
    else if(KEY_DOWN_NOW(KEY_R))
        DMA_TRANSFER(pal_bg_mem, pal, 2, 
 3, DMA_DEMO | DMA_DST_RESET)
    else
        pal_bg_mem[0]= CLR_BLACK;

    vid_vsync();
    // disable DMA after all lines are done
    DMA_DISABLE(3);
}
Fig 2: dma_demo results
Fig 2: results of the buttons of dma_demo.

This code shouldn't be too hard to understand. The buttons A, B, L, R invoke different kinds of HBlank DMA. When nothing's pressed the screen is black. To make sure the source pointer doesn't run off the deep end, I disable the DMA at the VBlank. If you don't do this the source address will continue to increase forever. Think about what each button should do, then look at fig 2 below to see is you can understand the results. Both A and B give the correct results (except that it is offset by 1 scanline, because HBlank n follows HDraw n). Because there's only one copy, there is no difference between fixed and reset destinations. For L and R the results are quite different. Because we do two copies each HBlank now, only every other palette entry is used. With a fixed destination both copies go into pal_bg_mem[0], and you end up with the even ones. DMA_DST_RESET copies into entries 0 and 1 then resets, so you'll see the odd entries.

Oh, in case you're wondering what the funky lines at the bottom half of the L and R results are, the palette I've used is only 160 entries long so you run out of entries half-way through the screen. The rest is just the part of IWRAM that follows it.

手把手教你配置MCAL的SPI+DMA+ICU模块(附AURIX实战代码) 本文详细介绍了在英飞凌AURIX TC3xx系列MCU上配置MCAL的SPI、DMA与ICU模块的实战指南。针对域控制器与SoC间高速数据交换需求,文章深入解析了SPI通道与序列配置、DMA自动搬运数据机制以及ICU精准捕获握手信号的实现方法,并提供了完整的实战代码和调试技巧,帮助开发者构建高性能、低CPU占用的通信链路。 阅读详情

相关推荐

Linux 下的DMA浅析

DMA是一种无需CPU的参与就可以让外设和系统内存之间进行双向数据传输的硬件机制。使用DMA可以使系统CPU从实际的I/O数据传输过程中摆脱出来,从而大大提高系统的吞吐率。DMA经常与硬件体系结构特别是外设的总线技术密切相关。 一、DMA控制器硬件结构        DMA允许外围设备和主内存之间直接传输 I/O 数据, DMA 依赖于系统。每一种体系结构DMA传输不同,编程接口也不同

知秋一叶 3万+

绝地求生雷达实战经验:让你在游戏中如鱼得水

首先,要正确使用雷达,我们需要知道雷达显示的是周围玩家的大致方位,但并不会告诉我们具体的位置和距离。其次,要时刻关注雷达上的变化,特别是敌人的移动方向,这可以让我们更好地调整自己的战术和防守位置。在游戏中,雷达是我们的眼睛和耳朵,让我们能够发现敌人的动向,保护自己和队友。通过结合观察力和经验,及时刷新雷达,善于根据雷达信息制定战术,我们能够更好地掌握敌人的动向,取得更多的胜利。当我们打开雷达时,游戏内外的人都会听到雷达的声音,这会吸引敌方注意,并暴露我们的位置。在绝地求生中,雷达是一项非常重要的战术工具。

2301_81195708的博客 1689

DMA-BUF与mmap共享内存对比分析

DMA-BUF 和传统的 mmap 共享内存(如 POSIX + 或 SysV )在功能上有重叠,但设计目标和适用场景有本质区别。DMA-BUF 在特定场景下可以替代 mmap,但并非所有场景都适用。 下面从多个维度深入分析:需要硬件加速器直接访问数据:场景示例: GPU 渲染 → 视频编码器输出。优势: DMA-BUF 允许硬件设备直接读写内存,无需 CPU 参与拷贝。传统 mmap 瓶颈: 数据需先由 GPU 驱动读到 CPU,再通过 mmap 到用户态,最后拷贝到编码器驱动 → 两次冗余拷贝。跨驱

u012456479的博客 1349

雷达编程实战之提高探测速度

本篇文章提供了在车载雷达产品中,提高雷达探测速度,降低工作周期,提高有效帧频率的方法,希望读者能够在类似的嵌入式开发任务中能够举一反三,有效利用片上资源,提高产品任务处理效率。

十六宿舍的博客 1655

TI 2837xD SPI DMA配置与多核通信实战

本文详细解析了TI 2837xD芯片中SPI与DMA的协同配置方法及多核通信实现。通过关键寄存器设置、双核同步机制和官方例程剖析,提供了工业控制与实时数据采集的高效解决方案,重点介绍了DMA在提升系统实时性和降低CPU负载方面的核心作用。

gitlab7runner的博客 814

Linux V4L2实战:手把手教你用videobuf2实现零拷贝视频采集(附DMA配置)

本文详细介绍了在Linux V4L2框架下,如何利用videobuf2的DMA连续内存模型实现零拷贝视频采集。通过分析三种内存模型的优劣,并以i.MX6ULL平台为例,提供了完整的驱动实现代码、DMA配置及性能优化技巧,旨在解决嵌入式视频应用中的数据拷贝瓶颈,显著降低CPU占用率。

g9h0i1的博客 1118

DMDSC共享集群搭建

目录路径及其可用空间可以根据业务需求修改,本文仅作学习使用,故而未单独挂载那么多磁盘,可用空间也无需太大。 数据库软件安装目录 /home/dmdba/dmdbms 可用空间>50 GB(视情况而定) 本地归档日志存放目录 /home/dmdba/dmarch 可单独挂载磁盘 远程归档日志存放目录 /home/dmdba/remote_arch 可单独挂载磁盘 备份文件存放目录 /home/dmdba/dmbak 可单独挂载磁盘

qq_58514644的博客 829

Linux DMA-BUF 实战解析:dma_buf_attach与map_attachment在异构设备内存共享中的核心作用

本文深入解析Linux DMA-BUF机制中dma_buf_attach与dma_buf_map_attachment的核心作用,详细探讨其在异构设备内存共享中的关键实现。通过实战案例和代码示例,阐述如何避免数据拷贝、处理Cache一致性及优化性能,为构建高效异构计算系统提供专业指导。

nginx7reverse的博客 909

一文搞懂XDMA核详细配置,手把手教你学会用IP,让你不在挠头

XDMA的详细配置以及接口说明

qq_45029834的博客 1万+

STM32 cubemx配置USART DMA传输

本篇文章来讲解DMA的概念,并使用DMA来进行串口的数据收发。下面我们来看到DMA的两种模式,一种是循环模式,一种是内存到内存的模式。在循环模式下,DMA传输的数据可以在源和目的地之间循环传输,以连续地进行数据传输操作。这种模式下,一旦DMA传输完成,它会自动重新开始下一轮传输,而无需软件干预。循环模式对于需要在连续数据块之间进行重复传输的应用非常有用,如音频、视频流等。它可以在不中断DMA传输的情况下循环传输数据,大大提高了数据传输效率和系统性能。

m0_49476241的博客 7745

GD32F130之DMA

什么是DMA DMA,即Direct Memory Access,是一种在无需CPU参与的情况下,将数据块在内存(SRAM)和外设(一般是I/O设备)之间高效传输的硬件机制。实现这种功能的集成电路单元叫做DMA Controller,即DMA 控制器。 使用DMA的好处 一般情况下,为了实现内存(SRAM)和外设(一般是I/O设备)之间的数据传输,有三种常用的方法:轮循法(polling),中断法(interrupt)以及本文要介绍的DMA方法。 轮循法(polling):在主循环中,CPU不断检查

luliplus的博客 5896

DMA配置

DMA可以认为连接两个“地址”数据通道。DMA共享系统总线,不占用CPU,所以可以实现快速数据传输。这里以DMA连接存储器(数组)和串口(USART1->DR)为例。 1 void DMA_init(void) 2 { 4 RCC->AHBENR|=1<<0;//时能DMA1时钟 5 7 DMA1_Channel4->CPAR=(u32)&a...

weixin_34015860的博客 1626

【更新】绝地求生主播内部定制BA搭建教程

教程开始: 十分安全,能有效防止被系统针对 电脑并不需要修改任何文件,使用任何软件,不用担心被本地检测,封号等 服务端无法察觉这种嗅探,因为嗅探的前后只会有小到可以忽略不计的延迟差异 可以实现直播,很多主播都可以搞。 不易被和谐,除非蓝洞加密通讯过程,或者更改通讯协议。 关于BA/BattleAim需要知道的一切 1:网页雷达需要购买一台服务器(地区看你自己,国外的服务器就相当于开了加速) 2:网页雷达教程在那里?(不会往下看嘛) 3:我按照教程架设出问题了怎么办?(请自己好好看清楚视频,教程已经很详细) 4:网页雷达安全不安全?(看上面介绍) 5:自己遇到问题请先百度,先自己想想,不要像个傻

TI DSP DMA配置

1 概述 DMA控制器可以无需CPU介入而在内部存储器、外部存储器及片上外设之间传送数据,HPI接口也使用DMA辅助端口传送数据。DMA具有如下的特点: DMA可以独立于CPU工作; 有4个标准端口(port)与DARAM、SARAM、外部存储器和外设相连; 一个辅助端口用于HPI和存储器之间的数据传送; 具有6个通道; 可以设置每个通道的优先级; 每个通道的传输可以由选定事

moonjagger的专栏 3795

保姆级教程:用Python+OpenCV实现相移法与格雷码三维重建(从生成条纹到点云生成)

本文详细介绍了使用Python和OpenCV实现相移法与格雷码三维重建的全流程,从条纹生成到点云计算。通过结构光技术,结合相移法和格雷码,实现高精度的三维重建,适用于无纹理物体表面的密集对应点生成。教程包含环境搭建、条纹生成、相位计算、三维点云重建及常见问题排查,适合计算机视觉开发者和研究人员。

weixin_33443333的博客 349

【后端】主流后端语言:JAVA、C、C++、GO、PYTHON

软件开发领域,语言本身在各自领域都有适用场景,有许多流行的编程语言可供选择,每种语言都有其独特的特点和适用场景。

wnm23的专栏 1万+

STM32之DMA

寄存器名称作用DMA_CCRxDMA通道x配置寄存器用于配置DMA(核心控制寄存器)DMA_ISRDMA中断状态寄存器用于查询当前DMA传输状态DMA_IFCRDMA中断标志清除寄存器用来清除DMA_ISR对应位DMA_CNDTRxDMA通道x传输数量寄存器用于控制DMA通道x每次传输的数据量DMA_CPARxDMA通道x外设地址寄存器用于存储STM32外设地址DMA_CMARxDMA通道x存储器地址寄存器。

huangjavase的博客 2142

PP触发EWM产生PMR捡配

PP触发EWM产生PMR捡配 前言 PMR: Production Material Request 在流程订单/生产订单下达后,可以在EWM中产生PMR,在EWM中, PMR其实代表了ERP中的流程订单/生产订单。 You can use SAP EWM in conjunction with the following PP application components: • Production Orders • Process Orders • Repetitive Manufacturing •

ZevYang的博客 1918

linux驱动之DMA

转载自:https://www.jianshu.com/p/e1b622234d13 一、前言 在嵌入式Linux的内核及驱动中,DMA常常被人提起。我们也许清楚它的原理且很明白它非常重要,但在某种程度上,对于DMA的使用者来说,我们一般使用其接口,而很少去了解整个DMA的运作方式。那么本文就从头到尾,简单地说一下DMA吧注意:本文对DMA的概念不做讲述,请各位读者自行了解DMA的概念。 二、正文 2.1 高端内存 2.1.1 内核虚拟内存 在了解DMA之前,我们需要先了解...

RopenYuan的专栏 5338

基于陀螺仪航向反馈的轮式机器人PID直线控制

航向角控制是移动机器人实现稳定直线运动的基础技术,其本质是通过实时感知机体朝向偏差并动态调节驱动输出,以抵消机械不对称、轮径误差等固有扰动。该方法依托陀螺仪测量角速度并积分解算航向角,结合离散化PID算法生成补偿性PWM指令,在嵌入式平台(如STM32)上构建低延迟闭环。相比依赖编码器的速度闭环,它规避了轮径标定与安装偏心等误差源,显著提升低成本平台的工程鲁棒性与部署效率。典型应用场景包括教育机器人直线循迹、AGV基础导航模块开发及IMU-PID融合控制原型验证。

web39explorer的博客 1108

重访时间与覆盖分析的stk操作

1.打开stk 2.创建一个新的场景,命名为Test,选择地球为场景星球,若为金星,可在Central Body里选择Venus(金星自转周期慢,自转周期243天,卫星轨道变化不明显)(其中start stop时间可设置长一些) 3.插入一个AreaTarget或者place,以AreaTarget为例 选择Pattern,Add三个点(用法可见前面的博客,有时候编程的代码也可以帮助理解stk的操作) 4.插入Satellite,选择Orbit Wizard(若想设置卫星的六根数也可

weixin_42664107的博客 1万+

STM32之DMA学习

概述: 传统的DMA的概念是用于大批量数据的传输,但是我理解,在STM32中,它的概念被扩展了,也许更多的时候快速是其应用的重点。数据可以从1~65535个。 直接存储器存取(Direct Memory Access,DMA)是计算机科学中的一种内存访问技术。它允许某些电脑内部的硬体子系统(电脑外设),可以独立地直接读写系统存储器,而不需绕道 CPU。在同等程度的CPU负担下,DMA是一种快速的数据传送方式。它允许不同速度的硬件装置来沟通,而不需要依于 CPU的大量中断请求。【摘自数据手册】 现在越来越多的

qeekje的博客 2874

SAP Parallel Accounting(平行分类账业务)配置及操作手册(超详细的说明和测试)

非常详细的介绍了SAP 的平行分类账配置以及测试效果哦

nopicture的博客 4341

dma和通道的区别_ZYNQ开发(四)DMA配置

DMA的特点和体系结构01DMA外设特点:DMA引擎拥有一个灵活的指令设置DMA的传输;拥有8个cache线,每一个cache线宽度是4个字;拥有8个可以并行的DMA通道线程;拥有8个中断给中断控制器;拥有8个DMA触发事件并且可以编码控制;128个(64bit)的MFIFO,在传输的时候读写端可写入到此FIFO;支持任意内存到内存的传输;整个系统中的DMA控制器如图1所示:图1 DMA...

weixin_39953673的博客 1275

泛微OA提交流程到下一个节点

泛微OA后端接口强制流程归档

CXYCMY的博客 2245

【WRFDA实操第一期】服务器中安装 WRFPLUS 和 WRFDA

【WRFDA实操第一期】安装 WRFPLUS 和 WRFDA

WW、forever的博客 2035
上一篇: 当CACHE和DMA坐在跷跷板上[共享]
下一篇: 杭州西湖.湖中音乐喷泉[录象]
embeddedsoft
博客等级 码龄20年 51粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值