реклама на сайте
подробности

 
 
3 страниц V  < 1 2 3  
Reply to this topicStart new topic
> Bootloader для MSP430, как написать бутлоадер для МСП430
rezident
сообщение Oct 11 2011, 23:16
Сообщение #31


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Нет, Сергей, как сделать "перемещаемые" вектора прерываний я лично понимаю. Для пользовательского приложения "аппаратные" вектора прерываний как таковые вообще не используются. Пишутся лишь функции-обработчики прерываний, адреса которых "раскладываются" в таблицу переходов, расположенную в ОЗУ.
У ТС же возник вопрос по совмещению двух проектов/прошивок в одном кристалле и вызове одного из другого. Как я понял, ты предлагаешь замещать вектор сброса тем, который генерируется при компиляции именно бутлоадера. А то содержимое вектора RESET, которое компилируется в пользовательском приложении из прошивки выкинуть, использовав его лишь как адрес для старта приложения. Так?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 12 2011, 06:14
Сообщение #32


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (rezident @ Oct 12 2011, 02:16) *
Нет, Сергей, как сделать "перемещаемые" вектора прерываний я лично понимаю. Для пользовательского приложения "аппаратные" вектора прерываний как таковые вообще не используются. Пишутся лишь функции-обработчики прерываний, адреса которых "раскладываются" в таблицу переходов, расположенную в ОЗУ.
Верно. И раскладывает их туда загрузчик перед тем, как запустить приложение. И берет он их из таблицы, которая расположена в фиксированном месте приложения. И таблицей этой является содержимое сегмента INTVEC приложения.
QUOTE (rezident @ Oct 12 2011, 02:16) *
У ТС же возник вопрос по совмещению двух проектов/прошивок в одном кристалле и вызове одного из другого. Как я понял, ты предлагаешь замещать вектор сброса тем, который генерируется при компиляции именно бутлоадера. А то содержимое вектора RESET, которое компилируется в пользовательском приложении из прошивки выкинуть, использовав его лишь как адрес для старта приложения. Так?
Зачем же выбрасывать и замещать? Пусть он лежит в таблице векторов приложения. Тогда загрузчик точно будет знать, откуда его брать. Вот смотрите, я в сообщении №26 давал пример. Вот структура таблицы векторов приложения, т.е. полное содержимое сегмента INTVEC приложения:
CODE
__attribute__ ((section(".app_vectors"))) struct
{
    void *Vectors[INT_VECTORS_COUNT - 1];
    void (*ResetVector)();
} Application;
Тут и все вектора прерываний и вектор сброса.

Вот загрузчик копирует эту таблицу в ОЗУ, в то место, откуда берут адреса функции-трамплины:
CODE
        uint_fast8_t i = INT_VECTORS_COUNT - 1; // do not copy reset vector
        while(i--)
        {
            InterruptVectors[i] = Application.Vectors[i];
        }

А вот из этой же таблицы берется адрес, на который надо перейти для старта приложения:
CODE
Application.ResetVector();


А "железный" вектор RESET указывает на старт загрузчика. Тогда и приложение знает, как запустить загрузчик - адрес его точки входа всегда лежит в ячейках по адресу 0xFFFE.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
KARLSON
сообщение Oct 12 2011, 12:42
Сообщение #33


Знающий
****

Группа: Свой
Сообщений: 604
Регистрация: 5-05-06
Из: Нижегородская обл.
Пользователь №: 16 819



А что делает запись ((void(*)() )0x2200)();?
Если после программировании в бутлоадере с помощью этой записи обратиться к инструкции по адресу 0x2200 ( от куда и начинается приложение) старт приложения с инициализацией произойдёт?


--------------------
Кризис - это не отсутствие денег, а отсутствие идей! Учитесь и никаких кризисов не будет.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 12 2011, 13:07
Сообщение #34


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (KARLSON @ Oct 12 2011, 15:42) *
А что делает запись ((void(*)() )0x2200)();?
Вызов функции вида void func(void), расположенной по адресу 2200.
QUOTE (KARLSON @ Oct 12 2011, 15:42) *
Если после программировании в бутлоадере с помощью этой записи обратиться к инструкции по адресу 0x2200 ( от куда и начинается приложение) старт приложения с инициализацией произойдёт?
Если по адресу 0x2200 расположена первая инструкция стартапа. Если же там располагается указатель на адрес точки входа (как было бы, если бы там располагался) вектор сброса, то запись должна была бы быть несколько иной: ((void(**)() )0x2200)().


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
KARLSON
сообщение Oct 13 2011, 06:35
Сообщение #35


Знающий
****

Группа: Свой
Сообщений: 604
Регистрация: 5-05-06
Из: Нижегородская обл.
Пользователь №: 16 819



Захотел я сделать прошивку с переходами между приложениями пока без использовании прерываний:
приложение 1
Код
#include "io430.h"

void main( void )
{
  // Stop watchdog timer to prevent time out reset
  WDTCTL = WDTPW + WDTHOLD;
  P1DIR = BIT0;
  P1OUT = BIT0;
  char j=0;
  unsigned int k = 40000, z=2;
  
  while(1)
  {
    for(unsigned int i=0; i<k; i++);
    for(unsigned int i=0; i<z; i++);
    P1OUT ^= BIT0;
    ++j;
    if(j == 30)
    {
      ((void(*)() )0x2200)();
    }
  }
}

xcl файл приложения 1
Код
// -----------------------------------------------
// Read/write memory
//

-Z(DATA)DATA16_I,DATA16_Z,DATA16_N,DATA16_HEAP+_DATA16_HEAP_SIZE=1100-20FF
-Z(DATA)CODE_I
-Z(DATA)CSTACK+_STACK_SIZE#

// -------------------------------------
// Constant data
//

-Z(CONST)DATA16_C,DATA16_ID,DIFUNCT,CHECKSUM=2100-FFBF

// -------------------------------------
// Code
//
-Z(CODE)CSTART,ISR_CODE,CODE_ID=EC00-FFBF
-P(CODE)CODE=EC00-FFBF

// -------------------------------------
// Interrupt vectors
//

-Z(CODE)INTVEC=FFC0-FFFF
-Z(CODE)RESET=FFFE-FFFF

прошивка приложения 1
Код
@EC00
31 40 00 21 B0 12 0C EC B0 12 4E EC 0A 12 0B 12
08 12 B2 40 80 5A 20 01 D2 43 22 00 D2 43 21 00
4A 43 3B 40 40 9C 28 43 0B 3C 1F 53 0F 98 FD 2B
D2 E3 21 00 5A 53 7A 90 1E 00 02 20 B0 12 00 22
0F 43 01 3C 1F 53 0F 9B FD 2B 0F 43 EF 3F 30 40
52 EC 30 40 56 EC FF 3F
@FFFE
00 EC


приложение 2
Код
#include "io430.h"

void main( void )
{
  // Stop watchdog timer to prevent time out reset
  WDTCTL = WDTPW + WDTHOLD;
  P1DIR = BIT0;
  P1OUT = BIT0;
  char j=0;
  unsigned int k = 65535, z=65535;
  
  while(1)
  {
    for(unsigned int i=0; i<k; i++);
    for(unsigned int i=0; i<z; i++);
    P1OUT ^= BIT0;
    ++j;
    if(j == 30)
    {
      ((void(*)() )0xEC00)();
    }
  }
}


xcl файл приложения 2
Код
// -----------------------------------------------
// Read/write memory
//

-Z(DATA)DATA16_I,DATA16_Z,DATA16_N,DATA16_HEAP+_DATA16_HEAP_SIZE=1100-20FF
-Z(DATA)CODE_I
-Z(DATA)CSTACK+_STACK_SIZE#

// -------------------------------------
// Constant data
//

-Z(CONST)DATA16_C,DATA16_ID,DIFUNCT,CHECKSUM=2200-9FBF

// -------------------------------------
// Code
//
-Z(CODE)CSTART,ISR_CODE,CODE_ID=2200-9FBF
-P(CODE)CODE=2200-9FBF

// -------------------------------------
// Interrupt vectors
//
-Z(CODE)INTVEC=9FC0-9FFF
-Z(CODE)RESET=9FFE-9FFF


прошивка приложения 2
Код
@2200
31 40 00 21 B0 12 0C 22 B0 12 4C 22 0A 12 0B 12
08 12 B2 40 80 5A 20 01 D2 43 22 00 D2 43 21 00
4A 43 3B 43 38 43 0B 3C 1F 53 0F 98 FD 2B D2 E3
21 00 5A 53 7A 90 1E 00 02 20 B0 12 00 EC 0F 43
01 3C 1F 53 0F 9B FD 2B 0F 43 EF 3F 30 40 50 22
30 40 54 22 FF 3F
@9FFE
00 22
q


общая прошивка
Код
@2200
31 40 00 21 B0 12 0C 22 B0 12 4C 22 0A 12 0B 12
08 12 B2 40 80 5A 20 01 D2 43 22 00 D2 43 21 00
4A 43 3B 43 38 43 0B 3C 1F 53 0F 98 FD 2B D2 E3
21 00 5A 53 7A 90 1E 00 02 20 B0 12 00 EC 0F 43
01 3C 1F 53 0F 9B FD 2B 0F 43 EF 3F 30 40 50 22
30 40 54 22 FF 3F
@9FFE
00 22
@EC00
31 40 00 21 B0 12 0C EC B0 12 4E EC 0A 12 0B 12
08 12 B2 40 80 5A 20 01 D2 43 22 00 D2 43 21 00
4A 43 3B 40 40 9C 28 43 0B 3C 1F 53 0F 98 FD 2B
D2 E3 21 00 5A 53 7A 90 1E 00 02 20 B0 12 00 22
0F 43 01 3C 1F 53 0F 9B FD 2B 0F 43 EF 3F 30 40
52 EC 30 40 56 EC FF 3F
@FFFE
00 EC
q


Прошил. Вроде работает. Первая прошивка часто моргает (~3Гц), затем переходит на вторую прошивку, моргает медленно (~1.5 Гц). И так бесконечно.
Я всё правильно сделал? Есть ли минусы?

Кстати, Сергей, пробовал делать переход на адрес вектора ((void(**)() )0x9FFE)(); в одном и ((void(**)() )0xFFFE)(); в другом приложении. Компилятор ругнулся на эти записи "Error[Pe109]: expression must have (pointer-to-) function type "

Сообщение отредактировал KARLSON - Oct 13 2011, 10:11
Прикрепленные файлы
Прикрепленный файл  perehod_po_prilogeniyam.rar ( 39.68 килобайт ) Кол-во скачиваний: 29
 


--------------------
Кризис - это не отсутствие денег, а отсутствие идей! Учитесь и никаких кризисов не будет.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 13 2011, 15:56
Сообщение #36


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (KARLSON @ Oct 13 2011, 09:35) *
Кстати, Сергей, пробовал делать переход на адрес вектора ((void(**)() )0x9FFE)(); в одном и ((void(**)() )0xFFFE)(); в другом приложении. Компилятор ругнулся на эти записи "Error[Pe109]: expression must have (pointer-to-) function type "
Да, это я лопухнулся. (*((void(**)() )0xFFFE))();


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Kurt
сообщение Oct 21 2011, 04:49
Сообщение #37


Участник
*

Группа: Свой
Сообщений: 63
Регистрация: 16-06-04
Из: Россия, Уфа
Пользователь №: 31



Мои пять копеек.
Вариант, если в устройстве есть внешняя память (в моем случае AT45DB или FRAM33). Посредством основной программы по существующему протоколу связи заливаем образ прошивки во внешнюю память (с проверкой версии прошивки, аппаратуры, контрольных сумм и пр.). Затем передаем управление ассемблерной процедуре, которая копирует себя в ОЗУ и затем оттуда быстро и тупо копирует образ из внешней памяти во FLASH.

Исходник для msp430f2x и at45db:

CODE

#include <msp430.h>
#include "hardware_config.h"
#include "fwupdate.h"

// Forward declarations of segments.
RSEG CSTACK:DATA:NOROOT
RSEG DATA16_I:DATA:NOROOT
MODULE FW_UPDATE_ROUTINES
PUBLIC fw_at45_update

WD_EXT_STB MACRO
xor.b #(1<<PIN_WD_STROBE), &WD_EXT_PORT
ENDM

AT45_ENABLE MACRO
bic.b #(1<<PIN_AT45_CS), &AT45_CS_PORT
ENDM

AT45_DISABLE MACRO
bis.b #(1<<PIN_AT45_CS), &AT45_CS_PORT
ENDM

SPI_WRITE MACRO N
mov.b N, r12
call r8
ENDM

RSEG CODE
fw_at45_update
dint
nop
mov.w #(WDTPW|WDTHOLD), &WDTCTL
ftg_w_ready bit #BUSY, &FCTL3
jnz ftg_w_ready

mov #SFE(CSTACK), sp

// copy to RAM
mov.w #FW_INIT, r12
mov.w #SFE(DATA16_I), r14
push.w r14
copy_2_ram: mov.w @r12+, 0(r14)
incd.w r14
cmp.w #FW_UPDATE_END, r12
jnc copy_2_ram
ret

FW_INIT
WD_EXT_STB

// Init DCO
mov.b &CALBC1_12MHZ,&BCSCTL1 // Set DCO to 12MHz
clr.b &BCSCTL2 // MCLK = SMCLK = DCOCLK
mov.b &CALDCO_12MHZ,&DCOCTL

mov.w #(FWKEY|FSSEL_1|FN5), &FCTL2 // Flash clock = MCLK/35 ~ 360kHz

// configure SPI module
mov.b #(UCSSEL_2|UCSWRST), &UCB1CTL1 // SMCLK
mov.b #(UCMST|UCSYNC|UCMSB|UCCKPL), &UCB1CTL0 // 3-pin, 8-bit SPI master
mov.b #1, &UCB1BR0
mov.b #0, &UCB1BR1
bic.b #(1<<2), &P5DIR
bis.b #((1<<1)|(1<<3)), &P5DIR
bis.b #((1<<1)|(1<<2)|(1<<3)), &P5SEL // P5.1,2,3 option select
bic.b #UCSWRST, &UCB1CTL1 // Initialize USCI state machine

// configure AT45DB
AT45_DISABLE
mov #(SFE(DATA16_I) + (spi_wr-FW_INIT)), R8 // R8 = &spi_write

// wait for ready at45db
wait_at45db AT45_ENABLE
SPI_WRITE #0x57
SPI_WRITE #0x00
AT45_DISABLE
bit.b #(1<<7), r12
jnc wait_at45db

// erase main memory
mov.w #3, r12 // erase cycles count
meras_loop mov.w #(FWKEY | MERAS), &FCTL1 // Set Mass Erase bit
mov.w #(FWKEY), &FCTL3 // Clear Lock bit
mov.w #0xFFFF, &fw_at45_update // write stuff byte to flash
meras_wait bit #BUSY, &FCTL3
jnz meras_wait
dec.w r12
jnz meras_loop

WD_EXT_STB

// at45db start read
AT45_ENABLE
SPI_WRITE #0xE8 // Continues Array Read(Legacy Command)
SPI_WRITE #0x00 // upper part of page address
SPI_WRITE #0x04 // lower part of page address and MSB of int.page adr.
mov.b #0, R12
call r8 // LSB byte of internal page address
call r8 // perform 4 dummy writes
call r8 // in order to initiate DataFlash
call r8 // address pointers
call r8 // --

mov.w #FW_FIRST_ADDR, r14
mov.w #FWKEY,&FCTL3 // Clear LOCK

prg_blocks WD_EXT_STB
mov.w #(FWKEY|BLKWRT|WRT),&FCTL1 // Enable block write
prg_bytes SPI_WRITE #0x00 // Read byte from dataflash
mov.b r12, 0(r14) // Write location
prg_wait bit #WAIT, &FCTL3 // Test WAIT
jz prg_wait // Loop while WAIT=0
inc.w r14 // Point to next byte
jz prg_finish
bit.b #0x3F, r14 // end of block (addr % 0x40) == 0
jne prg_bytes
mov.w #(FWKEY|WRT), &FCTL1 // Set BLKWRT=0
prg_busy bit #BUSY, &FCTL3
jnz prg_busy
jmp prg_blocks
prg_finish
mov.w #(FWKEY|WRT), &FCTL1 // Set BLKWRT=0
prg_finb bit #BUSY, &FCTL3
jnz prg_finb
mov.w #FWKEY, &FCTL1 // Clear WRT bit
mov.w #(FWKEY|LOCK), &FCTL3 // Set Lock Bit
AT45_DISABLE

mov.w #0, &WDTCTL // RESET!

spi_wr bit.b #UCB1TXIFG, &UC1IFG
jnc spi_wr
mov.b r12, &UCB1TXBUF
?w_txend: bit.b #UCB1RXIFG, &UC1IFG
jnc ?w_txend
mov.b &UCB1RXBUF, r12
ret
FW_UPDATE_END


ENDMOD
END
Go to the top of the page
 
+Quote Post

3 страниц V  < 1 2 3
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 27th July 2025 - 20:37
Рейтинг@Mail.ru


Страница сгенерированна за 0.01433 секунд с 7
ELECTRONIX ©2004-2016