切换到宽版
  • 8340阅读
  • 29回复

[ARM]挖尽GD32潜力,做逻辑分析仪(续),采样速率提高至23M,60k存储深度,真正体现GD优越性 [复制链接]

上一主题 下一主题
离线huaweiwx
 

发帖
1372
M币
2167
专家
65
粉丝
297
只看楼主 倒序阅读 我要置顶 楼主  发表于: 2016-06-13
在我的帖子:挖尽GD32潜力,做逻辑分析仪,15M采样速率,60k存储深度,体现GD优越性 http://bbs.mydigit.cn/read.php?tid=1589478,近来通过进一步优化,将速度再次提高到23M,优化过程如下:



1 影响采样速度的是采样核心循环部分(原帖line 73~75):
     for (i = BUFFERSIZE-1; i != 0; i--)  buffer [ i ]= GPIO_PORT_DATA_R

优化1 将指向端口的指针GPIO_PORT_DATA_R,这是一个常量,编译时指针放在代码段,在循环中需要读取这个存放在flash的地址;
现在我定义个指针变量:  volatile uint32_t *port = &GPIO_PORT_DATA_R
并将循环内的: buffer[ i ] = GPIO_PORT_DATA_R
改为:               buffer[ i ] = *port
port 为函数内局部变量,这样循环内部gcc优化时首先分配寄存器来存放局部变量,这样将port装入寄存器,就不需要每次去读取这个地址值了,节约了至少一个指令周期(可能还不止,视缓冲区情况而定);

2 经测试,buffer [ i ] = *port  在循环内,生成的指令是:

80002a8:    68a2          ldr    r2, [r4, #8]
80002aa:    751a          strb    r2, [r3, #20]

核心部分读端口、写数组仅用两条指令就完成了,按平均1.2 mps/mhz 两个指令周期都不会到(stm 为三级流水线)考虑端口操作没有核心速度那么快,需要插入等待,写RAM也没有寄存器操作那么快(也需要插入等待)
因此如不考虑循环,这部分要使用4个左右的指令周期,即极限30Mhz的采样速率;
加上循环的i--和跳转;又会消耗4~6个指令周期,使实际速率只有15M(最高);

3 从上可见,一半时间在处理循环变量和判断跳转,由于指令跳转还会导致指令高速缓冲区 ICACH的命中率降低,需要重复从flash中去读取指令,进一步降低了速率,因此改造这一步是关键:我将其写成:
  i= MAX_CAPTURE_SIZE;
  systick_disable();
  do{  
     logicdata[i--] =*port;  //1
     logicdata[i--] =*port;  //2;
     logicdata[i--] =*port;  //3
     logicdata[i--] =*port;  //4
     logicdata[i--] =*port;  //5
     logicdata[i--] =*port;  //6
     logicdata[i--] =*port;  //7
     logicdata[i--] =*port;  //8
     logicdata[i--] =*port;  //9
     logicdata[i--] =*port;  //10
     logicdata[i--] =*port;  //11
     logicdata[i--] =*port;  //12
     logicdata[i--] =*port;  //13
     logicdata[i--] =*port;  //14
     logicdata[i--] =*port;  //15
     logicdata[i--] =*port;  //16
     logicdata[i--] =*port;  //17
     logicdata[i--] =*port;  //18
     logicdata[i--] =*port;  //19
     logicdata[i--] =*port;  //20
  }while(i);
  systick_enable();
现在,我在循环内部,连续多次读取端口及写入数组,显然降低了循环所占时间的比例;经试验从2~20,读写整个60*1024个数据的总时间逐步降低,试验用24时间又明显升高(这和内部ICACH DCACH)大小和是否命中有关),再逐步增大,总时间又逐步减少;最终确定使用20次(这个数值需要保证能被数组大小MAX_CAPTURE_SIZE整除,否则会导致i=0,没有恰好到达while(i)来结束循环;
在进入循环前 我还关闭了systick的中断,防止干扰采样的时间准确性;最后一句是重新允许systick中断;
附 源程序 sllogiclogger_gd32.ino:
  1. /*
  2.    SLLogicLogger - Simple logic analyser for Stellaris Launchpad
  3.    SLLogicLogger supports the SUMP protocol over UART. The UART is mapped
  4.    through the debug/flash controller on the Stellaris Launchpad to a virtual
  5.    com port. It samples signals on PORTB with samplerate 10 Mhz, buffersize
  6.    16kByte, sampling starts at any change on PORTB[0..7].
  7.    PB0 and PB1 are limited to 3.6 V! All other pins are 5 V tolerant.
  8.    The idea for this simple analyser comes from http://jjmz.free.fr/?p=148
  9.    Description of the SUMP protocol:
  10.    - http://www.sump.org/projects/analyzer/protocol/
  11.    - http://dangerousprototypes.com/docs/The_Logic_Sniffer%27s_extended_SUMP_protocol
  12.    A multiplatform client which supports the SUMP protocol is OLS:
  13.    http://www.lxtreme.nl/ols/
  14.    To install device support for OLS, copy ols.profile* file into the
  15.    ols/plugins folder.
  16.    Copyright (C) 2012 Thomas Fischl <tfischl@gmx.de> http://www.fischl.de
  17.    Last update: 2012-12-24
  18.    for gd32f103ret6 120M f_cpu samples signals on PORTA(0..7) with samplerate 23 Mhz, buffersize
  19.    60kByte. by huaweiwx@sina.com 2016.6.12
  20. */
  21. #define VERSION "SLLogicLogger v0.1"
  22. //boards
  23. #define LED  LED_BUILTIN  //LED_BUILTIN
  24. // buffer size
  25. #define MAX_CAPTURE_SIZE 60*1024
  26. #define MAX_SAMPLERATE  23000000
  27. // input port read regaddress & pins_arry
  28. #define GPIO_PORT_DATA_R GPIOA->regs->IDR
  29. uint8_t pin[8] = {PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7};
  30. // SUMP command defintions
  31. #define SUMP_RESET 0x00
  32. #define SUMP_ARM   0x01
  33. #define SUMP_QUERY 0x02
  34. #define SUMP_GET_METADATA 0x04
  35. // sampling buffer
  36. uint8_t logicdata[MAX_CAPTURE_SIZE+1];
  37. // send 32bit unsigned integer as SUMP metadata
  38. void sump_sendmeta_uint32(char type, unsigned int i) {
  39.   Serial1.write(type);
  40.   Serial1.write((i >> 24) & 0xff);
  41.   Serial1.write((i >> 16) & 0xff);
  42.   Serial1.write((i >> 8)  & 0xff);
  43.   Serial1.write(i & 0xff);
  44. }
  45. // send 8bit unsigned integer as SUMP metadata
  46. void sump_sendmeta_uint8(char type, unsigned char i) {
  47.   Serial1.write(type);
  48.   Serial1.write(i);
  49. }
  50. // wait for trigger and do sampling
  51. void dosampling() {
  52.   uint32_t i = 0xfffffff;
  53.   volatile uint32_t *port = &GPIO_PORT_DATA_R;
  54.   char v = GPIO_PORT_DATA_R;
  55. // get current gpio state an wait for change or timeout
  56.   while ((i-- != 0) && (GPIO_PORT_DATA_R == v));
  57.   digitalWrite(LED, LOW);  //for lowplus check
  58.   
  59.   i= MAX_CAPTURE_SIZE;
  60.   systick_disable();
  61.   
  62.   do{  
  63.      logicdata[i--] =*port;  //1
  64.      logicdata[i--] =*port;  //2;
  65.      logicdata[i--] =*port;  //3
  66.      logicdata[i--] =*port;  //4
  67.      logicdata[i--] =*port;  //5
  68.      logicdata[i--] =*port;  //6
  69.      logicdata[i--] =*port;  //7
  70.      logicdata[i--] =*port;  //8
  71.      logicdata[i--] =*port;  //9
  72.      logicdata[i--] =*port;  //10
  73.      logicdata[i--] =*port;  //11
  74.      logicdata[i--] =*port;  //12
  75.      logicdata[i--] =*port;  //13
  76.      logicdata[i--] =*port;  //14
  77.      logicdata[i--] =*port;  //15
  78.      logicdata[i--] =*port;  //16
  79.      logicdata[i--] =*port;  //17
  80.      logicdata[i--] =*port;  //18
  81.      logicdata[i--] =*port;  //19
  82.      logicdata[i--] =*port;  //20
  83.   }while(i);   //60/20=3*1024 cicules speed 23M
  84.   digitalWrite(LED, HIGH);
  85.   systick_enable();
  86. // send it over uart
  87.   for (i = MAX_CAPTURE_SIZE; i != 0; i--) Serial1.write(logicdata[i]); //output unsigned char 8bit data
  88. }
  89. //init
  90. void setup() {
  91.   pinMode(LED, OUTPUT);
  92.   for (uint32_t i = 0; i < 8; i++) pinMode(pin[i], INPUT); //for sample input
  93.   Serial1.begin(115200);
  94.   for (uint32_t i = 0; i < 7; i++) { //ready blink 3 times
  95.     digitalToggle(LED);
  96.     delay(250);
  97.   }
  98. }
  99. // main routine
  100. void loop () {
  101.   if (Serial1.available()) {
  102.     // get the new byte:
  103.     unsigned char cmd = Serial1.read();
  104.     switch (cmd) {
  105.       case SUMP_RESET:
  106.         break;
  107.       case SUMP_ARM:
  108.         dosampling();
  109.         break;
  110.       case SUMP_QUERY:
  111.         Serial1.print("1ALS");
  112.         break;
  113.       case SUMP_GET_METADATA:
  114.         // device name
  115.         Serial1.write(0x01);
  116.         Serial1.print(VERSION);
  117.         Serial1.write((uint8_t)0x00);
  118.         // amount of sample memory available (bytes)
  119.         sump_sendmeta_uint32(0x21, MAX_CAPTURE_SIZE);
  120.         // maximum sample rate (hz)
  121.         sump_sendmeta_uint32(0x23, MAX_SAMPLERATE);
  122.         // number of usable probes (short)
  123.         sump_sendmeta_uint8(0x40, 0x08);
  124.         // protocol version (short)
  125.         sump_sendmeta_uint8(0x41, 0x02);
  126.         // end of meta data
  127.         Serial1.write((uint8_t)0x00);
  128.         break;
  129.       // long commands.. consume bytes from uart
  130.       case 0xC0:
  131.       case 0xC4:
  132.       case 0xC8:
  133.       case 0xCC:
  134.       case 0xC1:
  135.       case 0xC5:
  136.       case 0xC9:
  137.       case 0xCD:
  138.       case 0xC2:
  139.       case 0xC6:
  140.       case 0xCA:
  141.       case 0xCE:
  142.       case 0x80:
  143.       case 0x81:
  144.       case 0x82:
  145.         Serial1.read();
  146.         Serial1.read();
  147.         Serial1.read();
  148.         Serial1.read();
  149.         break;
  150.     }
  151.   }
  152. }


SLLogicLogger配置文件ols.profile-SLLogicLogger.cfg:
  1. # Configuration for SLLogicLogger
  2. # The short (single word) type of the device described in this profile
  3. device.type = SLLogicLogger
  4. # A longer description of the device
  5. device.description = SLLogicLogger (GD32RET6@120M)
  6. # The device interface, SERIAL only
  7. device.interface = SERIAL
  8. # The device's native clockspeed, in Hertz.
  9. #device.clockspeed = 80000000
  10. device.clockspeed = 120000000
  11. # Whether or not double-data-rate is supported by the device (also known as the "demux"-mode).
  12. device.supports_ddr = false
  13. # Supported sample rates in Hertz, separated by comma's
  14. #device.samplerates = 10000000
  15. device.samplerates =  23000000
  16. # The clockspeed used in the divider calculation, in Hertz. Defaults to 100MHz as most devices appear to use this.
  17. device.dividerClockspeed = 100000000
  18. # What capture clocks are supported
  19. device.captureclock = INTERNAL
  20. # The supported capture sizes, in bytes
  21. #device.capturesizes = 16384
  22. device.capturesizes = 61440
  23. # Whether or not the noise filter is supported
  24. device.feature.noisefilter = false
  25. # Whether or not Run-Length encoding is supported
  26. device.feature.rle = false
  27. # Whether or not a testing mode is supported
  28. device.feature.testmode = false
  29. # Whether or not triggers are supported
  30. device.feature.triggers = false
  31. # The number of trigger stages
  32. device.trigger.stages = 4
  33. # Whether or not "complex" triggers are supported
  34. device.trigger.complex = false
  35. # The total number of channels usable for capturing
  36. device.channel.count = 8
  37. # The number of channels groups, together with the channel count determines the channels per group
  38. device.channel.groups = 1
  39. # Whether the capture size is limited by the enabled channel groups
  40. device.capturesize.bound = true
  41. # Which numbering does the device support
  42. device.channel.numberingschemes = INSIDE, OUTSIDE
  43. # Is a delay after opening the port and device detection needed? (0 = no delay, >0 = delay in milliseconds)
  44. device.open.portdelay = 0
  45. # The receive timeout for the device (in milliseconds, 100 = default, <=0 = no timeout)
  46. device.receive.timeout = 100
  47. # Does the device need a high or low DTR-line to operate correctly? (high = true, low = false)
  48. device.open.portdtr = false
  49. # Which metadata keys correspond to this device profile? Value is a comma-separated list of (double quoted) names...
  50. device.metadata.keys = "SLLogicLogger"
  51. # In which order are samples sent back from the device? false = last sample first, true = first sample first
  52. device.samples.reverseOrder = true
  53. ###EOF###


上述内容+已编译的执行文件:













[ 此帖被huaweiwx在2016-06-13 16:43重新编辑 ]
本文内容包含图片或附件,获取更多资讯,请 登录 后查看;或者 注册 成为会员获得更多权限
本帖最近打赏记录:共12条打赏 ,M币+36
12
离线mosliu

发帖
29913
M币
14893
专家
2
粉丝
64
只看该作者 1楼 发表于: 2016-06-13
Re:挖尽GD32潜力,做逻辑分析仪(续),采样速率提高至23M,60k存储深度,真正体现GD优 ..
请登录后查看
本帖最近打赏记录:共1条打赏 ,M币+2
离线yulijie

发帖
398
M币
273
专家
1
粉丝
22
只看该作者 2楼 发表于: 2016-06-13
本帖最近打赏记录:共1条打赏 ,M币+2
离线huaweiwx

发帖
1372
M币
2167
专家
65
粉丝
297
只看该作者 3楼 发表于: 2016-06-13
回 yulijie 的帖子
请登录后查看
本帖最近打赏记录:共1条打赏 ,M币+3
离线mindlwj
发帖
47
M币
-370
专家
0
粉丝
2
只看该作者 4楼 发表于: 2016-06-13
Re:挖尽GD32潜力,做逻辑分析仪(续),采样速率提高至23M,60k存储深度,真正体现GD优 ..
请登录后查看
本帖最近打赏记录:共1条打赏 ,M币+2
离线amo73

发帖
882
M币
1363
专家
9
粉丝
34
只看该作者 5楼 发表于: 2016-06-13
Re:挖尽GD32潜力,做逻辑分析仪(续),采样速率提高至23M,60k存储深度,真正体现GD优 ..
请登录后查看
本帖最近打赏记录:共1条打赏 ,M币+2
离线huaweiwx

发帖
1372
M币
2167
专家
65
粉丝
297
只看该作者 6楼 发表于: 2016-06-13
Re:挖尽GD32潜力,做逻辑分析仪(续),采样速率提高至23M,60k存储深度,真正体现GD优 ..
请登录后查看
本帖最近打赏记录:共1条打赏 ,M币+3
离线2545889167

发帖
13268
M币
20754
专家
302
粉丝
4860
只看该作者 7楼 发表于: 2016-06-13
Re:挖尽GD32潜力,做逻辑分析仪(续),采样速率提高至23M,60k存储深度,真正体现GD优 ..
请登录后查看
本帖最近打赏记录:共1条打赏 ,M币+2
离线huaweiwx

发帖
1372
M币
2167
专家
65
粉丝
297
只看该作者 8楼 发表于: 2016-06-13
回 2545889167 的帖子
请登录后查看
本帖最近打赏记录:共1条打赏 ,M币+3
离线2545889167

发帖
13268
M币
20754
专家
302
粉丝
4860
只看该作者 9楼 发表于: 2016-06-13
回 huaweiwx 的帖子
请登录后查看
快速回复
限80 字节
温馨提示:欢迎交流讨论,请勿发布纯表情、纯引用等灌水帖子;以免被删除
 
上一个 下一个