| // 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 |