我正在使用一台 STM32F4,我想与我的 LSM303 加速度计进行通信。为此,我使用 I2C,仅使用 I2C 工作正常,但当我尝试使用 DMA 时,它停止工作。当我使用 HAL_I2C_Master_Transmit_DMA 时,它可以工作,并且我得到了 IRQHandler 和 . 但是之后当我想使用 HAL_I2C_Master_Receive_DMA 时,它说 I2C 的状态尚未准备好...我读到 I2C 与 STM32FX 有点混乱,但我不明白为什么它在没有 DMA 的情况下工作正常。
此外,当它命中 Master_Transmit_DMA 的回调 I2C_DMAXferCplt 时,它表示 I2C_HandleTypeDef 的 CurrentState 仍然等于 HAL_I2C_STATE_BUSY_TX,因此它不会将状态恢复为 READY。这就是为什么当我调用 Master_Receive_DMA 时它没有收到任何东西。
这是我的 I2C 初始化:
void MX_I2C2_Init(void)
{
I2C_ST_INS.Instance = I2C2;
I2C_ST_INS.Init.ClockSpeed = 400000;
I2C_ST_INS.Init.DutyCycle = I2C_DUTYCYCLE_2;
I2C_ST_INS.Init.OwnAddress1 = 0;
I2C_ST_INS.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
I2C_ST_INS.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED;
I2C_ST_INS.Init.OwnAddress2 = 0;
I2C_ST_INS.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED;
I2C_ST_INS.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED;
HAL_I2C_Init(&I2C_ST_INS);
}
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(i2cHandle->Instance==I2C1) …Run Code Online (Sandbox Code Playgroud) 我正在尝试将 I2S 麦克风 (Invensense ICS43432) 连接到运行 Arch Linux 的 Raspberry Pi (B+),但失败了。我已经在相关的 Arch Linux ARM 论坛中寻求了具体的建议,但我的问题实际上比这更笼统:如何调试 Linux 音频输入问题?
我已经使用逻辑分析仪验证了 I2S 麦克风正在正确的通道(左)和 Raspberry Pi 的正确引脚中发送敏感数据。I2S 麦克风在 ALSA 下显示为“声卡”。 arecord我非常高兴从该设备进行录音,并且我已将该设备的增益提高了alsamixer30 dB。然而记录文件的所有数据字节都是零。
在Linux下如何检查音频数据流、DMA操作?
我正在 Qemu 上编写 PCI 设备,并在来宾操作系统中编写驱动程序(LKM)。虽然 Qemu 提供了一个示例 PCI 设备edu(edu.txt和edu.c)及其发行版,但我在编写内核模块来进行 DMA 传输时遇到了问题。这里介绍了一个基本的驱动程序,但它不支持 DMA。
我正在跟踪 link 和this的实现。我尝试将缓冲区从 IRQ 处理程序传输到 PCI 设备。设备可以读取数据(pci_dma_read),但我没有得到我应该接收的正确数据。这是进行 DMA 传输的代码段:
static int write_to_HyPerf(void *dev, void* addr, uint32_t size)
{
/* ----------------------------------------------------------------------------
* PCI address 'addr':
* addr -> DMA source address
* 0x40000 -> DMA destination address
* 100 -> DMA transfer count
* 1 -> DMA command register
* while (DMA command register & 1)
*-------------------------------------------------------------------------------- …Run Code Online (Sandbox Code Playgroud) 我已将 UART 配置为以 DMA 模式接收,其中缓冲区的大小约为 64 字节。因此,基本上,HAL_UART_RxCpltCallback() DMA 接收完成中断仅在接收到 64 个字符时才会触发。
STM32中有没有一种方法可以为DMA Rx配置超时,当缓冲区仅部分填充(即接收到的字符少于64个)并且我们在指定的超时时间内不再接收到任何字符时,DMA将然后引发相同的基于 HAL_UART_RxCpltCallback() 的中断,让消费者使用 UART 当前接收到的任何部分数据?
我正在使用带有 FreeRTOS 和 STM32CubeMX 的STM32L432设备。
我尝试通过基于 ASCII 协议的 USART 实现 M2M 通信。协议序列的长度可以不同,但具有最大长度和定义的结束字符 (' \r ' / 0x0D )。
因此,我考虑使用 DMA(如FIFO)收集所有 RX-USART 数据,并使用基于USART_ICR_CMCF标志的地址匹配 isr 来确定结束字符。
初始化USART1并启用地址匹配ISR
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(uartHandle->Instance==USART1) {
/* USART1 clock enable */
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART1 interrupt Init */
HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_MspInit 1 …Run Code Online (Sandbox Code Playgroud) 我有通过中断读取USCI(UART)的"正常"代码,但TI SimpliciTI堆栈是CPU占用的,并且在维护无线电时它会丢弃UART字节.
我假设DMA是可行的方法,但我找不到使用USCI作为输入的DMA的完整示例.
我写这篇文章是因为我对DMA的行为有些怀疑.我正在阅读PCI布局以及设备驱动程序如何与卡交互,我读到了有关DMA的信息.由于我的理解,PCI卡没有DMA控制器,而不是他们要求成为总线的主控制器,然后他们能够获取DMA地址并在存储器和设备之间进行传输(通过总线).
这个DMA地址是RAM的一部分,实际上它是一个物理地址,在无所事事之前你需要将它转换成你的驱动程序可以使用的东西,比如内核虚拟内存.我用这段代码检查过:
/* Virtual kernel address */
kernel_buff = pci_alloc_consistent(dev, PAGE_SIZE, &dma_addr);
pr_info("Kernel buffer - %12p , Dma_addr - %12p\n", kernel_buff, (void *)dma_addr );
pr_info( "Kernelbuffer - dma_addr - %12p\n", kernel_buff - dma_addr);
strcpy(kernel_buff, "Test dma\n");
/* Test memory */
ptest = (void *)dma_addr;
ptest = phys_to_virt((unsigned long)ptest);
pr_info("Ptest virtual memory(%p) containts - %s\n", ptest, (char *)ptest);
Run Code Online (Sandbox Code Playgroud)
输出是:
[425971.835669] Kernel buffer - ffff8800ca70a000 , Dma_addr - ca70a000
[425971.835671] Kernelbuffer - dma_addr - ffff880000000000
[425971.835673] Ptest virtual memory(ffff8800ca70a000) containts - Test …Run Code Online (Sandbox Code Playgroud) 我在c#中使用serialport组件,效果很好!但问题是如何更快地处理高速(例如2 Mbps)数据传输.
正如我研究过的那样,我发现可以直接访问内存(使用像这个链接的 DMA ).谁能告诉我如何在我的应用程序中定义和使用它?
我尝试使用DMA通道使用SPI发送数据.当我在没有DMA的情况下发送一切都没问题,但是用DMA确实是错误的.当我调试我的程序时,SPI DR寄存器始终为0.我想使用dma循环模式一直发送我的数组.有我的代码GPIO INIT:
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(SPI_PERIPH_CLOCK, ENABLE);
RCC_AHBPeriphClockCmd(GPIO_PERIPH_CLOCK, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
GPIO_PinAFConfig(GPIOB, AF_PIN_SOURCE, GPIO_AF);
GPIO_InitStructure.GPIO_Pin = GPIO_PIN_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
Run Code Online (Sandbox Code Playgroud)
SPI INIT
SPI_I2S_DeInit(SPI1);
SPI_InitTypeDef SPI_InitStructure;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
Run Code Online (Sandbox Code Playgroud)
DMA INIT:
DMA_InitTypeDef dma;
DMA_DeInit(DMA1_Channel1);
DMA_StructInit(&dma);
dma.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_PeripheralDataSize …Run Code Online (Sandbox Code Playgroud) 我们的任务旨在证明使用DMA复制大量数据与依靠处理器直接处理复制相比的好处。处理器是ST发现板上的STM32F407。
为了测量复制时间,必须在复制期间将GPIO引脚打开,并在复制后将其关闭。
该代码似乎是功能性,但它当前示出了CPU服用约2.15ms至完整和DMA约4.5ms,这是何意相反。我不确定是否没有足够的数据来提供更快的DMA速度来抵消设置数据的开销?
我尝试使用CPU和memcpy函数复制数组的元素,这似乎产生非常相似的时间。
功能代码如下所示:
DMASpeed(void)
{
#define elementNum 32000
int *ptr = NULL;
ptr = (int*)malloc(elementNum * sizeof(int));
int *ptr2 = NULL;
ptr2 = (int*)malloc(elementNum * sizeof(int));
for (int i = 0; i < elementNum; i++)
{
ptr[i] = 4;
}
LD5_GPIO_Port->BSRR = (uint32_t)LD5_Pin << 16U;
LD6_GPIO_Port->BSRR = (uint32_t)LD6_Pin << 16U;
// Initial value
// printf("BEFORE: dst = '%s'\n", dst);
// Transfer
printf("Initiate DMA Transfer...\n");
HAL_DMA_Start(&hdma_memtomem_dma2_stream0, (int)ptr, (int)ptr2, (elementNum * sizeof(int)));
LD5_GPIO_Port->BSRR = LD5_Pin;
printf("DMA …Run Code Online (Sandbox Code Playgroud)