В дополнение к предыдущей статье хост программа 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 из вне с помощью аргумета командной строки. В следующей статье разберем как вставить дамп в исходный код.