ตรวจสอบวงจรนาฬิกาสำหรับรหัสใน arduino / AVR หรือไม่


11

เป็นไปได้หรือไม่ที่จะตรวจสอบบล็อคของรหัสและกำหนดจำนวนรอบสัญญาณนาฬิกาของหน่วยประมวลผลที่โค้ดใช้กับโปรเซสเซอร์ Arduino และ / หรือ AVR atmel? หรือฉันควรตรวจสอบไมโครวินาทีก่อนและหลังการรันโค้ดหรือไม่ หมายเหตุ: ฉันไม่ได้กังวลกับเวลาจริง (เท่าที่ผ่านมาจำนวนวินาทีจริง) เท่าที่ฉันเป็นใน "จำนวนรอบนาฬิกาไม่รหัสนี้ต้องใช้จาก CPU"

โซลูชันปัจจุบันที่ฉันสามารถหาได้คือจาก time.c:

#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )

เดินสาย c เพิ่ม:

#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )

โดยบัญชีนี้ฉันสามารถคำนวณ cyles นาฬิกาที่ส่งผ่านโดยการตรวจสอบ microseconds ที่ผ่านไปแล้วส่งไปยัง microsecondsToClockCycles () คำถามของฉันคือมีวิธีที่ดีกว่า

ด้านข้าง: มีทรัพยากรที่ดีสำหรับการตรวจสอบประสิทธิภาพของ AVR lmgtfy.com และการค้นหาฟอรัมต่างๆไม่ได้ให้ผลลัพธ์ที่ชัดเจนใด ๆ นอกเหนือจากการสำรวจตัวนับ

ขอบคุณ

คำตอบ:


6

วิธีที่ง่ายที่สุดคือการทำให้รหัสของคุณดึงบางอย่างขึ้นก่อนที่จะประมวลผลรหัสที่คุณต้องการเวลาและดึงมันต่ำหลังจากที่มันเสร็จสิ้นการทำอะไร จากนั้นทำโค้ดวนซ้ำ (หรือใช้ออสซิลโลสโคปแบบดิจิตอลพร้อมหน่วยความจำในโหมดถ่ายภาพครั้งเดียว) และเพียงแค่กำหนดขอบเขตจากนั้นปักหมุด ความยาวของพัลส์จะบอกคุณว่าต้องใช้เวลานานแค่ไหนในการประมวลโค้ดและบวกหนึ่งรอบสัญญาณนาฬิกาจากการเปลี่ยนสถานะพิน (ฉันคิดว่าใช้เวลาหนึ่งรอบไม่แน่ใจ 100%)


ขอบคุณ ใช่ฉันเห็นว่านี่อาจเป็นวิธีที่แม่นยำที่สุด ฉันยังคงโยนรหัสที่จะให้ฉันอย่างน้อยก็รอบการวิเคราะห์การใช้งานทั่วไปภายในรหัส ฉันจะใช้สิ่งนี้เพื่อสร้างเครื่องมือทดสอบและมันจะเป็นการดีที่จะตั้งค่าขอบเขตบนของฉันสำหรับพารามิเตอร์เช่นเวลาทำงานสูงสุดที่อนุญาตตามประสิทธิภาพของรหัส + ทุกอย่างที่เกี่ยวข้องกับมันกำลังทำงานอยู่บน Atmel CPU ในปัจจุบัน ใช้
cyphunk

4

คุณหมายถึงอะไรโดย "มอนิเตอร์"

ไม่ควรนับรอบสัญญาณนาฬิกาของ AVR เป็นเรื่องยากสำหรับรหัสแอสเซมบลีขนาดเล็ก

คุณยังสามารถตั้งค่าพอร์ตก่อนที่จะมีการเรียกใช้รหัสและรีเซ็ตในภายหลังและตรวจสอบว่ามีตัววิเคราะห์เชิงตรรกะหรือ oszilloscope เพื่อให้ได้เวลา

และคุณยังสามารถอ่านเวลาจากตัวจับเวลาที่ทำงานได้เร็วอย่างที่คุณพูด


โดยการตรวจสอบฉันหมายถึงกำหนดจำนวนรอบที่ใช้โดยรหัส บางอย่างเช่น (หมายเหตุการจัดรูปแบบของโค้ดอาจจะถูกทำให้แบนโดยเอ็นจิ้นความคิดเห็น): นาฬิกา = startCountingAtmegaClocks (); สำหรับ ... {สำหรับ ... {digitalRead ... }} Serial.print ("จำนวนรอบที่ใช้:"); Serial.print (currentCountingAtmegaClocks () - นาฬิกา, DEC);
cyphunk

แต่ใช่คำตอบของคุณคือสิ่งที่ฉันคิดว่าตัวเลือกของฉันคือ ผมคิดว่าผมถือว่าถ้าผมสามารถคำนวณรอบนาฬิกาประกอบจะใช้เวลาด้วยมือที่มีใครบางคนอาจจะเขียนแล้วบางรหัสที่ดีที่จะทำเช่นนี้ programatically
cyphunk

3

นี่คือตัวอย่างสำหรับ Arduino ที่ใช้ฟังก์ชั่น clockCyclesPerMicrosecond () เพื่อคำนวณนาฬิกาที่ผ่านไปแล้ว รหัสนี้จะรอ 4 วินาทีจากนั้นพิมพ์เวลาที่ผ่านไปตั้งแต่เริ่มต้นโปรแกรม ค่าที่เหลือ 3 คือเวลาทั้งหมด (ไมโครวินาที, มิลลิวินาที, รอบนาฬิกาทั้งหมด) และเวลาส่วนใหญ่ที่ถูกต้อง 3 ครั้งคือ:

เอาท์พุท:

clocks for 1us:16
runtime us, ms, ck :: elapsed tme us, ms ck
4003236 4002	64051776	::	4003236	4002	64051760
8006668 8006	128106688	::	4003432	4004	64054912
12010508    12010	192168128	::	4003840	4004	64061440
16014348    16014	256229568	::	4003840	4004	64061440
20018188    20018	320291008	::	4003840	4004	64061440
24022028    24022	384352448	::	4003840	4004	64061440
28026892    28026	448430272	::	4004864	4004	64077824
32030732    32030	512491712	::	4003840	4004	64061440
36034572    36034	576553152	::	4003840	4004	64061440
40038412    40038	640614592	::	4003840	4004	64061440
44042252    44042	704676032	::	4003840	4004	64061440
48046092    48046	768737472	::	4003840	4004	64061440
52050956    52050	832815296	::	4004864	4004	64077824

ฉันแน่ใจว่ามีคำอธิบายที่สมเหตุสมผลว่าทำไมลูปแรกเกินไปมีวงจรนาฬิกาที่ผ่านไปสั้นกว่าส่วนใหญ่และทำไมลูปอื่น ๆ ทั้งหมดสลับระหว่างความยาวสองรอบของนาฬิกา

รหัส:

unsigned long us, ms, ck;
unsigned long _us, _ms, _ck;
unsigned long __us, __ms, __ck;
void setup() {
        Serial.begin(9600);
}
boolean firstloop=1;
void loop() { 
        delay(4000);

        if (firstloop) {
                Serial.print("clocks for 1us:");
                ck=microsecondsToClockCycles(1);
                Serial.println(ck,DEC);
                firstloop--;
                Serial.println("runtime us, ms, ck :: elapsed tme us, ms ck");
        }

        _us=us;
        _ms=ms;
        _ck=ck;

        us=micros(); // us since program start
        ms=millis();
        //ms=us/1000;
        ck=microsecondsToClockCycles(us);
        Serial.print(us,DEC);
        Serial.print("\t");
        Serial.print(ms,DEC);
        Serial.print("\t");
        Serial.print(ck,DEC);     
        Serial.print("\t::\t");

        __us = us - _us;
        __ms = ms - _ms;
        __ck = ck - _ck;
        Serial.print(__us,DEC);
        Serial.print("\t");
        Serial.print(__ms,DEC);
        Serial.print("\t");
        Serial.println(__ck,DEC);     

}

Sidenote: หากคุณลบการหน่วงเวลา 4 วินาทีคุณจะเริ่มเห็นผลกระทบของ Serial.print () ชัดเจนยิ่งขึ้น หมายเหตุ: ที่นี่ 2 วิ่งจะถูกเปรียบเทียบ ฉันได้รวม 4 ตัวอย่างใกล้ ๆ กันจากบันทึกที่เกี่ยวข้อง

เรียกใช้ 1:

5000604 5000	80009664	::	2516	2	40256
6001424 6001	96022784	::	2520	3	40320
7002184 7002	112034944	::	2600	3	41600
8001292 8001	128020672	::	2600	3	41600

เรียกใช้ 2:

5002460 5002	80039360	::	2524	3	40384
6000728 6000	96011648	::	2520	2	40320
7001452 7001	112023232	::	2600	3	41600
8000552 8000	128008832	::	2604	3	41664

เวลาที่ผ่านไปจะเพิ่มขึ้นตามเวลาดำเนินการทั้งหมด หลังจากผ่านไปหนึ่งวินาทีนาฬิกาจะเพิ่มโดยเฉลี่ยจาก 40k เป็น 44k สิ่งนี้เกิดขึ้นอย่างสม่ำเสมอไม่กี่มิลลิวินาทีหลังจาก 1 วินาทีและนาฬิกาที่ผ่านไปยังคงอยู่ประมาณ 44k เป็นเวลาอย่างน้อย 10 วินาทีถัดไป (ฉันไม่ได้ทดสอบเพิ่มเติม) นี่คือเหตุผลที่การตรวจสอบมีประโยชน์หรือจำเป็น บางทีประสิทธิภาพที่ลดลงเกี่ยวข้องกับการกำหนดค่าหรือข้อบกพร่องในอนุกรมหรือไม่ หรือบางทีรหัสไม่ได้ใช้หน่วยความจำอย่างเหมาะสมและมีการรั่วไหลที่มีผลต่อประสิทธิภาพ ฯลฯ


หลายปีต่อมาฉันยังต้องการบางสิ่งบางอย่างที่แสดงนาฬิกาได้อย่างถูกต้องมากขึ้นด้วยรหัส ที่ฉันพยายามที่จะกำหนดจำนวนรอบนาฬิกาที่จำเป็นสำหรับ digitalWrite () ทั้งใน 16MHZ และ 8MHZ ใน 16MHZ ฉันได้รับ 8us / 64clk แต่ใน 8MHZ ฉันได้ 0us / 0clk
cyphunk

1

เนื่องจากทุกบรรทัดของโค้ดที่เพิ่มในซอร์สของคุณจะมีผลกระทบต่อประสิทธิภาพการทำงานและสามารถเปลี่ยนแปลงการปรับให้เหมาะสมได้ การเปลี่ยนแปลงควรเป็นขั้นต่ำที่จำเป็นในการปฏิบัติงาน

ฉันเพิ่งพบปลั๊กอิน Atmel Studio ชื่อ "Annotated Assembly File Debugger" http://www.atmel.com/webdoc/aafdebugger/pr01.htmlดูเหมือนว่าการก้าวผ่านภาษาแอสเซมบลีที่เกิดขึ้นจริงในขณะที่อาจน่าเบื่อจะแสดงให้คุณเห็นสิ่งที่เกิดขึ้น คุณอาจยังต้องถอดรหัสว่าต้องใช้กี่รอบสำหรับแต่ละคำสั่ง แต่มันจะเข้าใกล้กว่าตัวเลือกการโพสต์อื่น ๆ

สำหรับผู้ที่ไม่ทราบในโฟลเดอร์เอาท์พุทของโครงการของคุณคือไฟล์ที่มีนามสกุล LSS ไฟล์นี้มีซอร์สโค้ดต้นฉบับของคุณทั้งหมดเป็นความคิดเห็นและด้านล่างแต่ละบรรทัดเป็นภาษาแอสเซมบลีที่สร้างขึ้นตามบรรทัดของโค้ดนั้น การสร้างไฟล์ LSS สามารถปิดได้เพื่อตรวจสอบการตั้งค่าต่อไปนี้

คุณสมบัติโครงการ Toolchain | AVR / GNU Common | OutputFiles

ช่องทำเครื่องหมาย ".lss (สร้างไฟล์ lss)


1

คุณสามารถใช้หนึ่งในตัวนับ รับการตั้งค่าทุกอย่างสำหรับ prescaller = 1 และ TCNT = 0 ก่อนการบล็อก จากนั้นเปิดใช้งานตัวจับเวลาในบรรทัดก่อนบล็อกและปิดการใช้งานบนบรรทัดหลังบล็อก ตอนนี้ TCNT จะระงับจำนวนรอบของบล็อกที่ใช้งานน้อยรอบคงที่สำหรับรหัสเปิดใช้งานและปิดใช้งาน

โปรดทราบว่า TNCT จะล้นหลังนาฬิกา 65535 รอบในตัวจับเวลา 16 บิต คุณสามารถใช้ค่าสถานะโอเวอร์โฟลว์เพื่อเพิ่มเวลารันได้ หากคุณยังต้องการอีกต่อไปคุณสามารถใช้พรีสเกลเลอร์ แต่จะได้รับการแก้ไขน้อยลง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.