В предыдущей статье в класс 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 SortedDictionaryRead_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( KeyValuePairkvp 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] .