NFLic

STM8uLoader

COM-порт и чтение адресного пространства STM8S103F3 в консоль (Статья 5)

В дополнение к предыдущей статье хост программа boot_PC должна:

- окрыть COM-порт и отправить с настройками 9600N1 в RAM память дамп из файла first_block.s19;

- изменить настройки COM-порта на 128000N1;

- выводить в консоль блоками по 64 байт содержимое адресного пространства STM8S103F3, для этого;

- отправлять двумя байтами адрес (начиная с $0000 и заканчивая адресом $9FC0) требуемого блока памяти;

- принимать и выводить в консоль блоки из 64 байтов.

 

Начальный блок в памяти RAM (файл first_block.asm) должен:

- изменить скорость UART на 128000;

- принять по UART два байта (старший и младший байты адреса блока памяти);

- выгрузить и отправить последовательно в UART 64 байта блока памяти;

- включать светодиод на время передачи.

 

Схема (сигналы Rx, Tx должны быть с уровнями 3,3В) :

 

      USB-UART    5V  ->>--- +5V плата STM8
      USB-UART    VCC ->>-,
      USB-UART    3V3 ->>-'
      USB-UART    TXD ->>--- Rx  плата STM8
      USB-UART    RXD ->>--- Tx  плата STM8
      USB-UART    GND ->>--- GND плата STM8

 

Классы [FileOpenMemorySorting], [IntelHEXfile], [MotorolaS19file].

Файл STMuLoader.cs :

 

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

public partial class STM8S103F3 uLoader
{
	
	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);
						
		FileOpenMemorySorting fileSorted = new FileOpenMemorySorting(fileName);

		Console.Write("\nAll memory:");
		foreach( KeyValuePair kvp in fileSorted.GetAllMemoryaddressByteSorted() ){
			//if(kvp.Key % 16 == 0) Console.Write("\n${0:X4} ", kvp.Key);
			if(kvp.Key % 32 == 0) Console.Write("\n${0:X4} ", kvp.Key);
			Console.Write("${0:X2} ", kvp.Value);
		}// foreach
		Console.WriteLine();

		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 % 32 == 0) Console.Write("\n${0:X4} ", kvp.Key);
			Console.Write("${0:X2} ", kvp.Value);
		}// foreach
		Console.WriteLine();

		Console.Write("\nEEPROM memory:");
		foreach( KeyValuePair kvp in fileSorted.GetEEPROMaddressByteSorted() ){
			//if(kvp.Key % 16 == 0) Console.Write("\n${0:X4} ", kvp.Key);
			if(kvp.Key % 32 == 0) Console.Write("\n${0:X4} ", kvp.Key);
			Console.Write("${0:X2} ", kvp.Value);
		}// foreach
		Console.WriteLine();
		
		Console.Write("\nFLASH memory:");
		foreach( KeyValuePair kvp in fileSorted.GetFLASHaddressByteSorted() ){
			//if(kvp.Key % 16 == 0) Console.Write("\n${0:X4} ", kvp.Key);
			if(kvp.Key % 32 == 0) Console.Write("\n${0:X4} ", kvp.Key);
			Console.Write("${0:X2} ", kvp.Value);
		}// foreach
		Console.WriteLine("\n");
		
		List list_Bytes = new List();
		list_Bytes.Clear();
		
		// извлечем дамп для RAM памяти
		foreach( KeyValuePair kvp in fileSorted.GetAllMemoryaddressByteSorted() ){
			list_Bytes.Add(kvp.Value);
		}// foreach
		list_Bytes.Reverse();  // дамп должен быть передан в обратном порядке
		
		// инициализация 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 порта

		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} байт блока", list_Bytes.Count);		
				byte[] txBytes = {(byte)list_Bytes.Count};
				sPort.Write(txBytes, 0, 1); // отправляем размер дампа
				unready = false;
			}

		}//while(unready)

		sPort.Write(list_Bytes.ToArray(), 0, list_Bytes.Count);				// отправляем сам дамп
		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; )

		//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 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;
}
// STM8uLoader.cs

 

Файл first_block.asm :

 

stm8/

	TITLE first_block.asm”
	MOTOROLA

	#include "STM8S103F3P.inc"

	BYTES
	segment byte at 0000 'first_block'
boot_RAM_start:
; Включаем pull-up на портах (если подтяжка не предусмотрена внешней схемой) или не включаем, все равно работает, экономим 14 байт
;  ld    A, #%01001100              ; [A6 4C]
;  cpl    A                         ; [43]
;  ld    PA_CR1, A                  ; [C7 50 03]
;  ld    PB_CR1, A                  ; [C7 50 08]
;  ld    PC_CR1, A                  ; [C7 50 0D]
;  ld    PD_CR1, A                  ; [C7 50 12] подтяжка на PD6(UART1_RX), PD2, PD1
; настраиваем UART1 на прием/передачу на скорости 9600, остальные настройки по умолчанию (8 бит, нет бита четности, 1 стоповый бит)
  mov    UART1_BRR2, #0            ; [35 00 52 33]  для Fmaster=16/8=2МГц и 9600
;   mov    UART1_BRR1, #13           ; [35 0D 52 32]  для Fmaster=16/8=2МГц и 9600
   mov    UART1_BRR1, #1           ; [35 0D 52 32]  для Fmaster=16/8=2МГц и 128000
   mov    UART1_CR2, #%00001100     ; [35 0C 52 35]    UART1_CR2.TEN <- 1  UART1_CR2.REN <- 1  разрешаем передачу/прием
   
boot_RAM_main_cycle:
	
boot_RAM_wait_byte1:
    btjf  UART1_SR, #5, boot_RAM_wait_byte1
    ld     A, UART1_DR
    ld     XH, A
boot_RAM_wait_byte2:
    btjf  UART1_SR, #5, boot_RAM_wait_byte2
    ld     A, UART1_DR
    ld     XL, A
  
; включаем светодиод	
    bset 	PB_DDR,#5 		;
    bset 	PB_CR1,#5 		; 

	ldw		Y, #64
boot_RAM_read_cycle:
	ld		A, (X)
    ld     UART1_DR, A
boot_RAM_wait_tx:
	btjf	UART1_SR, #7, boot_RAM_wait_tx	; skip if UART1_SR.TXE = 0		TXE: Transmit data register empty
	incw	X
	decw	Y
	jrne	boot_RAM_read_cycle
	
; выключаем светодиод	
    bres 	PB_DDR,#5 		;
    bres 	PB_CR1,#5 		; 

	
    jra     boot_RAM_main_cycle
   

	end
	

 

Файл run.bat :

 

STM8S103F3 uLoader first_block.s19 
pause

 

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

 

Запускаем bat файл и изучим содержимое.

 

Область RAM памяти $0000...$003F. Здесь в адресах $0000...$0034 находится код начального загрузчика boot_OPTION (см. также адреса $480B...$483F).

 

Область RAM памяти $0380...$03FF. Здесь в адресах $03BA...$03FF находится дамп файла first_block.s19.

 

Область EEPROM памяти $4000...$403F. Здесь находится образ кода прикладной программы.

 

Область OPTION памяти $4800...$483F. Здесь в адресах $4800...$480A находятся OPTION байты STM8S103F3 и в адресах $480B...$483F находится образ начального загрузчика boot_OPTION (см. также адреса $0000...$0034).

 

Область FLASH памяти $8000...$80FF. Здесь в адресах $8000...$8003 находятся первые 4 байта кода копировщика boot_FLASH, в адресах $8004...$80ED находится код прикладной программы.

 

Область FLASH памяти $9FC0...$9FFF. Здесь в адресах $9FF0...$9FFF находятся последние 16 байт кода копировщика boot_FLASH.

 

Подробнее с адресным простраством STM8S103F3 можно познакомиться по ссылке .

 

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

 

В этой статье мы подгружали файл с дампом first_block из вне с помощью аргумета командной строки. В следующей статье разберем как вставить дамп в исходный код.

 

[Функционал хост-программы boot_PC. (Статья 4)] [Оглавление.] [Создатель дампов. (Статья 6)]