Notes:
1.	Design Guidelines
1.1.	Robert C. Martin’s SOLID principles are a good starting point. https://team-coder.com/solid-principles/#:~:text=SOLID%20is%20an%20acronym%20for,Interface%20segregation%20and%20Dependency%20inversion.
1.2.	My main goal it to make sure the code is reasonably easy to understand by a competent but not necessarily expert C/C++ developer. I assume a basic understanding of Object Oriented programming e.g. classes and inheritance. And there are lots of useful libraries in the C++ stdlib.
1.3.	Minimize the number of files a developer needs to look at to understand a specific object. For example, the CPF uses a GPS receiver.  There is a GPS1 class.  Everything you need to know about that GPS receiver is in there.  The current GPS receiver uses a UART to communicate, USART1 in this case.  Everything you need to know about how USART1 works is in the USART1.hpp and .cpp files plus the UARTBase class that every USARTX.hpp or UARTX.hpp instanticates.
1.4.	The code should be non-blocking.  Prefer DMA drivers for peripherals, then IT drivers. Polling may be OK in non-time critical parts of the code with a timeout to prevent lockup in the event of a non-responsive device.  No delays in time-critical parts of the code, maybe a few milliseconds might be OK but probably not.
1.5.	Prefer straight C with namespace in .hpp file if the file is basically a collection of static functions that don’t need to remember state variables. Use a C++ class if it make the code easier to understand or reduces cut and paste or some other good reason. For example, the USART1.hpp and .cpp files described above are currently classes but a TODO item is investigate if it makes more sense to make them namespaces.
1.6.	Minimize the use of dynamic memory. The Autosar spec has a good but extremely long set of guidelines.      https://www.autosar.org/fileadmin/standards/R22-11/AP/AUTOSAR_RS_CPP14Guidelines.pdf
1.6.1.	 Don’t use new except during program initialization.
1.6.2.	 Follow the Resource Acquisition Is Initialization (RAII, https://en.cppreference.com/w/cpp/language/raii ) idiom. Make sure variables, especially ones that use dynamic memory like std::string declared inside functions get deallocated when the function ends.
1.6.3.	 Things like std::string and std::vector use dynamic memory under the hood (std::array does not use dynamic memory).  However, they are supposed to follow the RAII principle (see above) and clean up after themselves when declared inside a function.
1.6.4.	 Don’t use malloc or calloc or any similar bologna.
1.7.	Functions shouldn't be more than a screen full of lines unless you have a good reason.
1.8.	Files shouldn't be more than a couple of 100 lines long unless you have a good reason.
1.9.	Functions should be loosely coupled. Loosely coupled to me means for example: GPS receiver code shouldn't need to know very much, better yet nothing at all, about the details of the UART or I2C or whatever port it's using to communicate. One metric: minimizing #include statements generally minimizes coupling.
1.10.	Prefer the STM low level drivers instead of the HAL drivers.
2.	Mods made in VGDB project after importing from CubeIDE.
2.1.	 Add to top of stm32h7xx_it.c
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */

extern void USART1_IRQHandlerCPF(void);
extern void DMA1_Stream0_IRQHandlerCPF(void);
extern void DMA1_Stream1_IRQHandlerCPF(void);
/* USER CODE END PFP */

2.2.	 Add to DMA1_stream0_IRQHandler
/**
  * @brief This function handles DMA1 stream0 global interrupt.
  */
void DMA1_Stream0_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Stream0_IRQn 0 */

    DMA1_Stream0_IRQHandlerCPF();
  /* USER CODE END DMA1_Stream0_IRQn 0 */

  /* USER CODE BEGIN DMA1_Stream0_IRQn 1 */

  /* USER CODE END DMA1_Stream0_IRQn 1 */
2.3.	 Add to DMA1_Stream1_IRQHandler
/**
  * @brief This function handles DMA1 stream1 global interrupt.
  */
void DMA1_Stream1_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Stream1_IRQn 0 */

    DMA1_Stream1_IRQHandlerCPF();
  /* USER CODE END DMA1_Stream1_IRQn 0 */

  /* USER CODE BEGIN DMA1_Stream1_IRQn 1 */

  /* USER CODE END DMA1_Stream1_IRQn 1 */
}
2.4.	 Add to USART1_IRQHandler
/**
  * @brief This function handles USART1 global interrupt.
  */
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

    USART1_IRQHandlerCPF();
  /* USER CODE END USART1_IRQn 0 */
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}
2.5.	 Comment out _isatty from syscalls.c in order to use VGDB fast semi-hosting
//int _isatty(int file)
//{
//    return 1;
//}
3.