blob: 0bd2f3829f43bba9a1f9e5f25c2d58c18aced412 [file] [log] [blame]
// 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 <array>
#include <cstdint>
#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<pw::digital_io::InterruptHandler,
FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS>
interrupt_handlers;
std::array<PINT_Type*, FSL_FEATURE_PINT_NUMBER_OF_CONNECTED_OUTPUTS> 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<pw::digital_io::State> 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