static void Main(string[] args) { if (args.Length < 2) { throw new Exception("Usage: stm32.exe <SW package directory> <STM32Cube directory>"); } ///If the MCU list format changes again, create a new implementation of the IDeviceListProvider interface, switch to using it, but keep the old one for reference & easy comparison. IDeviceListProvider provider = new DeviceListProviders.CubeProvider(); var bspBuilder = new STM32BSPBuilder(new BSPDirectories(args[0], @"..\..\Output", @"..\..\rules"), args[1]); var devices = provider.LoadDeviceList(bspBuilder); if (devices.Where(d => d.RAMSize == 0 || d.FlashSize == 0).Count() > 0) { throw new Exception($"Some devices are RAM Size ({devices.Where(d => d.RAMSize == 0).Count()}) = 0 or FLASH Size({devices.Where(d => d.FlashSize == 0).Count()}) = 0 "); } List <MCUFamilyBuilder> allFamilies = new List <MCUFamilyBuilder>(); foreach (var fn in Directory.GetFiles(bspBuilder.Directories.RulesDir + @"\families", "*.xml")) { allFamilies.Add(new MCUFamilyBuilder(bspBuilder, XmlTools.LoadObject <FamilyDefinition>(fn))); } var rejects = BSPGeneratorTools.AssignMCUsToFamilies(devices, allFamilies); if (rejects.Count > 0) { Console.WriteLine("Globally unsupported MCUs:"); foreach (var r in rejects) { Console.WriteLine("\t{0}", r.Name); } } List <MCUFamily> familyDefinitions = new List <MCUFamily>(); List <MCU> mcuDefinitions = new List <MCU>(); List <EmbeddedFramework> frameworks = new List <EmbeddedFramework>(); List <MCUFamilyBuilder.CopiedSample> exampleDirs = new List <MCUFamilyBuilder.CopiedSample>(); bool noPeripheralRegisters = args.Contains("/noperiph"); var files = string.Join("\r\n", File.ReadAllLines(@"E:\ware\Logfile.CSV").Select(l => l.Split(',')[4].Trim('\"')).Distinct().OrderBy(x => x).ToArray()); var commonPseudofamily = new MCUFamilyBuilder(bspBuilder, XmlTools.LoadObject <FamilyDefinition>(bspBuilder.Directories.RulesDir + @"\CommonFiles.xml")); foreach (var fw in commonPseudofamily.GenerateFrameworkDefinitions()) { frameworks.Add(fw); } foreach (var fam in allFamilies) { bspBuilder.GetMemoryMcu(fam); var rejectedMCUs = fam.RemoveUnsupportedMCUs(true); if (rejectedMCUs.Length != 0) { Console.WriteLine("Unsupported {0} MCUs:", fam.Definition.Name); foreach (var mcu in rejectedMCUs) { Console.WriteLine("\t{0}", mcu.Name); } } fam.AttachStartupFiles(ParseStartupFiles(fam.Definition.StartupFileDir, fam)); if (!noPeripheralRegisters) { fam.AttachPeripheralRegisters(ParsePeripheralRegisters(fam.Definition.PrimaryHeaderDir, fam)); } familyDefinitions.Add(fam.GenerateFamilyObject(true)); fam.GenerateLinkerScripts(false); foreach (var mcu in fam.MCUs) { mcuDefinitions.Add(mcu.GenerateDefinition(fam, bspBuilder, !noPeripheralRegisters)); } foreach (var fw in fam.GenerateFrameworkDefinitions()) { frameworks.Add(fw); } foreach (var sample in fam.CopySamples()) { exampleDirs.Add(sample); } } foreach (var sample in commonPseudofamily.CopySamples(null, allFamilies.Where(f => f.Definition.AdditionalSystemVars != null).SelectMany(f => f.Definition.AdditionalSystemVars))) { exampleDirs.Add(sample); } var prioritizer = new SamplePrioritizer(Path.Combine(bspBuilder.Directories.RulesDir, "SamplePriorities.txt")); exampleDirs.Sort((a, b) => prioritizer.Prioritize(a.RelativePath, b.RelativePath)); BoardSupportPackage bsp = new BoardSupportPackage { PackageID = "com.sysprogs.arm.stm32", PackageDescription = "STM32 Devices", GNUTargetID = "arm-eabi", GeneratedMakFileName = "stm32.mak", MCUFamilies = familyDefinitions.ToArray(), SupportedMCUs = mcuDefinitions.ToArray(), Frameworks = frameworks.ToArray(), Examples = exampleDirs.Where(s => !s.IsTestProjectSample).Select(s => s.RelativePath).ToArray(), TestExamples = exampleDirs.Where(s => s.IsTestProjectSample).Select(s => s.RelativePath).ToArray(), PackageVersion = "4.5R2", IntelliSenseSetupFile = "stm32_compat.h", FileConditions = bspBuilder.MatchedFileConditions.ToArray(), MinimumEngineVersion = "5.1", FirstCompatibleVersion = "3.0", InitializationCodeInsertionPoints = commonPseudofamily.Definition.InitializationCodeInsertionPoints, }; File.Copy(@"..\..\stm32_compat.h", Path.Combine(bspBuilder.BSPRoot, "stm32_compat.h"), true); Console.WriteLine("Saving BSP..."); bspBuilder.Save(bsp, true); }
static void Main(string[] args) { if (args.Length < 2) { throw new Exception("Usage: stm32.exe <SW package directory> <STM32Cube directory>"); } var bspBuilder = new STM32BSPBuilder(new BSPDirectories(args[0], @"..\..\Output", @"..\..\rules"), args[1]); var devices = BSPGeneratorTools.ReadMCUDevicesFromCommaDelimitedCSVFile(bspBuilder.Directories.RulesDir + @"\stm32devices.csv", "Part Number", "FLASH Size (Prog)", "Internal RAM Size", "Core", true); List <MCUFamilyBuilder> allFamilies = new List <MCUFamilyBuilder>(); foreach (var fn in Directory.GetFiles(bspBuilder.Directories.RulesDir + @"\families", "*.xml")) { allFamilies.Add(new MCUFamilyBuilder(bspBuilder, XmlTools.LoadObject <FamilyDefinition>(fn))); } var rejects = BSPGeneratorTools.AssignMCUsToFamilies(devices, allFamilies); if (rejects.Count > 0) { Console.WriteLine("Globally unsupported MCUs:"); foreach (var r in rejects) { Console.WriteLine("\t{0}", r.Name); } } List <MCUFamily> familyDefinitions = new List <MCUFamily>(); List <MCU> mcuDefinitions = new List <MCU>(); List <EmbeddedFramework> frameworks = new List <EmbeddedFramework>(); List <MCUFamilyBuilder.CopiedSample> exampleDirs = new List <MCUFamilyBuilder.CopiedSample>(); bool noPeripheralRegisters = args.Contains("/noperiph"); var commonPseudofamily = new MCUFamilyBuilder(bspBuilder, XmlTools.LoadObject <FamilyDefinition>(bspBuilder.Directories.RulesDir + @"\CommonFiles.xml")); foreach (var fw in commonPseudofamily.GenerateFrameworkDefinitions()) { frameworks.Add(fw); } foreach (var fam in allFamilies) { bspBuilder.GetMemoryMcu(fam); var rejectedMCUs = fam.RemoveUnsupportedMCUs(true); if (rejectedMCUs.Length != 0) { Console.WriteLine("Unsupported {0} MCUs:", fam.Definition.Name); foreach (var mcu in rejectedMCUs) { Console.WriteLine("\t{0}", mcu.Name); } } fam.AttachStartupFiles(ParseStartupFiles(fam.Definition.StartupFileDir, fam)); if (!noPeripheralRegisters) { fam.AttachPeripheralRegisters(ParsePeripheralRegisters(fam.Definition.PrimaryHeaderDir, fam)); } familyDefinitions.Add(fam.GenerateFamilyObject(true)); fam.GenerateLinkerScripts(false); foreach (var mcu in fam.MCUs) { mcuDefinitions.Add(mcu.GenerateDefinition(fam, bspBuilder, !noPeripheralRegisters)); } foreach (var fw in fam.GenerateFrameworkDefinitions()) { frameworks.Add(fw); } foreach (var sample in fam.CopySamples()) { exampleDirs.Add(sample); } } foreach (var sample in commonPseudofamily.CopySamples(null, allFamilies.Where(f => f.Definition.AdditionalSystemVars != null).SelectMany(f => f.Definition.AdditionalSystemVars))) { exampleDirs.Add(sample); } var prioritizer = new SamplePrioritizer(Path.Combine(bspBuilder.Directories.RulesDir, "SamplePriorities.txt")); exampleDirs.Sort((a, b) => prioritizer.Prioritize(a.RelativePath, b.RelativePath)); BoardSupportPackage bsp = new BoardSupportPackage { PackageID = "com.sysprogs.arm.stm32", PackageDescription = "STM32 Devices", GNUTargetID = "arm-eabi", GeneratedMakFileName = "stm32.mak", MCUFamilies = familyDefinitions.ToArray(), SupportedMCUs = mcuDefinitions.ToArray(), Frameworks = frameworks.ToArray(), Examples = exampleDirs.Where(s => !s.IsTestProjectSample).Select(s => s.RelativePath).ToArray(), TestExamples = exampleDirs.Where(s => s.IsTestProjectSample).Select(s => s.RelativePath).ToArray(), PackageVersion = "4.1", IntelliSenseSetupFile = "stm32_compat.h", FileConditions = bspBuilder.MatchedFileConditions.ToArray(), MinimumEngineVersion = "5.1", FirstCompatibleVersion = "3.0", InitializationCodeInsertionPoints = commonPseudofamily.Definition.InitializationCodeInsertionPoints, }; File.Copy(@"..\..\stm32_compat.h", Path.Combine(bspBuilder.BSPRoot, "stm32_compat.h"), true); Console.WriteLine("Saving BSP..."); bspBuilder.Save(bsp, true); }
static void Main(string[] args) { var regKey = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Sysprogs\BSPGenerators\STM32"); var sdkRoot = regKey.GetValue("SDKRoot") as string ?? throw new Exception("Please specify STM32 SDK root via registry"); var cubeRoot = regKey.GetValue("CubeMXRoot") as string ?? throw new Exception("Please specify STM32CubeMX location via registry"); if (args.Contains("/fetch")) { //This will load the latest SDK list from the STM32CubeMX directory and will fetch/unpack them to our SDKRoot directory. //Before running this, ensure the STM32CubeMX has the up-to-date SDK definitions (using the 'check for update' function), as //otherwise the BSP generator will fetch the old versions. SDKFetcher.FetchLatestSDKs(sdkRoot, cubeRoot); } string rulesetName = args.FirstOrDefault(a => a.StartsWith("/rules:"))?.Substring(7) ?? STM32Ruleset.Classic.ToString(); STM32Ruleset ruleset = Enum.GetValues(typeof(STM32Ruleset)) .OfType <STM32Ruleset>() .First(v => StringComparer.InvariantCultureIgnoreCase.Compare(v.ToString(), rulesetName) == 0); ///If the MCU list format changes again, create a new implementation of the IDeviceListProvider interface, switch to using it, but keep the old one for reference & easy comparison. IDeviceListProvider provider = new DeviceListProviders.CubeProvider(); var bspBuilder = new STM32BSPBuilder(new BSPDirectories(sdkRoot, @"..\..\Output\" + rulesetName, @"..\..\rules\" + rulesetName), cubeRoot); Directory.CreateDirectory(@"..\..\Logs"); using (var wr = new ParseReportWriter(@"..\..\Logs\registers.log")) { var devices = provider.LoadDeviceList(bspBuilder); if (devices.Where(d => d.FlashSize == 0 && !d.Name.StartsWith("STM32MP1")).Count() > 0) { throw new Exception($"Some deviceshave FLASH Size({devices.Where(d => d.FlashSize == 0).Count()}) = 0 "); } List <MCUFamilyBuilder> allFamilies = new List <MCUFamilyBuilder>(); string extraFrameworksFile = Path.Combine(bspBuilder.Directories.RulesDir, "FrameworkTemplates.xml"); if (!File.Exists(extraFrameworksFile) && File.Exists(Path.ChangeExtension(extraFrameworksFile, ".txt"))) { extraFrameworksFile = Path.Combine(bspBuilder.Directories.RulesDir, File.ReadAllText(Path.ChangeExtension(extraFrameworksFile, ".txt"))); } Dictionary <string, STM32SDKCollection.SDK> sdksByVariable = bspBuilder.SDKList.SDKs.ToDictionary(s => $"$$STM32:{s.Family}_DIR$$"); List <STM32SDKCollection.SDK> referencedSDKs = new List <STM32SDKCollection.SDK>(); foreach (var fn in Directory.GetFiles(bspBuilder.Directories.RulesDir + @"\families", "*.xml")) { var fam = XmlTools.LoadObject <FamilyDefinition>(fn); if (File.Exists(extraFrameworksFile)) { int idx = fam.PrimaryHeaderDir.IndexOf('\\'); string baseDir = fam.PrimaryHeaderDir.Substring(0, idx); if (!baseDir.StartsWith("$$STM32:")) { throw new Exception("Invalid base directory. Please recheck the family definition."); } string baseFamName = fam.Name; if (baseFamName.EndsWith("_M4")) { baseFamName = baseFamName.Substring(0, baseFamName.Length - 3); } referencedSDKs.Add(sdksByVariable[baseDir]); var dict = new Dictionary <string, string> { { "STM32:FAMILY_EX", fam.Name }, { "STM32:FAMILY", baseFamName }, { "STM32:FAMILY_DIR", baseDir }, }; var extraFrameworkFamily = XmlTools.LoadObject <FamilyDefinition>(extraFrameworksFile); //USB host/device libraries are not always compatible between different device families. Hence we need to ship separate per-family copies of those. var expandedExtraFrameworks = extraFrameworkFamily.AdditionalFrameworks.Select(fw => { fw.ID = VariableHelper.ExpandVariables(fw.ID, dict); fw.Name = VariableHelper.ExpandVariables(fw.Name, dict); fw.RequiredFrameworks = ExpandVariables(fw.RequiredFrameworks, dict); fw.IncompatibleFrameworks = ExpandVariables(fw.IncompatibleFrameworks, dict); foreach (var job in fw.CopyJobs) { job.SourceFolder = VariableHelper.ExpandVariables(job.SourceFolder, dict); job.TargetFolder = VariableHelper.ExpandVariables(job.TargetFolder, dict); job.AdditionalIncludeDirs = VariableHelper.ExpandVariables(job.AdditionalIncludeDirs, dict); } return(fw); }); //Furthermore, some families do not include a USB host peripheral and hence do not contain a USB Host library. We need to skip it automatically. var extraFrameworksWithoutMissingFolders = expandedExtraFrameworks.Where(fw => fw.CopyJobs.Count(j => { string expandedJobSourceDir = j.SourceFolder; bspBuilder.ExpandVariables(ref expandedJobSourceDir); return(!Directory.Exists(expandedJobSourceDir)); }) == 0); fam.AdditionalFrameworks = fam.AdditionalFrameworks.Concat(extraFrameworksWithoutMissingFolders).ToArray(); } bspBuilder.InsertLegacyHALRulesIfNecessary(fam, bspBuilder.ReverseFileConditions); switch (ruleset) { case STM32Ruleset.STM32WB: allFamilies.Add(new STM32WBFamilyBuilder(bspBuilder, fam)); break; case STM32Ruleset.STM32MP1: allFamilies.Add(new STM32MP1FamilyBuilder(bspBuilder, fam)); break; case STM32Ruleset.Classic: default: allFamilies.Add(new STM32ClassicFamilyBuilder(bspBuilder, fam)); break; } } var rejects = BSPGeneratorTools.AssignMCUsToFamilies(devices, allFamilies); if (rejects.Count > 0 && ruleset == STM32Ruleset.Classic) { Console.WriteLine("Globally unsupported MCUs:"); foreach (var r in rejects) { Console.WriteLine("\t{0}", r.Name); } } List <MCUFamily> familyDefinitions = new List <MCUFamily>(); List <MCU> mcuDefinitions = new List <MCU>(); List <EmbeddedFramework> frameworks = new List <EmbeddedFramework>(); List <MCUFamilyBuilder.CopiedSample> exampleDirs = new List <MCUFamilyBuilder.CopiedSample>(); bool noPeripheralRegisters = args.Contains("/noperiph"); string specificDeviceForDebuggingPeripheralRegisterGenerator = args.FirstOrDefault(a => a.StartsWith("/periph:"))?.Substring(8); var commonPseudofamily = new MCUFamilyBuilder(bspBuilder, XmlTools.LoadObject <FamilyDefinition>(bspBuilder.Directories.RulesDir + @"\CommonFiles.xml")); foreach (var fw in commonPseudofamily.GenerateFrameworkDefinitions()) { frameworks.Add(fw); } List <ConditionalToolFlags> allConditionalToolFlags = new List <ConditionalToolFlags>(); foreach (var fam in allFamilies) { bspBuilder.GetMemoryMcu(fam); var rejectedMCUs = fam.RemoveUnsupportedMCUs(true); if (rejectedMCUs.Length != 0) { Console.WriteLine("Unsupported {0} MCUs:", fam.Definition.Name); foreach (var mcu in rejectedMCUs) { Console.WriteLine("\t{0}", mcu.Name); } } fam.AttachStartupFiles(ParseStartupFiles(fam.Definition.StartupFileDir, fam)); if (!noPeripheralRegisters) { fam.AttachPeripheralRegisters(ParsePeripheralRegisters(fam.Definition.PrimaryHeaderDir, fam, specificDeviceForDebuggingPeripheralRegisterGenerator, wr), throwIfNotFound: specificDeviceForDebuggingPeripheralRegisterGenerator == null); } familyDefinitions.Add(fam.GenerateFamilyObject(MCUFamilyBuilder.CoreSpecificFlags.All, true)); fam.GenerateLinkerScripts(false); foreach (var mcu in fam.MCUs) { mcuDefinitions.Add(mcu.GenerateDefinition(fam, bspBuilder, !noPeripheralRegisters && specificDeviceForDebuggingPeripheralRegisterGenerator == null)); } foreach (var fw in fam.GenerateFrameworkDefinitions()) { frameworks.Add(fw); } foreach (var sample in fam.CopySamples()) { exampleDirs.Add(sample); } if (fam.Definition.ConditionalFlags != null) { allConditionalToolFlags.AddRange(fam.Definition.ConditionalFlags); } } foreach (var sample in commonPseudofamily.CopySamples(null, allFamilies.Where(f => f.Definition.AdditionalSystemVars != null).SelectMany(f => f.Definition.AdditionalSystemVars))) { exampleDirs.Add(sample); } var prioritizer = new SamplePrioritizer(Path.Combine(bspBuilder.Directories.RulesDir, "SamplePriorities.txt")); exampleDirs.Sort((a, b) => prioritizer.Prioritize(a.RelativePath, b.RelativePath)); var bsp = XmlTools.LoadObject <BoardSupportPackage>(Path.Combine(bspBuilder.Directories.RulesDir, "BSPTemplate.xml")); bsp.MCUFamilies = familyDefinitions.ToArray(); bsp.SupportedMCUs = mcuDefinitions.ToArray(); bsp.Frameworks = frameworks.ToArray(); bsp.Examples = exampleDirs.Where(s => !s.IsTestProjectSample).Select(s => s.RelativePath).ToArray(); bsp.TestExamples = exampleDirs.Where(s => s.IsTestProjectSample).Select(s => s.RelativePath).ToArray(); bsp.PackageVersion = bspBuilder.SDKList.BSPVersion; bsp.FileConditions = bspBuilder.MatchedFileConditions.ToArray(); bsp.InitializationCodeInsertionPoints = commonPseudofamily.Definition.InitializationCodeInsertionPoints; bsp.ConditionalFlags = allConditionalToolFlags.ToArray(); bspBuilder.SDKList.SDKs = referencedSDKs.Distinct().ToArray(); XmlTools.SaveObject(bspBuilder.SDKList, Path.Combine(bspBuilder.BSPRoot, "SDKVersions.xml")); bspBuilder.ValidateBSP(bsp); bspBuilder.ReverseFileConditions.SaveIfConsistent(bspBuilder.Directories.OutputDir, bspBuilder.ExportRenamedFileTable(), ruleset == STM32Ruleset.STM32WB); File.Copy(@"..\..\stm32_compat.h", Path.Combine(bspBuilder.BSPRoot, "stm32_compat.h"), true); Console.WriteLine("Saving BSP..."); bspBuilder.Save(bsp, true); } }
static void Main(string[] args) { if (args.Length < 2) throw new Exception("Usage: stm32.exe <SW package directory> <STM32Cube directory>"); var bspBuilder = new STM32BSPBuilder(new BSPDirectories(args[0], @"..\..\Output", @"..\..\rules"), args[1]); var devices = BSPGeneratorTools.ReadMCUDevicesFromCommaDelimitedCSVFile(bspBuilder.Directories.RulesDir + @"\stm32devices.csv", "Part Number", "FLASH Size (Prog)", "Internal RAM Size", "Core", true); List<MCUFamilyBuilder> allFamilies = new List<MCUFamilyBuilder>(); foreach(var fn in Directory.GetFiles(bspBuilder.Directories.RulesDir + @"\families", "*.xml")) allFamilies.Add(new MCUFamilyBuilder(bspBuilder, XmlTools.LoadObject<FamilyDefinition>(fn))); var rejects = BSPGeneratorTools.AssignMCUsToFamilies(devices, allFamilies); if (rejects.Count > 0) { Console.WriteLine("Globally unsupported MCUs:"); foreach (var r in rejects) Console.WriteLine("\t{0}", r.Name); } List<MCUFamily> familyDefinitions = new List<MCUFamily>(); List<MCU> mcuDefinitions = new List<MCU>(); List<EmbeddedFramework> frameworks = new List<EmbeddedFramework>(); List<MCUFamilyBuilder.CopiedSample> exampleDirs = new List<MCUFamilyBuilder.CopiedSample>(); bool noPeripheralRegisters = args.Contains("/noperiph"); var commonPseudofamily = new MCUFamilyBuilder(bspBuilder, XmlTools.LoadObject<FamilyDefinition>(bspBuilder.Directories.RulesDir + @"\CommonFiles.xml")); foreach (var fw in commonPseudofamily.GenerateFrameworkDefinitions()) frameworks.Add(fw); foreach (var fam in allFamilies) { bspBuilder.GetMemoryMcu(fam); var rejectedMCUs = fam.RemoveUnsupportedMCUs(true); if (rejectedMCUs.Length != 0) { Console.WriteLine("Unsupported {0} MCUs:", fam.Definition.Name); foreach (var mcu in rejectedMCUs) Console.WriteLine("\t{0}", mcu.Name); } fam.AttachStartupFiles(ParseStartupFiles(fam.Definition.StartupFileDir, fam)); if (!noPeripheralRegisters) fam.AttachPeripheralRegisters(ParsePeripheralRegisters(fam.Definition.PrimaryHeaderDir, fam)); familyDefinitions.Add(fam.GenerateFamilyObject(true)); fam.GenerateLinkerScripts(false); foreach (var mcu in fam.MCUs) mcuDefinitions.Add(mcu.GenerateDefinition(fam, bspBuilder, !noPeripheralRegisters)); foreach (var fw in fam.GenerateFrameworkDefinitions()) frameworks.Add(fw); foreach (var sample in fam.CopySamples()) exampleDirs.Add(sample); } foreach (var sample in commonPseudofamily.CopySamples(null, allFamilies.Where(f => f.Definition.AdditionalSystemVars != null).SelectMany(f => f.Definition.AdditionalSystemVars))) exampleDirs.Add(sample); var prioritizer = new SamplePrioritizer(Path.Combine(bspBuilder.Directories.RulesDir, "SamplePriorities.txt")); exampleDirs.Sort((a,b) => prioritizer.Prioritize(a.RelativePath, b.RelativePath)); BoardSupportPackage bsp = new BoardSupportPackage { PackageID = "com.sysprogs.arm.stm32", PackageDescription = "STM32 Devices", GNUTargetID = "arm-eabi", GeneratedMakFileName = "stm32.mak", MCUFamilies = familyDefinitions.ToArray(), SupportedMCUs = mcuDefinitions.ToArray(), Frameworks = frameworks.ToArray(), Examples = exampleDirs.Where(s => !s.IsTestProjectSample).Select(s => s.RelativePath).ToArray(), TestExamples = exampleDirs.Where(s => s.IsTestProjectSample).Select(s => s.RelativePath).ToArray(), PackageVersion = "4.0", IntelliSenseSetupFile = "stm32_compat.h", FileConditions = bspBuilder.MatchedFileConditions.ToArray(), MinimumEngineVersion = "5.1", FirstCompatibleVersion = "3.0", InitializationCodeInsertionPoints = commonPseudofamily.Definition.InitializationCodeInsertionPoints, }; File.Copy(@"..\..\stm32_compat.h", Path.Combine(bspBuilder.BSPRoot, "stm32_compat.h"), true); Console.WriteLine("Saving BSP..."); bspBuilder.Save(bsp, true); }