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