
-
UID:1023450
-
- 注册时间2011-12-16
- 最后登录2022-04-17
- 在线时间2350小时
-
-
访问TA的空间加好友用道具
|
在我的帖子:挖尽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 ] = *portport 为函数内局部变量,这样循环内部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:- /*
- SLLogicLogger - Simple logic analyser for Stellaris Launchpad
- SLLogicLogger supports the SUMP protocol over UART. The UART is mapped
- through the debug/flash controller on the Stellaris Launchpad to a virtual
- com port. It samples signals on PORTB with samplerate 10 Mhz, buffersize
- 16kByte, sampling starts at any change on PORTB[0..7].
- PB0 and PB1 are limited to 3.6 V! All other pins are 5 V tolerant.
- The idea for this simple analyser comes from http://jjmz.free.fr/?p=148
- Description of the SUMP protocol:
- - http://www.sump.org/projects/analyzer/protocol/
- - http://dangerousprototypes.com/docs/The_Logic_Sniffer%27s_extended_SUMP_protocol
- A multiplatform client which supports the SUMP protocol is OLS:
- http://www.lxtreme.nl/ols/
- To install device support for OLS, copy ols.profile* file into the
- ols/plugins folder.
- Copyright (C) 2012 Thomas Fischl <tfischl@gmx.de> http://www.fischl.de
- Last update: 2012-12-24
- for gd32f103ret6 120M f_cpu samples signals on PORTA(0..7) with samplerate 23 Mhz, buffersize
- 60kByte. by huaweiwx@sina.com 2016.6.12
- */
- #define VERSION "SLLogicLogger v0.1"
- //boards
- #define LED LED_BUILTIN //LED_BUILTIN
- // buffer size
- #define MAX_CAPTURE_SIZE 60*1024
- #define MAX_SAMPLERATE 23000000
- // input port read regaddress & pins_arry
- #define GPIO_PORT_DATA_R GPIOA->regs->IDR
- uint8_t pin[8] = {PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7};
- // SUMP command defintions
- #define SUMP_RESET 0x00
- #define SUMP_ARM 0x01
- #define SUMP_QUERY 0x02
- #define SUMP_GET_METADATA 0x04
- // sampling buffer
- uint8_t logicdata[MAX_CAPTURE_SIZE+1];
- // send 32bit unsigned integer as SUMP metadata
- void sump_sendmeta_uint32(char type, unsigned int i) {
- Serial1.write(type);
- Serial1.write((i >> 24) & 0xff);
- Serial1.write((i >> 16) & 0xff);
- Serial1.write((i >> 8) & 0xff);
- Serial1.write(i & 0xff);
- }
- // send 8bit unsigned integer as SUMP metadata
- void sump_sendmeta_uint8(char type, unsigned char i) {
- Serial1.write(type);
- Serial1.write(i);
- }
- // wait for trigger and do sampling
- void dosampling() {
- uint32_t i = 0xfffffff;
- volatile uint32_t *port = &GPIO_PORT_DATA_R;
- char v = GPIO_PORT_DATA_R;
- // get current gpio state an wait for change or timeout
- while ((i-- != 0) && (GPIO_PORT_DATA_R == v));
- digitalWrite(LED, LOW); //for lowplus check
-
- 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); //60/20=3*1024 cicules speed 23M
- digitalWrite(LED, HIGH);
- systick_enable();
- // send it over uart
- for (i = MAX_CAPTURE_SIZE; i != 0; i--) Serial1.write(logicdata[i]); //output unsigned char 8bit data
- }
- //init
- void setup() {
- pinMode(LED, OUTPUT);
- for (uint32_t i = 0; i < 8; i++) pinMode(pin[i], INPUT); //for sample input
- Serial1.begin(115200);
- for (uint32_t i = 0; i < 7; i++) { //ready blink 3 times
- digitalToggle(LED);
- delay(250);
- }
- }
- // main routine
- void loop () {
- if (Serial1.available()) {
- // get the new byte:
- unsigned char cmd = Serial1.read();
- switch (cmd) {
- case SUMP_RESET:
- break;
- case SUMP_ARM:
- dosampling();
- break;
- case SUMP_QUERY:
- Serial1.print("1ALS");
- break;
- case SUMP_GET_METADATA:
- // device name
- Serial1.write(0x01);
- Serial1.print(VERSION);
- Serial1.write((uint8_t)0x00);
- // amount of sample memory available (bytes)
- sump_sendmeta_uint32(0x21, MAX_CAPTURE_SIZE);
- // maximum sample rate (hz)
- sump_sendmeta_uint32(0x23, MAX_SAMPLERATE);
- // number of usable probes (short)
- sump_sendmeta_uint8(0x40, 0x08);
- // protocol version (short)
- sump_sendmeta_uint8(0x41, 0x02);
- // end of meta data
- Serial1.write((uint8_t)0x00);
- break;
- // long commands.. consume bytes from uart
- case 0xC0:
- case 0xC4:
- case 0xC8:
- case 0xCC:
- case 0xC1:
- case 0xC5:
- case 0xC9:
- case 0xCD:
- case 0xC2:
- case 0xC6:
- case 0xCA:
- case 0xCE:
- case 0x80:
- case 0x81:
- case 0x82:
- Serial1.read();
- Serial1.read();
- Serial1.read();
- Serial1.read();
- break;
- }
- }
- }
SLLogicLogger配置文件ols.profile-SLLogicLogger.cfg:- # Configuration for SLLogicLogger
- # The short (single word) type of the device described in this profile
- device.type = SLLogicLogger
- # A longer description of the device
- device.description = SLLogicLogger (GD32RET6@120M)
- # The device interface, SERIAL only
- device.interface = SERIAL
- # The device's native clockspeed, in Hertz.
- #device.clockspeed = 80000000
- device.clockspeed = 120000000
- # Whether or not double-data-rate is supported by the device (also known as the "demux"-mode).
- device.supports_ddr = false
- # Supported sample rates in Hertz, separated by comma's
- #device.samplerates = 10000000
- device.samplerates = 23000000
- # The clockspeed used in the divider calculation, in Hertz. Defaults to 100MHz as most devices appear to use this.
- device.dividerClockspeed = 100000000
- # What capture clocks are supported
- device.captureclock = INTERNAL
- # The supported capture sizes, in bytes
- #device.capturesizes = 16384
- device.capturesizes = 61440
- # Whether or not the noise filter is supported
- device.feature.noisefilter = false
- # Whether or not Run-Length encoding is supported
- device.feature.rle = false
- # Whether or not a testing mode is supported
- device.feature.testmode = false
- # Whether or not triggers are supported
- device.feature.triggers = false
- # The number of trigger stages
- device.trigger.stages = 4
- # Whether or not "complex" triggers are supported
- device.trigger.complex = false
- # The total number of channels usable for capturing
- device.channel.count = 8
- # The number of channels groups, together with the channel count determines the channels per group
- device.channel.groups = 1
- # Whether the capture size is limited by the enabled channel groups
- device.capturesize.bound = true
- # Which numbering does the device support
- device.channel.numberingschemes = INSIDE, OUTSIDE
- # Is a delay after opening the port and device detection needed? (0 = no delay, >0 = delay in milliseconds)
- device.open.portdelay = 0
- # The receive timeout for the device (in milliseconds, 100 = default, <=0 = no timeout)
- device.receive.timeout = 100
- # Does the device need a high or low DTR-line to operate correctly? (high = true, low = false)
- device.open.portdtr = false
- # Which metadata keys correspond to this device profile? Value is a comma-separated list of (double quoted) names...
- device.metadata.keys = "SLLogicLogger"
- # In which order are samples sent back from the device? false = last sample first, true = first sample first
- device.samples.reverseOrder = true
- ###EOF###
上述内容+已编译的执行文件: [ 此帖被huaweiwx在2016-06-13 16:43重新编辑 ]
|