一乐电子

一乐电子百科

 找回密码
 请使用微信账号登录和注册会员

QQ登录

只需一步,快速开始

快捷登录

手机号码,快捷登录

搜索
楼主: MOWEIWEI
收起左侧

[arduino] AVR lcd驱动程序加速优化

[复制链接]
发表于 2017-1-14 21:11 | 显示全部楼层
MOWEIWEI 发表于 2017-1-14 20:49
优化的地方就几行代码。越底层速度越快吧。但越底层的写法抽象性太高。要查阅芯片资料和记很多东西。
没 ...

是的
发表于 2017-1-14 23:04 | 显示全部楼层
本帖最后由 钟义亭 于 2017-1-15 10:12 编辑

http://kaopu.so/pan/AVR

http://kaopu.so/pan/arduino

http://kaopu.so/pan/PIC%E5%8D%95%E7%89%87%E6%9C%BA

http://kaopu.so/pan/STm8%20%E5%8D%95%E7%89%87%E6%9C%BA


6.png 5.png
4.png
3.png
2.png
1.png

掏寶用 ID 號代買的 , 不在內
私下交易的
STM8 五年前 就買了
大部分 只買回看看
現在技術  PCB 放上五年 還很新的
我有很多事 ,  計畫中 的



评分

参与人数 1一乐金币 -40 收起 理由
40560335 -40 淡定

查看全部评分

发表于 2017-1-16 00:12 | 显示全部楼层
avr的芯片用【PORTD=0X08;】这种语句改变IO输出电平,只需要运行一个时钟周期。
但是如果需要改变立刻生效,再需要多一个运行时钟周期。
也就是nop代码。
#define _NOP() {asm volatile("nop");}

如果【PORTD=0X08;】后面有其他代码,就不需要加nop,



        i2c_sda_lo();
        i=i+1;                //比如这样就是生效的
        i2c_sda_hi();
        i=i+1;                //比如这样就是生效的

        i2c_sda_lo();
        i2c_sda_hi();        //这样,avr的io口不一定是,先输出低电平,再变成高电平的


//另一种优化速度方式是,如果有发生8bit数据的代码,不要用for代码,因为循环代码的入口出口,都需要消耗时钟周期。

uint8_t SoftwareWire::i2c_write( uint8_t c )
{
  /*
    for ( uint8_t i = 0; i < 8; i++)
    {
    i2c_writebit(c & 0x80);           // highest bit first
    c <<= 1;
    }
  */
  i2c_write_bit(c & 128);
  i2c_write_bit(c & 64);
  i2c_write_bit(c & 32);
  i2c_write_bit(c & 16);
  i2c_write_bit(c & 8);
  i2c_write_bit(c & 4);
  i2c_write_bit(c & 2);
  i2c_write_bit(c & 1);
  /* read ack from client */
  /* 0: ack was given by client */
  /* 1: nothing happend during ack cycle */
  return (i2c_read_bit());

}


arduino的IDE,各种芯片的digitalWrite(LED_BUILTIN, HIGH); 代码,都可以扒里面封装的IO口设置寄存器代码,出来优化的。
除了少数芯片的arduino的IDE,封装得太厉害,没有给出寄存器,封装成函数xxxxx.s这种连接文件,就不能进一步优化了。
 楼主| 发表于 2017-1-16 01:21 | 显示全部楼层
本帖最后由 MOWEIWEI 于 2017-1-16 03:08 编辑
狗狗百里游 发表于 2017-1-16 00:12
avr的芯片用【PORTD=0X08;】这种语句改变IO输出电平,只需要运行一个时钟周期。
但是如果需要改变立刻生效 ...

多谢提供技术资料。

我是业余搞编程的,因此对于某些技术内幕不是很了解。因为有些东西的确不容易查到。
但是我有其他方式debug。

不知道你说的一个周期是指晶振的周期吗?还是单片机程序的周期。单片机的周期最小貌似是 晶振/2
因为单片机能输出频率貌似最大也就晶振/2.   

另我在示波器上观察到
PORTD=0X08;
PORTD=0X00;
的波形是这样的,2.6mhz
_| ̄|_____________| ̄|___

PORTD=0X08;
PORTD=0X00;
PORTD=0X08;
PORTD=0X00;
的波形是这样的
_| ̄|___| ̄|__________| ̄|___

PORTD=0X08;
PORTD=0X00;
PORTD=0X08;
PORTD=0X00;
PORTD=0X08;
PORTD=0X00;
_| ̄|___| ̄|___| ̄|_______| ̄|___

最高貌似6m这样吧。再多加一组语句就输出0mhz。

有没有什么语句能再提高一倍呢?上面就算是一个波挨着一个波。貌似也就是你说的要一定的时钟周期。 16m晶振下达到 4mhz
也许有方法我不知道。也许不行。看到spi的时钟可以达到8mhz。定时器也可以达到8mhz。但那时特定针脚。普通针脚也许最高也就4mhz吧。
求解答。


nokia  lcd需要9bit spi驱动。可是这方面的资料好少。能驱动那块lcd核心代码,就是发送数据那块。我是抄过来用的。 但我拿一些8bit spi驱动试验移植成9bit的。都不成功。也不知道为什么。也许我需要一个逻辑分析仪。但又不想买。用着proteus里面的逻辑分析仪。貌似不上实体机不好说。唉!
发表于 2017-1-16 09:34 | 显示全部楼层
arduino我用过,loop函数外还要执行一部分代码,所以输出的频率不会超过一个极限。
我给你的建议是取消loop循环,在setup时就使用自定义的循环就可以达到很高的速度,不过这个是我的想法,还没有测试过。不知道编译是不是会出问题。
发表于 2017-1-16 10:57 | 显示全部楼层
本帖最后由 钟义亭 于 2017-1-16 18:22 编辑

也就是nop代码。
#define _NOP() {asm volatile("nop");}
這是 C語加入組語用


LCD開機誤動作 , 可 NOP 去處理波形
我只是看程式 , 偶而小改動
沒在寫程式 , 書都看不完  ,  又不能看太長時間

  i2c_sda_lo();
  i2c_sda_hi();        
//这样,avr的io口不一定是,先输出低电平,再变成高电平的

i2c_sda_lo();
nop
i2c_sda_hi();  
nop

用C語很難做出 ,  你想要的 方波序列
有看過有賣  , 做一序列方波的書 , 少人會買這種天書

https://read01.com/AEn7dP.html

阻塞 與 非阻塞
两种赋值不会对语句本身的赋值有影响,
但会影响以后对赋值结果的引用。

2.jpg
1.jpg


http://blog.chinaaet.com/yimeng/p/5100017472

http://www.ttfanwen.com/info_10/fw_2304119.html







评分

参与人数 1一乐金币 -40 收起 理由
40560335 -40 淡定

查看全部评分

发表于 2017-1-16 15:35 | 显示全部楼层
我这里的【i2c_sda_lo();】实际代码只是相当于#define i2c_sda_lo() {PORTD=0X08}
用i2c_sda_lo表示是为了以后检查代码思路,方便知道当时是什么意思。

PORTD=0X08;
_NOP;
PORTD=0X00;
_NOP;
PORTD=0X08;
_NOP;
PORTD=0X00;
_NOP;
PORTD=0X08;
_NOP;
PORTD=0X00;
_NOP;
要这样才能保证IO口正确切换电平,avr芯片的说明书里面说过的。
avr芯片用寄存器改变io口电平状态,不是一个时钟周期就可以的
如果你没有用看门狗复位,可以在大量改变io口状态的时候,关闭中断,之后再打开中断,这样millis()得到的结果,就不会计数了。

avr的硬件spi输出io电平是最快的的。只有这样了。
其他的芯片我测试ssd1306屏幕,刷新一个屏幕的缓存,硬件i2c,跟模拟i2c,来比较io口操作的速度。

#if defined(SoftwareWire_h)
//如果使用的是模拟I2C,发送Wire.write();是阻塞函数,一次发送1024个字节
void OLED::update()
{
  // noInterrupts();
  _sendTWIcommand(SSD1306_SET_COLUMN_ADDR);
  _sendTWIcommand(0);
  _sendTWIcommand(127);
  _sendTWIcommand(SSD1306_SET_PAGE_ADDR);
  _sendTWIcommand(0);
  _sendTWIcommand(7);
  Wire.beginTransmission(SSD1306_ADDR);
  Wire.write(SSD1306_DATA_CONTINUE);
  Wire.write(&scrbuf[0], 1024);
  // for (uint16_t i = 0; i < 1024; i++) {
  //    Wire.write(scrbuf[i]);  }
  Wire.endTransmission();
  //  interrupts();
}

#else
//如果使用的是IDE自带的<Wire.h>库,发送Wire.write();是用中断函数,
//以Wire.endTransmission();为结尾,通过缓存发送的,一次只能发送16个字节
void OLED::update()
{
  // noInterrupts();
  _sendTWIcommand(SSD1306_SET_COLUMN_ADDR);
  _sendTWIcommand(0);
  _sendTWIcommand(127);
  _sendTWIcommand(SSD1306_SET_PAGE_ADDR);
  _sendTWIcommand(0);
  _sendTWIcommand(7);
  // I2C
  for (uint16_t i = 0; i < 1024; i++) {
    // send a bunch of data in one xmission
    Wire.beginTransmission(SSD1306_ADDR);
    Wire.write(SSD1306_DATA_CONTINUE);
    /*
      // defined(__arc__) 34频画面
      for (uint8_t x = 0; x < 16; x++)
      {
       Wire.write(scrbuf[i]);
       i++;
      }
      i--;
    */
    Wire.write(&scrbuf[i], 16);
    i +=  15;
    Wire.endTransmission();
  }
  //  interrupts();
}
#endif

直接操作io口,目前芯片最快的是esp32。硬件的是ArduinoDUE,测试是自己编写的模拟i2c,跟自己编写的简化硬件i2c代码,在打开Arduino中断计数的情况下,没有测试过用dma模式发生数据。
Arduino的IDE,完全可以用gcc代码编译avr芯片,ide只是重新定义了void setup() void loop(),可以改回来的...

发表于 2017-1-16 15:36 | 显示全部楼层
本帖最后由 狗狗百里游 于 2017-1-16 15:39 编辑


//刷新一个测试需要的时间  77924us   12频  Avr 328P 16MHz 硬件I2C while ((TWCR & _BV(TWINT)) == 0) {};
//刷新一个测试需要的时间  122916us   7频, Avr 328P 16MHz 模拟I2C digitalPinToPort(_sdaPin);
//用pinMode模拟开漏输出
//#define SDA_LOW()       pinMode(i2c_sda_pin, OUTPUT);        //设置I2C强下拉
//#define SDA_HIGH()      pinMode(i2c_sda_pin, INPUT_PULLUP);  //设置I2C关闭弱上拉,变成高阻,I2C端口需要外接上拉电阻
//刷新一个测试需要的时间  34588us  28频,  ESP8266 160MHz  硬件I2C,
//刷新一个测试需要的时间  20993us  47频,  ESP8266 160MHz 【#define SDA_LOW()    (GPES = i2c_sda_pin_BIT)】模拟I2C,提前计算移位,//1x NOP U8GLIB_SSD1306_128X64_2X
//目前ESP32 240MHz的速度很快,暂时不优化设置IO口的代码
//刷新一个测试需要的时间  14083us  70频,  ESP32 240MHz 模拟I2C,使用#define SDA_LOW() digitalWrite(i2c_sda_pin, LOW)
//刷新一个测试需要的时间  17453us  56频,  ESP32 240MHz I2C,<Wire.h> Wire.setClock(900000L);
//刷新一个测试需要的时间  32069us  31频,  ESP32 240MHz I2C,<Wire.h> Wire.setClock(400000L);
//刷新一个测试需要的时间  11468us  87频,  DUE(ARM 32) 84MHz 硬件I2C,  <HW_ARM.h> DUE_TWI_SetClock(twi, 2400000L, VARIANT_MCK);
//刷新一个测试需要的时间  24777us  40频,  DUE(ARM 32) 84MHz 模拟I2C,  _sclBitMask  = digitalPinToBitMask(_sclPin);
//刷新一个测试需要的时间  27404us  36频,  DUE(ARM 32) 84MHz 硬件I2C   <Wire.h>
//刷新一个测试需要的时间  72544us  13频,  DUE(ARM 32) 84MHz 模拟I2C,  pinMode(_sda_pin, OUTPUT);  digitalWrite(_scl_pin, LOW);

//刷新一个测试需要的时间  40916us  24频,  Arduino101 32MHz  硬件I2C,
//刷新一个测试需要的时间  67519us  14频,  Arduino101 32MHz  模拟I2C,提前计算移位,精简到【SET_ARC_BIT_YUKI(reg_sda_pin, READ_ARC_REG(reg_sda_pin) & ~ (ulGPIOId_sda_pin_BIT));】
//刷新一个测试需要的时间  176582us   5频, DFRobot Bluno M3 72Mhz 【STM32 F103RET6】 I2C,<Wire.h> IDE自带库,其实是模拟I2C,使用【digitalWrite】设置IO模拟I2C,Wire.setClock(400000L)//刷新一个测试需要的时间  2210596us  DFRobot Bluno M3 72Mhz 【STM32 F103RET6】 模拟I2C,使用【g_APinDescription】设置IO模拟I2C,//u8g原始代码,U8GLIB_SSD1306_128X64_2X
//刷新一个测试需要的时间   32361us  30频, DFRobot Bluno M3 72Mhz 【STM32 F103RET6】 模拟I2C,使用【g_APinDescription[i2c_sda_pin].pPort->BRR】+【ulPin】设置IO模拟I2C,//u8g原始代码,U8GLIB_SSD1306_128X64_2X
//Fireduino开发板 模拟I2C,使用digitalPinToPort(_sclPin),不能用A4,A5等ad端口,以及硬件SDA,SCL端口,做为模拟端口使用
//#define SDA 8   //有些开发板的芯片,不能用A4,A5等ad端口,以及硬件SDA,SCL端口,做为模拟端口使用
//#define SCL 9
//刷新一个测试需要的时间   43657us  23频, Fireduino开发板 模拟I2C,使用digitalPinToPort(_sclPin),不能用A4,A5等ad端口,以及硬件SDA,SCL端口,做为模拟端口使用

发表于 2017-1-16 15:56 | 显示全部楼层
1.jpg
2.jpg
3.jpg
IMG_7457.mp4 (3.62 MB, 下载次数: 43)
手机拍的mov视频,我改名字成mp4上传.
8位芯片跟32位芯片运算速度,上电时的晶振误差,跟io电平的波形(IO口是开漏输出,实际测试发现5v电平速度稍微快点,因为我检测了ssd1306屏幕IO脚的反馈,作为数据接收成功),造成屏幕刷新速度的误差,本人概不负责....


 楼主| 发表于 2017-1-16 16:24 | 显示全部楼层
嗯。不错。
硬件i2c跟软i2c对比。

我看过网上视频。i2c要比spi慢很多。
根据你的测试综合一下速度对比
软i2c<硬i2c
软spi<硬spi
硬i2c  软spi  ????

你的单片机比较强大。搞这个没多大意思。

我的目的是tft屏用在atmega8级别的这种单片机上。替代1206之类的屏。或者其他单色屏。毕竟tft便宜,有的几块钱一片。能显示比较多的信息。大家手上多多少少都有些烂手机。拆了屏拿来玩。

本版积分规则

QQ|一淘宝店|手机版|商店|电子DIY套件|一乐电子 ( 粤ICP备09076165号 ) 公安备案粤公网安备 44522102000183号

GMT+8, 2024-5-2 20:01 , Processed in 0.056136 second(s), 36 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表