В предыдущей статье в класс Dumps.cs был добавлен модуль чтения данных из памяти STM8. В этой статье добавляем модули записи в RAM и копирования в RAM. Включаем в командную строку файл прошивки, извлекаем содержимое, помещаем в RAM, копируем из EEPROM в RAM.
Внесены изменения в классы [FileOpenMemorySorting], [IntelHEXfile], [MotorolaS19file].
Файл Dumps.cs :
// Dumps.cs
using System;
using System.IO;
using System.IO.Ports;
using System.Threading;
using System.Collections.Generic;
public class Dumps
{
public Dumps()
{
//Load_Dump(ReadByte_128000v14);
// переходим на общение с отправленным дампом, меняем скорость COM-порта
// sPort.BaudRate = 128000;
}// Dumps()
public static void Load_First_Dump(byte[] dmp){
// метод вызывается при загрузке первого блока в верхние адреса RAM после нажатия кнопки сброса
byte[] dmpToLoad = dmp;
Console.WriteLine("Ждем байт 0x14 версии загрузчика. Нажми кнопку сброса на плате.");
while(unready)
{
while(queueBytes.Count == 0){} rx_byte = queueBytes.Dequeue();
//while(sPort.BytesToRead == 0){} rx_byte = (byte)sPort.ReadByte(); // ждем версию загрузчика
if(rx_byte == 0x14)
{
Console.WriteLine("Принят байт 0x{0:X2} от boot_OPTION", rx_byte);
byte[] txBytes = {(byte)dmpToLoad.Length};
sPort.Write(txBytes, 0, 1); // отправляем размер дампа
unready = false;
} else Console.WriteLine("Принят байт 0x{0:X2}. Нажми кнопку сброса на плате.", rx_byte);
}//while(unready)
sPort.Write(dmpToLoad, 0, dmpToLoad.Length); // отправляем сам дамп
while(sPort.BytesToWrite > 0){}
Thread.Sleep(500); // подождем пока очистится буфер передачи
sPort.BaudRate = 128000;
Thread.Sleep(10);
Console.WriteLine();
}// Load_first_Dump()
public static void Load_Dump(byte[] dmp){
// метод вызывается при замене блока в верхних адресах RAM памяти
// необходимо отправить команду загруженному блоку в формате { GO cmd, YH, YL, go_adrH, go_adrL, cntr }
err_Msg = "OK";
byte[] dmpToLoad = dmp;
go_bytes[0] = 0xF5; // GO cmd команда перехода
// go_bytes[1] = 0x00; // YH не для этого метода
// go_bytes[2] = 0x00; // YL не для этого метода
go_bytes[3] = 0x00; // go_adrH старший байт требуемого адреса boot_OPTION
go_bytes[4] = 0x17; // go_adrL младший байт требуемого адреса boot_OPTION
go_bytes[5] = (byte)dmpToLoad.Length; // cntr размер следующего к загрузке блока
queueBytes.Clear(); // очистим очередь приема
sPort.Write(go_bytes, 0, 1); // передаем команду $F5
while(queueBytes.Count == 0){} rx_byte = queueBytes.Dequeue();
if ( rx_byte != go_bytes[0] ){
err_Msg = "Эхо не соответствует команде 0xF5";
return; }
sPort.Write(go_bytes, 1, go_bytes.Length-1); // передаем адреса и размер модуля
sPort.Write(dmpToLoad, 0, dmpToLoad.Length); // передаем сам модуль
while(sPort.BytesToWrite > 0){} Console.WriteLine("Модуль отправлен в boot_OPTION\n");
Thread.Sleep(10);
}// Load_Dump()
public static SortedDictionary Read_128000(int adr, int cntr){
err_Msg = "OK";
int addrSpc = adr; // начальный адрес оласти памяти для выгрузки (адрес первого блока)
int cntrSpc = cntr; // размер оласти памяти для выгрузки
int sizeBlck = 64; // размер блока
SortedDictionary AddressByte = new SortedDictionary();
AddressByte.Clear();
if ( addrSpc < 0x0000 | addrSpc >= 0xF000){
err_Msg = "Адрес должен быть в диапазоне 0x0000...0xEFFF";
return AddressByte;
}
int j = sizeBlck; // размер блока 64 байта
queueBytes.Clear(); // очистим очередь приема
for (; cntrSpc > 0; ){
if(cntrSpc > 64) j = sizeBlck; else j = cntrSpc;
//Console.WriteLine(" ${0:X4}", addrSpc);
//queueBytes.Clear(); // очистим очередь приема
tx2Bytes[0] = (byte)(addrSpc>>8);
tx2Bytes[1] = (byte)addrSpc;
sPort.Write(tx2Bytes, 0, 1); // отправляем старший байт адрес блока / команду
while(queueBytes.Count == 0){} rx_byte = queueBytes.Dequeue();
//Console.WriteLine("Принят байт 0x{0:X2}.", rx_byte);
if ( rx_byte != tx2Bytes[0] ){
err_Msg = "Эхо не соответствует старшему байту адреса";
return AddressByte;}
sPort.Write(tx2Bytes, 1, 1); // отправляем младший байт адрес блока
tx2Bytes[0] = (byte)j;
sPort.Write(tx2Bytes, 0, 1); // отправляем размер блока
while(sPort.BytesToWrite > 0){}
for (; j > 0x0000; addrSpc++){ // принимаем 64 байта
while(queueBytes.Count == 0){} rx_byte = queueBytes.Dequeue();
//Console.WriteLine(" ${0:X4} ${1:X2} {2}", addrSpc, rx_byte, cntrSpc);
AddressByte.Add(addrSpc, rx_byte);
cntrSpc--; j--;
}
Thread.Sleep(100);
}
//Console.WriteLine();
return AddressByte;
}// ReadB_128000()
public static void Write_RAM_128000(SortedDictionary adrBt){
err_Msg = "OK";
SortedDictionary AddressByte = new SortedDictionary(adrBt);
queueBytes.Clear(); // очистим очередь приема
foreach( KeyValuePair kvp in AddressByte ){
if ( kvp.Key < 0x0000 | kvp.Key > 0x03FF){
err_Msg = "Адрес должен быть в диапазоне $0000...#03FF.";
return;}
tx2Bytes[0] = (byte)(kvp.Key>>8);
tx2Bytes[1] = (byte)kvp.Key;
sPort.Write(tx2Bytes, 0, 1); // отправляем старший байт адрес блока / команду
while(queueBytes.Count == 0){} rx_byte = queueBytes.Dequeue();
//Console.WriteLine("Принят байт 0x{0:X2}.", rx_byte);
if ( rx_byte != tx2Bytes[0] ){
err_Msg = "Эхо не соответствует старшему байту адреса";
return;}
sPort.Write(tx2Bytes, 1, 1); // отправляем младший байт адрес блока
tx2Bytes[0] = (byte)kvp.Value.Length;
sPort.Write(tx2Bytes, 0, 1); // отправляем размер блока
sPort.Write(kvp.Value, 0, kvp.Value.Length); // отправляем сам блок
while(sPort.BytesToWrite > 0){}
while(queueBytes.Count == 0){} rx_byte = queueBytes.Dequeue();
//Console.WriteLine("Принят байт 0x{0:X2}.", rx_byte);
if ( rx_byte != 0xFA ){
err_Msg = "Ответ модуля не равен OK $FA";
return;}
}
return;
}// Write_RAM_128000()
public static void Copy_RAM_128000(int adrDst, int adrSrc, int cntr){
err_Msg = "OK";
int dstAdrCopy = adrDst;
int srcAdrCopy = adrSrc;
int cntrCopy = cntr;
if ( dstAdrCopy < 0x0000 | (dstAdrCopy + cntrCopy) > 0x03FF){
err_Msg = "Адреса для копирования должны быть в диапазоне $0000...#03FF.";
return;}
queueBytes.Clear(); // очистим очередь приема
int j;
for (; cntrCopy > 0; ){
if(cntrCopy > 255) j = 255; else j = cntrCopy;
tx2Bytes[0] = (byte)(dstAdrCopy>>8);
tx2Bytes[1] = (byte)dstAdrCopy;
sPort.Write(tx2Bytes, 0, 1); // отправляем старший байт адреса назначения / команду
while(queueBytes.Count == 0){} rx_byte = queueBytes.Dequeue();
//Console.WriteLine("Принят байт 0x{0:X2}.", rx_byte);
if ( rx_byte != tx2Bytes[0] ){
err_Msg = "Эхо не соответствует старшему байту адреса";
return;} else Console.WriteLine("Эхо соответствует старшему байту адреса");
sPort.Write(tx2Bytes, 1, 1); // отправляем младший байт байт адреса назначения
tx2Bytes[0] = (byte)(srcAdrCopy>>8);
tx2Bytes[1] = (byte)srcAdrCopy;
sPort.Write(tx2Bytes, 0, 2); // отправляем адрес источника
tx2Bytes[0] = (byte)j;
sPort.Write(tx2Bytes, 0, 1); // отправляем размер блока для копирования
while(queueBytes.Count == 0){} rx_byte = queueBytes.Dequeue();
//Console.WriteLine("Принят байт 0x{0:X2}.", rx_byte);
if ( rx_byte != 0xFA ){
err_Msg = "Ответ модуля не равен OK $FA";
return;} else Console.WriteLine("Ответ модуля равен OK $FA");
dstAdrCopy = dstAdrCopy + j;
srcAdrCopy = srcAdrCopy + j;
cntrCopy = cntrCopy - j;
}
return;
}// Copy_RAM_128000()
public static void COM_port_Open(){
// инициализация COM порта
if(SerialPort.GetPortNames().Length == 0)
{ Console.WriteLine("COM порты не найдены");
Console.ReadKey();
return;}
Console.WriteLine("Доступны COM порты:");
foreach (string s in SerialPort.GetPortNames())
{
Console.WriteLine(" {0}", s);
portName = s;
}
// создаем экземпляр COM-порта с настройками для общения с начальным загрузчиком
sPort = new SerialPort(portName, 9600, Parity.None, 8, StopBits.One);
try
{
sPort.Open(); //открываем COM порт
}
catch (ThreadAbortException) {Console.WriteLine("sPort.Open() ThreadAbortException"); }
catch (IOException) {Console.WriteLine("sPort.Open() IOException"); }
catch (TimeoutException) {Console.WriteLine("sPort.Open() TimeoutException"); }
catch (Exception ex) { Console.WriteLine("sPort.Open() Exception" + ex.Message + "\n: read()"); }
queueBytes = new Queue();
queueBytes.Clear();
}
public static void COM_port_Close(){
//readThread.Join(); // останавливаем поток чтения COM порта
sPort.Close(); // закрываем COM порт
}
public static void Read()
{
while (inCycle)
{
if (sPort.IsOpen)
{
try
{
if(sPort.BytesToRead > 0){
queueBytes.Enqueue((byte)sPort.ReadByte());
//Console.WriteLine((byte)sPort.ReadByte());
}
} catch (TimeoutException) {Console.WriteLine("Read. TimeoutException"); }
}
//}
}
}// Read()
public static void Dump_To_Console(SortedDictionary rxAB){
SortedDictionary AddressByte = new SortedDictionary(rxAB);
if(Dumps.err_Msg == "OK"){ Console.Write(Dumps.err_Msg);
int i = 0; int predAdr = 0;
foreach( KeyValuePair kvp in AddressByte){
if (i == 0) { Console.Write("\n ${0:X4} ", kvp.Key);
predAdr = kvp.Key;}
else { if( (kvp.Key % 16) == 0 | (kvp.Key - predAdr) > 1) Console.Write("\n ${0:X4} ", kvp.Key); }
Console.Write("${0:X2} ", kvp.Value);
i++;
predAdr = kvp.Key;
}// foreach
}else Console.WriteLine("\n" + Dumps.err_Msg);
Console.WriteLine("\n");
}
public readonly static byte[] Read_128000v14 = { 0x00,
0x00, 0xFE, 0x03, 0xCC, 0x72, 0x94, 0xFF, 0x03, 0xAE, 0x31, 0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B,
0x72, 0xFF, 0x03, 0x31, 0x52, 0x55, 0xFB, 0x30, 0x52, 0x0B, 0x72, 0xFE, 0x03, 0x31, 0x52, 0x55,
0xFB, 0x30, 0x52, 0x0B, 0x72, 0x95, 0x90, 0x31, 0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B, 0x72, 0x95,
0x90, 0x31, 0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B, 0x72, 0xFB, 0x30, 0x52, 0x0F, 0x72, 0x31, 0x52,
0xC7, 0xA5, 0x20, 0xF7, 0x30, 0x52, 0x0F, 0x72, 0x31, 0x52, 0xF1, 0x35, 0x0B, 0x27, 0xF5, 0xA1,
0xB4, 0x20, 0x08, 0x50, 0x1B, 0x72, 0x07, 0x50, 0x1B, 0x72, 0xF2, 0x26, 0x5A, 0x90, 0x5C, 0xFB,
0x30, 0x52, 0x0F, 0x72, 0x31, 0x52, 0xC7, 0xF6, 0x08, 0x50, 0x1A, 0x72, 0x07, 0x50, 0x1A, 0x72,
0x97, 0x90, 0x31, 0x52, 0xC6, 0x95, 0x90, 0x00, 0xA6, 0xFB, 0x30, 0x52, 0x0B, 0x72, 0x97, 0x31,
0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B, 0x72, 0xFB, 0x30, 0x52, 0x0F, 0x72, 0x31, 0x52, 0xC7, 0x95,
0x40, 0x22, 0xEF, 0xA1, 0x31, 0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B, 0x72, 0x35, 0x52, 0x0C, 0x35,
0x32, 0x52, 0x01, 0x35, 0x33, 0x52, 0x00, 0x35 };
public readonly static byte[] Wtite_RAM_128000v14 = { 0x00,
0x00, 0xFE, 0x03, 0xCC, 0x72, 0x94, 0xFF, 0x03, 0xAE, 0x31, 0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B,
0x72, 0xFF, 0x03, 0x31, 0x52, 0x55, 0xFB, 0x30, 0x52, 0x0B, 0x72, 0xFE, 0x03, 0x31, 0x52, 0x55,
0xFB, 0x30, 0x52, 0x0B, 0x72, 0x95, 0x90, 0x31, 0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B, 0x72, 0x95,
0x90, 0x31, 0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B, 0x72, 0xFB, 0x30, 0x52, 0x0F, 0x72, 0x31, 0x52,
0xC7, 0x9C, 0x20, 0xFB, 0x30, 0x52, 0x0F, 0x72, 0x31, 0x52, 0xF1, 0x35, 0x0B, 0x27, 0xF5, 0xA1,
0xAB, 0x20, 0x08, 0x50, 0x1B, 0x72, 0x07, 0x50, 0x1B, 0x72, 0xFB, 0x30, 0x52, 0x0F, 0x72, 0x31,
0x52, 0xFA, 0x35, 0xF2, 0x26, 0x5A, 0x90, 0x5C, 0xF7, 0x31, 0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B,
0x72, 0x08, 0x50, 0x1A, 0x72, 0x07, 0x50, 0x1A, 0x72, 0x97, 0x90, 0x31, 0x52, 0xC6, 0x00, 0x00,
0xAE, 0x90, 0xFB, 0x30, 0x52, 0x0B, 0x72, 0x97, 0x31, 0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B, 0x72,
0xFB, 0x30, 0x52, 0x0F, 0x72, 0x31, 0x52, 0xC7, 0x95, 0x49, 0x22, 0xEF, 0xA1, 0x31, 0x52, 0xC6,
0xFB, 0x30, 0x52, 0x0B, 0x72, 0x35, 0x52, 0x0C, 0x35, 0x32, 0x52, 0x01, 0x35, 0x33, 0x52, 0x00,
0x35 };
public readonly static byte[] Copy_RAM_128000v14 = { 0x00,
0x00, 0xFE, 0x03, 0xCC, 0x72, 0x94, 0xFF, 0x03, 0xAE, 0x31, 0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B,
0x72, 0xFF, 0x03, 0x31, 0x52, 0x55, 0xFB, 0x30, 0x52, 0x0B, 0x72, 0xFE, 0x03, 0x31, 0x52, 0x55,
0xFB, 0x30, 0x52, 0x0B, 0x72, 0x95, 0x90, 0x31, 0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B, 0x72, 0x95,
0x90, 0x31, 0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B, 0x72, 0xFB, 0x30, 0x52, 0x0F, 0x72, 0x31, 0x52,
0xC7, 0x8E, 0x20, 0xFB, 0x30, 0x52, 0x0F, 0x72, 0x31, 0x52, 0xF1, 0x35, 0x0B, 0x27, 0xF5, 0xA1,
0x9D, 0x20, 0x08, 0x50, 0x1B, 0x72, 0x07, 0x50, 0x1B, 0x72, 0xFB, 0x30, 0x52, 0x0F, 0x72, 0x31,
0x52, 0xFA, 0x35, 0xF4, 0x26, 0xFF, 0x03, 0x5A, 0x72, 0x5C, 0x5C, 0x90, 0xF7, 0xF6, 0x90, 0x08,
0x50, 0x1A, 0x72, 0x07, 0x50, 0x1A, 0x72, 0xFF, 0x03, 0x31, 0x52, 0x55, 0xFB, 0x30, 0x52, 0x0B,
0x72, 0x97, 0x90, 0x31, 0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B, 0x72, 0x95, 0x90, 0x31, 0x52, 0xC6,
0xFB, 0x30, 0x52, 0x0B, 0x72, 0x97, 0x31, 0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B, 0x72, 0xFB, 0x30,
0x52, 0x0F, 0x72, 0x31, 0x52, 0xC7, 0x95, 0x57, 0x22, 0xEF, 0xA1, 0x31, 0x52, 0xC6, 0xFB, 0x30,
0x52, 0x0B, 0x72, 0x35, 0x52, 0x0C, 0x35, 0x32, 0x52, 0x01, 0x35, 0x33, 0x52, 0x00, 0x35 };
public static bool inCycle = true;
public static Queue queueBytes;
public static Thread readThread;
public static SerialPort sPort;
public static string portName;
public static SortedDictionary rxAddressByte;
//public static ArrayList adrArrayList;
//public static ArrayList btArrayList;
public static bool unready = true;
public static byte rx_byte;
public static string err_Msg = "OK";
public static byte[] rx1Byte = new byte[1];
public static byte[] tx2Bytes = new byte[2];
public static byte[] rx4Bytes = new byte[4];
public static byte[] rx64Bytes = new byte[64];
public static byte[] tx64Bytes = new byte[64];
public static byte[] go_bytes = { 0xF5, 0x00, 0x00, 0x00, 0x17, 0x00}; // { GO cmd, YH, YL, go_adrH, go_adrL, cntr }
}// class Dumps
// Dumps.cs
Файл STM8uLoader.cs :
// STM8uLoader.cs
using System;
using System.IO;
using System.IO.Ports;
using System.Threading;
using System.Collections.Generic;
public class STM8uLoader
{
public static void Main(string[] arg) {
if (arg.Length == 0) {Console.WriteLine("Отсутствуют аргументы командной строки");
Console.ReadKey(); return;}
else fileName = arg[0];
Console.WriteLine("Обнаружены {0} аргумент(ов) командной строки", arg.Length);
foreach(string strArg in arg){
Console.WriteLine(strArg);
}//foreach
FileOpenMemorySorting fileSorted = new FileOpenMemorySorting(fileName);
Console.Write("Из файла");
foreach( KeyValuePair kvp in fileSorted.GetRAMaddressLineSorted() ){
Console.Write("\n${0:X4} ", kvp.Key);
for(int i = 0; i < kvp.Value.Length; i++) Console.Write("${0:X2} ", kvp.Value[i]);
}// foreach
Console.WriteLine("\n");
//Dumps myDumps = new Dumps();
Dumps.COM_port_Open();
readThread = new Thread(Dumps.Read);
readThread.IsBackground = true; // не позволит остаться потоку в памяти после закрытия программы ?
try {
readThread.Start(); // запускаем поток чтения COM порта
} catch (Exception ex) {Console.WriteLine("readThread.Start(). Exception" + ex.Message); }
Dumps.Load_First_Dump(Dumps.Read_128000v14);
blckAdr = 0x0100; blckSize = 178;
Console.WriteLine("Из памяти до записи");
Dumps.Damp_To_Console(Dumps.Read_128000(blckAdr, blckSize));
Dumps.Load_Dump(Dumps.Wtite_RAM_128000v14);
Console.WriteLine("пишем в память");
Dumps.Write_RAM_128000(fileSorted.GetRAMaddressLineSorted());
Dumps.Load_Dump(Dumps.Read_128000v14);
blckAdr = 0x0100; blckSize = 178;
Console.WriteLine("Из памяти после записи");
Dumps.Damp_To_Console(Dumps.Read_128000(blckAdr, blckSize));
Dumps.Load_Dump(Dumps.Copy_RAM_128000v14);
Console.WriteLine("Копируем из EEPROM в RAM");
Dumps.Copy_RAM_128000(0x0100, 0x4000, 255);
Dumps.Load_Dump(Dumps.Read_128000v14);
blckAdr = 0x4000; blckSize = 255;
Console.WriteLine("Из EEPROM");
Dumps.Damp_To_Console(Dumps.Read_128000(blckAdr, blckSize));
blckAdr = 0x0100; blckSize = 255;
Console.WriteLine("Из памяти после копирования");
Dumps.Damp_To_Console(Dumps.Read_128000(blckAdr, blckSize));
readThread.Join(); // останавливаем поток чтения COM порта
Dumps.COM_port_Close();
Console.ReadKey(); return;
} // Main();
public static Thread readThread;
public static string stringMemoryMap = "";
public static byte rx_byte = 0x00;
public static byte[] btBytes = new byte[1];
public static byte[] wrd4Bytes = new byte[4];
public static byte[] blck64Bytes = new byte[64];
public static int blckAdr;
public static int blckSize;
public static bool unready = true;
public static string fileName;
public static byte[] txBytes = {0, 0};
}// class STM8uLoader
// STM8uLoader.cs
В BAT файле добавляем файл прошивки в командную строку. Запускаем файл [run.bat], нажимаем кнопку сброса на плате STM8.
В следующей статье добавим в класс Dumps.cs модули записи в EEPROM память.
Исходники:[boot_PC.zip] , [RAM_0100.asm] , [Wtite_RAM_128000v14.asm] , [Copy_RAM_128000v14.asm] .