2019-02-05 08:26 PM
I have a custom C# application for production testing of one of our boards that has an STM32 processor on it. To program the bootloader into the flash I use the ST-LINK utility software. I would like to integrate the program and verify functionality into my production test software so the user doesn't have to leave my software to run the ST-LINK utility. Is there an API available that would give me access to the ST-LINK to program a processor?
Thank you.
2019-02-06 12:22 AM
Don't know about C#, but STM32CubeProgrammer provides a C++ API:
In addition to the graphical user interface and to the command line interfaceSTM32CubeProgrammer offers a C++ API that can be used to develop your application...
...For more information about the C++ API, read the help file provided within theSTM32CubeProgrammer package under API\doc folder.
2020-01-17 05:31 AM
Hello! I happen to have a similar case like you @jprinster . Do you manage to get those APIs? I do know that SEGGER (link) have those APIs but they need us to purchase the license before downloading it.
2020-01-18 12:43 PM
I ended up just creating a system process (basically the same as a command window) and then called the ST-LINK Utility command line interface. It means the target PC has to have ST-LINK Utility installed, but that's not a big deal since the application I wrote is only used within our building. Here's the code I created from some other example.
using System;
using System.Diagnostics;
using System.IO;
namespace Application.STLink {
public class STLinkAdapter {
//====================================================
#region Data Properties
private const string CmdListDevices = "-List";
private const string CmdConnectToTarget = "-c ID=0 SWD";
private const string CmdProgramFromFile = "-P";
private const string CmdFlashErase = "-ME";
private const string CmdVerifyProgramming = "-V";
private const string CmdRunFirmware = "-Run";
private const string CmdNoPrompt = "-NoPrompt";
private const string STLinkCLIDefaultPath = @"C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility\ST-LINK_CLI.exe ";
public string STLinkCLIAppPath { get; set; }
#endregion
//=======================================================
#region Constructor
public STLinkAdapter(string a_STLinkCLIAppPath) {
if (string.IsNullOrEmpty(a_STLinkCLIAppPath)) {
STLinkCLIAppPath = STLinkCLIDefaultPath;
}
}
#endregion
//=======================================================
#region Procedures
public STLinkReturnCodes FindSTLink(out string a_ResultOut) {
STLinkReturnCodes l_STLinkReturnCode = STLinkReturnCodes.Success;
l_STLinkReturnCode = ExecuteCommandSync(STLinkCLIAppPath, CmdListDevices, out a_ResultOut);
if (l_STLinkReturnCode == STLinkReturnCodes.Success) {
if (a_ResultOut.Contains("No ST-LINK detected")) {
a_ResultOut = "No ST-Link found";
l_STLinkReturnCode = STLinkReturnCodes.Failure;
}
else {
a_ResultOut = "ST-Link detected";
}
}
return l_STLinkReturnCode;
}
//-----------------------------------
public STLinkReturnCodes ConnectToTarget(string a_TargetProcessor, out string a_ResultOut) {
STLinkReturnCodes l_STLinkReturnCode = STLinkReturnCodes.Success;
l_STLinkReturnCode = ExecuteCommandSync(STLinkCLIAppPath, CmdConnectToTarget, out a_ResultOut);
if (l_STLinkReturnCode == STLinkReturnCodes.Success) {
if (a_ResultOut.Contains(a_TargetProcessor)) {
a_ResultOut = "Target processor found: " + a_TargetProcessor;
l_STLinkReturnCode = STLinkReturnCodes.Success;
}
else {
a_ResultOut = "Target processor not found.";
l_STLinkReturnCode = STLinkReturnCodes.Failure;
}
}
return l_STLinkReturnCode;
}
//-----------------------------------
public STLinkReturnCodes ProgramTarget(string a_BinFilePath, UInt32 a_FlashAddress, out string a_ResultOut) {
STLinkReturnCodes l_STLinkReturnCode = STLinkReturnCodes.Success;
a_ResultOut = string.Empty;
if (File.Exists(a_BinFilePath) == false) {
l_STLinkReturnCode = STLinkReturnCodes.Failure;
a_ResultOut = "Bin file doesn't exist.";
}
if (l_STLinkReturnCode == STLinkReturnCodes.Success) {
string l_CommandArguments = string.Format("{0} {1} {2} \"{3}\" 0x{4:X8} {5} {6} {7}", CmdConnectToTarget, CmdFlashErase, CmdProgramFromFile, a_BinFilePath, a_FlashAddress, CmdVerifyProgramming, CmdNoPrompt, CmdRunFirmware);
l_STLinkReturnCode = ExecuteCommandSync(STLinkCLIAppPath, l_CommandArguments, out a_ResultOut);
if (l_STLinkReturnCode == STLinkReturnCodes.Success) {
if (a_ResultOut.Contains("Verification...OK")) {
a_ResultOut = "Target successfully programmed.";
l_STLinkReturnCode = STLinkReturnCodes.Success;
}
else {
a_ResultOut += "Programming failed!";
l_STLinkReturnCode = STLinkReturnCodes.Failure;
}
}
}
return l_STLinkReturnCode;
}
//-----------------------------------
/// <summary>
/// Executes a shell command synchronously.
/// </summary>
/// <param name="command">string command</param>
/// <returns>string, as output of the command.</returns>
private STLinkReturnCodes ExecuteCommandSync(string a_AppPath, string a_CommandParameters, out string a_ResultOut) {
STLinkReturnCodes l_STLinkReturnCode = STLinkReturnCodes.Success;
a_ResultOut = string.Empty;
try {
// create the ProcessStartInfo using "cmd" as the program to be run, and "/c " as the parameters.
// Incidentally, /c tells cmd that we want it to execute the command that follows, and then exit.
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo();
procStartInfo.FileName = a_AppPath;
procStartInfo.Arguments = a_CommandParameters;
// The following commands are needed to redirect the standard output.
//This means that it will be redirected to the Process.StandardOutput StreamReader.
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
// Do not create the black window.
procStartInfo.CreateNoWindow = true;
// Now we create a process, assign its ProcessStartInfo and start it
using (Process l_process = Process.Start(procStartInfo)) {
l_process.WaitForExit();
// Get the output into a string
using (StreamReader reader = l_process.StandardOutput) {
a_ResultOut = reader.ReadToEnd();
}
}
l_STLinkReturnCode = STLinkReturnCodes.Success;
}
catch (Exception objException) {
l_STLinkReturnCode = STLinkReturnCodes.Failure;
a_ResultOut = "Failure";
}
return l_STLinkReturnCode;
}
//-----------------------------------
#endregion
}
}
2020-01-18 12:50 PM
The other half of the code....
namespace Application.STLink {
public enum STLinkReturnCodes {
Success = 0,
Failure = 1
}
}
The calls to actually use it.....
// Connecting to the ST-LINK/V2.
if (l_STLinkReturnCode == STLinkReturnCodes.Success) {
l_STLinkReturnCode = await Task.Run(() => l_STLinkAdapter.FindSTLink(out l_STLinkResponse));
}
// Connecting to the processor target. The target process or is a string like "STM32F05".
if (l_STLinkReturnCode == STLinkReturnCodes.Success) {
l_STLinkReturnCode = await Task.Run(() => l_STLinkAdapter.ConnectToTarget(l_FirmwareInfo.TargetProcessor, out l_STLinkResponse));
}
// Programming flashloader
if (l_STLinkReturnCode == STLinkReturnCodes.Success) {
l_STLinkReturnCode = await Task.Run(() => l_STLinkAdapter.ProgramTarget(l_BinFilePath, l_FirmwareInfo.FlashloaderFlashAddress, out l_STLinkResponse));
}
2020-01-19 11:21 PM
wow thank you very much for your kind help! I will try out this code.. Thanks again!!