DMA(Direct Memory Access),直接内存存取,是一种AMBA 先进高性能总线(AHB)模块,是独立于CPU的一种数据高速传输的方式。

DMA 可以让数据的传输工作在后台进行,能够在没有CPU干预的情况下快速实现数据的转移。但并非不需要占用系统总线,只是可以在不显著影响系统性能的情况下进行大量数据的传输。
DMA 主要用于实现不同外设模块的集中数据缓冲和存储
DMA从本质上看,是从“地址”到“地址”的方式来实现数据传输的。当设定好"源地址"、"目标地址"和"需要传输的数据量"后,DMA控制器就会启动传输,直至剩余传输数据量到0为止(非循环模式下)。DMA主要有四种数据传输类型:
最后一个“外设到外设”的传输类型,是指从外设的数据存储器到外设的数据存储器,外设的数据存储器实质上也是一种数据存储单元。后面章节会具体讲述其中的原理
以下内容以F4xx系列为例。
由下面的总线架构图中可以看到,一个DMA控制器通过一个专用的AHB主端口连接到AHB总线矩阵。而总线矩阵则采用主/从结构。
整个架构中只有CPU和DMA充当主机,其他所有连接的部件都只作为从机访问。
在总线矩阵内,只要两个独立的AHB主机针对不同的AHB总线矩阵从机端口提交两个并发AHB传输,就不存在总线矩阵仲裁。例如,当CPU从闪存读取指令,而DMA从另一个存储器读取数据时,它们不会以任何方式相互限制。换句话说,就是仲裁只在两个主机需要访问相同的从机存储器或外设时发生。
从以上的描述能得出两个结论:
总线带宽:定义为总线可以在固定时间内传输的数据量,通常以每秒传输多少数据量来表示。它由时钟速度、总线宽度和总线管理开销决定

注意
1.图中有一个64KB的CCM data RAM只能由D-Bus总线访问,而DMA是无权访问的,后续应用时需要留意。
2.DMA1 控制器 AHB 外设端口与 DMA2 控制器的情况不同,不连接到总线矩阵,因此,仅 DMA2 数据流能够执行存储器到存储器的传输
DMA的结构如下,并有几个大特点。
要传输的数据项的数目可以由 DMA 控制器或外设管理:
1.DMA 流控制器:要传输的数据项的数目是 1 到 65535,可用软件编程
2.外设流控制器:要传输的数据项的数目未知并由源或目标外设控制,这些外设通过硬件发出传输结束的信号

源传输和目标传输支持在整个 4 GB 区域(地址在 0x0000 0000 和 0xFFFF FFFF 之间)内寻址外设和存储器。
DMA 事务由给定数目的数据传输序列组成。要传输的数据项的数目及其宽度(8 位、16 位 或 32 位)可用软件编程。
每个 DMA 传输包含三项操作:
存储器对存储器的置位,就相当于相应通道的事件有效。对应通道的事件有效和存储器对存储器的置位,就是传输的触发位。每次传输的事件置位一次,完成一次传输。如果是由外设引发的DMA传输,则传输完成后,相应传输事件会置为无效,而存储器对存储器的传输,则一次传输完成后,相应事件一直有效,直至完成设定的传输量
每个数据流都与一个 DMA 请求相关联,这个请求可以从 8 个可能的通道请求中选出。

而来自外设的 8 个请求独立连接到每个通道,具体连接方式每个系列都不一样,我们需要选择将某个外设作为DMA数据流的源地址或目标地址。下表是F4xx系列的通道请求映射。
每个外设请求都占用一个数据流通道,如数据流0的通道0占用了数据流通道,那么其他通道(1-7)则处于不可用状态。
相同外设请求可以占用不同数据流通道,比如SDIO可以同时占用DMA2的数据流3和数据流6(一个作TX,一个作RX)

注意:只有DMA2可以使用“M2M”模式
一个DMA 控制器对应8 个数据流,数据流包含要传输数据的源地址、目标地址、数据等信息。如果同一个DMA同时有多个外设请求时,则需要分配优先级。
优先级管理分为两个阶段:
根据控制和传输模式的不同,DMA存储多种组合的配置,F4xx的DMA工作配置组合如下所示。

1.FIFO特点
每个数据流都有一个独立的 4 字 FIFO,阈值级别可由软件配置为 1/4、1/2、3/4 或Full。
2.FIFO的结构
FIFO 的结构随源与目标数据宽度的不同而不同。

3.FIFO的数据传输
FIFO 用于在源数据传输到目标地址之前临时存放这些数据。可以设置阈值,如果数据存储量达到阈值级别时,FIFO 内容将传输到目标中。
1.FIFO模式对于源地址和目标地址数据宽度不同的情况非常有用,比如源数据是字节数据,而目标地址要求输出字宽度的数据,即在实现数据传输时同时把原来4 个8 位字节的数据拼凑成一个32 位字数据。此时可使用FIFO功能先把数据缓存起来,分别根据需要输出数据
2.FIFO模式也常使用于突发(burst) 传输
3.当在直接模式(禁止 FIFO)下将 DMA 配置为以存储器到外设模式传输数据时,DMA 会将一 个数据从存储器预加载到内部 FIFO,从而确保一旦外设触发 DMA 请求时则立即传输数据。
4.FIFO 阈值与突发配置
使用 FIFO 阈值和存储器突发大小配置时需要注意,FIFO 阈值所指向的内容必须与整数个存储器突发传输完全匹配。否则,当使能数据流时会报 FIFO 错误,然后DMA将自动禁止数据流传输。
以下是FIFO阈值配置表。

循环模式可用于处理循环缓冲区或连续数据流,比如ADC的多通道连续扫描。当Enable循环模式时,要传输的数据项的数目,在数据流配置阶段自动用设置的初始值进行加载,并持续响应 DMA 的请求。
注意在循环模式下,如果同时为存储器配置了突发模式,那么必须遵循下列规则:
DMA_SxNDTR = ((Mburst 节拍 ) × (Msize)/(Psize)) 的倍数
其中,
例如:
Mburst 节拍 = 8 (INCR8),MSIZE =“00”(字节)和 PSIZE =“01”(半字),则可以计数得到:DMA_SxNDTR 必须是 (8 × 1/2 = 4) 的倍数,否则 DMA 行为和数据完整性得不到保证。
NDTR 还必须是外设突发大小与外设数据大小乘积的倍数,否则会导致错误的 DMA 行为
直接模式在每个外设请求时,都会立即启动对存储器传输的单次传输。同时要求源地址和目标地址的数据宽度必须一致,所以只有PSIZE 控制,而MSIZE 值会被忽略。默认情况下,DMA 工作在直接模式,不使能FIFO 阈值级别。
直接模式不能用于存储器到存储器传输。
在此模式下,每次DMA事务结束时,DMA 控制器都从当前目标存储器转换到另一个目标存储器。 这样,当软件在处理当前存储器区域的同时,DMA 传输还可以填充或使用第二个存储器区域。以加快传输速度。
1.使能双缓冲区模式时,自动使能循环模式,所以也不适用于M2M模式
2.双缓冲模式在I2S解码或传输PDM信号时经常使用,使用该模式去播放音频时可以减少不流畅现象

1.FIFO模式
每次产生外设请求,数据流都会启动数据源到 FIFO 的传输。当数据量达到 FIFO 所设定的阈值级别时,FIFO 的内容将移出并存储到目标中。
2.直接模式
每完成一次从外设到 FIFO 的数据传输后,相应的数据立即就会移出并存储到目标中。
不使用 FIFO 的阈值级别控制功能
两种模式下,如果 DMA_SxNDTR 寄存器计数到零,或外设请求传输终止(在使用外设流控制器的情况下)或 DMA_SxCR 寄存器中的 EN 位由软件清零,传输都会立即停止。

1.FIFO模式
数据流会立即启动传输,从存储器源完全填充到FIFO中。每次发生外设请求,FIFO 的内容都会移出并存储到目标中。
当 FIFO 的级别小于或等于预定 义的阈值级别时,将使用存储器中的数据完全重载 FIFO
2.直接模式
该模式下,一旦使能了数据流,DMA便会预装载第一个数据,将其传输到内部 FIFO。这时当发生外设请求数据传输,DMA便会将预装载的值传输到配置的目标。紧接着,DMA会使用要传输的下一个数据再次重载内部空 FIFO。预装载的数据大小为 DMA_SxCR 寄存器中 PSIZE 位字段的值。
两种模式下,如果 DMA_SxNDTR 寄存器计数到零,或外设请求传输终止(在使用外设流控制器的情况下)或 DMA_SxCR 寄存器中的 EN 位由软件清零,传输都会立即停止。

默认使用FIFO模式,当使能数据流时,数据流会立即开始填充 FIFO,直至达到阈值级别。达到阈值级别后,FIFO 的内容便会移出,并存储到目标中。
如果 DMA_SxNDTR 寄存器计数到零,或外设请求传输终止(在使用外设流控制器的情况下)或 DMA_SxCR 寄存器中的 EN 位由软件清零,传输都会立即停止。
1.该模式下,不允许使用循环模式和直接模式,所以也不能使用双缓冲区模式(自动启用循环模式)
2.只有 DMA2 控制器能够执行存储器到存储器的传输

参考手册中没有提到这个模式,但DMA的本质是“地址到地址”。
如果源地址是外设,目标地址是内存,那么传输模式就是外设到内存;
如果源地址是外设,目标地址也是外设,那传输模式就是外设到外设。
例如用DMA把ADC数据寄存器的值直接传送到SPI数据寄存器,即属于“外设”到“外设”的传输模式。
当 AHB 外设端口被配置为单次传输时,根据 DMA_SxCR 寄存器 PSIZE[1:0] 位的值,每个 DMA 请求产生一次字节、半字或字的数据传输。
单次传输时必须通过AHB 的总线仲裁多次控制才传输完成
突发传输就是用非常短时间结合非常高数据信号率传输数据,相对正常传输速度,突发传输就是在传输阶段把速度瞬间提高,实现高速传输,在数据传输完成后恢复正常速度。
DMA 控制器可以产生单次传输或 4 个、8 个和 16 个节拍的增量突发传输。当 AHB 外设端口被配置为突发传输时,根据 DMA_SxCR 寄存器 PBURST[1:0] 和PSIZE[1:0] 位的值,每个 DMA 请求相应地生成 4 个、8 个或 16 个节拍的字节、半字或字的传输。
突发模式下,当DMA请求总线成功后会连续传送数据,而不给CPU使用总线的机会,直到数据传送完毕。比如设置了4个节拍的突发传输,而传输宽度位为8 bit,则一个DMA请求会连续传送4个字节,是单次传输的4倍,大提高了传输的速度。
突发传输需要结合FIFO 使用,具体配置可看FIFO阈值与突发配置章节。
1.在直接模式下,数据流只能生成单次传输,而 MBURST[1:0] 和 PBURST[1:0] 位由硬件强制配置
2.突发传输过程会一直占用AHB 总线,保证每个数据项在传输过程不被分割
对于每个 DMA 数据流,可在发生以下事件时产生中断:
DMA 数据传输达到一半时,HTIF 标志位会被置位。
DMA 数据传输完成时,TCIF 标志位会被置位。
DMA 访问总线发生错误或者在双缓冲模式下试图访问“受限”存储器地址寄存器时,TEIF 标志位被置位。
发生FIFO 下溢或者上溢时FEIF 标志位被置位。
在外设到存储器的直接模式下,因为存储器总线没得到授权,使得先前数据没有完成被传输到存储器空间上,此时DMEIF 标志位被置1。

在将使能控制位置‘1’前,应将相应的事件标志清零,否则会立即产生中断
这里应用了“外设”到“存储器”的方式,把DCMI->DR寄存器的数据直接传送到挂在FSMC总线的LCD数据地址上。开启循环模式和FIFO,并将外设设为单次传输,而存储器设为8个节拍的突发传输。在字节宽度的设置上,DCMI的数据寄存器宽度为32bit,而LCD端的RGB565,宽度为16bit。
上述使用了如下图红框所示的配置。

整个传输过程是这样的,当DCMI的数据寄存器收到32bit数据才会触发一次DMA请求,然后存入DMA的FIFO中,当存满到4字节的FIFO阈值时,突发传输1次8个节拍的半字数据到LCD中显示。
#define DEBUG_DCMI_DR_BASE (uint32_t)&DCMI->DR
#define DEBUG_DCMI_DMA_CLK RCC_AHB1Periph_DMA2
#define DEBUG_DCMI_DMA_CHANNEL DMA_Channel_1
#define DEBUG_DCMI_DMA_STREAM DMA2_Stream1
#define FSMC_LCD_DATA_SIZE 1
#define FSMC_LCD_ADDRESS ((uint32_t) 0x68000002)
void OV2640_DMAConfig(void)
{
DMA_InitTypeDef DMA_InitStructure;
/* 配置DMA从DCMI中获取数据*/
/* 使能DMA*/
RCC_AHB1PeriphClockCmd(DEBUG_DCMI_DMA_CLK, ENABLE);
DMA_Cmd(DEBUG_DCMI_DMA_STREAM,DISABLE);
while (DMA_GetCmdStatus(DEBUG_DCMI_DMA_STREAM) != DISABLE)
{
}
DMA_InitStructure.DMA_Channel = DEBUG_DCMI_DMA_CHANNEL;
DMA_InitStructure.DMA_PeripheralBaseAddr = DEBUG_DCMI_DR_BASE;
DMA_InitStructure.DMA_Memory0BaseAddr = FSMC_LCD_ADDRESS;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = FSMC_LCD_DATA_SIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC8;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
/* DMA初始化 */
DMA_Init(DEBUG_DCMI_DMA_STREAM, &DMA_InitStructure);
DMA_Cmd(DEBUG_DCMI_DMA_STREAM,ENABLE);
while(DMA_GetCmdStatus(DEBUG_DCMI_DMA_STREAM) != ENABLE)
{
}
}
这里应用了“外设”到“存储器”的方式,因为ADC数据寄存器地址不会随通道不同而变化,所以使能了存储器增量模式,禁止外设增量。而控制模式使用“循环模式” + “单次传输”的方式。
/** 定义ADC 相关信息*/
#define DEBUG_ADC_BASE ADC1_BASE
#define DEBUG_ADC_DR_ADDR ((uint32_t)DEBUG_ADC_BASE + 0x4C)
/** 定义数据存储数组*/
#define ADC_CONV_CH_SIZE 3
uint16_t adcConvertedValue[ADC_CONV_CH_SIZE];
/** 定义ADC DMA相关信息*/
#define DEBUG_ADC_DMA_CLK RCC_AHB1Periph_DMA2
#define DEBUG_ADC_DMA_CHANNEL DMA_Channel_0
#define DEBUG_ADC_DMA_STREAM DMA2_Stream0
/** 初始化ADC相应的DMA*/
void ADC_DMAConfig(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(DEBUG_ADC_DMA_CLK, ENABLE);
/** ADC 数据寄存器地址*/
DMA_InitStructure.DMA_PeripheralBaseAddr = DEBUG_ADC_DR_ADDR;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&adcConvertedValue;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
/** buffer size 和需扫描的ADC通道数一致*/
DMA_InitStructure.DMA_BufferSize = ADC_CONV_CH_SIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
/** 存储器地址递增*/
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
/** ADC DR数据大小为半字,即两个字节*/
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
/** 存储器数据大小为半字*/
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_Channel = DEBUG_ADC_DMA_CHANNEL;
DMA_Init(DEBUG_ADC_DMA_STREAM, &DMA_InitStructure);
DMA_Cmd(DEBUG_ADC_DMA_STREAM, ENABLE);
}
这里应用了“存储器”到“外设”的方式,因为USART数据寄存器地址是固定的,所以使能了存储器增量模式,禁止外设增量。控制模式使用“循环模式” + “单次传输”的方式。
#define TX_BUFFER_SIZE 100
#define DEBUG_USART_DR_BASE (USART1_BASE + 0x04)
#define DEBUG_USART_DMA_CLK RCC_AHB1Periph_DMA2
#define DEBUG_USART_DMA_CHANNEL DMA_Channel_4
#define DEBUG_USART_DMA_STREAM DMA2_Stream7
uint8_t txBuffer[TX_BUFFER_SIZE];
void USART_DMAConfig(void)
{
DMA_InitTypeDef DMA_InitStructure;
/* 开启DMA时钟*/
RCC_AHB1PeriphClockCmd(DEBUG_USART_DMA_CLK, ENABLE);
/* 复位初始化DMA数据流 */
DMA_DeInit(DEBUG_USART_DMA_STREAM);
/* 确保DMA数据流复位完成 */
while (DMA_GetCmdStatus(DEBUG_USART_DMA_STREAM) != DISABLE) {
}
/* usart1 tx对应DMA2,通道4,数据流7 */
DMA_InitStructure.DMA_Channel = DEBUG_USART_DMA_CHANNEL;
/* 设置DMA源:串口数据寄存器地址*/
DMA_InitStructure.DMA_PeripheralBaseAddr = DEBUG_USART_DR_BASE;
/* 存储器地址*/
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)txBuffer;
/* 从内存到外设*/
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
/* 传输大小*/
DMA_InitStructure.DMA_BufferSize = TX_BUFFER_SIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
/* 内存地址自增*/
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
/* 外设数据单位*/
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
/* 内存数据单位 8bit*/
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
/* 开启循环循环*/
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
/* 禁用FIFO*/
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
/* 存储器单次传输*/
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
/* 外设单次传输*/
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DEBUG_USART_DMA_STREAM, &DMA_InitStructure);
/*使能DMA*/
DMA_Cmd(DEBUG_USART_DMA_STREAM, ENABLE);
/* 等待DMA数据流有效*/
while(DMA_GetCmdStatus(DEBUG_USART_DMA_STREAM) != ENABLE)
{
}
}
1.[STM32 DMA使用详解]
2.[AN4031]
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr
我有一个在Linux服务器上运行的ruby脚本。它不使用rails或任何东西。它基本上是一个命令行ruby脚本,可以像这样传递参数:./ruby_script.rbarg1arg2如何将参数抽象到配置文件(例如yaml文件或其他文件)中?您能否举例说明如何做到这一点?提前谢谢你。 最佳答案 首先,您可以运行一个写入YAML配置文件的独立脚本:require"yaml"File.write("path_to_yaml_file",[arg1,arg2].to_yaml)然后,在您的应用中阅读它:require"yaml"arg
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm
是否可以在应用程序中包含的gem代码中知道应用程序的Rails文件系统根目录?这是gem来源的示例:moduleMyGemdefself.included(base)putsRails.root#returnnilendendActionController::Base.send:include,MyGem谢谢,抱歉我的英语不好 最佳答案 我发现解决类似问题的解决方案是使用railtie初始化程序包含我的模块。所以,在你的/lib/mygem/railtie.rbmoduleMyGemclassRailtie使用此代码,您的模块将在
无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD
导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵