Tuier 发表于 2025-8-24 07:15:15

版主你好,我的OLED12864驱动芯片是ST7567,MCU为AI8051U,用P2端口。通过你的讲解,硬件SPI硬件驱动成功了,但SPI_DMA移植不顺利。看到“跟帖问OLED12864程序给您全搞定”,想求助版主技术支持!谢谢!

大明狐 发表于 2025-8-25 08:30:35

Tuier 发表于 2025-8-24 07:15
版主你好,我的OLED12864驱动芯片是ST7567,MCU为AI8051U,用P2端口。通过你的讲解,硬件SPI硬件驱动成功了 ...

不清楚你说的DMA移植不顺利集体是什么,就先忙猜一下是速度问题。
因为不同型号的控制芯片,时序之类其实都不太一样。比如,即便是驱动程序看起来通用的OLED,不同型号之间,对单片机的速度要求也不完全一样。所以,硬件SPI通过了而DMA没通过,就有可能是SPI的速度配置对了,DMA的速度没配置合适。
而ST7567是LCD液晶屏的驱动芯片,不是OLED的,而是跟TFT彩屏是一个系统的,它们对时序要求更高。

Tuier 发表于 2025-8-25 15:34:10

大明狐 发表于 2025-8-25 08:30
不清楚你说的DMA移植不顺利集体是什么,就先忙猜一下是速度问题。
因为不同型号的控制芯片,时序之类其实 ...
我可能描述不清楚,重新交流一下。
就是移植后,SPI硬件驱动(无DMA)屏幕能正常驱动显示。加了DMA后,显示不正常,只有第一行(程序中只能显示一行,即第6page,其它页都显示乱码,且显示不对应)显示正常,其它乱码,怎么修改都不得其法。现将截图和程序贴上,请版主指导!

大明狐 发表于 2025-8-25 16:50:34

Tuier 发表于 2025-8-25 15:34
我可能描述不清楚,重新交流一下。
就是移植后,SPI硬件驱动(无DMA)屏幕能正常驱动显示。加了DMA后,显 ...
不知道没有DMA的成功代码是什么样。从照片上看,用DMA的这个是只刷新了屏幕的最上面一行。
手头也暂时没有这种屏幕,没法测试想法。
这个DMA的代码里,刷新全屏用的是一次性发送1024个数据。
但是找了下ST7567的资料,控制芯片的结构是每个page有132列,只用到其中128列,类似SH1106的OLED屏幕,而且列地址只在指定行里自增和归零,相当于OLED屏幕的“页地址模式”。
这样的话,128×64的区域应该不能用这种方式填充数据,而是分成8行,每次发送128个数据才对。

把OLED_Refresh函数的一次性发送1024个数据,换成分8行发送,每次128个数据试试看?


Tuier 发表于 2025-8-26 10:06:07

大明狐 发表于 2025-8-25 16:50
不知道没有DMA的成功代码是什么样。从照片上看,用DMA的这个是只刷新了屏幕的最上面一行。
手头也暂时没有 ...
还是不行{:4_167:}。未成功代码在12楼末尾
void OLED_Refresh(void)
{
    uint8_t cmd;
   
    cmd = 0x40;                      //设置行起始地址
    cmd = 0x00;                      //设置低列起始地址
    cmd = 0x10;                      //设置高列起始地址
    OLED_WR_CMD(cmd, 3);
//    OLED_WR_DAT(OledCache, 1024);       //写数据...
          OLED_WR_DAT(OledCache, 128);      
                OLED_WR_DAT(OledCache, 128);
                OLED_WR_DAT(OledCache, 128);
                OLED_WR_DAT(OledCache, 128);
                OLED_WR_DAT(OledCache, 128);
                OLED_WR_DAT(OledCache, 128);
                OLED_WR_DAT(OledCache, 128);
                OLED_WR_DAT(OledCache, 128);
      
}

大明狐 发表于 2025-8-26 13:54:39

Tuier 发表于 2025-8-26 10:06
还是不行。未成功代码在12楼末尾
void OLED_Refresh(void)
{

12楼末尾的代码看过了,上面的回复就是根据这个代码推测的。

关于OLED_Refresh函数的修改方法,结构可以参考显示图片的函数。
分成8行发送,就是分别定位每一行,然后发送对应的128个数据。
你的这个修改,依旧是在第一行里反复发送缓存数组里的钱128个数据。可以借助一个变量,对行号进行递增,然后发送对应的128个数据。

根据芯片手册里关于设置页地址的指令表,是以0xB0为基础的(1011xxxx),低四位是行号,


所以比如像这样写:


void OLED_Refresh(void)
{
    uint8_t page;
    uint8_t cmd;
   
    for( page=0; page<8; page++ )
    {
      cmd = 0x40;                      //设置屏幕最顶上一行作为第0行
      cmd = 0xB0+page;             //设置行起始地址
      cmd = 0x10;                      //设置低列起始地址(高四位)
      cmd = 0x00;                      //设置高列起始地址(低四位)
      OLED_WR_CMD( cmd, 4 );

      OLED_WR_DAT( OledCache + page*128 , 128 );      
    }      
}


其中0x40也可以放到初始化函数里,就不用每次都发送了。

Tuier 发表于 7 天前

大明狐 发表于 2025-8-26 13:54
12楼末尾的代码看过了,上面的回复就是根据这个代码推测的。

关于OLED_Refresh函数的修改方法,结构可以 ...
按照版主老师的程序,显示有所改善:不花屏了,但显示不正常,无法定位显示,自己试着修改其它参数仍不能正常,奈何技术水平有限,再次与版主交流。具体描述如下:
程序里所有页都有内容时,显示如下:
第一种情况:
while (1)
    {
      //<<AICUBE_USER_MAIN_LOOP_BEGIN>>
      // 在此添加主函数中用户主循环代码
         
      OLED_ClearScreen(0);
      OLED_SetFontHeight(16);
      OLED_DrawString(0, 0, "   OLED-12864   ", 0);
      OLED_DrawString(0, 2, "    文本模式    ", 0);
      OLED_SetFontHeight(8);
      OLED_DrawString(0, 4, "OLED Model : SSD1306", 0);
      OLED_DrawString(0, 5, "Target MCU : Ai8051U", 0);
      OLED_DrawString(0, 6, "Work Freq. : 40.0MHz", 1);

}有显示,但显示不全。而且重复显示。
***************************************************
第二种情况:
屏蔽掉
while (1)
    {
      //<<AICUBE_USER_MAIN_LOOP_BEGIN>>
      // 在此添加主函数中用户主循环代码
         
      OLED_ClearScreen(0);
      OLED_SetFontHeight(16);
      OLED_DrawString(0, 0, "   OLED-12864   ", 0);
      OLED_DrawString(0, 2, "    文本模式    ", 0);
      OLED_SetFontHeight(8);
       // OLED_DrawString(0, 4, "OLED Model : SSD1306", 0);
      //OLED_DrawString(0, 5, "Target MCU : Ai8051U", 0);
      //OLED_DrawString(0, 6, "Work Freq. : 40.0MHz", 1);

}屏幕无显示。

*******************************************************
第三种情况:
屏蔽掉
while (1)
    {
      //<<AICUBE_USER_MAIN_LOOP_BEGIN>>
      // 在此添加主函数中用户主循环代码
         
      OLED_ClearScreen(0);
       // OLED_SetFontHeight(16);
       // OLED_DrawString(0, 0, "   OLED-12864   ", 0);
       // OLED_DrawString(0, 2, "    文本模式    ", 0);
      OLED_SetFontHeight(8);
      OLED_DrawString(0, 4, "OLED Model : SSD1306", 0);
      OLED_DrawString(0, 5, "Target MCU : Ai8051U", 0);
      OLED_DrawString(0, 6, "Work Freq. : 40.0MHz", 1);

}只显示第6页。只要把第6页去掉,其它再多的内容都不显示了
只要保留第6页,刷屏只能显示偶数页(0、2、4、6页的内容),奇数页显示是偶数页的内容。
*************************************************
试着修改OLED_Refresh()其它参数,都不得要领。
如果想在第0行、0列开始显示内容,结果是空白。根本无法实现随心所欲在任何位置显示。感觉DMA好难理解{:4_167:}。






大明狐 发表于 6 天前

Tuier 发表于 2025-8-27 11:08
按照版主老师的程序,显示有所改善:不花屏了,但显示不正常,无法定位显示,自己试着修改其它参数仍不能 ...
刚刚拿到了一块ST7567的屏幕,用你的程序试了一下,的确不是速度原因,而是DMA发送数据的问题。
然后发现,上个回复里的OLED_Refresh函数的修改建议里,发送数据的部分写错了,应该是:
void OLED_Refresh(void)
{
    uint8_t page;
    uint8_t cmd;
   
    for( page=0; page<8; page++ )
    {
      cmd = 0x40;                      //设置屏幕最顶上一行作为第0行
      cmd = 0xB0+page;             //设置行起始地址
      cmd = 0x10;                      //设置低列起始地址(高四位)
      cmd = 0x00;                      //设置高列起始地址(低四位)
      OLED_WR_CMD( cmd, 4 );

      OLED_WR_DAT( OledCache + page*128, 128 );
    }      
}

也可以写成
void OLED_Refresh(void)
{
    uint8_t page;
    uint8_t cmd;
   
    for( page=0; page<8; page++ )
    {
      cmd = 0xB0+page;             //设置行起始地址
      cmd = 0x10;                      //设置低列起始地址(高四位)
      cmd = 0x00;                      //设置高列起始地址(低四位)
      OLED_WR_CMD( cmd, 3 );

      OLED_WR_DAT( OledCache + page*128, 128 );
    }      
}

就是把 0x40 指令拿到初始化函数里

    static uint8_t code INIT_SEQU[] =
    {
      0xAE,                //关闭显示
      0x40,                //设置屏幕第一行为起始行
      0xA0,                //设置列扫描方向从左向右
      0xC8,                //设置行扫描方向从上向下
      0xB0,                //设置起始页地址
      0x10,0x00,      //设置起始列地址
      0xA6,                //A6-正常显示,A7-反色显示
      0xA4,                //A4-正常显示,A5-显示全部点阵
      0xA2,                //设置偏压比
      0x26,                //调节电阻比,0x20+
      0x2F,                //打开电源,0x28+
      0x81,0x05,      //设置对比度(00h~3Fh)
      0xAD,                //AD-正常模式,AC-睡眠模式
      0xF8,0x00,      //设置升压倍数
      0xAF,                //开启显示
    };

这样每次就可以少发一个字节了。

======================================================

下面是用修改OLED_Refresh函数后的显示效果

928


Tuier 发表于 6 天前

大明狐 发表于 2025-8-28 12:25
刚刚拿到了一块ST7567的屏幕,用你的程序试了一下,的确不是速度原因,而是DMA发送数据的问题。
然后发现 ...
非常感谢版主,成功了!对于初学者或技术不硬来说,一点小细节可以让你想破脑袋。再次感谢版主辛苦付出!愿你工作越来越顺利!{:4_196:}
页: 1 [2]
查看完整版本: 用AiCube配置硬件SPI和DMA点亮OLED12864 | 跟帖问OLED12864程序给您全搞定