This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TM4C1297NCZAD:发送到 LCD 的额外 DMA 字

Guru**** 2378650 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/630449/tm4c1297nczad-extra-dma-words-transmitted-to-lcd

器件型号:TM4C1297NCZAD

我们已经连接到使用 Hitachi HD44780控制器的4x20字符显示屏。  一切都正常、但当我们使用 LCD DMA 传输整个屏幕的数据值(4x20 = 80 16位字)时、LCD DMA 首先传输16个字的0x0000数据、然后传输80个16位字。  这会导致显示屏显示顶行上头16个字符的空白数据。  在我们第一次使用 DMA 传输屏幕时、一切工作正常、传输80个字。  从这一点开始、即使我们已经告诉驱动器只发送80个字、也会传输96个字。  我们将使用最新的用于 LCD 的 Tiva 外设驱动程序库。  我们的帧缓冲器位于32位边界上。   

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、SH14599、

    您能否提供用于配置 DMA 以及如何使用 DMA 加载/发送数据的源代码?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    LCD DMA 的长度必须是32个字的倍数。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    /*启用我们的内部 LCD 控制器*/
    SysCtlPeripheralEnable (SYSCTL_Periph_LCD0);
    
    LCDModeSet (LCD0_BASE、LCD_MODE_LIDD、(g_ui32SysClock /240)、g_ui32SysClock); // MCLK=2MHz (500ns),是254
    LCDDMAConfigSet (LCD0_BASE,LCD_DMA_BURST_16);
    LCDIDDConfigSet (LCD0_BASE,LIDD_CONFIG_ASYNC_Hitachi);
    
    /*现在将 RS、R/WN、E 配置为 LCD 控制引脚*/
    GPIOPinConfigure (GPIO_PR1_LCDFP);
    GPIOPinConfigure (GPIO_PR2_LCDLP);
    GPIOPinConfigure (GPIO_PJ6_LCDAC);
    GPIOPinTypeLCD (GPIO_PORTJ_BASE、GPIO_PIN_6);
    GPIOPinTypeLCD (GPIO_PORTR_BASE,(GPIO_PIN_1 | GPIO_PIN_2));
    
    //将时序限制设置为最大值以获得可能的最慢设置*/
    sTimings.ui8WSSetup = 1;// WAS 31、TAS=WRSU=100ns
    sTimings.ui8WSDuration = 10;// WAS 63、tPW=WRDUR=4800ns (500ns * 10)
    sTimings.ui8WSHold = 15;// Wwas 15、TAH=WRHOLD=7500ns (500ns * 15) TC=12000ns
    sTimings.ui8RSSetup = 1;// WAS 31、TAS=RDSU=100ns
    sTimings.ui8RSDuration = 10;// WAS 63、tPW=RDDUR=4800ns (500ns * 10)
    sTimings.ui8RSHold = 15;// WAS 15、TAH=RDHOLD=7500ns (500ns * 15) TC=12000ns
    sTimings.ui8DelayCycles = 4;
    
    //向 LCD 控制器提供我们定义的时序*/
    LCDIDDTimingSet (LCD0_BASE、0、&sTimings);
    
    //确定 LCD 的数量0x38[0x38]、
    LCDINUCD8、
    0x38](0x38]、0xCDINUCD8、0x38] 0x06、0x0C、0x01};
    
    uint32_t ulDelayMsec = 25.0 *(cycles_ffrom _time_US (g_ui32SysClock、1000)/ 3);
    
    //初始化 LCD */
    for (ulIdx = 0;ulIdx < ulLimit;ulIdx++)
    {
    /*将命令写入显示屏*/
    LCDIDDCommandWrite (LCD0_BASE、0、(uint16_t) ucLCDInitCmd[ulIdx]);
    
    SysCtlDelay (ulDelayMsec);
    }
    
    if (ucRetVal =0)
    {
    /*确定 LCD init 命令的数量*/
    ulLimit = sizeof (GS_pucCustomChars)/sizeof (GS_pucCustomChars[0]);
    
    /*将 cgram 地址设置为0 */
    LCDIDDCommandWrite (LCD0_BASE、0、0x40);
    
    /*等待忙标志清除*/
    while (LCDIDDStatusRead (LCD0_BASE、0)& 0x80){};
    
    /*创建我们的自定义字符*/
    for (ulIdx = 0;ulIdx < ulLimit;ulIdx++)
    {
    for (ucIdx = 0;ucIdx < 8;ucIdx++)
    {
    RetucVal |= WriteData( GS_pucCustomChars[ulIdx][ucIdx]);
    }
    }
    
    /*将数据 RAM 地址设置为0 */
    LCDIDDCommandWrite (LCD0_BASE、0、0x80);
    
    /*等待忙标志清除*/
    while (LCDIDDStatusRead (LCD0_BASE、0)& 0x80){};
    }//
    
    如果成功发送 LCD 命令*/
    if (ucRetV=0)
    {
    /*延迟、以使对 LCD 的更改生效*/
    OSAL_TaskDelay (osalMsToTicks(10));
    
    /*注册我们的中断处理程序*/
    LCDIntRegister (LCD0_BASE、LCDIntHandler);
    
    /*最后、启用 LCD DMA 完成中断*/
    LCDIntEnable (LCD0_BASE、LCD_INT_DMA_DONE);
    
    /*设置中断优先级、因为我们在 ISR 中使用 RTOS 调用*/
    IntPrioritySet (INT_LCD0、osalMaxIntPrio+1);
    
    //如果需要,打开 LCD 背光*/
    bsp_lcd_backlight (get_enable_backlight());
    }
    
    
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    请注意、我们有一个互斥量/信标、可在 DMA 操作进行时保护我们不使用 LCD 外设。   要发送数据、我们使用:

         
       /* set cgram address to 0 */
       LCDIDDCommandWrite(LCD0_BASE, 0, 0x40);
       
       /* Wait for BUSY flag to clear */
       while(LCDIDDStatusRead(LCD0_BASE, 0) & 0x80) { };
         if (osal_TakeMutexSemaphore (g_xLCDBufMutex、osalMaxDelay、0)=osalTRUE)
         {
            //使用 DMA */
            LCDIDDDMAWrite (LCD0_BASE、0、GS_ulLCDDMABuf、DISPLAY_MAX_LEN
         
         
         
            )编写显示;}= 1;否则}
         

    我们的 ISR 执行以下操作:

    void LCDIntHandler (void)
    {
      uint32_t ulIntStatus;
      osal_EnterInterrupt ();
      ulIntStatus = LCDIntStatus (LCD0_BASE、osalTRUE);
      if (ulIntStatus &(LCD_INT_DMA_DONE)))
      {
          if (ulIntStatus!=
          
              0;
          }uluIntStatus & oslcd_dma_deone *
         )可以
         
         将命令发送回 LCD/ LCDMude*
         
      
      LCDIntClear (LCD0_BASE、ulIntStatus);
      osal_ExitInterrupt ();
    } 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    下面是我们声明帧缓冲区的方式。  在传输之前、我们将80个字节复制到该缓冲区中(打包的16位)。  我忘记了上面的内容...

    #pragma DATA_ALIGN (GS_ulLCDDMABuf、4);
    static uint32_t GS_ulLCDDMABuf[display_LCD_MAX_LEN/2];
    
    //从提供给我们32位缓冲区的8位缓冲区复制到我们的16位块中*/
    for (ulIdx = ulJdx = 0;ulUUUUUIDx+= 2;ulUUUUUIDx+)
    
    gs_ulLCDDMABuf[ulJdx]=(((((uint32_t)(puBuf[ulIdx + 1]))<< 16)+ puBuf[ulIdx]);
    } 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、SH14599、

    查看 DriverLib 文档"SW-TM4C-DRL-UG/2.1.4.178.pdf"以了解 LCDDMAConfigSet 的说明、您可能尚未对其进行完全配置。

    您发布的代码显示:

    LCDDMAConfigSet (LCD0_BASE、LCD_DMA_BURST_16); 

    但是 DriverLib 文档显示:"ui32Config 参数是各种标志的逻辑 OR。 它必须包含以下每个组中的一个值。"

    这些组为 LCD_DMA_FIFORDY_*(不存在)、LCD_DMA_BURST_*(存在)和 LCD_DMA_BYTE_ORD__Order_*(不存在)。

    您应该根据启动器的设置来考虑是否为您的屏幕添加正确设置、因为这可能是您面临的部分/全部问题。


    现在、我们来详细了解一下您正在执行的操作、现在我还想知道使用 DMA 是否对这个微型屏幕来说有点过分! E2E 上提到的 LCD 控制器有很多帖子、只需将名称放在搜索栏中、您就会发现许多线程、但我看到的另一个人使用 DMA 处理它! 我有一种感觉、您正在进行大规模的复杂过度。 实际上、您可能会更快地发现 、将 E2E 上已有的信息用于 HD44780控制器。 例如、CB1这篇文章详细介绍了: https://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/279206

    由于 CB1仍然非常重要、而且还在使用、我怀疑如果您与他的领导一起、而不是尝试使用 DMA、他会愿意在您尝试遵循他的建议时帮助您进一步指导。


    最后、"LCD DMA 的长度必须是16个字的倍数。" 80也是16的倍数? 您可能是指32字节? 但我也看不到任何暗示这种情况的概念。 仅供参考。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    (幸运的是)仍然(有些)-协议已完全符合 Ralph 供应商的建议、即采用(我敢说)"kiss!"

    LCD 控制器需要很长的时间来处理每个字符-因此 µDMA (通常为速度选择)似乎(如 Ralph 所述)误传。

    列出了四个0x38初始化字节-两个运行得非常好-请注意、在每个初始化字节期间、您必须遵守 LCD 控制器要求的(相对)长延迟时间。

    需要注意的是、"传输80字节的显示数据(完全填满显示屏)可实现"重复和风格化数据传输"、但几乎绝对不需要!   (可以采用更短的转账-进一步"击败"µDMA!"的需要 (笑声) 这是通过以下方法实现的:"光标方向-然后是选择性(和有限)显示写入-这可能是"快速、更高效地更新屏幕的"小部分"。")

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    感谢您的回答。 我完全同意你的意见。 对这么小的显示屏使用 DMA 过于复杂。 我更愿意调整 LCD 外设的时序参数、以匹配 LCD 控制器的时序、然后在循环中选择性地将数据推出、在数据字节之间轮询 LCD 控制器的 BUSY 标志。 但是、该代码的所有者对简化代码而不使用 DMA 有一些抗拒。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    拉尔夫

    感谢您的快速响应。 是的、我指的是32字节。 就好像 LCD DMA 要求帧缓冲区的大小是32字节的倍数一样。 关于 DMA 配置函数、该寄存器中唯一的非零设置是突发大小。 所有其他设置导致寄存器中的位为零。 因此、我认为这不是问题。 我尝试了各种设置、但没有解决问题。 对于此小型显示屏使用 LCD DMA、我完全同意您的观点、即它过于复杂。 我的意见是、我们应该将数据按一个循环推出、在写入之间检查 LCD 控制器的忙标志。 我会说服守则的原始作者采用这种方法。

    同时、您是否可以通过 LCD DMA 验证这一32字节明显的倍数要求?

    谢谢!
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢你们,因为你们可能(顾问)是这个政党的,(有些)必须采取外交手段。   (即"走一条紧绳!")   感受您的痛苦!

    轮询忙标志(除初始化之外的所有状态)是"优化数据传输"到此类基于字符的显示的首选方法。   但是轮询可能会"过度使用 MCU"(您是"坚持使用轮询循环")-并且可以(相反)允许"忙"切换"中断 MCU!"   (实现最快、最高效的数据传输... 尽管会增加代码复杂性、但会增加代码复杂性)

    您的客户似乎有、"挂接到 µDMA 马车"、因为"就在那里!"    或者、因为有人提到"lcd"、而 MCU 的"µDMA lcd reference"始终且仅针对更大的图形显示而不如此基本的4x20字符模块!

    了解"何时、何地、为何以及如何"(正确)利用、"独特的 MCU 外设功能"可能需要更高的"深度了解"(您拥有)-客户(看起来) 需要太多!    (还有... 希望能这样)

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    [引用用户="SH14599"]
    同时、您是否可以通过 LCD DMA 验证这一32字节明显的倍数要求?

    [/报价]

    您好、SH14599、

    DriverLib 用户指南明确指出,LCDIDDDMAWrite()函数“在将所需的数据块传输到显示屏之前启用 LCD 控制器中的 DMA 引擎。 DMA 引擎一次传输16位数据、因此如果使用具有8位接口的显示屏、则必须填充数据。" 请注意,它是*位*而不是*字节*。 因此、每次传输至少有2个字节。

    它还注意到、这是为了将大数据块传输到显示屏... 我不能确定你提出的情况是否完全符合这一标准。

    我肯定会鼓励"原始作者"重新考虑他们的方法、但同时阅读《适用于 LCD 接口显示驱动器(LIDD)模式的 DriverLib 用户指南》(第365页)的详细信息、以更好地了解应使用哪些 API 以及如何使用。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    谢谢 Jacobi。 我们最终将 LCD 屏幕写入函数更改为循环写入每个字符(4x20显示屏为80个字符)、等待 BUSY (D7)位变为低电平以指示 LCD 已接受数据。 通过优化 LCD 外设中的总线时序参数、我们能够在大约3.5ms 的时间内写出所有字符。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    请注意、"80个字符。 在3,500µS μ s"的持续时间内发送、工作在44µS μ s/char 以下。 (这是"合理的"。)

    使用(可能)更新的对比度增强型4x20显示屏-我们在~3,200µS 中实现了类似的"屏幕填充"-只需通过8位并行总线即可。 (不使用 EPI)

    请注意、"发出显示清除"(代码0x01)会导致"长时间延迟"-但是、如果"整个屏幕被重写"、则不需要此类"清除显示"。

    很大程度上取决于新数据的"内容、位置和长度"。   如果只有20-30个字符、则屏幕"写入次数"可以大幅减少。 职位将被"改写"。

    最后要注意的是、"写入现有数据过大、尤其是在"未指示/需要进行任何更改"时、可能会产生明显的"闪烁"、甚至可能产生具有"PWM"调制背光的"拍频"。   选择性显示更新(而不是盲更新)证明是最佳的...