FPGA config application

- New app added for fpga configuration. No functionality present yet.
- New pin_config library for common board pin config tasks.

Bug: b/310961133
Change-Id: Ice4e224ea7cc889caacaf636ee73304925337b66
Reviewed-on: https://pigweed-review.googlesource.com/c/gonk/+/181296
Reviewed-by: Eric Holland <hollande@google.com>
Commit-Queue: Anthony DiGirolamo <tonymd@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 53fc8c2..2120617 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -35,6 +35,7 @@
     "//applications/system_example(//targets/stm32f769i_disc0_stm32cube:stm32f769i_disc0_stm32cube.size_optimized)",
 
     # Arduino targets
+    "//applications/fpga_config($dir_pigweed/targets/arduino:arduino_size_optimized)",
     "//applications/spi_flash_test($dir_pigweed/targets/arduino:arduino_size_optimized)",
   ]
 }
diff --git a/applications/fpga_config/BUILD.gn b/applications/fpga_config/BUILD.gn
new file mode 100644
index 0000000..7bc6b85
--- /dev/null
+++ b/applications/fpga_config/BUILD.gn
@@ -0,0 +1,39 @@
+# 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.
+
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_arduino_build/arduino.gni")
+import("$dir_pw_build/target_types.gni")
+
+pw_executable("fpga_config") {
+  include_dirs = [ "//third_party/stm32duino/arduino-core/libraries/SPI/src" ]
+
+  sources = [
+    "//third_party/stm32duino/arduino-core/libraries/SPI/src/SPI.cpp",
+    "//third_party/stm32duino/arduino-core/libraries/SPI/src/utility/spi_com.c",
+    "main.cc",
+  ]
+
+  deps = [
+    "$dir_pw_log",
+    "$dir_pw_string",
+    "$dir_pw_third_party/arduino:arduino_core_sources",
+    "//lib/pin_config",
+  ]
+
+  ldflags = [ "-Wl,--print-memory-usage" ]
+
+  remove_configs = [ "$dir_pw_toolchain/arm_gcc:enable_float_printf" ]
+}
diff --git a/applications/fpga_config/main.cc b/applications/fpga_config/main.cc
new file mode 100644
index 0000000..89adae2
--- /dev/null
+++ b/applications/fpga_config/main.cc
@@ -0,0 +1,57 @@
+// 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 <cstdint>
+
+#include <Arduino.h>
+#include <SPI.h>
+
+#include "pw_log/log.h"
+
+#include "gonk/pin_config.h"
+
+using gonk::pin_config::PinConfig;
+using gonk::pin_config::StatusLed;
+
+namespace {
+
+PinConfig pin_config = PinConfig();
+
+} // namespace
+
+int main() {
+  pin_config.Init();
+  pin_config.InitFpgaPins();
+  pin_config.FpgaHalt();
+  pin_config.FpgaEnable();
+  delay(10);
+
+  uint16_t update_count = 0;
+
+  while (true) {
+    PW_LOG_INFO("update: %u", update_count);
+    delay(1000);
+
+    update_count = (update_count + 1) % UINT16_MAX;
+
+    // Toggle status LED each loop.
+    if (update_count % 2 == 0) {
+      digitalWrite(StatusLed, HIGH);
+    } else {
+      digitalWrite(StatusLed, LOW);
+    }
+  }
+
+  return 0;
+}
diff --git a/applications/spi_flash_test/BUILD.gn b/applications/spi_flash_test/BUILD.gn
index 69cb2f4..dd3cd63 100644
--- a/applications/spi_flash_test/BUILD.gn
+++ b/applications/spi_flash_test/BUILD.gn
@@ -30,6 +30,7 @@
     "$dir_pw_log",
     "$dir_pw_string",
     "$dir_pw_third_party/arduino:arduino_core_sources",
+    "//lib/pin_config",
   ]
 
   ldflags = [ "-Wl,--print-memory-usage" ]
diff --git a/applications/spi_flash_test/main.cc b/applications/spi_flash_test/main.cc
index e1d9bef..514817c 100644
--- a/applications/spi_flash_test/main.cc
+++ b/applications/spi_flash_test/main.cc
@@ -12,46 +12,35 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-#include <Arduino.h>
 #include <cstdint>
 
+#include <Arduino.h>
 #include <SPI.h>
 
 #include "pw_log/log.h"
 #include "pw_string/format.h"
 
-// STM32 Port & pin          // PCB NET Name
-const int ICE40Reset = PC13; // ICE_RST_N
-const int ICE40Done = PC8;   // ICE_CDONE
-const int FlashCS = PD2;     // ICE_SPI_SS
-const int FlashHold = PC11;  // FLASH_HOLD
-const int FlashWP = PC12;    // FLASH_WP
-const int FlashMOSI = PB5;   // ICE_SPI_MOSI
-const int FlashMISO = PB4;   // ICE_SPI_MOSI
-const int FlashCLK = PB3;    // ICE_SPI_SCK
-const int StatusLed = PB13;  // STATUS
+#include "gonk/pin_config.h"
+
+using gonk::pin_config::FlashCS;
+using gonk::pin_config::PinConfig;
+using gonk::pin_config::StatusLed;
+
+namespace {
+
+PinConfig pin_config = PinConfig();
+
+} // namespace
 
 int main() {
-  Serial.begin(115200);
+  pin_config.Init();
 
   // Put FPGA in reset.
-  PW_LOG_INFO("Hold FPGA in reset");
-  pinMode(ICE40Reset, OUTPUT);
-  digitalWrite(ICE40Reset, LOW);
+  pin_config.InitFpgaPins();
+  pin_config.FpgaHalt();
   delay(10);
 
-  // Debug status LED
-  pinMode(StatusLed, OUTPUT);
-  digitalWrite(StatusLed, LOW);
-
-  // SPI pin definitions
-  pinMode(FlashCS, OUTPUT);
-  digitalWrite(FlashCS, HIGH);
-
-  SPI.setMISO(FlashMISO);
-  SPI.setMOSI(FlashMOSI);
-  SPI.setSCLK(FlashCLK);
-  SPI.begin();
+  pin_config.SPIEnable();
 
   char buffer[32];
   uint16_t update_count = 0;
diff --git a/lib/pin_config/BUILD.gn b/lib/pin_config/BUILD.gn
new file mode 100644
index 0000000..ef9b399
--- /dev/null
+++ b/lib/pin_config/BUILD.gn
@@ -0,0 +1,35 @@
+# 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.
+
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_build/target_types.gni")
+
+config("default_config") {
+  include_dirs = [ "public" ]
+}
+
+pw_source_set("pin_config") {
+  public_configs = [ ":default_config" ]
+  public = [ "public/gonk/pin_config.h" ]
+
+  include_dirs = [ "//third_party/stm32duino/arduino-core/libraries/SPI/src" ]
+
+  sources = [ "pin_config.cc" ]
+
+  deps = [
+    "$dir_pw_log",
+    "$dir_pw_third_party/arduino:arduino_core_sources",
+  ]
+}
diff --git a/lib/pin_config/pin_config.cc b/lib/pin_config/pin_config.cc
new file mode 100644
index 0000000..61719e0
--- /dev/null
+++ b/lib/pin_config/pin_config.cc
@@ -0,0 +1,65 @@
+#include <Arduino.h>
+#include <SPI.h>
+
+#include "gonk/pin_config.h"
+
+#define PW_LOG_LEVEL PW_LOG_LEVEL_DEBUG
+#define PW_LOG_MODULE_NAME "PinConfig"
+
+#include "pw_log/log.h"
+
+namespace gonk::pin_config {
+
+PinConfig::PinConfig() {}
+
+void PinConfig::Init() {
+  // Set STATUS LED mode and initial state.
+  pinMode(StatusLed, OUTPUT);
+  digitalWrite(StatusLed, LOW);
+
+  // Default CS pin to output high.
+  pinMode(FlashCS, OUTPUT);
+  digitalWrite(FlashCS, HIGH);
+}
+
+void PinConfig::InitFpgaPins() {
+  // Set FPGA reset pin mode and initial state.
+  pinMode(ICE40ResetN, OUTPUT);
+  digitalWrite(ICE40ResetN, HIGH);
+
+  // Set FPGA configure done signal pin as an input.
+  pinMode(ICE40Done, INPUT);
+}
+
+void PinConfig::FpgaHalt() {
+  // Set FlashCS to signal the FPGA it should load the bitstream from external
+  // flash.
+  pinMode(FlashCS, INPUT_FLOATING);
+
+  // Hold in reset for a small amount of time.
+  digitalWrite(ICE40ResetN, LOW);
+  delay(50);
+
+  // Boot fpga and give it time to reset any internal SPI pin configuration.
+  digitalWrite(ICE40ResetN, HIGH);
+  delay(10);
+
+  // Finally, hold in reset.
+  digitalWrite(ICE40ResetN, LOW);
+}
+
+void PinConfig::FpgaEnable() { digitalWrite(ICE40ResetN, HIGH); }
+
+void PinConfig::SPIEnable() {
+  // SPI pin definitions
+  SPI.setMISO(FlashMISO);
+  SPI.setMOSI(FlashMOSI);
+  SPI.setSCLK(FlashCLK);
+  SPI.begin();
+
+  // Set FlashCS as output with initial state.
+  pinMode(FlashCS, OUTPUT);
+  digitalWrite(FlashCS, HIGH);
+}
+
+} // namespace gonk::pin_config
diff --git a/lib/pin_config/public/gonk/pin_config.h b/lib/pin_config/public/gonk/pin_config.h
new file mode 100644
index 0000000..3f6d72a
--- /dev/null
+++ b/lib/pin_config/public/gonk/pin_config.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <Arduino.h>
+
+namespace gonk::pin_config {
+
+// STM32 Port & pin                    // PCB NET Name
+constexpr uint16_t ICE40ResetN = PC13; // ICE_RST_N
+constexpr uint16_t ICE40Done = PC8;    // ICE_CDONE
+constexpr uint16_t FlashCS = PD2;      // ICE_SPI_SS
+constexpr uint16_t FlashHold = PC11;   // FLASH_HOLD
+constexpr uint16_t FlashWP = PC12;     // FLASH_WP
+constexpr uint16_t FlashMOSI = PB5;    // ICE_SPI_MOSI
+constexpr uint16_t FlashMISO = PB4;    // ICE_SPI_MISO
+constexpr uint16_t FlashCLK = PB3;     // ICE_SPI_SCK
+constexpr uint16_t StatusLed = PB13;   // STATUS
+
+class PinConfig {
+public:
+  PinConfig();
+
+  // Init common MCU pins such as the status LED.
+  void Init();
+  // Init FPGA specific pins.
+  void InitFpgaPins();
+
+  // Halt the FPGA with the SPI bus released so SPI flash is accessible from the
+  // MCU.
+  void FpgaHalt();
+  void FpgaEnable();
+  void SPIEnable();
+
+private:
+};
+
+} // namespace gonk::pin_config