ฉันจะใช้ตัวจัดการขัดจังหวะเดียวกันอย่างมีประสิทธิภาพสำหรับพอร์ตต่อพ่วงทุกพอร์ต (เหมือนกัน) ได้อย่างไร

(หวังว่า) ปัญหาของฉันในเวอร์ชันที่เรียบง่าย:

สมมติว่าฉันใช้พอร์ต GPIO ทุกพอร์ตของ mcu cortex M-4 ของฉันเพื่อทำสิ่งเดียวกันทุกประการ เช่น อ่านพอร์ตจากการเปลี่ยนแปลงระดับพิน ฉันทำให้โค้ดของฉันง่ายขึ้น ดังนั้นมันจึงไม่เชื่อเรื่องพระเจ้าในพอร์ต แต่ฉันมีปัญหากับวิธีแก้ปัญหาที่ดีสำหรับการนำฟังก์ชันตัวจัดการขัดจังหวะเดิมกลับมาใช้ใหม่

  1. มีวิธีที่ฉันสามารถใช้ฟังก์ชันตัวจัดการขัดจังหวะเดียวกันในขณะที่มีวิธีค้นหาว่าพอร์ตใดที่ทำให้เกิดการขัดจังหวะหรือไม่? ตามหลักการแล้ว O(1)/บางตัวจะไม่ขยายขนาดขึ้นอยู่กับจำนวนพอร์ตที่บอร์ดมี
  2. ฉันควรมีตัวจัดการที่แตกต่างกันสำหรับแต่ละพอร์ตที่เรียกใช้ฟังก์ชันเดียวกันกับที่รับพารามิเตอร์พอร์ตหรือไม่ (ดีที่สุดที่ฉันคิดได้จนถึงตอนนี้)

ชอบมาก:

void worker (uint32_t gpio_id) {
    *work goes here*
}

void GPIOA_IRQ_Handler(void) { worker(GPIOA_id); }
void GPIOB_IRQ_Handler(void) { worker(GPIOB_id); }
void GPIOC_IRQ_Handler(void) { worker(GPIOC_id); }
...

ปัญหาที่แท้จริงของฉัน:

ฉันกำลังเรียนรู้และเล่นซอกับ FreeRTOS และสร้างไดรเวอร์ง่ายๆ สำหรับ debug/stdio UART ซึ่งเป็นปุ่มบางปุ่มที่อยู่ใน dev ของฉัน คณะกรรมการเป็นต้น จนถึงตอนนี้ฉันได้สร้างไดรเวอร์สำหรับอุปกรณ์ต่อพ่วง/พอร์ตเฉพาะแล้ว

ตอนนี้ฉันกำลังต้องการสร้างไดรเวอร์ I2C โดยไม่รู้ว่าจะใช้อินเทอร์เฟซใด (มีพอร์ต I2C 10 พอร์ตใน MCU ของฉัน) และอาจอนุญาตให้ใช้รหัสไดรเวอร์กับหลายพอร์ตพร้อมกัน ฉันรู้ว่าพอร์ตทั้งหมดที่ใช้ในเวลาคอมไพล์

ฉันมีความคิดที่ดีทีเดียวเกี่ยวกับวิธีทำให้ไดรเวอร์ไม่เชื่อเรื่องพระเจ้าในพอร์ต ยกเว้นว่าฉันกำลังติดอยู่กับการหาวิธีที่ดีในการค้นหาว่าพอร์ตใดที่ทริกเกอร์การขัดจังหวะโดยใช้ฟังก์ชันตัวจัดการเดียว (นอกเหนือจากการวนรอบ reg สถานะการขัดจังหวะของทุกพอร์ตเนื่องจากนั่นคือ O (n))

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

  1. ฉันจะทำสิ่งนี้ผิดหรือเปล่าและควรทำให้มันโง่ง่าย ๆ และใช้ไดรเวอร์ตามพอร์ต / กรณีใช้งานที่ฉันต้องการจริง ๆ ในวิธีที่ง่ายที่สุดเท่าที่จะเป็นไปได้ (ไม่มีแผนที่จะใช้บัส I2C หลายตัวด้วยซ้ำ แม้ว่าจะใช้งานได้น่าสนใจก็ตาม)

ขอบคุณล่วงหน้า หวังว่ากระทู้จะไม่คลุมเครือหรือยาวจนเกินไป (รู้สึกว่าจะยาวไปนะ)


person EmbeddedManuel    schedule 03.07.2020    source แหล่งที่มา
comment
คุณสามารถมีตัวจัดการสำหรับแต่ละตัวจัดการนั้น ตัวจัดการนั้นตั้งค่าการลงทะเบียนเพื่อระบุว่าการขัดจังหวะใด จากนั้นจึงแยกไปยังตัวจัดการทั่วไปซึ่งจากนั้นสามารถใช้การลงทะเบียนนั้นหรือคำใบ้อะไรก็ตาม ใช่ เห็นได้ชัดว่าคุณสามารถตั้งค่าตัวจัดการเดียวกันสำหรับการขัดจังหวะใดๆ/ทุกครั้งได้ หากต้องการ   -  person old_timer    schedule 03.07.2020
comment
ปัญหาที่แท้จริงของคุณที่นี่คืออะไร? ปริมาณการใช้แฟลช? ผู้ดูแลของคุณใหญ่แค่ไหน?   -  person old_timer    schedule 03.07.2020
comment
ปัญหาของฉันคือวิธีการหลีกเลี่ยงการทำซ้ำโค้ดโดยใช้ฟังก์ชันตัวจัดการเดียวกันสำหรับการขัดจังหวะหลายครั้ง แต่ยังมีวิธีที่ซับซ้อนอย่างต่อเนื่องในการค้นหาแหล่งที่มาของอุปกรณ์ต่อพ่วงของการขัดจังหวะ ฉันไม่แน่ใจด้วยซ้ำว่ามีวิธีใดที่จะบรรลุเป้าหมายนั้นได้หรือไม่ ซึ่งอาจส่งผลให้เกิดการโพสต์/คำถามที่น่าสับสน   -  person EmbeddedManuel    schedule 03.07.2020
comment
แฮนด์เลอร์ไม่ใหญ่มาก สำหรับปัญหาจริงของฉันเกี่ยวกับไดรเวอร์ I2C มันจะเป็นเพียงการส่ง / รับไบต์ถัดไปมาตรฐานหากมี ; ปลุกงานเมื่อไม่มีไบต์ในการประมวลผลอีกต่อไป ซึ่งอาจง่ายกว่านี้หากฉันใช้การดำเนินการ DMA แต่ตอนนี้ฉันไม่ต้องการเจาะลึกขนาดนั้น   -  person EmbeddedManuel    schedule 03.07.2020
comment
หากคุณสามารถแยกตัวประกอบพารามิเตอร์ใดๆ ออกมาได้ ให้ลองใช้วิธีแก้ไขปัญหาที่ 2 ของโพสต์ของคุณ อย่างไรก็ตาม คุณต้องเขียนบรรทัด *handler() { ...} ทั้งหมดเหล่านี้ เนื่องจากบรรทัดเหล่านี้ให้อาร์กิวเมนต์เฉพาะและติดตั้งเวกเตอร์โดยทั่วไป การใช้เทคนิคการประกอบอันชาญฉลาดจะทำให้แหล่งที่มากลายเป็นฝันร้ายที่ต้องรักษาไว้ -- ฉันจะเริ่มต้นด้วยตัวจัดการ 2 ตัว โดยแต่ละตัวมีการใช้งานในตัวจัดการที่เปิดตัวของตัวเอง ต่อไปผมจะพัฒนาอัลกอริธึมขั้นสุดท้าย DMA หรืออย่างอื่น จากนั้นฉันก็จะตรวจสอบว่าความแตกต่างอยู่ที่ไหน และพิจารณาการปรับโครงสร้างใหม่ในแง่ของ DRY   -  person the busybee    schedule 03.07.2020
comment
@EmbeddedManuel DMA ในตัวเองอาจเป็นเรื่องยุ่งยากในการตั้งค่า แต่อาจทำให้โค้ดโดยรวมเร็วขึ้นและอ่านได้ง่ายขึ้น โดยเฉพาะอย่างยิ่งเมื่อต้องรับมือกับบัสอนุกรมเช่น I2C หรือ UART การมีทริกเกอร์ขัดจังหวะต่อไบต์ที่ได้รับนั้นค่อนข้างเจ็บปวด (แม้ว่าวิธีการทำสิ่งต่าง ๆ ของโรงเรียนเก่า)   -  person Lundin    schedule 03.07.2020
comment
@thebusybee ใช่นั่นคือสิ่งที่ฉันจะไป โพสต์นี้ทำให้ฉันมั่นใจว่าฉันทำสิ่งที่ถูกต้องมากกว่าสิ่งอื่นใด ซึ่งเป็นประโยชน์อย่างยิ่ง เนื่องจากนี่เป็นโปรเจ็กต์เดี่ยวในพื้นที่ใหม่ไม่มากก็น้อย ขอบคุณสำหรับความคิดเห็น!   -  person EmbeddedManuel    schedule 06.07.2020
comment
@Lundin ฉันเห็นด้วยอย่างยิ่ง! ในที่สุดฉันก็อยากจะนำ DMA ไปใช้ โดยเฉพาะอย่างยิ่งเมื่อฉันกำลังนำสิ่งนี้ไปใช้กับ FreeRTOS เหตุผลที่แท้จริงเดียวที่ฉันลังเลที่จะเลือกคือสำหรับบอร์ดของฉัน (ซีรีส์ tiva C) คุณสามารถเปิดใช้งาน DMA ได้เฉพาะกับสเลฟหรือมาสเตอร์ใน I2C เท่านั้น ดังนั้นการใช้งานจึงต้องมีงานพิเศษเพื่อตรวจสอบและตั้งค่า ได้อย่างปลอดภัย แน่นอนในสิ่งที่ต้องทำของฉัน ฮ่าๆ   -  person EmbeddedManuel    schedule 06.07.2020


คำตอบ (1)


  1. มีวิธีที่ฉันสามารถใช้ฟังก์ชันตัวจัดการขัดจังหวะเดียวกันในขณะที่มีวิธีค้นหาว่าพอร์ตใดที่ทำให้เกิดการขัดจังหวะหรือไม่?

เฉพาะในกรณีที่การขัดจังหวะที่แตกต่างกันถูกล้างในลักษณะเดียวกันและแอปพลิเคชันของคุณไม่สนใจว่าพินใดที่ทำให้เกิดการขัดจังหวะ กรณีการใช้งานที่ค่อนข้างไม่น่าเป็นไปได้

  1. ฉันควรมีตัวจัดการที่แตกต่างกันสำหรับแต่ละพอร์ตที่เรียกใช้ฟังก์ชันเดียวกันกับที่รับพารามิเตอร์พอร์ตหรือไม่

ใช่แล้ว นั่นคือสิ่งที่ฉันทำตามปกติ คุณควรส่งต่อพารามิเตอร์จาก ISR ไปยังฟังก์ชัน ที่ไม่ซ้ำกันสำหรับการขัดจังหวะเฉพาะ สำคัญ: โปรดทราบว่าฟังก์ชันควรเป็น inline static! ISR ที่รวดเร็วมีความสำคัญมากกว่าการบันทึกแฟลชเล็กน้อยโดยการใช้ฟังก์ชันเดิมซ้ำอีกครั้ง ดังนั้นในรหัสเครื่อง คุณจะมี ISR 4 แบบที่แตกต่างกันโดยมีฟังก์ชันผู้ปฏิบัติงานอยู่ในบรรทัด (อาจต้องการปิดการใช้งานอินไลน์ในการสร้างการดีบัก)

ฉันจะทำเรื่องนี้ผิดไปหรือเปล่าและควรทำให้มันงี่เง่าง่ายๆ

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

ลำดับความสำคัญในกรณีนี้ควรเป็นสิ่งสำคัญที่สุดก่อน:

  1. การขัดจังหวะที่รวดเร็วและบางที่สุดเท่าที่จะเป็นไปได้
  2. รหัสที่อ่านได้
  3. ขนาดแฟลชที่ใช้
  4. หลีกเลี่ยงการทำซ้ำโค้ด
person Lundin    schedule 03.07.2020
comment
ขอบคุณ คุณตอบทุกสิ่งที่ฉันสงสัย โดยเฉพาะคำถามสุดท้าย น่าเสียดายที่นี่เป็นบัญชีใหม่ ฉันไม่สามารถลงคะแนนได้ +1 ครับ - person EmbeddedManuel; 06.07.2020