Перейти к содержанию
    

Нет, Сергей, как сделать "перемещаемые" вектора прерываний я лично понимаю. Для пользовательского приложения "аппаратные" вектора прерываний как таковые вообще не используются. Пишутся лишь функции-обработчики прерываний, адреса которых "раскладываются" в таблицу переходов, расположенную в ОЗУ.

У ТС же возник вопрос по совмещению двух проектов/прошивок в одном кристалле и вызове одного из другого. Как я понял, ты предлагаешь замещать вектор сброса тем, который генерируется при компиляции именно бутлоадера. А то содержимое вектора RESET, которое компилируется в пользовательском приложении из прошивки выкинуть, использовав его лишь как адрес для старта приложения. Так?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нет, Сергей, как сделать "перемещаемые" вектора прерываний я лично понимаю. Для пользовательского приложения "аппаратные" вектора прерываний как таковые вообще не используются. Пишутся лишь функции-обработчики прерываний, адреса которых "раскладываются" в таблицу переходов, расположенную в ОЗУ.
Верно. И раскладывает их туда загрузчик перед тем, как запустить приложение. И берет он их из таблицы, которая расположена в фиксированном месте приложения. И таблицей этой является содержимое сегмента INTVEC приложения.

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

Тут и все вектора прерываний и вектор сброса.

 

Вот загрузчик копирует эту таблицу в ОЗУ, в то место, откуда берут адреса функции-трамплины:

        uint_fast8_t i = INT_VECTORS_COUNT - 1; // do not copy reset vector
        while(i--)
        {
            InterruptVectors[i] = Application.Vectors[i];
        }

А вот из этой же таблицы берется адрес, на который надо перейти для старта приложения:

Application.ResetVector();

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А что делает запись ((void(*)() )0x2200)();?

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А что делает запись ((void(*)() )0x2200)();?
Вызов функции вида void func(void), расположенной по адресу 2200.

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Захотел я сделать прошивку с переходами между приложениями пока без использовании прерываний:

приложение 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 "

perehod_po_prilogeniyam.rar

Изменено пользователем KARLSON

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мои пять копеек.

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

 

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

 

#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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...