สารบัญ:

GPIO ARM ASSEMBLY - TI.I. ชุดการเรียนรู้ระบบหุ่นยนต์ - LAB 6: 3 Steps
GPIO ARM ASSEMBLY - TI.I. ชุดการเรียนรู้ระบบหุ่นยนต์ - LAB 6: 3 Steps

วีดีโอ: GPIO ARM ASSEMBLY - TI.I. ชุดการเรียนรู้ระบบหุ่นยนต์ - LAB 6: 3 Steps

วีดีโอ: GPIO ARM ASSEMBLY - TI.I. ชุดการเรียนรู้ระบบหุ่นยนต์ - LAB 6: 3 Steps
วีดีโอ: Turtlebot3 Waffle Pi MOD: LEONARDO Upgrade Kit - Assembly Instructions | ROBOTIS | Travis Guy 2024, กรกฎาคม
Anonim
GPIO ARM ASSEMBLY - TI. I. ชุดการเรียนรู้ระบบหุ่นยนต์ - LAB 6
GPIO ARM ASSEMBLY - TI. I. ชุดการเรียนรู้ระบบหุ่นยนต์ - LAB 6

สวัสดี, ในคำแนะนำก่อนหน้านี้เกี่ยวกับการเรียนรู้การประกอบ ARM โดยใช้ Texas Instruments TI-RSLK (ใช้ไมโครคอนโทรลเลอร์ MSP432) หรือที่รู้จักในชื่อ Lab 3 หากคุณกำลังทำ T. I. แน่นอน เราได้ทบทวนคำแนะนำพื้นฐานบางอย่าง เช่น การเขียนไปยังการลงทะเบียน และการวนซ้ำแบบมีเงื่อนไข เราก้าวผ่านการดำเนินการโดยใช้ Eclipse IDE

โปรแกรมเล็ก ๆ ที่เราดำเนินการไม่ได้ทำอะไรเพื่อโต้ตอบกับโลกภายนอก

น่าเบื่อบ้าง.

วันนี้มาลองเปลี่ยนสิ่งนั้นสักหน่อยโดยเรียนรู้เล็กน้อยเกี่ยวกับพอร์ตอินพุต/เอาต์พุต โดยเฉพาะพิน GPIO ดิจิทัล

มันจึงเกิดขึ้นที่ MSP432 นี้มาในบอร์ดพัฒนาแล้วซึ่งมีสวิตช์ปุ่มกดสองตัว, ไฟ LED RGB และไฟ LED สีแดง ซึ่งทั้งหมดนี้เชื่อมโยงกับพอร์ต GPIO บางพอร์ต

ซึ่งหมายความว่าเมื่อเราเรียนรู้การตั้งค่าและจัดการพินเหล่านี้ผ่านการประกอบ เราจะมองเห็นเอฟเฟกต์เหล่านั้นด้วยสายตา

น่าสนใจมากกว่าแค่การผ่านตัวดีบั๊ก

(เรากำลังจะก้าวต่อไป - นี่จะเป็นฟังก์ชัน 'การหน่วงเวลา' ของเรา):-D

ขั้นตอนที่ 1: ลองเขียนถึง / อ่านจาก RAM

ก่อนที่เราจะข้ามไปที่การเข้าถึงและควบคุม GPIO เราควรดำเนินการเล็กน้อย

เริ่มต้นด้วยการอ่านและเขียนไปยังที่อยู่หน่วยความจำมาตรฐาน เรารู้จากคำสั่งก่อนหน้า (ดูภาพที่นั่น) ว่า RAM เริ่มต้นที่ 0x2000 0000 ดังนั้นให้ใช้ที่อยู่นั้น

เราจะย้ายข้อมูลระหว่าง core register (R0) และ 0x2000 0000

เราเริ่มต้นด้วยโครงสร้างไฟล์พื้นฐานหรือเนื้อหาของโปรแกรมประกอบ โปรดดูคำแนะนำนี้เพื่อสร้างโครงการแอสเซมบลีโดยใช้ Code Composer Studio (CCS) ของ TI และโครงการตัวอย่างบางโครงการ

.thumb

.text.align 2.global main.thumbfunc หลักหลัก:.asmfunc;------------------------------------------------ --------------------------------------------------------------; (รหัสของเราจะอยู่ที่นี่);------------------------------------------ ----------------------------------------.endasmfunc.end

ฉันต้องการเพิ่มสิ่งใหม่ๆ ในส่วนบนสุด หากมีการประกาศ (คำสั่ง) มันจะชัดเจนขึ้นในภายหลัง

ACONST.set 0x20000000; เราจะใช้สิ่งนี้ต่อไป (เป็นค่าคงที่)

; เห็นได้ชัดว่า '0x' หมายถึงสิ่งที่ตามมาคือค่าฐานสิบหก

ดังนั้นเนื้อหาไฟล์เริ่มต้นของเราจึงมีลักษณะดังนี้:

.thumb

.text.align 2 ACONST.set 0x20000000; เราจะใช้สิ่งนี้ต่อไป (เป็นค่าคงที่); เห็นได้ชัดว่า '0x' หมายถึงสิ่งที่ตามมาคือค่าฐานสิบหก.global main.thumbfunc หลักหลัก:.asmfunc;-------------------------------------- ------------------------------------; (รหัสของเราจะอยู่ที่นี่);------------------------------------------ ----------------------------------------.endasmfunc.end

เมื่อได้ข้อมูลข้างต้นแล้ว ให้เพิ่มโค้ดระหว่างเส้นประ

เราเริ่มต้นด้วยการเขียนไปยังตำแหน่ง RAM ขั้นแรกเราจะสร้างรูปแบบข้อมูลซึ่งเป็นค่าที่เราจะเขียนลงในแรม เราใช้การลงทะเบียนหลักเพื่อสร้างมูลค่าหรือข้อมูลนั้น

หมายเหตุ: จำไว้ว่าในโค้ด บรรทัดใดๆ ที่มีเซมิโคลอน (';') หมายความว่าเป็นความคิดเห็นทั้งหมดหลังจากเซมิโคลอนนั้น

;-----------------------------------------------------------------------------------------------

; การเขียน;------------------------------------------------ ----------------------------------------------------- MOV R0, #0x55; core register R0 จะมีข้อมูลที่เราต้องการเขียนไปยังตำแหน่ง RAM; เห็นได้ชัดว่า '0x' หมายถึงสิ่งที่ตามมาคือค่าฐานสิบหก

ต่อไป มาดูข้อความที่ไม่ทำงานกัน

; MOV MOV ไม่สามารถใช้เพื่อเขียนข้อมูลไปยังตำแหน่ง RAM

; MOV เป็นเพียงข้อมูลในการลงทะเบียนทันที; หรือจากทะเบียนหนึ่งไปยังอีกที่หนึ่ง เช่น MOV R1, R0; STR ต้องใช้ STR; STR R0, =ACONST; คำในนิพจน์ไม่ถูกต้อง ('='); STR R0, 0x20000000; โหมดการระบุที่อยู่ไม่ถูกต้องสำหรับคำแนะนำในการจัดเก็บ; STR R0, ACONST; โหมดระบุที่อยู่ไม่ถูกต้องสำหรับคำแนะนำร้านค้า

เราพยายามใช้ 'ACONST' ข้างต้นโดยไม่อธิบายมากเกินไป โดยพื้นฐานแล้ว มันคือสแตนด์อินหรือค่าคงที่แทนที่จะใช้ค่าตามตัวอักษร เช่น 0x20000000

เราไม่สามารถเขียนเพื่อเขียนไปยังตำแหน่ง RAM โดยใช้ข้างต้น มาลองอย่างอื่นกัน

; ดูเหมือนว่าเราต้องใช้รีจิสเตอร์อื่นที่มีตำแหน่ง RAM ใน

; เพื่อจัดเก็บไปยังตำแหน่ง RAM นั้น MOV R1, #0x20000000; ตั้งค่าตำแหน่ง RAM (ไม่ใช่เนื้อหา แต่เป็นตำแหน่ง) เป็น R1; เห็นได้ชัดว่า '0x' หมายถึงสิ่งที่ตามมาคือค่าฐานสิบหก STR R0, [R1]; เขียนสิ่งที่อยู่ใน R0 (0x55) ลงใน RAM (0x20000000) โดยใช้ R1; เราใช้ register (R1) อื่นที่มีที่อยู่ตำแหน่ง RAM; เพื่อเขียนไปยังตำแหน่ง RAM นั้น

อีกวิธีหนึ่งในการดำเนินการข้างต้น แต่ใช้ 'ACONST' แทนค่าที่อยู่ตามตัวอักษร:

; ลองทำด้านบนอีกครั้ง แต่ใช้สัญลักษณ์แทนค่าตำแหน่ง RAM ตามตัวอักษร

; เราต้องการใช้ 'ACONST' เป็นสแตนด์อินสำหรับ 0x20000000; เรายังต้องทำ '#' เพื่อแสดงค่าทันที; ดังนั้น (ดูด้านบน) เราต้องใช้คำสั่ง '.set'; เพื่อพิสูจน์สิ่งนี้ เรามาเปลี่ยนรูปแบบข้อมูลใน R0 MOV R0, #0xAA; ตกลงเราพร้อมที่จะเขียนไปยัง RAM โดยใช้สัญลักษณ์แทนค่าที่อยู่ตามตัวอักษร MOV R1, #ACONST STR R0, [R1]

วิดีโอมีรายละเอียดเพิ่มเติมรวมถึงการอ่านจากตำแหน่งหน่วยความจำ

คุณยังสามารถดูไฟล์.asm ต้นทางที่แนบมาได้ด้วย

ขั้นตอนที่ 2: ข้อมูลพอร์ตพื้นฐานบางอย่าง

Image
Image
ข้อมูลพอร์ตพื้นฐานบางอย่าง
ข้อมูลพอร์ตพื้นฐานบางอย่าง
ข้อมูลพอร์ตพื้นฐานบางอย่าง
ข้อมูลพอร์ตพื้นฐานบางอย่าง

ตอนนี้เรามีความคิดที่ดีแล้วว่าจะเขียน/อ่านจากตำแหน่ง RAM ได้อย่างไร จะช่วยให้เราเข้าใจวิธีควบคุมและใช้งานพิน GPIO ได้ดีขึ้น

แล้วเราจะโต้ตอบกับพิน GPIO ได้อย่างไร? จากการดูไมโครคอนโทรลเลอร์นี้และคำสั่ง ARM ก่อนหน้านี้ เรารู้วิธีจัดการกับรีจิสเตอร์ภายใน และเรารู้วิธีโต้ตอบกับที่อยู่หน่วยความจำ (RAM) แต่หมุด GPIO?

มันเกิดขึ้นที่หมุดเหล่านั้นมีการแมปหน่วยความจำ ดังนั้นเราจึงสามารถจัดการกับหมุดเหล่านั้นได้มากเหมือนกับที่อยู่หน่วยความจำ

ซึ่งหมายความว่าเราจำเป็นต้องรู้ว่าที่อยู่เหล่านั้นคืออะไร

ด้านล่างนี้คือที่อยู่เริ่มต้นของพอร์ต อย่างไรก็ตาม สำหรับ MSP432 "พอร์ต" คือชุดของหมุด ไม่ใช่แค่พินเดียว หากคุณคุ้นเคยกับ Raspberry Pi ผมเชื่อว่ามันแตกต่างจากสถานการณ์ที่นี่

วงกลมสีน้ำเงินในภาพด้านบนแสดงข้อความบนกระดานสำหรับสวิตช์และไฟ LED สองตัว เส้นสีน้ำเงินชี้ไปที่ LED จริง เราจะไม่ต้องสัมผัสหัวจัมเปอร์

ฉันสร้างพอร์ตที่เรากังวลด้วยตัวหนาด้านล่าง

  • GPIO P1: 0x4000 4C00 + 0 (ที่อยู่เท่ากัน)
  • GPIO P2: 0x4000 4C00 + 1 (ที่อยู่คี่)
  • GPIO P3: 0x4000 4C00 + 20 (เลขคู่)
  • GPIO P4: 0x4000 4C00 + 21 (ที่อยู่คี่)
  • GPIO P5: 0x4000 4C00 + 40 (เลขคู่)
  • GPIO P6: 0x4000 4C00 + 41 (ที่อยู่คี่)
  • GPIO P7: 0x4000 4C00 + 60 (เลขคู่)
  • GPIO P8: 0x4000 4C00 + 61 (ที่อยู่คี่)
  • GPIO P9: 0x4000 4C00 + 80 (เลขคู่)
  • GPIO P10: 0x4000 4C00 + 81 (ที่อยู่คี่)

เรายังไม่เสร็จ เราต้องการข้อมูลเพิ่มเติม

เพื่อควบคุมพอร์ต เราจำเป็นต้องมีที่อยู่หลายแห่ง นั่นเป็นสาเหตุว่าทำไมเราจึงเห็น "ที่อยู่คู่" หรือ "ที่อยู่คี่" ในรายการด้านบน

I/O Register Address Blocks

เราต้องการที่อยู่อื่นๆ เช่น:

  • พอร์ต 1 อินพุตการลงทะเบียนที่อยู่ = 0x40004C00
  • พอร์ต 1 เอาท์พุทการลงทะเบียนที่อยู่ = 0x40004C02
  • ที่อยู่พอร์ต 1 ทิศทางการลงทะเบียน = 0x40004C04
  • พอร์ต 1 เลือก 0 ที่อยู่ลงทะเบียน = 0x40004C0A
  • พอร์ต 1 เลือก 1 ที่อยู่ลงทะเบียน = 0x40004C0C

และเราอาจต้องการคนอื่น

ตกลง ตอนนี้เราทราบช่วงของที่อยู่ลงทะเบียน GPIO เพื่อควบคุม LED สีแดงดวงเดียวแล้ว

หมายเหตุที่สำคัญมาก: พอร์ต I/O แต่ละพอร์ตบนบอร์ด MSP432 LaunchPad เป็นชุดของพินหรือบรรทัดต่างๆ (โดยปกติคือ 8) และสามารถตั้งค่าแต่ละพอร์ตเป็นอินพุตหรือเอาต์พุตได้

ซึ่งหมายความว่า ตัวอย่างเช่น หากคุณกำลังตั้งค่าสำหรับ "ที่อยู่ลงทะเบียนของพอร์ต 1 ทิศทาง" คุณต้องคำนึงถึงบิต (หรือบิต) ที่คุณกำลังตั้งค่าหรือเปลี่ยนแปลงที่ที่อยู่นั้น เพิ่มเติมเกี่ยวกับเรื่องนี้ในภายหลัง

ลำดับการเขียนโปรแกรมพอร์ต GPIO

ชิ้นส่วนสุดท้ายที่เราต้องการคือกระบวนการหรืออัลกอริธึมที่จะใช้เพื่อควบคุม LED

การเริ่มต้นครั้งเดียว:

  • กำหนดค่า P1.0 (ลงทะเบียน P1SEL1REG:P1SEL0REG) <--- 0x00, 0x00 สำหรับฟังก์ชัน GPIO ปกติ
  • ตั้งค่า Direction register bit 1 ของ P1DIRREG เป็น output หรือ HIGH

วนซ้ำ:

เขียน HIGH เป็นบิต 0 ของการลงทะเบียน P1OUTREG เพื่อเปิดไฟ LED สีแดง

  • เรียกฟังก์ชันล่าช้า
  • เขียน LOW เป็นบิต 0 ของการลงทะเบียน P1OUTREG เพื่อปิดไฟ LED สีแดง
  • เรียกฟังก์ชันล่าช้า
  • วนซ้ำ

ฟังก์ชันอินพุต/เอาต์พุตใด (กำหนดค่า SEL0 และ SEL1)

หมุดจำนวนมากบน LaunchPad มีประโยชน์หลายอย่าง ตัวอย่างเช่น พินเดียวกันอาจเป็น GPIO ดิจิทัลมาตรฐาน หรืออาจใช้ในการสื่อสารแบบอนุกรม UART หรือ I2C

ในการใช้ฟังก์ชันเฉพาะสำหรับพินนั้น คุณต้องเลือกฟังก์ชันนั้น คุณต้องกำหนดค่าฟังก์ชันของพิน

มีรูปภาพด้านบนสำหรับขั้นตอนนี้ที่พยายามอธิบายแนวคิดนี้ในรูปแบบภาพ

ที่อยู่ SEL0 และ SEL1 รวมกันเป็นคู่ที่ทำหน้าที่เป็นการเลือกฟังก์ชัน/คุณสมบัติบางประเภท

สำหรับจุดประสงค์ของเรา เราต้องการ GPIO ดิจิทัลมาตรฐานสำหรับบิต 0 ซึ่งหมายความว่าเราต้องการบิต 0 สำหรับ SEL0 และ SEL1 ให้เป็น LOW

ลำดับการเขียนโปรแกรมพอร์ต (อีกครั้ง)

1. เขียน 0x00 ถึง P1 SEL 0 Register (ที่อยู่ 0x40004C0A) สิ่งนี้ตั้งค่า LOW สำหรับบิต 0

2. เขียน 0x00 ถึง P1 SEL 1 ลงทะเบียน (ที่อยู่ 0x40004C0C) นี่เป็นการตั้งค่า LOW สำหรับบิต 0 การตั้งค่าสำหรับ GPIO

3. เขียน 0x01 ถึง P1 DIR Register (ที่อยู่ 0x40004C04) สิ่งนี้ตั้งค่า HIGH สำหรับบิต 0 หมายถึง OUTPUT

4. เปิดไฟ LED โดยเขียน 0x01 ไปที่ P1 OUTPUT Register (ที่อยู่ 0x40004C02)

5. ทำการหน่วงเวลา (หรือเพียงแค่ขั้นตอนเดียวในขณะที่ทำการดีบั๊ก)

6. ปิด LED โดยเขียน 0x00 ถึง P1 OUTPUT Register (ที่อยู่ 0x40004C02)

7. ทำการหน่วงเวลา (หรือเพียงแค่ขั้นตอนเดียวในขณะที่ทำการดีบั๊ก)

8. ทำซ้ำขั้นตอนที่ 4 ถึง 7

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

ขั้นตอนที่ 3: คุณจับข้อบกพร่องเดียวในวิดีโอหรือไม่

ในวิดีโอที่อธิบายขั้นตอนการเขียนโปรแกรมและการจัดแสง LED ทั้งหมด มีขั้นตอนเพิ่มเติมในลูปหลัก ซึ่งสามารถเลื่อนขึ้นไปสู่การเริ่มต้นแบบครั้งเดียวได้

ขอขอบคุณที่สละเวลาอ่านคำแนะนำนี้

ต่อไปจะขยายสิ่งที่เราได้เริ่มต้นที่นี่

แนะนำ: