NFLic

STM8uLoader

Класс Dumps. Модули записи и копирования в память RAM (Статья 8)

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

 

[Класс Dumps. Модули чтения памяти (Статья 7)] [Оглавление.] [Класс Dumps. Модули записи в память EEPROM (Статья 9)]