跳转至内容
  • 版块
  • 最新
  • 标签
  • 热门
折叠
品牌标识

YunTu Forum

YTMicro.com
  1. 主页
  2. Discussion & Question
  3. YTM32B1L系列
  4. 使用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口输出电平的切换

已定时 已固定 已锁定 已移动 YTM32B1L系列
7 帖子 2 发布者 127 浏览
  • 从旧到新
  • 从新到旧
  • 最多赞同
登录后回复
此主题已被删除。只有拥有主题管理权限的用户可以查看。
  • yishui66Y 离线
    yishui66Y 离线
    yishui66
    写于 最后由 yishui66 编辑
    #1

    一、背景:
    ①使用LE05官方demo板 配置PTB_0~PTB_5引脚为输出模式
    ②启用dma,搬运buff中预设的编码到GPIO PCOR Register和GPIO PCOR Register以达到IO口输出电平的切换
    ada796bc-ae97-410b-8f6c-61507dc0444e-1740566752304.png
    e7f3e953-0562-42da-a1d1-f7089c912370-image.png

    编码如:

    /*
    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

    1 条回复 最后回复
    0
    • DigaD 离线
      DigaD 离线
      Diga
      写于 最后由 编辑
      #2

      你要触发一下 DMA,
      搜一下这个函数
      DMA_DRV_TriggerSwRequest(0);

      yishui66Y 1 条回复 最后回复
      0
      • yishui66Y 离线
        yishui66Y 离线
        yishui66
        在 回复了 Diga 最后由 编辑
        #3

        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

        1 条回复 最后回复
        0
        • DigaD 离线
          DigaD 离线
          Diga
          写于 最后由 编辑
          #4

          你 DMA 的配置有点问题,你就用那个 test 数组测试,保证每次 source 都能搬到 destination

          yishui66Y 1 条回复 最后回复
          0
          • yishui66Y 离线
            yishui66Y 离线
            yishui66
            在 回复了 Diga 最后由 编辑
            #5

            Diga 预设功能已经实现。但是LE05为什么DMA搬运无法一次写八个字节?即以下配置不行

            .srcTransferSize = DMA_TRANSFER_SIZE_8B,  // 源数据传输大小为8字节
            .destTransferSize = DMA_TRANSFER_SIZE_8B, // 目标数据传输大小为8字节
            
            1 条回复 最后回复
            0
            • DigaD 离线
              DigaD 离线
              Diga
              写于 最后由 编辑
              #6

              LE05 仅支持 1,2,4 bytes
              image.png

              yishui66Y 1 条回复 最后回复
              0
              • yishui66Y 离线
                yishui66Y 离线
                yishui66
                在 回复了 Diga 最后由 编辑
                #7

                Diga 明白了。感谢

                1 条回复 最后回复
                0

              • 云途论坛规则/Yuntu Forum Rules

                发帖前请查看

              • YCT离线License申请流程

                帮助没办法联网的电脑使用YCT

              • YT CONFIG TOOL调查问卷

                帮助改进和优化YT CONFIG TOOL,有机会抽取YTM32B1ME0 EVB哦...

              • demo
                12
                can
                9
                lin stack
                6
                yt-link
                5
                vscode
                3
                adc模块
                2
                i2c
                2
                uuid
                2
                Online Users
                • 登录

                • 登录或注册以进行搜索。
                • 第一个帖子
                  最后一个帖子
                0
                • 版块
                • 最新
                • 标签
                • 热门