让调试器中断 SerialPort Write 命令
Getting debugger break on SerialPort Write command
我为设备构建了一个固件更新应用程序,主机应用程序通过串行连接连接到设备。该应用程序一直在开发小型应用程序 (~18KB),我最近将固件大小增加到~200KB。
现在主机应用程序 (C#) 在串行端口写入时挂起,在调试中暂停程序会显示调试器中断。
下图的代码逐行读取 .HEX 文件(未显示)并使用 UART(串行通信)一次写入一个字节的 256 字节块。在 256 字节之后,为该块发送校验和,并留下循环以设置下一次传输。
应用程序挂起写入命令的原因可能是什么?是否有一些端口或缓冲区维护必须在块之间完成?我可以看到块的字节计数器(0 到 255)并且它没有挂在相同的字节数上。
此应用正在连接到 STM32F417IGT 开发板上的 ARM 处理器。
感谢您的帮助!
完成写入功能,在代码中:
public void WriteNewAppToFlash(SerialPort _serialPort)
{
int byte_read = 0;
long checksum = 0;
var ff = new byte[] { 0xFF };
// ------------------------------------------------------------------------------
// -------- WRITE MEMORY --------------------------------------------------------
// ------------------------------------------------------------------------------
// for Address
int baseAddress = 0x08004000;
int offset = 0;
// for string from HEX file
string line;
int length;
int type;
int hexChecksum = 0;
bool sendAddress = true;
int counter = 0; // Counting the number of lines in the file
int byteCounter = 0; // Counting nmumber of bytes in the current block
// Read the file and process one line at a time
System.IO.StreamReader file = new System.IO.StreamReader(path);
while ((line = file.ReadLine()) != null)
{
if (sendAddress == true)
{
/*
-------------------------------------------------------------------------------------------------------
SEND WRITE COMMAND
-----------------------------------------------------------------------------------------------------*/
// Send 0x43 (erase memory) and 0xBC
var writeMem = new byte[] { 0x31 };
var ce = new byte[] { 0xCE };
_serialPort.Write(writeMem, 0, 1);
//Console.WriteLine("writeMem = 0x" + BitConverter.ToInt32(writeMem, 0).ToString("X"));
_serialPort.Write(ce, 0, 1);
//Console.WriteLine("CE = 0x" + BitConverter.ToInt32(writeMem, 0).ToString("X"));
// Receive ACK byte
byte_read = _serialPort.ReadByte();
//Console.WriteLine("ACK = 0x" + byte_read.ToString("X"));
//Console.WriteLine("");
if (byte_read == NACK)
{
//Console.WriteLine("NACK received for WRITE MEMORY start");
//Console.WriteLine("");
}
// -- end SEND 0x31 and 0xCE and wait for ACK -----------------------------------------
-------------------------------------------------------------------------------------------------------
SEND CURRENT ADDRESS AND CHECKSUM TO FLASH MEMORY
-----------------------------------------------------------------------------------------------------*/
Byte[] currentAddr = BitConverter.GetBytes(baseAddress + offset);
// Increment offset by 0x100 (256 bytes)
offset = offset + 0x00000100;
//int msb;
// Reset Checksum and XOR address
checksum = 0;
foreach (byte b in currentAddr)
{
checksum ^= b;
}
//Console.WriteLine("cksum = " + checksum);
Byte[] cksum = BitConverter.GetBytes(checksum);
// Send address, MSB first, LSB last
_serialPort.Write(currentAddr, 3, 1);
_serialPort.Write(currentAddr, 2, 1);
_serialPort.Write(currentAddr, 1, 1);
_serialPort.Write(currentAddr, 0, 1);
// Send checksum of address bytes
_serialPort.Write(cksum, 0, 1);
// Receive ACK byte
byte_read = _serialPort.ReadByte();
//Console.WriteLine("ACK = 0x" + byte_read.ToString("X"));
//Console.WriteLine("");
if (byte_read == NACK)
{
//Console.WriteLine("NACK received for WRITE MEMORY address received");
//Console.WriteLine("");
}
// -- end addr or increment ---------------------------------------------------------
sendAddress = false;
// Send number of bytes, always 256, the last group will be padded with 0xFF
_serialPort.Write(ff, 0, 1);
hexChecksum = 0;
} // end IF for WRITE COMMAND and ADDRESS
/*
-------------------------------------------------------------------------------------------------------
WRITE 256 BYTES FROM HEX FILE TO FLASH MEMORY
-----------------------------------------------------------------------------------------------------*/
// FIRST CHARACTER in HEX FILE
// The colon indicates the start of a "record"
// Remove colon from beginning of string
line = line.Substring(1, line.Length - 1);
//Console.WriteLine(line);
// Create byte array from string
var bytes = GetBytesFromByteString(line).ToArray();
// Assign values to variables from byte array
type = bytes[3];
/* Next TWO CHARACTERS in HEX FILE 00-data
are the record type: 01-EOF
02-
03-
04-
05- */
// Check type for data = 00
if (type == 0)
{
// The first two characters represent the number of data bytes for the record
// Obtain length, convert to int (counter for sending data)
length = bytes[0];
for ( int i = 0; i < length; i++ )
{
// Send individual characters to device
_serialPort.Write(bytes, 4 + i, 1);
//Thread.Sleep(100);
// increment counter
byteCounter++;
if( byteCounter % 32 == 0 )
{
Thread.Sleep(40);
}
// Add byte to checksum
hexChecksum ^= bytes[4 + i];
//Console.WriteLine("cum checksum = " + hexChecksum);
// If counter == 256, reset counter, send checksum
if (byteCounter == 256)
{
sendAddress = true;
byteCounter = 0;
//Console.WriteLine("checksum = " + hexChecksum.ToString("X"));
// Convert checksum to a byte value and send
hexChecksum = hexChecksum ^ 0xFF;
byte csByte = Convert.ToByte(hexChecksum);
//Console.WriteLine("CSBYTE = " + Convert.ToInt32(csByte));
Byte[] csByte_arr = BitConverter.GetBytes(csByte);
_serialPort.Write(csByte_arr, 0, 1);
// Receive ACK byte
byte_read = _serialPort.ReadByte();
//Console.WriteLine("ACK = 0x" + byte_read.ToString("X"));
//Console.WriteLine("");
if (byte_read == NACK)
{
//Console.WriteLine("NACK received for write memory DATA received");
//Console.WriteLine("");
}
} // end IF byteCounter == 256
//Console.WriteLine(byteCounter);
} // end FOR loop
}
else if (type == 5)
{
// Address thingy
//Console.WriteLine("Hit address thingy");
//Console.WriteLine("");
}
else if (type == 1) // Check for end of file
{
// End of file
while (byteCounter != 0)
{
// Send individual bytes to device
_serialPort.Write(ff, 0, 1);
// increment counter
byteCounter++;
// Add byte to checksum
hexChecksum ^= 0xFF;
//Console.WriteLine("cum checksum = " + hexChecksum);
if (byteCounter == 256)
{
byteCounter = 0;
hexChecksum = hexChecksum ^ 0xFF;
byte csByte = Convert.ToByte(hexChecksum);
//Console.WriteLine("CSBYTE = " + Convert.ToInt32(csByte));
Byte[] csByte_arr = BitConverter.GetBytes(csByte);
_serialPort.Write(csByte_arr, 0, 1);
// Receive ACK byte
byte_read = _serialPort.ReadByte();
//Console.WriteLine("ACK = 0x" + byte_read.ToString("X"));
//Console.WriteLine("");
if (byte_read == NACK)
{
//Console.WriteLine("NACK received for write memory DATA received");
//Console.WriteLine("");
}
}
}
} // end ELSE if TYPE == 1
counter++;
} // end WHILE loop for loading hex file
file.Close();
//System.Console.WriteLine("There were {0} lines.", counter);
//Console.WriteLine("");
// -- end WRITE MEMORY ------------------------------------------------------
} // end WriteNewAppToFlash
更改了代码以写入一个 256 字节的块。它现在写入两个块并且不会写入第三个块。程序执行到Write行,字节缓冲区已满,但不会发起写入。
if (byteCounter >= 255)
{
// Convert checksum to a byte value
hexChecksum = hexChecksum ^ 0xFF;
byte csByte = Convert.ToByte(hexChecksum);
Byte[] csByte_arr = BitConverter.GetBytes(csByte);
do
{
// send byte array
_serialPort.Write(buffer256, 0, 256);
Thread.Sleep(70);
// send checksum
_serialPort.Write(csByte_arr, 0, 1);
// Receive ACK byte
byte_read = _serialPort.ReadByte();
Thread.Sleep(100);
if (byte_read == NACK)
{
//Console.WriteLine("NACK received for write memory DATA received");
//Console.WriteLine("");
}
} while (byte_read != ACK);
// Clear buffer, reset byte count, set flag to send write cmd and send new addr
Array.Clear(buffer256, 0, buffer256.Length);
byteCounter = 0;
sendAddress = true;
}
我最终让这个应用程序运行,但它运行的确切原因尚不清楚。以下是我查看的内容和所做的更改:
从传输单个字节,然后在 256 字节末尾传输校验和,切换到将 256 放入缓冲区,然后一次传输所有字节,然后传输校验和。这种方法起初失败了,但结果证明比以前的方法更快。
更改了处理十六进制代码行和检查块是否已准备好发送的顺序(参见下面的代码)。差异很小,但似乎最重要的是让整个事情顺利进行。之前,它检查要发送的 256 个字节,发送它,然后将一行中的数据放入下一个 256 块中。我单步执行了代码,没有看到任何会导致它失败的东西,但它一定已经完成了东西。
从那时起,该应用程序运行良好,我对在嵌入式设备上使用 .NET SerialPort class 不再有任何疑虑。
// BLOCK WRITE TO MEMORY
if (type == 0)
{
// Length of line is stored at byte 0, in this case 0x10, or 16 bytes of data
length = bytes[0];
// Add data from current line to buffer of 256 bytes
for (int i = 0; i < length; i++)
{
// Stuff all bytes from line into buffer of 256 bytes
buffer256[byteCounter++] = bytes[4 + i];
// Add byte to checksum
hexChecksum ^= bytes[4 + i];
}
// When buffer is full, send block of 256 bytes and checksum, reset variables for next block
if (byteCounter >= 255)
{
// Convert checksum to a byte value
hexChecksum = hexChecksum ^ 0xFF;
byte csByte = Convert.ToByte(hexChecksum);
Byte[] csByte_arr = BitConverter.GetBytes(csByte);
// Send byte array
_serialPort.Write(buffer256, 0, 256);
// For testing
// Console.WriteLine("block number [{0}]", ++blockCount);
//send checksum
_serialPort.Write(csByte_arr, 0, 1);
//Receive ACK byte
byte_read = _serialPort.ReadByte();
Console.WriteLine("block/ACK = [{0}] | {1}", ++blockCount, byte_read);
while (byte_read != ACK)
{
Array.Clear(buffer256, 0, buffer256.Length);
hexChecksum = 0;
lineCount = 0;
// reprocess the previous 16 lines stored in the line buffer
for ( int j = 0; j < 16; j++ )
{
line = lineBuffer[j];
line = line.Substring(1, line.Length - 1);
var bytesLocal = GetBytesFromByteString(line).ToArray();
length = bytesLocal[0];
for (int i = 0; i < length; i++)
{
buffer256[byteCounter++] = bytesLocal[4 + i];
hexChecksum ^= bytesLocal[4 + i];
}
}
// Convert checksum to a byte value
hexChecksum = hexChecksum ^ 0xFF;
byte csByteLocal = Convert.ToByte(hexChecksum);
Byte[] csByte_arrLocal = BitConverter.GetBytes(csByteLocal);
// Send byte array
_serialPort.Write(buffer256, 0, 256);
//send checksum
_serialPort.Write(csByte_arrLocal, 0, 1);
//Receive ACK byte
byte_read = _serialPort.ReadByte();
Console.WriteLine("block/ACK = [{0}] | {1}", ++blockCount, byte_read);
}
// Clear buffer, reset byte count, clear checksum, set flag to send write cmd/send new addr
Array.Clear(buffer256, 0, buffer256.Length);
byteCounter = 0;
hexChecksum = 0;
lineCount = 0;
sendAddress = true;
}
} // end BLOCK WRITE TO MEMORY
我为设备构建了一个固件更新应用程序,主机应用程序通过串行连接连接到设备。该应用程序一直在开发小型应用程序 (~18KB),我最近将固件大小增加到~200KB。
现在主机应用程序 (C#) 在串行端口写入时挂起,在调试中暂停程序会显示调试器中断。
下图的代码逐行读取 .HEX 文件(未显示)并使用 UART(串行通信)一次写入一个字节的 256 字节块。在 256 字节之后,为该块发送校验和,并留下循环以设置下一次传输。
应用程序挂起写入命令的原因可能是什么?是否有一些端口或缓冲区维护必须在块之间完成?我可以看到块的字节计数器(0 到 255)并且它没有挂在相同的字节数上。
此应用正在连接到 STM32F417IGT 开发板上的 ARM 处理器。
感谢您的帮助!
完成写入功能,在代码中:
public void WriteNewAppToFlash(SerialPort _serialPort)
{
int byte_read = 0;
long checksum = 0;
var ff = new byte[] { 0xFF };
// ------------------------------------------------------------------------------
// -------- WRITE MEMORY --------------------------------------------------------
// ------------------------------------------------------------------------------
// for Address
int baseAddress = 0x08004000;
int offset = 0;
// for string from HEX file
string line;
int length;
int type;
int hexChecksum = 0;
bool sendAddress = true;
int counter = 0; // Counting the number of lines in the file
int byteCounter = 0; // Counting nmumber of bytes in the current block
// Read the file and process one line at a time
System.IO.StreamReader file = new System.IO.StreamReader(path);
while ((line = file.ReadLine()) != null)
{
if (sendAddress == true)
{
/*
-------------------------------------------------------------------------------------------------------
SEND WRITE COMMAND
-----------------------------------------------------------------------------------------------------*/
// Send 0x43 (erase memory) and 0xBC
var writeMem = new byte[] { 0x31 };
var ce = new byte[] { 0xCE };
_serialPort.Write(writeMem, 0, 1);
//Console.WriteLine("writeMem = 0x" + BitConverter.ToInt32(writeMem, 0).ToString("X"));
_serialPort.Write(ce, 0, 1);
//Console.WriteLine("CE = 0x" + BitConverter.ToInt32(writeMem, 0).ToString("X"));
// Receive ACK byte
byte_read = _serialPort.ReadByte();
//Console.WriteLine("ACK = 0x" + byte_read.ToString("X"));
//Console.WriteLine("");
if (byte_read == NACK)
{
//Console.WriteLine("NACK received for WRITE MEMORY start");
//Console.WriteLine("");
}
// -- end SEND 0x31 and 0xCE and wait for ACK -----------------------------------------
-------------------------------------------------------------------------------------------------------
SEND CURRENT ADDRESS AND CHECKSUM TO FLASH MEMORY
-----------------------------------------------------------------------------------------------------*/
Byte[] currentAddr = BitConverter.GetBytes(baseAddress + offset);
// Increment offset by 0x100 (256 bytes)
offset = offset + 0x00000100;
//int msb;
// Reset Checksum and XOR address
checksum = 0;
foreach (byte b in currentAddr)
{
checksum ^= b;
}
//Console.WriteLine("cksum = " + checksum);
Byte[] cksum = BitConverter.GetBytes(checksum);
// Send address, MSB first, LSB last
_serialPort.Write(currentAddr, 3, 1);
_serialPort.Write(currentAddr, 2, 1);
_serialPort.Write(currentAddr, 1, 1);
_serialPort.Write(currentAddr, 0, 1);
// Send checksum of address bytes
_serialPort.Write(cksum, 0, 1);
// Receive ACK byte
byte_read = _serialPort.ReadByte();
//Console.WriteLine("ACK = 0x" + byte_read.ToString("X"));
//Console.WriteLine("");
if (byte_read == NACK)
{
//Console.WriteLine("NACK received for WRITE MEMORY address received");
//Console.WriteLine("");
}
// -- end addr or increment ---------------------------------------------------------
sendAddress = false;
// Send number of bytes, always 256, the last group will be padded with 0xFF
_serialPort.Write(ff, 0, 1);
hexChecksum = 0;
} // end IF for WRITE COMMAND and ADDRESS
/*
-------------------------------------------------------------------------------------------------------
WRITE 256 BYTES FROM HEX FILE TO FLASH MEMORY
-----------------------------------------------------------------------------------------------------*/
// FIRST CHARACTER in HEX FILE
// The colon indicates the start of a "record"
// Remove colon from beginning of string
line = line.Substring(1, line.Length - 1);
//Console.WriteLine(line);
// Create byte array from string
var bytes = GetBytesFromByteString(line).ToArray();
// Assign values to variables from byte array
type = bytes[3];
/* Next TWO CHARACTERS in HEX FILE 00-data
are the record type: 01-EOF
02-
03-
04-
05- */
// Check type for data = 00
if (type == 0)
{
// The first two characters represent the number of data bytes for the record
// Obtain length, convert to int (counter for sending data)
length = bytes[0];
for ( int i = 0; i < length; i++ )
{
// Send individual characters to device
_serialPort.Write(bytes, 4 + i, 1);
//Thread.Sleep(100);
// increment counter
byteCounter++;
if( byteCounter % 32 == 0 )
{
Thread.Sleep(40);
}
// Add byte to checksum
hexChecksum ^= bytes[4 + i];
//Console.WriteLine("cum checksum = " + hexChecksum);
// If counter == 256, reset counter, send checksum
if (byteCounter == 256)
{
sendAddress = true;
byteCounter = 0;
//Console.WriteLine("checksum = " + hexChecksum.ToString("X"));
// Convert checksum to a byte value and send
hexChecksum = hexChecksum ^ 0xFF;
byte csByte = Convert.ToByte(hexChecksum);
//Console.WriteLine("CSBYTE = " + Convert.ToInt32(csByte));
Byte[] csByte_arr = BitConverter.GetBytes(csByte);
_serialPort.Write(csByte_arr, 0, 1);
// Receive ACK byte
byte_read = _serialPort.ReadByte();
//Console.WriteLine("ACK = 0x" + byte_read.ToString("X"));
//Console.WriteLine("");
if (byte_read == NACK)
{
//Console.WriteLine("NACK received for write memory DATA received");
//Console.WriteLine("");
}
} // end IF byteCounter == 256
//Console.WriteLine(byteCounter);
} // end FOR loop
}
else if (type == 5)
{
// Address thingy
//Console.WriteLine("Hit address thingy");
//Console.WriteLine("");
}
else if (type == 1) // Check for end of file
{
// End of file
while (byteCounter != 0)
{
// Send individual bytes to device
_serialPort.Write(ff, 0, 1);
// increment counter
byteCounter++;
// Add byte to checksum
hexChecksum ^= 0xFF;
//Console.WriteLine("cum checksum = " + hexChecksum);
if (byteCounter == 256)
{
byteCounter = 0;
hexChecksum = hexChecksum ^ 0xFF;
byte csByte = Convert.ToByte(hexChecksum);
//Console.WriteLine("CSBYTE = " + Convert.ToInt32(csByte));
Byte[] csByte_arr = BitConverter.GetBytes(csByte);
_serialPort.Write(csByte_arr, 0, 1);
// Receive ACK byte
byte_read = _serialPort.ReadByte();
//Console.WriteLine("ACK = 0x" + byte_read.ToString("X"));
//Console.WriteLine("");
if (byte_read == NACK)
{
//Console.WriteLine("NACK received for write memory DATA received");
//Console.WriteLine("");
}
}
}
} // end ELSE if TYPE == 1
counter++;
} // end WHILE loop for loading hex file
file.Close();
//System.Console.WriteLine("There were {0} lines.", counter);
//Console.WriteLine("");
// -- end WRITE MEMORY ------------------------------------------------------
} // end WriteNewAppToFlash
更改了代码以写入一个 256 字节的块。它现在写入两个块并且不会写入第三个块。程序执行到Write行,字节缓冲区已满,但不会发起写入。
if (byteCounter >= 255)
{
// Convert checksum to a byte value
hexChecksum = hexChecksum ^ 0xFF;
byte csByte = Convert.ToByte(hexChecksum);
Byte[] csByte_arr = BitConverter.GetBytes(csByte);
do
{
// send byte array
_serialPort.Write(buffer256, 0, 256);
Thread.Sleep(70);
// send checksum
_serialPort.Write(csByte_arr, 0, 1);
// Receive ACK byte
byte_read = _serialPort.ReadByte();
Thread.Sleep(100);
if (byte_read == NACK)
{
//Console.WriteLine("NACK received for write memory DATA received");
//Console.WriteLine("");
}
} while (byte_read != ACK);
// Clear buffer, reset byte count, set flag to send write cmd and send new addr
Array.Clear(buffer256, 0, buffer256.Length);
byteCounter = 0;
sendAddress = true;
}
我最终让这个应用程序运行,但它运行的确切原因尚不清楚。以下是我查看的内容和所做的更改:
从传输单个字节,然后在 256 字节末尾传输校验和,切换到将 256 放入缓冲区,然后一次传输所有字节,然后传输校验和。这种方法起初失败了,但结果证明比以前的方法更快。
更改了处理十六进制代码行和检查块是否已准备好发送的顺序(参见下面的代码)。差异很小,但似乎最重要的是让整个事情顺利进行。之前,它检查要发送的 256 个字节,发送它,然后将一行中的数据放入下一个 256 块中。我单步执行了代码,没有看到任何会导致它失败的东西,但它一定已经完成了东西。
从那时起,该应用程序运行良好,我对在嵌入式设备上使用 .NET SerialPort class 不再有任何疑虑。
// BLOCK WRITE TO MEMORY
if (type == 0)
{
// Length of line is stored at byte 0, in this case 0x10, or 16 bytes of data
length = bytes[0];
// Add data from current line to buffer of 256 bytes
for (int i = 0; i < length; i++)
{
// Stuff all bytes from line into buffer of 256 bytes
buffer256[byteCounter++] = bytes[4 + i];
// Add byte to checksum
hexChecksum ^= bytes[4 + i];
}
// When buffer is full, send block of 256 bytes and checksum, reset variables for next block
if (byteCounter >= 255)
{
// Convert checksum to a byte value
hexChecksum = hexChecksum ^ 0xFF;
byte csByte = Convert.ToByte(hexChecksum);
Byte[] csByte_arr = BitConverter.GetBytes(csByte);
// Send byte array
_serialPort.Write(buffer256, 0, 256);
// For testing
// Console.WriteLine("block number [{0}]", ++blockCount);
//send checksum
_serialPort.Write(csByte_arr, 0, 1);
//Receive ACK byte
byte_read = _serialPort.ReadByte();
Console.WriteLine("block/ACK = [{0}] | {1}", ++blockCount, byte_read);
while (byte_read != ACK)
{
Array.Clear(buffer256, 0, buffer256.Length);
hexChecksum = 0;
lineCount = 0;
// reprocess the previous 16 lines stored in the line buffer
for ( int j = 0; j < 16; j++ )
{
line = lineBuffer[j];
line = line.Substring(1, line.Length - 1);
var bytesLocal = GetBytesFromByteString(line).ToArray();
length = bytesLocal[0];
for (int i = 0; i < length; i++)
{
buffer256[byteCounter++] = bytesLocal[4 + i];
hexChecksum ^= bytesLocal[4 + i];
}
}
// Convert checksum to a byte value
hexChecksum = hexChecksum ^ 0xFF;
byte csByteLocal = Convert.ToByte(hexChecksum);
Byte[] csByte_arrLocal = BitConverter.GetBytes(csByteLocal);
// Send byte array
_serialPort.Write(buffer256, 0, 256);
//send checksum
_serialPort.Write(csByte_arrLocal, 0, 1);
//Receive ACK byte
byte_read = _serialPort.ReadByte();
Console.WriteLine("block/ACK = [{0}] | {1}", ++blockCount, byte_read);
}
// Clear buffer, reset byte count, clear checksum, set flag to send write cmd/send new addr
Array.Clear(buffer256, 0, buffer256.Length);
byteCounter = 0;
hexChecksum = 0;
lineCount = 0;
sendAddress = true;
}
} // end BLOCK WRITE TO MEMORY