blob: 8f5247aff4945a6f008a4dee2036475e1e4c2df9 [file] [log] [blame]
// Copyright 2021 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_board_led/led.h"
#include <cinttypes>
#include "pw_preprocessor/compiler.h"
namespace pw::board_led {
namespace {
// Base address for everything peripheral-related on the STM32F4xx.
constexpr uint32_t kPeripheralBaseAddr = 0x40000000u;
// Base address for everything AHB1-related on the STM32F4xx.
constexpr uint32_t kAhb1PeripheralBase = kPeripheralBaseAddr + 0x00020000U;
// Base address for everything APB2-related on the STM32F4xx.
constexpr uint32_t kApb2PeripheralBase = kPeripheralBaseAddr + 0x00010000U;
// Reset/clock configuration block (RCC).
// `reserved` fields are unimplemented features, and are present to ensure
// proper alignment of registers that are in use.
PW_PACKED(struct) RccBlock {
uint32_t reserved1[12];
uint32_t ahb1_config;
uint32_t reserved2[4];
uint32_t apb2_config;
};
// GPIO register block definition.
PW_PACKED(struct) GpioBlock {
uint32_t modes;
uint32_t out_type;
uint32_t out_speed;
uint32_t pull_up_down;
uint32_t input_data;
uint32_t output_data;
uint32_t gpio_bit_set;
uint32_t port_config_lock;
uint32_t alt_low;
uint32_t alt_high;
};
// Constants related to GPIO mode register masks.
constexpr uint32_t kGpioPortModeMask = 0x3u;
constexpr uint32_t kGpio13PortModePos = 26;
constexpr uint32_t kGpioPortModeOutput = 1;
// Constants related to GPIO output mode register masks.
constexpr uint32_t kGpioOutputModeMask = 0x1u;
constexpr uint32_t kGpio13OutputModePos = 13;
constexpr uint32_t kGpioOutputModePushPull = 0;
constexpr uint32_t kGpio13BitSetHigh = 0x1u << 13;
constexpr uint32_t kGpio13BitSetLow = kGpio13BitSetHigh << 16;
// Mask for ahb1_config (AHB1ENR) to enable the "G" GPIO pins.
constexpr uint32_t kGpioGEnable = 0x1u << 6;
// Declare a reference to the memory mapped RCC block.
volatile RccBlock& platform_rcc =
*reinterpret_cast<volatile RccBlock*>(kAhb1PeripheralBase + 0x3800U);
// Declare a reference to the 'G' GPIO memory mapped block.
volatile GpioBlock& gpio_g =
*reinterpret_cast<volatile GpioBlock*>(kAhb1PeripheralBase + 0x1800U);
} // namespace
void Init() {
// Enable 'G' GIPO clocks.
platform_rcc.ahb1_config |= kGpioGEnable;
// Enable Pin 13 in output mode.
gpio_g.modes = (gpio_g.modes & ~(kGpioPortModeMask << kGpio13PortModePos)) |
(kGpioPortModeOutput << kGpio13PortModePos);
// Enable Pin 13 in output mode "push pull"
gpio_g.out_type =
(gpio_g.out_type & ~(kGpioOutputModeMask << kGpio13OutputModePos)) |
(kGpioOutputModePushPull << kGpio13OutputModePos);
}
void TurnOff() { gpio_g.gpio_bit_set = kGpio13BitSetLow; }
void TurnOn() { gpio_g.gpio_bit_set = kGpio13BitSetHigh; }
void Toggle() {
// Check if the LED is on. If so, turn it off.
if (gpio_g.output_data & kGpio13BitSetHigh) {
TurnOff();
} else {
TurnOn();
}
}
} // namespace pw::board_led