| 523 | } |
| 524 | |
| 525 | int attach_external_handler(u8 pin, const isr_config_t& config, isr_handle_t* out_handle) FL_NOEXCEPT { |
| 526 | if (!config.handler) { |
| 527 | FL_WARN("attachExternalHandler: handler is null"); |
| 528 | return -1; // Invalid parameter |
| 529 | } |
| 530 | |
| 531 | // Allocate an EIC channel |
| 532 | u8 eic_ch = 0; |
| 533 | if (!allocate_eic_channel(eic_ch)) { |
| 534 | FL_WARN("attachExternalHandler: no free EIC channels"); |
| 535 | return -3; // Out of resources |
| 536 | } |
| 537 | |
| 538 | // Allocate handle data |
| 539 | auto handle_owner = fl::make_unique<samd_isr_handle_data>(); |
| 540 | auto* handle_data = handle_owner.get(); |
| 541 | if (!handle_data) { |
| 542 | free_eic_channel(eic_ch); |
| 543 | FL_WARN("attachExternalHandler: failed to allocate handle data"); |
| 544 | return -5; // Out of memory |
| 545 | } |
| 546 | |
| 547 | handle_data->is_timer = false; |
| 548 | handle_data->eic_channel = eic_ch; |
| 549 | handle_data->gpio_pin = pin; |
| 550 | handle_data->user_handler = config.handler; |
| 551 | handle_data->user_data = config.user_data; |
| 552 | |
| 553 | // Store handle for ISR access |
| 554 | eic_handles[eic_ch] = handle_data; |
| 555 | |
| 556 | // Enable EIC clock |
| 557 | #if defined(FL_IS_SAMD21) |
| 558 | GCLK->CLKCTRL.reg = (u16)(GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_EIC); |
| 559 | while (GCLK->STATUS.bit.SYNCBUSY) { |
| 560 | // Wait for sync |
| 561 | } |
| 562 | #elif defined(FL_IS_SAMD51) |
| 563 | GCLK->PCHCTRL[EIC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN; |
| 564 | while (!(GCLK->PCHCTRL[EIC_GCLK_ID].reg & GCLK_PCHCTRL_CHEN)) { |
| 565 | // Wait for enable |
| 566 | } |
| 567 | #endif |
| 568 | |
| 569 | // Configure GPIO pin for EIC function |
| 570 | // Note: Pin-to-EIC-channel mapping is board-specific |
| 571 | // For now, we use a simple mapping (this may need board-specific adjustments) |
| 572 | u8 port = pin / 32; |
| 573 | u8 pin_num = pin % 32; |
| 574 | |
| 575 | PORT->Group[port].PINCFG[pin_num].reg |= PORT_PINCFG_PMUXEN; |
| 576 | |
| 577 | // Set PMUX to function A (EIC) for the pin |
| 578 | if (pin_num & 1) { |
| 579 | PORT->Group[port].PMUX[pin_num >> 1].reg |= PORT_PMUX_PMUXO_A; |
| 580 | } else { |
| 581 | PORT->Group[port].PMUX[pin_num >> 1].reg |= PORT_PMUX_PMUXE_A; |
| 582 | } |
nothing calls this directly
no test coverage detected