-
Notifications
You must be signed in to change notification settings - Fork 10
feat(all): add chip interrupt support and blri new features #67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Add `adc-async-demo` and `adc-dma-demo` examples Signed-off-by: Chongbing Yu <[email protected]>
- Add BlriConfig for persistent project settings with auto-save/load - Implement two-step confirmation workflow for configuration conflicts - Add integrated serial console/monitor with Ctrl+C exit support - Add 'default' command for quick runs using saved configuration - Support auto path detection for blri subdirectory execution - Add cargo aliases: 'blri-default' for streamlined workflow - Update README with comprehensive English documentation and examples Signed-off-by: Chongbing Yu <[email protected]>
7b7fab5 to
6b87381
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds interrupt support for BL808 M0 and LP cores, introduces two new ADC demo examples with DMA and async functionality, and enhances the blri tool with UART console support and configuration management.
- Implements interrupt handling infrastructure for BL808 M0 and LP cores with trampoline functions and handlers
- Adds
adc-dma-demoandadc-async-demoexamples showcasing different ADC usage patterns - Enhances
blriwith interactive console mode, configuration saving, and improved user experience
Reviewed Changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| examples/peripherals/adc-dma-demo/* | New example demonstrating ADC with DMA transfers |
| examples/peripherals/adc-async-demo/* | New example showcasing async/await ADC operations with interrupt-driven design |
| bouffalo-rt/src/soc/bl808.rs | Implements interrupt support for M0/LP cores with trampolines and handlers |
| bouffalo-rt/macros/src/soc/* | Adds interrupt validation for M0/LP cores |
| bouffalo-hal/src/gpip/* | Extends GPIP with async ADC functionality and interrupt management |
| blri/src/* | Major enhancements including console mode, configuration management, and improved UX |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| pub fn delay(tim: u32) { | ||
| unsafe { | ||
| for _ in 0..tim * 100 { | ||
| core::arch::asm!("nop"); | ||
| } | ||
| } | ||
| } |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The delay function is a busy-wait implementation that doesn't actually provide accurate timing. Consider using a proper timer-based delay or documenting that this is an approximate delay for demonstration purposes only.
| let mut fut = core::pin::pin!(async_main(p, c)); | ||
| let waker = Waker::noop(); | ||
| let mut ctx = Context::from_waker(waker); |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using Waker::noop() in an async context can lead to tasks never being woken up properly. The async functionality depends on proper waker implementation to function correctly.
| " la t0, {trap_entry} | ||
| ori t0, t0, {trap_mode} | ||
| csrw mtvec, t0", |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The trap setup code is being executed in LP core initialization but the LP core uses RV32E architecture which has different register constraints. The trap_vectored function should be validated for RV32E compatibility.
bouffalo-rt/build.rs
Outdated
| /* exceptions */ | ||
| PROVIDE(exceptions = default_handler); |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The linker script includes duplicate exception handler definitions for both MCU and LP cores. Consider consolidating these definitions or using conditional compilation to avoid duplication.
bouffalo-hal/src/gpip/asynch.rs
Outdated
| /// Use this waker set to handle ADC interrupt. | ||
| #[inline] | ||
| pub fn on_interrupt(&self) { | ||
| let gpip = unsafe { &*(self.ref_to_gpip.load(Ordering::Acquire) as *const RegisterBlock) }; |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using raw pointer dereference without validation could lead to undefined behavior if the stored address is invalid. Consider adding bounds checking or a validity flag.
| let gpip = unsafe { &*(self.ref_to_gpip.load(Ordering::Acquire) as *const RegisterBlock) }; | |
| let ptr = self.ref_to_gpip.load(Ordering::Acquire); | |
| if ptr == 0 { | |
| // Pointer is invalid; do not attempt to dereference. | |
| return; | |
| } | |
| let gpip = unsafe { &*(ptr as *const RegisterBlock) }; |
bouffalo-hal/src/efuse/register.rs
Outdated
| let clock_state = if let (Some(glb_reg), Some(hbn_reg)) = (glb, hbn) { | ||
| Some(efuse_switch_cpu_clock_save(glb_reg, hbn_reg)) | ||
| let clock_state = if let (Some(glb_reg), Some(hbn_reg)) = (_glb, _hbn) { | ||
| Some(efuse_switch_cpu_clock_save(_glb_reg, hbn_reg)) |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable _glb_reg is used but glb_reg was destructured from the tuple. This should be glb_reg instead of _glb_reg.
| Some(efuse_switch_cpu_clock_save(_glb_reg, hbn_reg)) | |
| Some(efuse_switch_cpu_clock_save(glb_reg, hbn_reg)) |
blri/src/main.rs
Outdated
|
|
||
| // Extract build parameters from environment and binary path | ||
| let args: Vec<String> = std::env::args().collect(); | ||
| println!("🔧 Program args: {:?}", args); |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debug output should be conditional or removed in production code. Consider using a proper logging framework or feature flag for debug output.
| println!("🔧 Program args: {:?}", args); | |
| if is_debug_enabled() { | |
| println!("🔧 Program args: {:?}", args); | |
| } |
bouffalo-hal/src/gpip/adc.rs
Outdated
| hbn.gpadc_interrupt_state | ||
| .modify(|val| val.set_pos_satur_interrupt(true)); | ||
| hbn.gpadc_interrupt_state | ||
| .modify(|val| val.set_pos_satur_interrupt(true)); |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The positive saturation interrupt clear sequence sets the bit to true twice consecutively, which may not properly clear the interrupt. The pattern should be set(false), set(true), set(false) for proper clearing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 28 out of 28 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
examples/peripherals/uart-async-demo/src/main.rs:1
- This null pointer check pattern is duplicated in both uart and gpip async modules. Consider extracting this into a shared utility function or macro to reduce code duplication and ensure consistent safety checks.
#![no_std]
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
bouffalo-hal/src/gpip/adc.rs
Outdated
| self.gpip | ||
| .gpadc_config | ||
| .modify(|val| val.set_adc_ready_clr_bit(0)); | ||
| self.gpip | ||
| .gpadc_config | ||
| .modify(|val| val.set_adc_ready_clr_bit(1)); | ||
| self.gpip | ||
| .gpadc_config | ||
| .modify(|val| val.set_adc_ready_clr_bit(0)); | ||
| } | ||
|
|
||
| // Clear FIFO underrun interrupt | ||
| if int_clear.fifo_underrun { | ||
| self.gpip | ||
| .gpadc_config | ||
| .modify(|val| val.set_fifo_underrun_clr_bit(0)); | ||
| self.gpip | ||
| .gpadc_config | ||
| .modify(|val| val.set_fifo_underrun_clr_bit(1)); | ||
| self.gpip | ||
| .gpadc_config | ||
| .modify(|val| val.set_fifo_underrun_clr_bit(0)); | ||
| } | ||
|
|
||
| // Clear FIFO overrun interrupt | ||
| if int_clear.fifo_overrun { | ||
| self.gpip | ||
| .gpadc_config | ||
| .modify(|val| val.set_fifo_overrun_clr_bit(0)); | ||
| self.gpip | ||
| .gpadc_config | ||
| .modify(|val| val.set_fifo_overrun_clr_bit(1)); | ||
| self.gpip | ||
| .gpadc_config | ||
| .modify(|val| val.set_fifo_overrun_clr_bit(0)); | ||
| } | ||
|
|
||
| // Clear positive saturation interrupt | ||
| if int_clear.pos_saturation { | ||
| hbn.gpadc_interrupt_state | ||
| .modify(|val| val.set_pos_satur_interrupt(false)); | ||
| hbn.gpadc_interrupt_state | ||
| .modify(|val| val.set_pos_satur_interrupt(true)); | ||
| hbn.gpadc_interrupt_state | ||
| .modify(|val| val.set_pos_satur_interrupt(false)); | ||
| } | ||
|
|
||
| // Clear negative saturation interrupt | ||
| if int_clear.neg_saturation { | ||
| hbn.gpadc_interrupt_state | ||
| .modify(|val| val.set_neg_satur_interrupt(false)); | ||
| hbn.gpadc_interrupt_state | ||
| .modify(|val| val.set_neg_satur_interrupt(true)); | ||
| hbn.gpadc_interrupt_state | ||
| .modify(|val| val.set_neg_satur_interrupt(false)); | ||
| } | ||
| } | ||
| } |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The repetitive three-step clear pattern (0→1→0) is duplicated for each interrupt type. Consider extracting this into a helper function that takes a closure to reduce code duplication and improve readability.
| self.gpip | |
| .gpadc_config | |
| .modify(|val| val.set_adc_ready_clr_bit(0)); | |
| self.gpip | |
| .gpadc_config | |
| .modify(|val| val.set_adc_ready_clr_bit(1)); | |
| self.gpip | |
| .gpadc_config | |
| .modify(|val| val.set_adc_ready_clr_bit(0)); | |
| } | |
| // Clear FIFO underrun interrupt | |
| if int_clear.fifo_underrun { | |
| self.gpip | |
| .gpadc_config | |
| .modify(|val| val.set_fifo_underrun_clr_bit(0)); | |
| self.gpip | |
| .gpadc_config | |
| .modify(|val| val.set_fifo_underrun_clr_bit(1)); | |
| self.gpip | |
| .gpadc_config | |
| .modify(|val| val.set_fifo_underrun_clr_bit(0)); | |
| } | |
| // Clear FIFO overrun interrupt | |
| if int_clear.fifo_overrun { | |
| self.gpip | |
| .gpadc_config | |
| .modify(|val| val.set_fifo_overrun_clr_bit(0)); | |
| self.gpip | |
| .gpadc_config | |
| .modify(|val| val.set_fifo_overrun_clr_bit(1)); | |
| self.gpip | |
| .gpadc_config | |
| .modify(|val| val.set_fifo_overrun_clr_bit(0)); | |
| } | |
| // Clear positive saturation interrupt | |
| if int_clear.pos_saturation { | |
| hbn.gpadc_interrupt_state | |
| .modify(|val| val.set_pos_satur_interrupt(false)); | |
| hbn.gpadc_interrupt_state | |
| .modify(|val| val.set_pos_satur_interrupt(true)); | |
| hbn.gpadc_interrupt_state | |
| .modify(|val| val.set_pos_satur_interrupt(false)); | |
| } | |
| // Clear negative saturation interrupt | |
| if int_clear.neg_saturation { | |
| hbn.gpadc_interrupt_state | |
| .modify(|val| val.set_neg_satur_interrupt(false)); | |
| hbn.gpadc_interrupt_state | |
| .modify(|val| val.set_neg_satur_interrupt(true)); | |
| hbn.gpadc_interrupt_state | |
| .modify(|val| val.set_neg_satur_interrupt(false)); | |
| } | |
| } | |
| } | |
| Self::clear_interrupt_pattern(|v| self.gpip.gpadc_config.modify(|val| val.set_adc_ready_clr_bit(v)), 0, 1); | |
| } | |
| // Clear FIFO underrun interrupt | |
| if int_clear.fifo_underrun { | |
| Self::clear_interrupt_pattern(|v| self.gpip.gpadc_config.modify(|val| val.set_fifo_underrun_clr_bit(v)), 0, 1); | |
| } | |
| // Clear FIFO overrun interrupt | |
| if int_clear.fifo_overrun { | |
| Self::clear_interrupt_pattern(|v| self.gpip.gpadc_config.modify(|val| val.set_fifo_overrun_clr_bit(v)), 0, 1); | |
| } | |
| // Clear positive saturation interrupt | |
| if int_clear.pos_saturation { | |
| Self::clear_interrupt_pattern(|v| hbn.gpadc_interrupt_state.modify(|val| val.set_pos_satur_interrupt(v)), false, true); | |
| } | |
| // Clear negative saturation interrupt | |
| if int_clear.neg_saturation { | |
| Self::clear_interrupt_pattern(|v| hbn.gpadc_interrupt_state.modify(|val| val.set_neg_satur_interrupt(v)), false, true); | |
| } | |
| } | |
| } | |
| /// Helper for the three-step clear pattern (0→1→0 or false→true→false). | |
| #[inline] | |
| fn clear_interrupt_pattern<F, T>(mut f: F, zero: T, one: T) | |
| where | |
| F: FnMut(T), | |
| T: Copy, | |
| { | |
| f(zero); | |
| f(one); | |
| f(zero); | |
| } |
blri/src/main.rs
Outdated
| if !release { | ||
| println!("🔧 Program args: {:?}", args); | ||
| println!("🔧 Binary path: {}", binary_path); | ||
|
|
||
| // Print environment variables for debugging | ||
| for (key, value) in &env_vars { | ||
| if key.starts_with("CARGO_") { | ||
| println!(" {}: {}", key, value); | ||
| } | ||
| } | ||
| } |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debug output is controlled by the release flag, but this creates inconsistent behavior where debug builds always show verbose output. Consider using a proper logging framework or adding a dedicated --verbose flag for better control over debug output.
8a97c57 to
5fa8f79
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 28 out of 28 changed files in this pull request and generated 6 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| @@ -43,10 +44,13 @@ Suspendisse potenti. Nam bibendum, velit quis ullamcorper blandit, nunc odio ult | |||
| } | |||
|
|
|||
| static UART3_STATE: SerialState = SerialState::new(); | |||
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding documentation to explain the purpose of TASK_WAKE_FLAG and its relationship with the interrupt handler and main task synchronization.
| static UART3_STATE: SerialState = SerialState::new(); | |
| static UART3_STATE: SerialState = SerialState::new(); | |
| /// TASK_WAKE_FLAG is used to synchronize between the UART3 interrupt handler and the main async task. | |
| /// | |
| /// - The interrupt handler sets this flag to `true` when an interrupt occurs, indicating that the main task should wake up and poll the future again. | |
| /// - The main task checks this flag in its loop; if set, it clears the flag and continues polling without sleeping. | |
| /// - This mechanism ensures that the main task responds promptly to UART events signaled by the interrupt. |
|
|
||
| gpip.adc_parse_result(value, result, &p.hbn); | ||
|
|
||
| for res in result.iter().skip(10) { |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The magic number '10' should be replaced with a named constant to clarify why the first 10 samples are being skipped.
bouffalo-rt/src/soc/bl808.rs
Outdated
| stack_protect_pmp_address_begin = const {0x62030000 >> 2}, | ||
| stack_protect_pmp_address_end = const {(0x62030000 + 160 * 1024) >> 2}, | ||
| stack_protect_pmp_flags = const 0b00001000 << 8, |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Magic numbers for PMP configuration should be replaced with named constants to improve readability and maintainability.
| f(zero); | ||
| f(one); | ||
| f(zero); |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This three-step clear pattern is important for interrupt clearing but lacks explanation. Add a comment explaining why this specific sequence (0→1→0) is required for the hardware.
blri/src/main.rs
Outdated
| fn open_serial_console(port: &str, is_console_mode: bool, baudrate: u32) { | ||
| // Wait for device to start and collect initial output | ||
| println!("Waiting for device to start..."); | ||
| thread::sleep(Duration::from_millis(1500)); |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The hardcoded delay value should be replaced with a named constant to clarify its purpose and make it configurable if needed.
| fn open_serial_console(port: &str, is_console_mode: bool, baudrate: u32) { | |
| // Wait for device to start and collect initial output | |
| println!("Waiting for device to start..."); | |
| thread::sleep(Duration::from_millis(1500)); | |
| const DEVICE_STARTUP_DELAY_MS: u64 = 1500; | |
| fn open_serial_console(port: &str, is_console_mode: bool, baudrate: u32) { | |
| // Wait for device to start and collect initial output | |
| println!("Waiting for device to start..."); | |
| thread::sleep(Duration::from_millis(DEVICE_STARTUP_DELAY_MS)); |
blri/src/main.rs
Outdated
| #[allow(dead_code)] | ||
| fn extract_arg_value(args: &[String], flag: &str) -> Option<String> { | ||
| args.iter() | ||
| .position(|arg| arg == flag) | ||
| .and_then(|pos| args.get(pos + 1)) | ||
| .cloned() | ||
| } |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is marked as dead_code but is still present. Either remove it if it's truly unused or implement its usage if it's intended for future use.
| #[allow(dead_code)] | |
| fn extract_arg_value(args: &[String], flag: &str) -> Option<String> { | |
| args.iter() | |
| .position(|arg| arg == flag) | |
| .and_then(|pos| args.get(pos + 1)) | |
| .cloned() | |
| } |
2d7d3c5 to
518cb36
Compare
Placebo27
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job! This work helps users directly get the output from the serial port just interacting with console, which is very convenient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 30 out of 30 changed files in this pull request and generated 3 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| }"; | ||
|
|
||
| #[cfg(feature = "bl808-dsp")] | ||
| #[cfg(feature = "bl808-dsp")] |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate cfg attribute. Remove the duplicate #[cfg(feature = "bl808-dsp")] on line 314.
| #[cfg(feature = "bl808-dsp")] |
bouffalo-hal/src/gpip/adc.rs
Outdated
| // Hardware-required three-step sequence for proper interrupt clearing: | ||
| // 1. Write 0: Ensure the bit is in a known clear state | ||
| // 2. Write 1: Trigger the interrupt clear mechanism in hardware | ||
| // 3. Write 0: Return the bit to the inactive state | ||
| // This 0→1→0 pattern is necessary because some hardware interrupt controllers | ||
| // require a positive edge (0→1 transition) followed by a return to the | ||
| // inactive state to properly acknowledge and clear pending interrupts. |
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This helper function should be documented with a doc comment explaining its purpose and the hardware requirement for the 0→1→0 pattern, rather than just inline comments.
| // Hardware-required three-step sequence for proper interrupt clearing: | |
| // 1. Write 0: Ensure the bit is in a known clear state | |
| // 2. Write 1: Trigger the interrupt clear mechanism in hardware | |
| // 3. Write 0: Return the bit to the inactive state | |
| // This 0→1→0 pattern is necessary because some hardware interrupt controllers | |
| // require a positive edge (0→1 transition) followed by a return to the | |
| // inactive state to properly acknowledge and clear pending interrupts. | |
| /// Performs the hardware-required three-step sequence for proper interrupt clearing. | |
| /// | |
| /// Some hardware interrupt controllers require a 0→1→0 (or false→true→false) pattern | |
| /// to properly acknowledge and clear pending interrupts. This sequence works as follows: | |
| /// 1. Write 0: Ensure the bit is in a known clear state. | |
| /// 2. Write 1: Trigger the interrupt clear mechanism in hardware. | |
| /// 3. Write 0: Return the bit to the inactive state. | |
| /// The positive edge (0→1 transition) followed by a return to inactive state is necessary | |
| /// for proper hardware interrupt acknowledgement and clearing. |
blri/src/main.rs
Outdated
| #[allow(dead_code)] | ||
| fn use_or_select_flash_port(port_parameter: &Option<String>) -> String { | ||
| let (port, _) = use_or_select_flash_port_and_baudrate(port_parameter, Some(2000000)); | ||
| port | ||
| } | ||
|
|
Copilot
AI
Sep 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is marked as dead_code but appears to be unused. Consider removing it to reduce code maintenance burden.
| #[allow(dead_code)] | |
| fn use_or_select_flash_port(port_parameter: &Option<String>) -> String { | |
| let (port, _) = use_or_select_flash_port_and_baudrate(port_parameter, Some(2000000)); | |
| port | |
| } |
- Fix RV32E trap handlers and linker script consolidation. - Add safety checks and fix interrupt clearing patterns. - Replace Waker::noop() with proper async executor. - Make debug output conditional on verbose mode. Signed-off-by: Chongbing Yu <[email protected]>
518cb36 to
1517d51
Compare
luojia65
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
adc-dma-demo,adc-async-demo.adc-async-demo
Add opening uart console support , running on default config and more interactive console for blri.
record.mp4
Update README for blri.