// Copyright 2023 The Pigweed Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #include "pw_digital_io_mcuxpresso/interrupt_controller.h" #include #include #include "fsl_pint.h" #include "pw_digital_io/digital_io.h" #include "pw_function/function.h" #include "pw_result/result.h" #include "pw_status/status.h" namespace pw::digital_io { namespace { using ::pw::digital_io::InterruptTrigger; using ::pw::digital_io::State; // PINT API doesn't allow context on callback API, so store globally. std::array interrupt_handlers; std::array bases; void PintCallback(pint_pin_int_t pin, uint32_t) { PW_CHECK(pin < interrupt_handlers.size()); State state = PINT_PinInterruptGetStatus(bases[pin], pin) == 1 ? State::kActive : State::kInactive; interrupt_handlers[pin](state); SDK_ISR_EXIT_BARRIER; } } // namespace McuxpressoInterruptController::McuxpressoInterruptController(PINT_Type* base) : base_(base) { PINT_Init(base_); } McuxpressoInterruptController::~McuxpressoInterruptController() { PINT_Deinit(base_); } pw::Status McuxpressoInterruptController::Config( pint_pin_int_t pin, InterruptTrigger trigger, pw::digital_io::InterruptHandler&& handler) { if (pin >= interrupt_handlers.size()) { return pw::Status::InvalidArgument(); } interrupt_handlers[pin] = std::move(handler); bases[pin] = base_; switch (trigger) { case InterruptTrigger::kActivatingEdge: PINT_PinInterruptConfig( base_, pin, kPINT_PinIntEnableRiseEdge, PintCallback); break; case InterruptTrigger::kDeactivatingEdge: PINT_PinInterruptConfig( base_, pin, kPINT_PinIntEnableFallEdge, PintCallback); break; case InterruptTrigger::kBothEdges: PINT_PinInterruptConfig( base_, pin, kPINT_PinIntEnableBothEdges, PintCallback); break; default: return pw::Status::InvalidArgument(); } return pw::OkStatus(); } pw::Status McuxpressoInterruptController::EnableHandler(pint_pin_int_t pin, bool enable) { if (enable) { PINT_EnableCallbackByIndex(base_, pin); } else { PINT_DisableCallbackByIndex(base_, pin); } return pw::OkStatus(); } pw::Result McuxpressoInterruptController::GetState( pint_pin_int_t pin) { switch (PINT_PinInterruptGetStatus(base_, pin)) { case 0: return State::kInactive; case 1: return State::kActive; default: return pw::Status::Unknown(); } } } // namespace pw::digital_io