0Pricing
C++ Academy · บทเรียน

IO แบบแมปหน่วยความจำและ Volatile

สื่อสารกับรีจิสเตอร์ฮาร์ดแวร์อย่างปลอดภัยด้วย volatile และ IO แบบแมปหน่วยความจำ

IO แบบแมปหน่วยความจำและ Volatile เป็นบทเรียน C++ Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C++ Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C++ Academy มีบทเรียนทั้งหมด 4 บทเรียน

I/O แบบแมปหน่วยความจำ

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

เหตุใดจึงใช้ volatile

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

volatile uint32_t* GPIO = (uint32_t*)0x40020000;
*GPIO = 0x01;     // write must happen
uint32_t v = *GPIO;

สิ่งที่ volatile ป้องกัน

คอมไพเลอร์ไม่สามารถ:

  • แคชค่าไว้ในรีจิสเตอร์ระหว่างการอ่านแต่ละครั้ง
  • จัดลำดับการเข้าถึงใหม่
  • ตัดการอ่านหรือเขียนที่ "ซ้ำซ้อน" ออก

รูปแบบทั่วไปสำหรับรีจิสเตอร์

กำหนด struct ให้ตรงกับผังรีจิสเตอร์ฮาร์ดแวร์ แล้วแปลงที่อยู่คงที่ให้เป็นพอยน์เตอร์

struct GpioRegs {
    volatile uint32_t MODER;
    volatile uint32_t OTYPER;
    volatile uint32_t OSPEEDR;
    volatile uint32_t IDR;
    volatile uint32_t ODR;
};

auto* GPIOA = reinterpret_cast<GpioRegs*>(0x40020000);
GPIOA->ODR = 0x01;

ข้อควรระวังของการอ่าน-แก้ไข-เขียน

แม้ใช้ volatile การดำเนินการ RMW ก็ไม่เป็นอะตอมิก ในระบบหลายคอร์หรือเมื่อมีการเข้าถึงจาก ISR พร้อมกัน คุณต้องใช้อะตอมิกอย่างชัดเจนหรือปิดการขัดจังหวะ

volatile ไม่ใช่สิ่งสำหรับการทำงานแบบเธรด

นี่เป็นความเข้าใจผิดที่พบบ่อย volatile ไม่ได้จัดเตรียมการจัดลำดับหน่วยความจำระหว่างเธรด ให้ใช้ std::atomic เพื่อการเข้าถึงที่ปลอดภัยต่อเธรด แม้แต่กับแฟล็กที่ใช้ร่วมกัน

การจัดการรีจิสเตอร์ด้วยตัวดำเนินการระดับบิต

ตั้งค่า ล้าง หรือสลับบิตด้วยตัวดำเนินการระดับบิต

GPIOA->ODR |= (1 << 5);    // set bit 5
GPIOA->ODR &= ~(1 << 5);   // clear bit 5
GPIOA->ODR ^= (1 << 5);    // toggle bit 5

ฟิลด์บิต

หากต้องการเข้าถึงบิตด้วยชื่อ ให้กำหนด union ของจำนวนเต็ม 32 บิตกับโครงสร้างที่มีฟิลด์บิต โปรดทราบว่าลำดับของฟิลด์บิตขึ้นอยู่กับการใช้งาน

ตัวกั้นหน่วยความจำ

บนแพลตฟอร์มที่มีแบบจำลองหน่วยความจำแบบอ่อน (ARM) ให้ใช้ __DMB(), __DSB() หรือ std::atomic_thread_fence เพื่อบังคับลำดับระหว่างการเข้าถึง

ข้อควรพิจารณาเกี่ยวกับแคช

หาก MCU มีแคช โดยทั่วไปต้องกำหนดให้หน่วยความจำของอุปกรณ์ต่อพ่วงไม่ใช้แคช มิฉะนั้นคุณอาจอ่านข้อมูลเก่าได้ การกำหนดค่า MMU/MPU จะจัดการเรื่องนี้

บัฟเฟอร์ DMA

บัฟเฟอร์ที่ DMA ใช้งานต้องจัดแนว ไม่ใช้แคช และมีการดำเนินการล้างแคชที่เหมาะสมบนแพลตฟอร์มที่ใช้แคช โปรดอ่านคู่มือ CPU ของคุณ

การทดสอบโค้ดฮาร์ดแวร์

ทดสอบโค้ดที่เข้าถึงฮาร์ดแวร์ในระดับหน่วย โดยแยกการเข้าถึงรีจิสเตอร์ไว้เบื้องหลังส่วนติดต่อ — จำลองส่วนดังกล่าวในการทดสอบ และสร้างอินสแตนซ์ของส่วนจริงบนฮาร์ดแวร์

ตรวจสอบความเข้าใจ

คีย์เวิร์ด volatile รับประกันอะไร

สรุปทบทวน

ใช้ volatile กับรีจิสเตอร์ฮาร์ดแวร์ที่แมปกับหน่วยความจำ เพราะจะป้องกันไม่ให้คอมไพเลอร์ตัดการเข้าถึงออกระหว่างการปรับปรุงประสิทธิภาพ แต่ volatile ไม่ได้ใช้สำหรับการซิงโครไนซ์เธรด — ให้ใช้ std::atomic แทน รวมเข้ากับตัวกั้นหน่วยความจำเมื่อใช้ CPU ที่มีแบบจำลองหน่วยความจำแบบอ่อน

คำถามที่พบบ่อย

บทเรียน “IO แบบแมปหน่วยความจำและ Volatile” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “IO แบบแมปหน่วยความจำและ Volatile” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C++ Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C++ Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “IO แบบแมปหน่วยความจำและ Volatile”

สื่อสารกับรีจิสเตอร์ฮาร์ดแวร์อย่างปลอดภัยด้วย volatile และ IO แบบแมปหน่วยความจำ คุณปฏิบัติ C++ Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C++ Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน C++ Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “IO แบบแมปหน่วยความจำและ Volatile” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน C++ Academy นี้ได้ไหม

ได้ บทเรียน C++ Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ข้อจำกัดในระบบฝังตัว: ไม่มี RTTI และไม่มีข้อยกเว้น
  2. IO แบบแมปหน่วยความจำและ Volatile
  3. ข้อควรพิจารณาสำหรับระบบเรียลไทม์และเวลาแฝง
  4. การคอมไพล์ข้ามแพลตฟอร์มสำหรับเป้าหมาย ARM
← กลับไปที่ C++ Academy