NFLic

STM8uLoader

Создатель дампов. (Статья 6)

В предыдущей статье первый блок для загрузки мы подгружали извне с помощью командной строки. Ввиду того, что энергонезависимая память в STM8 пишется/стирается байтами, словами (4 байта), блоками (64 байта) и у областей EEPROM, OPTION, FLASH различные сигнатуры/регистры разрешения записи/стирания нам потребуется некоторое количество различных дампов для поочередной передачи в загрузчик. Логично было бы хранить все необходимые дампы в исходном коде в виде, напр. (не забываем об обратом порядке байтов):

 

       public readonly byte[] ReadBlock_128000 = {0x00, ..., 0x01};

 

В этой статье пишем создатель дампов который

- принимает в командной строке файл прошивки;

- извлекает из области RAM массив байтов;

- изменяет порядок байтов в массиве на обратный;

- создает текстовый файл с именем как у файла прошивки;

- создает переменну типа byte[] с имененм как у файла прошивки;

- инициализирует переменную массивом байтов;

- сохраняет в текстовый файл;

- выходит.

 

Классы [FileOpenMemorySorting], [IntelHEXfile], [MotorolaS19file]. Файл dump_creator.cs :

 

// dump_creator.cs
using System;
using System.IO;
using System.Collections.Generic;

public partial class Dump_creator
{
	
	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
		Console.WriteLine("Загружен файл {0}", fileName);
		
		fileToWrite = fileName.Replace(".s19", "");
		fileToWrite = fileToWrite.Replace(".S19", "");
		fileToWrite = fileToWrite.Replace(".hex", "");
		fileToWrite = fileToWrite.Replace(".HEX", "");
		
		stringDump = stringDump + fileToWrite + " = { ";
						
		FileOpenMemorySorting fileSorted = new FileOpenMemorySorting(fileName);
		
		List list_Bytes = new List();
		list_Bytes.Clear();
		
		Console.Write("\nRAM memory:");
		foreach( KeyValuePair kvp in fileSorted.GetRAMaddressByteSorted() ){
			//if(kvp.Key % 16 == 0) Console.Write("\n${0:X4} ", kvp.Key);
			if(kvp.Key % 16 == 0) Console.Write("\n${0:X4} ", kvp.Key);
			Console.Write("${0:X2} ", kvp.Value);
		}// foreach
		Console.WriteLine("\n");
		
		
		// извлечем дамп для RAM памяти
		foreach( KeyValuePair kvp in fileSorted.GetAllMemoryaddressByteSorted() ){
			list_Bytes.Add(kvp.Value);
		}// foreach
		list_Bytes.Reverse();  // дамп должен быть передан в обратном порядке
		byte[] bytesDump = list_Bytes.ToArray();

		for(int i = 0; i < bytesDump.Length; i++){
			stringDump = stringDump + String.Format("0x{0:X2}", bytesDump[i]);
			if(i < bytesDump.Length - 1) stringDump = stringDump + ", ";
			if(i % 16 == 0) stringDump = stringDump + "\n";	
		}
		
		stringDump = stringDump + " };\n";
		Console.WriteLine(stringDump);
		
		StreamWriter fstr_out;

		try {
			fstr_out = new StreamWriter(fileToWrite + ".txt");
		}
		catch(IOException exc) {
			Console.WriteLine(exc.Message);
			Console.ReadLine();
			return;
		}
		
			try {
				fstr_out.WriteLine(stringDump);
			}
			catch(IOException exc) {
				Console.WriteLine(exc.Message);
				Console.ReadLine();
				return;
			}			

		fstr_out.Close();


		Console.ReadKey(); return;
    } // Main();
	public static string stringDump = "   public readonly byte[] ";
	public readonly byte[] ReadBlock_128000 = {0x00, 0x01};
	public static string fileName;	
	public static string fileToWrite;	
}
// dump_creator.cs

 

Файл first_block.s19 (из предыдущей статьи) :

 

S00600004844521B
S11300003500523335015232350C5235720B5230B1
S1130010FBC6523195720B5230FBC6523197721A9D
S11300205007721A50083520523690AE0040F6C779
S11300305231720F5230FB5C905A26F2721B5007F9
S1090040721B500820C6EB
S9030000FC

 

Файл run.bat :

 

dump_creator first_block.s19 
pause

 

Программа, прошивка, bat-ник одним архивом[dump_creator.zip].

 

Запускаем bat файл:.

 

 

Созданный программой файл first_block.txt :

 

   public readonly static byte[] first_block = { 0xC6, 
0x20, 0x08, 0x50, 0x1B, 0x72, 0x07, 0x50, 0x1B, 0x72, 0xF2, 0x26, 0x5A, 0x90, 0x5C, 0xFB, 0x30, 
0x52, 0x0F, 0x72, 0x31, 0x52, 0xC7, 0xF6, 0x40, 0x00, 0xAE, 0x90, 0x36, 0x52, 0x20, 0x35, 0x08, 
0x50, 0x1A, 0x72, 0x07, 0x50, 0x1A, 0x72, 0x97, 0x31, 0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B, 0x72, 
0x95, 0x31, 0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B, 0x72, 0x35, 0x52, 0x0C, 0x35, 0x32, 0x52, 0x01, 
0x35, 0x33, 0x52, 0x00, 0x35 };

 

Исходники:[dump_creator_src.zip] и [first_block_asm.zip] .

 

Теперь самое время пересобрать проект C# из предыдущей статьи путем вставки полученного дампа в исходный код. Добавим также запись содержимого памяти STMS103F3 в файл stringMemoryMap.txt

Файл STM8S103F3 uLoader.cs :

 

// STM8uLoader.cs
using System;
using System.IO;
using System.IO.Ports;
using System.Threading;
using System.Collections.Generic;

public partial class STM8S103F3 uLoader
{
	
	public static void Main()   { 
		
		
		// инициализация 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);
		sPort.ReadBufferSize = 20000;
		sPort.Open();		//открываем COM порт
		//queueBytes = new Queue();
		//readThread = new Thread(Read);
		//readThread.Start();		// запускаем поток чтения COM порта
		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);
				Console.WriteLine("Отправляем размер 0x{0:X2} байт блока", first_block.Length);		
				byte[] txBytes = {(byte)first_block.Length};
				sPort.Write(txBytes, 0, 1); // отправляем размер дампа
				unready = false;
			}

		}//while(unready)

		sPort.Write(first_block, 0, first_block.Length);				// отправляем сам дамп
		Thread.Sleep(500); // подождем пока очистится буфер передачи

		// переходим на общение с отправленным дампом, меняем скорость COM-порта
		sPort.BaudRate = 128000;
		 // где-то здесь не плохо бы очистить приемный буфер COM-порта
		
		int i = 0x0000;	// адрес первого блока
		//queueBytes.Clear(); // очистим очередь приема
		for (; i <= 0x9FFF; ){
			Console.WriteLine();
			//Console.WriteLine("${0:X4} ", i);
			
			int j = 0x003F;  // размер блока 64 байта
		
			byte[] txBytes = {(byte)(i>>8), (byte)i};
			sPort.Write(txBytes, 0, txBytes.Length); // отправляем адрес текущего блока

			Thread.Sleep(20000*j/sPort.BaudRate); // 2994 для sPort.BaudRate == 64000 и j == 0x1FFF

			for (; j >= 0x0000; i++, j-- ){ // принимаем 64 байта
				//while(queueBytes.Count == 0){}  rx_byte = queueBytes.Dequeue();
				while(sPort.BytesToRead == 0){}  rx_byte = (byte)sPort.ReadByte();
				//if((j+1) % 32 == 0) Console.Write("\n${0:X4} ", i);
				if((j+1) % 16 == 0) Console.Write("\n${0:X4} ", i);
				Console.Write("${0:X2} ", rx_byte);
				//if (j==0x0000 | j==0x0010 | j==0x0020 | j==0x0030) Console.WriteLine(); // 16 байт в строке
				//if (j==0x0000 | j==0x0020 ) Console.WriteLine(); // 32 байта в строке
			}
		}//for (; i <= 0x9FFF; )
		Console.WriteLine();
		
		Console.Write("\nПодождите идет повторное чтение памяти с записью в файл.\n");
		
		// повторим в файл
		i = 0x0000;	// адрес первого блока
		//queueBytes.Clear(); // очистим очередь приема
		for (; i <= 0x9FFF; ){
			//Console.WriteLine();
			stringMemoryMap = stringMemoryMap + "\n";
			//Console.WriteLine("${0:X4} ", i);
			
			int j = 0x003F;  // размер блока 64 байта
		
			byte[] txBytes = {(byte)(i>>8), (byte)i};
			sPort.Write(txBytes, 0, txBytes.Length); // отправляем адрес текущего блока

			Thread.Sleep(20000*j/sPort.BaudRate); // 2994 для sPort.BaudRate == 64000 и j == 0x1FFF

			for (; j >= 0x0000; i++, j-- ){ // принимаем 64 байта
				//while(queueBytes.Count == 0){}  rx_byte = queueBytes.Dequeue();
				while(sPort.BytesToRead == 0){}  rx_byte = (byte)sPort.ReadByte();
				//if((j+1) % 32 == 0) Console.Write("\n${0:X4} ", i);
				if((j+1) % 16 == 0) stringMemoryMap = stringMemoryMap + String.Format("\n${0:X4} ", i);
				//if((j+1) % 16 == 0) Console.Write("\n${0:X4} ", i);
				stringMemoryMap = stringMemoryMap + String.Format("${0:X2} ", rx_byte);
				//Console.Write("${0:X2} ", rx_byte);
				//if (j==0x0000 | j==0x0010 | j==0x0020 | j==0x0030) Console.WriteLine(); // 16 байт в строке
				//if (j==0x0000 | j==0x0020 ) Console.WriteLine(); // 32 байта в строке
			}
		}//for (; i <= 0x9FFF; )
		stringMemoryMap = stringMemoryMap + "\n";

		
		StreamWriter fstr_out;

		try {
			fstr_out = new StreamWriter("stringMemoryMap.txt");
		}
		catch(IOException exc) {
			Console.WriteLine(exc.Message);
			Console.ReadLine();
			return;
		}
		
			try {
				fstr_out.WriteLine(stringMemoryMap);
			}
			catch(IOException exc) {
				Console.WriteLine(exc.Message);
				Console.ReadLine();
				return;
			}			

		fstr_out.Close();
		
		Console.Write("\nГотово.\n");
		
		//readThread.Join();
		sPort.Close();
		Console.ReadKey(); return;
    } // Main();

	/*
	    public static void Read()
		{
			while (inCycle)
			{
				try
				{
					if(sPort.BytesToRead > 0){
					queueBytes.Enqueue((byte)sPort.ReadByte());
					}
				}
				catch (TimeoutException) { }
			}
		}*/
	    
	//public static Thread readThread;
	//public static Queue queueBytes;
	public static string stringMemoryMap = "";
	public static bool inCycle = true;
	public  static byte rx_byte = 0x00;
	public  static bool unready = true;
	public  static string fileName;	
	public static SerialPort sPort;
	public static string portName;
   public readonly static byte[] first_block = { 0xC6, 
0x20, 0x08, 0x50, 0x1B, 0x72, 0x07, 0x50, 0x1B, 0x72, 0xF2, 0x26, 0x5A, 0x90, 0x5C, 0xFB, 0x30, 
0x52, 0x0F, 0x72, 0x31, 0x52, 0xC7, 0xF6, 0x40, 0x00, 0xAE, 0x90, 0x36, 0x52, 0x20, 0x35, 0x08, 
0x50, 0x1A, 0x72, 0x07, 0x50, 0x1A, 0x72, 0x97, 0x31, 0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B, 0x72, 
0x95, 0x31, 0x52, 0xC6, 0xFB, 0x30, 0x52, 0x0B, 0x72, 0x35, 0x52, 0x0C, 0x35, 0x32, 0x52, 0x01, 
0x35, 0x33, 0x52, 0x00, 0x35 };

	
}
// STM8uLoader.cs

 

BAT файл теперь не требуется. Просто запускаем файл [STM8uLoader.exe], нажимаем кнопку сброса на плате STM8 и ждем появление файла [stringMemoryMap.txt] .

 

Исходники:[boot_PC.zip] и [first_block_asm.zip] .

 

Если first_block.asm назвать прикладной программой, то мы отправили дамп прикладной программы и передали ей управление. Если ограничиться размером 255 байт, забыть про прерывания и подпрограммы (дамп располагается в области стека RAM памяти) и пытаться сохранить от перезаписи области FLASH и EEPROM, то уже можно назваться "прграмматором-загрузчиком". В следующей статье пора подумать, что нам нужно для полноценного освоения областей RAM, EEPROM, FLASH.

 

[COM-порт и чтение адресного пространства STM8S103F3 в консоль. (Статья 5)] [Оглавление.] [Класс Dumps. Модули чтения памяти (Статья 7)]