В предыдущей статье в класс Dumps.cs были добавлены модули записи в EEPROM память данных микоконтроллера STM8S103F3. В этой статье добавляем модули записи во FLASH память программ.
В адресном пространстве STM8S103F3 ячейки FLASH памяти программ расположена в адресах $8000...$9FFF. Память FLASH разделена на 128 блоков(block) по 16 слов(word) или 64 байта, в каждом слове 4 байта. Начальные адреса блоков, выровненны по маске $xx00 $xx40 $xx80 $xxC0. Начальные адреса слов, выровненны по маске $xxx0 $xxx4 $xxx8 $xxC. Байты имеют произвольный доступ в пределах адресного пространства. Адреса блоков :
$8000...$803F, $8040...$807F, $8080...$80BF, $80C0...$80FF, $8100...$813F, $8140...$817F, $8180...$81BF, $81C0...$81FF, $8200...$823F, $8240...$827F, $8280...$82BF, $82C0...$82FF, $8300...$833F, $8340...$837F, $8380...$83BF, $83C0...$83FF, $8400...$843F, $8440...$847F, $8480...$84BF, $84C0...$84FF, $8500...$853F, $8540...$857F, $8580...$85BF, $85C0...$85FF, $8600...$863F, $8640...$867F, $8680...$86BF, $86C0...$86FF, $8700...$873F, $8740...$877F, $8780...$87BF, $87C0...$87FF, $8800...$883F, $8840...$887F, $8880...$88BF, $88C0...$88FF, $8900...$893F, $8940...$897F, $8980...$89BF, $89C0...$89FF, $8A00...$8A3F, $8A40...$8A7F, $8A80...$8ABF, $8AC0...$8AFF, $8B00...$8B3F, $8B40...$8B7F, $8B80...$8BBF, $8BC0...$8BFF, $8C00...$8C3F, $8C40...$8C7F, $8C80...$8CBF, $8CC0...$8CFF, $8D00...$8D3F, $8D40...$8D7F, $8D80...$8DBF, $8DC0...$8DFF, $8E00...$8E3F, $8E40...$8E7F, $8E80...$8EBF, $8EC0...$8EFF, $8F00...$8F3F, $8F40...$8F7F, $8F80...$8FBF, $8FC0...$8FFF, $9000...$903F, $9040...$907F, $9080...$90BF, $90C0...$90FF, $9100...$913F, $9140...$917F, $9180...$91BF, $91C0...$91FF, $9200...$923F, $9240...$927F, $9280...$92BF, $92C0...$92FF, $9300...$933F, $9340...$937F, $9380...$93BF, $93C0...$93FF, $9400...$943F, $9440...$947F, $9480...$94BF, $94C0...$94FF, $9500...$953F, $9540...$957F, $9580...$95BF, $95C0...$95FF, $9600...$963F, $9640...$967F, $9680...$96BF, $96C0...$96FF, $9700...$973F, $9740...$977F, $9780...$97BF, $97C0...$97FF, $9800...$983F, $9840...$987F, $9880...$98BF, $98C0...$98FF, $9900...$993F, $9940...$997F, $9980...$99BF, $99C0...$99FF, $9A00...$9A3F, $9A40...$9A7F, $9A80...$9ABF, $9AC0...$9AFF, $9B00...$9B3F, $9B40...$9B7F, $9B80...$9BBF, $9BC0...$9BFF, $9C00...$9C3F, $9C40...$9C7F, $9C80...$9CBF, $9CC0...$9CFF, $9D00...$9D3F, $9D40...$9D7F, $9D80...$9DBF, $9DC0...$9DFF, $9E00...$9E3F, $9E40...$9E7F, $9E80...$9EBF, $9EC0...$9EFF, $9F00...$9F3F, $9F40...$9F7F, $9F80...$9FBF, $9FC0...$9FFF.
В отличие от записи в RAM запись в FLASH требует :
- разблокирования FLASH памяти после каждого сброса устройства последовательной записью значений $56 и $AE в регистр FLASH_PUKR ($5062). С этого момента доступна побайтовая запись ячеек памяти FLASH. При некорректной записи в регистр FLASH_PUKR потребуется перезагрузка устройства;
- выбора режима (Standard block programming (запись блока со стиранием) $01/$FE, Fast block programming (запись блока без стиранием) $10/$EF, Block erase (стирание блока) $20/$DF, Word programming $40/$BF последовательной записью в регистры FLASH_CR2 ($505B) и FLASH_NCR2 ($505C). При некорректной записи в регистры FLASH_CR2 ($505B) и FLASH_NCR2 ($505C) будет выполняться только побайтовая(медленная) запись;
- на время записи/стирания FLASH памяти останавливается выполнение программы;
- программа записи/стирания FLASH памяти (кроме побайтовой записи) желательно должна исполняться из RAM памяти;
- при побайтовой записи в FLASH требуется только предварительное разблокирование последовательной записью значений $56 и $AE в регистр FLASH_PUKR ($5062), далее обычные команды записи в ячейки памяти (напр LD).
Запись в ячейки памяти FLASH с адресами $8000...$8003, $9FF0...$9FFD повредит код начального копировщика boot_FLASH. Необходимо предусмотреть соответствующие блокировки в хост-программе компьютера и, возможно, в соответствующих модулях/дампах.
Standard block programming. В этом режиме происходит запись блока с автоматическим стиранием (требуется в два раза больше времени на запись). Алгоритм записи:
1 - разблокировть запись/стирание FLASH памяти программ последовательным копированием значений $56 и $AE в регистр FLASH_PUKR ($5062)), если это еще не сделано;
2 - выбрать режим Standard block programming последовательным копированием значений $01 и $FE в регистры FLASH_CR2 ($505B) и FLASH_NCR2 ($505C) соответственно;
3 - наполнить блок с начального адреса, выровненного по маске $xx00 $xx40 $xx80 $xxC0 требуемым содержимым командами записи в ячейки памяти (напр LD, MOV и пр.);
4 - при копировании в блок всех 64 байтов автоматически начинается запись блока, на время записи останавливается выполнение команд;
5 - после записи блока режим Standard block programming отключается;
6 - при необходимоти записи следующего блока перейти к п.2;
7 - при копирования более 64 байт лишние байты будут записываться в побайтовом (медленном) режиме ;
8 - после окончания записи автоматически начнется выполнение следующих команд.
; unlock FLASH memory (writing the correct MASS keys) mov FLASH_PUKR, #$56 ; Write $56 then $AE in FLASH_PUKR($5062) mov FLASH_PUKR, #$AE mov FLASH_CR2, #$01 ; Write $01 then $FE in FLASH_CR2($505B) and FLASH_NCR2($505C) mov FLASH_NCR2, #$FE ldw X, #$4240 ; src table in EEPROM ldw Y, #$9300 ; dst table in FLASH mov $0000, #64 ; counter in RAM write_block_cycle: ld A, (X) ld (Y), A ; после выполнения этой команды при последней итерации начинается запись блока dec $0000 ; после окончания записи блока начинает выполняться эта команда jrne write_block_cycle
Fast block programming. В этом режиме происходит запись блока с предварительно стертым содержимым (требуется меньше времени на запись). Алгоритм записи:
1 - разблокировать запись/стирание FLASH памяти программ последовательным копированием значений $56 и $AE в регистр FLASH_PUKR ($5062), если это еще не сделано;
2 - выбрать режим Fast block programming последовательным копированием значений $10 и $EF в регистры FLASH_CR2 ($505B) и FLASH_NCR2 ($505C) соответственно;
3 - наполнить блок с начального адреса, выровненного по маске $xx00 $xx40 $xx80 $xxC0 требуемым содержимым командами записи в ячейки памяти (напр LD, MOV и пр.);
4 - при копировании в блок всех 64 байтов автоматически начинается запись блока, на время записи останавливается выполнение команд;
5 - после записи блока режим Fast block programming отключается;
6 - при необходимоти записи следующего блока перейти к п.2;
7 - при копирования более 64 байт лишние байты будут записываться в побайтовом (медленном) режиме ;
8 - после окончания записи автоматически начнется выполнение следующих команд.
Block erase. В этом режиме происходит стирание содержимого блока. Алгоритм стирания:
1 - разблокировать запись/стирание FLASH памяти программ последовательным копированием значений $56 и $AE в регистр FLASH_PUKR ($5062), если это еще не сделано;
2 - выбрать режим Block erase последовательным копированием значений $20 и $DF в регистры FLASH_CR2 ($505B) и FLASH_NCR2 ($505C) соответственно;
3 - скопировть значение $00 в четыре последовательные ячейки памяти внутри блока с начальным адресом выровненым по маске $xxx0 $xxx4 $xxx8 $xxxC командами записи в ячейки памяти (напр LD, MOV и пр.);
4 - автоматически начнется стирание блока, на время стирания останавливается выполнение команд;
5 - после стирания блока режим Block erase отключается;
6 - при необходимоти стереть следующий блок перейти к п.2;
7 - после окончания стирания блока автоматически начнется выполнение следующих команд.
Word programming. В этом режиме происходит запись слова. Алгоритм записи:
1 - разблокировать запись/стирание FLASH памяти программ последовательным копированием значений $56 и $AE в регистр FLASH_PUKR ($5062), если это еще не сделано;
2 - выбрать режим Word programming последовательным копированием значений $40 и $BF в регистры FLASH_CR2 ($505B) и FLASH_NCR2 ($505C) соответственно;
3 - заполнить содержимым четыре последовательные ячейки памяти с начальным адресом выровненным по маске $xxx0 $xxx4 $xxx8 $xxxC;
4 - при копировании всех 4 байтов автоматически начинается запись слова, на время записи останавливается выполнение команд;
5 - после записи блока режим Word programming отключается;
7 - при копирования более 4 байт лишние байты будут записываться в побайтовом (медленном) режиме ;
8 - после окончания записи автоматически начнется выполнение следующих команд.
; unlock FLASH memory (writing the correct MASS keys) mov FLASH_PUKR, #$56 ; Write $56 then $AE in FLASH_PUKR($5062) mov FLASH_PUKR, #$AE mov FLASH_CR2, #$40 mov FLASH_NCR2, #$BF ; следующая запись произойдет с начальным адресом $9C00 mov $9C00, #$11 ; запись произойдет по адресу $9C00 mov $9C01, #$11 ; запись произойдет по адресу $9C01 mov $9C02, #$11 ; запись произойдет по адресу $9C02 mov $9C03, #$11 ; запись произойдет по адресу $9C03 mov FLASH_PUKR, #$40 mov FLASH_PUKR, #$BF ; следующая запись произойдет с начальным адресом $8780 вместо ожидаемого $877F ld A, #$33 ld $877F, A ; запись произойдет по адресу $8780 ld $8780, A ; запись произойдет по адресу $8781 ld $8781, A ; запись произойдет по адресу $8782 ld $8782, A ; запись произойдет по адресу $8783 ; следующая запись произойдет с начальным адресом $9234 вместо ожидаемого $9231 mov FLASH_PUKR, #$40 mov FLASH_PUKR, #$BF ldw X, #$4100 ldw Y, #$9231 mov $0000, #4 write_word_cycle: ld A, (X) ld (Y), A dec $0000 jrne write_word_cycle
Byte programming. В этом режиме происходит побайтовая запись в ячейки FLASH. Для STM8S103F3 на время записи также останавливается выполнеие команд. Алгоритм записи:
1 - разблокировать запись/стирание FLASH последовательным копированием значений $56 и $AE в регистр FLASH_PUKR ($5062), если это еще не сделано;
2 - скопировать байт(байты) в ячейку(ячейки) EEPROM командами записи в ячейки памяти (напр LD, MOV и пр.);
3 - на время записи каждого байта останавливается выполнение команд.
; unlock FLASH memory (writing the correct MASS keys) mov FLASH_PUKR, #$56 ; Write $56 then $AE in FLASH_PUKR($5062) mov FLASH_PUKR, #$AE mov $427F, #$14
Классы [Dumps], [FileOpenMemorySorting], [IntelHEXfile], [MotorolaS19file].
Файл STM8uLoader.cs :
// STM8uLoader.cs using System; using System.IO; using System.IO.Ports; using System.Threading; using System.Collections.Generic; public 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 FileOpenMemorySorting fileSorted = new FileOpenMemorySorting(fileName); Console.Write("Из файла RAM память"); foreach( KeyValuePairkvp 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"); Console.Write("Из файла EEPROM память"); foreach( KeyValuePair kvp in fileSorted.GetEEPROMaddressLineSorted() ){ 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"); Console.Write("Из файла FLASH память"); foreach( KeyValuePair kvp in fileSorted.GetFLASHaddressLineSorted() ){ 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 = 0x4100; blckSize = 512; Console.WriteLine("Из EEPROM до записи"); Dumps.Dump_To_Console(Dumps.Read_128000(blckAdr, blckSize)); addressBytesBlock.Clear(); blckAdr = 0x4100; for(int i = 0; blckAdr < 0x4280; i = i + 64){ for(int j = 0; j < 64; j++){ blck64Bytes[j] = (byte)0x01; } addressBytesBlock.Add(blckAdr, blck64Bytes); blckAdr = blckAdr + 64; } Dumps.WriteBlock_EEPROM_128000(addressBytesBlock); addressBytesBlock.Clear(); blckAdr = 0x4100; for(; blckAdr < 0x4280;){ for(int j = 0; j < 4; j++){ wrd4Bytes[j] = (byte)0x06; } addressBytesBlock.Add(blckAdr, wrd4Bytes); blckAdr = blckAdr + 19; } Dumps.WriteWord_EEPROM_128000(addressBytesBlock); addressBytesBlock.Clear(); blckAdr = 0x4100; for(; blckAdr < 0x4280;){ btBytes[0] = (byte)0x09; addressBytesBlock.Add(blckAdr, btBytes); blckAdr = blckAdr + 17; } Dumps.WriteByte_EEPROM_128000(addressBytesBlock); blckAdr = 0x4100; blckSize = 512; Console.WriteLine("Из EEPROM после записи"); Dumps.Dump_To_Console(Dumps.Read_128000(blckAdr, blckSize)); blckAdr = 0x9100; blckSize = 512; Console.WriteLine("Из FLASH до записи"); Dumps.Dump_To_Console(Dumps.Read_128000(blckAdr, blckSize)); addressBytesBlock.Clear(); blckAdr = 0x9100; for(int i = 0; blckAdr < 0x9280; i = i + 64){ for(int j = 0; j < 64; j++){ blck64Bytes[j] = (byte)0x01; } addressBytesBlock.Add(blckAdr, blck64Bytes); blckAdr = blckAdr + 64; } Dumps.WriteBlock_FLASH_128000(addressBytesBlock); addressBytesBlock.Clear(); blckAdr = 0x9100; for(; blckAdr < 0x9280;){ for(int j = 0; j < 4; j++){ wrd4Bytes[j] = (byte)0x06; } addressBytesBlock.Add(blckAdr, wrd4Bytes); blckAdr = blckAdr + 19; } Dumps.WriteWord_FLASH_128000(addressBytesBlock); addressBytesBlock.Clear(); blckAdr = 0x9100; for(; blckAdr < 0x9280;){ btBytes[0] = (byte)0x09; addressBytesBlock.Add(blckAdr, btBytes); blckAdr = blckAdr + 17; } Dumps.WriteByte_FLASH_128000(addressBytesBlock); blckAdr = 0x9100; blckSize = 512; Console.WriteLine("Из FLASH после записи"); Dumps.Dump_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 byte[] blck192Bytes = new byte[192]; public static SortedDictionary addressBytesBlock = new SortedDictionary (); 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.
В следующей статье попытаемся разработать метод сортировки содержимого по блокам / словам / байтам.
Исходники:[boot_PC.zip] , [WriteByte_FLASH_128000v14.asm] , [WriteWord_FLASH_128000v14.asm] , [WriteBlock_FLASH_128000v14.asm] .