使用LE05官方demo板 配置PTB_0~PTB_5引脚为输出模式,启用dma,搬运buff中预设的编码到GPIO PCOR Register和GPIO PCOR Register以达到IO口输出电平的切换
-
一、背景:
①使用LE05官方demo板 配置PTB_0~PTB_5引脚为输出模式
②启用dma,搬运buff中预设的编码到GPIO PCOR Register和GPIO PCOR Register以达到IO口输出电平的切换
编码如:
/* PB0: 预设 PB1: 1 (固定高电平) PB2: 预设 PB3: 0 (固定低电平) PB4: 预设 PB5: 预设 */ /*dma_config0*/ volatile uint32_t ioSentBuff[16] = { // 第一组 PB0 = 高电平,PB1 = 高电平,PB2 = 高电平,PB3 = 低电平,PB4 = 高电平,PB5 = 高电平 0x00000037, // PSOR: PB0, PB1, PB2, PB4, PB5为高电平,PB3为低电平 0x00000000, // PCOR: 不变 // 第二组 PB0 = 低电平,PB1 = 高电平,PB2 = 低电平,PB3 = 低电平,PB4 = 高电平,PB5 = 高电平 0x00000000, // PSOR: 不变 0x00000005, // PCOR: 将PB0, PB2, PB4, PB5设置为低电平,PB3保持低电平,PB1保持高电平 // 第三组 PB0 = 高电平,PB1 = 高电平,PB2 = 高电平,PB3 = 低电平,PB4 = 低电平,PB5 = 低电平 0x00000005, // PSOR: PB0, PB2为高电平 0x00000030, // PCOR: PB4, PB5设置为低电平 // 第四组 0x00000030, 0x0000005, // 第五组 0x0000005, 0x00000030, // 第六组 0x000000030, 0x0000005, // 第七组 0x00000005, 0x00000030, // 第八组 0x00000030, 0x00000005, };
二、现状
①DMA配置完后不工作,回调函数也从来没有触发过DMA配置如下:
#define REG_ADDR_PSOR 0x4000f104 #define REG_ADDR_PCOR 0x4000f108 /* * dma_config0:配置DMA通道的结构体 * 该结构体定义了DMA通道的配置参数,包括虚拟通道配置、源请求、回调函数等 */ const dma_channel_config_t dma_config0 = { .virtChnConfig = 0, // 虚拟通道配置,设置为0表示未配置 .source = DMA_REQ_DISABLED, // 源请求禁用,表示DMA通道不从任何源接收请求 .callback = NULL, // 回调函数,设置为NULL表示不使用回调函数 .callbackParam = NULL, // 回调函数参数,设置为NULL }; /* * dmaChnConfigArray:DMA通道配置数组 * 该数组存储了所有DMA通道的配置结构体指针。此示例只配置了一个DMA通道。 */ const dma_channel_config_t *const dmaChnConfigArray[NUM_OF_CONFIGURED_DMA_CHANNEL] = { &dma_config0, // 配置第一个DMA通道的配置结构体 }; /* * dmaController_InitConfig:DMA控制器初始化配置 * 该结构体用于初始化DMA控制器的一些全局设置,例如错误停止行为等。 */ const dma_user_config_t dmaController_InitConfig = { .haltOnError = false, // 配置DMA控制器在发生错误时不停止 }; /* * dma_config0_State:DMA通道0的状态结构体 * 该结构体用于存储DMA通道0的状态信息,通常用于DMA操作的追踪和管理。 */ dma_chn_state_t dma_config0_State; /* * dmaChnState:DMA通道状态数组 * 该数组存储每个DMA通道的状态结构体指针。在此示例中只配置了一个DMA通道。 */ dma_chn_state_t *const dmaChnState[NUM_OF_CONFIGURED_DMA_CHANNEL] = { &dma_config0_State, // 指向通道0的状态结构体 }; /* * dmaState:DMA控制器状态结构体 * 该结构体用于存储DMA控制器的整体状态信息。 */ dma_state_t dmaState; /* * dma_transfer_config0LoopConfig:DMA循环传输配置 * 该结构体定义了DMA传输的循环配置参数,适用于数据传输时的循环模式。 */ dma_loop_transfer_config_t dma_transfer_config0LoopConfig = { .triggerLoopIterationCount = 1, // 循环触发的迭代次数为1 .srcOffsetEnable = true, // 启用源地址偏移 .dstOffsetEnable = false, // 禁用目标地址偏移 .triggerLoopOffset = 0, // 触发循环的偏移量为0 .transferLoopChnLinkEnable = false, // 禁用DMA通道链接 .transferLoopChnLinkNumber = 0, // 没有链接到其他DMA通道 .triggerLoopChnLinkEnable = false, // 禁用触发循环的DMA通道链接 .triggerLoopChnLinkNumber = 0, // 没有链接到其他DMA通道 }; /* * dma_transfer_config0:DMA传输配置结构体 * 该结构体定义了DMA的源地址、目标地址、传输大小、偏移量等设置。 * 这里的设置意味着DMA将从`ioSentBuff`(源地址)传输数据到目标地址。 */ dma_transfer_config_t dma_transfer_config0 = { .srcAddr = (uint32_t)&ioSentBuff, // 源地址,指向ioSentBuff数组test .destAddr = REG_ADDR_PSOR, // 初始目标地址为0x4000f104 .srcOffset = 8, // 源地址每次偏移8字节 .destOffset = 0, // 目标地址每次偏移0字节,结合逻辑实现地址切换 .srcTransferSize = DMA_TRANSFER_SIZE_8B, // 源数据传输大小为8字节 .destTransferSize = DMA_TRANSFER_SIZE_8B, // 目标数据传输大小为8字节 .srcModulo = DMA_MODULO_OFF, // 禁用源地址的环形缓冲 .destModulo = DMA_MODULO_OFF, // 禁用目标地址的环形缓冲 .transferLoopByteCount = 8, // 每次传输4字节 .srcLastAddrAdjust = 0, // 源地址最后的调整为0 .destLastAddrAdjust = -8, // 目标地址最后的调整为-8 .interruptEnable = true, // 启用DMA中断 .loopTransferConfig = &dma_transfer_config0LoopConfig, // 循环传输配置,使用之前定义的循环配置 };
main.c主要代码如下:
/* USER CODE BEGIN PV */ volatile bool g_finish_flag = false; // 完成标志,用于标记 DMA 传输完成 /* USER CODE END PV */ /* Private function declare --------------------------------------------------*/ /* USER CODE BEGIN PFDC */ /* USER CODE END PFDC */ static void Board_Init(void); /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ void dma_transfer_callback(void) { g_finish_flag = true; // 设置完成标志为 true,表示 DMA 传输已完成 } /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ status_t status = STATUS_SUCCESS; /* USER CODE END 1 */ Board_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ status=DMA_DRV_InstallCallback(0, (dma_callback_t)dma_transfer_callback, NULL); //安装回调函数 if(status!=STATUS_SUCCESS) PRINTF("DMA_DRV_InstallCallback return err:%x\r\n",status); status=DMA_DRV_ConfigLoopTransfer(0U, &dma_transfer_config0);// 再配置 DMA 循环传输 if(status!=STATUS_SUCCESS) PRINTF("DMA_DRV_ConfigLoopTransfer return err:%x\r\n",status); DMA_DRV_DisableRequestsOnTransferComplete(0U, true); // 在传输完成后禁用请求 status=DMA_DRV_StartChannel(0U); if(status!=STATUS_SUCCESS) PRINTF("DMA_DRV_StartChannel return err:%x\r\n",status); while (1) { /* USER CODE END WHILE */ if (g_finish_flag) // 如果 DMA 传输完成 { PRINTF("DMA Transfer Completed!\r\n"); g_finish_flag = false; // 重置完成标志 DMA_DRV_StartChannel(0U); } /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }
能否帮我看一下我的工程哪里有问题吗? 十分感谢
工程如附件IOPort_FlipLevel_Demo.zip -
Diga 感谢支持。增加了DMA_DRV_TriggerSwRequest(0);后,回调函数确认能够如期触发。但是用逻辑分析仪抓IO口的波形发现还是没有变化。手动操作 GPIO 寄存器时,逻辑分析仪能够捕获到波形变化,说明还是DMA的问题。能够再帮我看一下吗?
这是我手动操作 GPIO 寄存器的代码内容:
/* 测试手动设置GPIOB的PSOR和PCOR寄存器 */ void test_manual_gpio_control(void) { /* 手动将GPIOB的某些引脚设置为高电平 */ GPIOB->PSOR = (1 << 0); // 设置PB0为高电平 GPIOB->PSOR = (1 << 1); // 设置PB1为高电平 GPIOB->PSOR = (1 << 2); // 设置PB2为高电平 /* 手动将GPIOB的某些引脚设置为低电平 */ GPIOB->PCOR = (1 << 3); // 设置PB3为低电平 GPIOB->PCOR = (1 << 4); // 设置PB4为低电平 GPIOB->PCOR = (1 << 5); // 设置PB5为低电平 /* 手动将GPIOB的某些引脚设置为低电平 */ GPIOB->PCOR = (1 << 0); // 设置PB3为低电平 GPIOB->PCOR = (1 << 1); // 设置PB4为低电平 GPIOB->PCOR = (1 << 2); // 设置PB5为低电平 /* 手动将GPIOB的某些引脚设置为高电平 */ GPIOB->PSOR = (1 << 3); // 设置PB0为高电平 GPIOB->PSOR = (1 << 4); // 设置PB1为高电平 GPIOB->PSOR = (1 << 5); // 设置PB2为高电平 }
DMA源地址进行了volatile uint32_t attribute((aligned(4))) ioSentBuff[16]的4字节对齐操作。谢谢IOPort_FlipLevel_Demo.zip
发帖前请查看
帮助没办法联网的电脑使用YCT
帮助改进和优化YT CONFIG TOOL,有机会抽取YTM32B1ME0 EVB哦...