关于stm8 iap 中断向量表的重定向问题

2019-07-19 21:05发布

本帖最后由 stopshooting 于 2016-7-10 03:11 编辑

在STM8 IAP的官方bootloader例程中, 中断向量表的重定向是这样的。
[mw_shl_code=c,true]/*        Redirected interrupt vector table
*        Copyright (c) 2008 STMicroelectronics
*/

#include "main.h"

typedef void @far (*interrupt_handler_t)(void);

struct interrupt_vector {
        unsigned char interrupt_instruction;
        interrupt_handler_t interrupt_handler;
};

@far @interrupt void NonHandledInterrupt (void)
{
        /* in order to detect unexpected events during development,
           it is recommended to set a breakpoint on the following instruction
        */
        return;
}

extern void _stext();     /* startup routine */
struct interrupt_vector const UserISR_IRQ[32] @ MAIN_USER_RESET_ADDR;

//redirected interrupt table
struct interrupt_vector const _vectab[] = {
    {0x82, (interrupt_handler_t)_stext}, /* reset */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 1)}, /* trap  */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 2)}, /* irq0  */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 3)}, /* irq1  */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 4)}, /* irq2  */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 5)}, /* irq3  */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 6)}, /* irq4  */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 7)}, /* irq5  */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 8)}, /* irq6  */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 9)}, /* irq7  */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+10)}, /* irq8  */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+11)}, /* irq9  */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+12)}, /* irq10 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+13)}, /* irq11 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+14)}, /* irq12 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+15)}, /* irq13 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+16)}, /* irq14 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+17)}, /* irq15 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+18)}, /* irq16 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+19)}, /* irq17 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+20)}, /* irq18 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+21)}, /* irq19 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+22)}, /* irq20 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+23)}, /* irq21 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+24)}, /* irq22 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+25)}, /* irq23 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+26)}, /* irq24 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+27)}, /* irq25 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+28)}, /* irq26 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+29)}, /* irq27 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+30)}, /* irq28 */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+31)}, /* irq29 */
};
[/mw_shl_code]

其中MAIN_USER_RESET_ADDR 为0x9000,也就是说用户APP的中断向量表是放在0x9000上的
我的问题是,为什么重定向的地址是(interrupt_handler_t)(UserISR_IRQ+xx)?
根据上面的程序,
(UserISR_IRQ+ 1)表示0x9004,(UserISR_IRQ+ 2)表示0x9008,
(UserISR_IRQ+ 3)表示0x900c,
(UserISR_IRQ+ 4)表示0x9010,
(UserISR_IRQ+ N)表示(0x9000+N*4),而bootloader的的中断向量表是放在0x8000上的,
从这个表格中可以看出,bootloader的中断向量表_vectab中的interrupt_handler_t变量的地址明明就是0x8005, 0x8009, 0x800d, 0x8011, ((0x8000+N*4)+1)啊。。
难道重定向后的地址不应该0x9005, 0x9009, 0x900d, 0x9011, (0x9000+N*4+1)吗?
也就是 (interrupt_handler_t)((void*) (interrupt_handler_t)(UserISR_IRQ+xx)+(void*)1)吗?
用STVD仿真看到附件的图片:
可以看到中断向量表的interrupt_handler_t变量所在地址与其内容的比较
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
5条回答
电脑小白
2019-07-20 01:51
0x8000是bootloader开始执行的flash地址,0x9000是用户app的固件起始地址。
(0x9000可以修改的,我用的就是0xA000,没办法bootloader代码有些大)
因为用户app固件地址是从0x9000开始的,所以中断向量表要重定向到0x9000 。

在bootloader里不能使用中断处理函数,因为一中断就跑0x9000里去了,会死机的。
bootloader里串口接收数据就用while在哪里死等,没办法中断向量表给用户app了,没有处理函数呀,如下:
void Transmit(u8 Data){
//wait for Tx empty
        sr = UART1->SR;
  while(!(sr & 0x80/*TxNE*/)) sr = UART1->SR;
  //send data
   UART1->DR = Data;
  //wait for transmission complete
  sr = UART1->SR;
  while(!(sr & 0x40/*TxNE*/)) sr = UART1->SR;

u8 Receive_while(u8* ReceivedData){
  //wait for Rx full
        sr = UART1->SR;
  while(!(sr & 0x20 /*RXNE*/)) sr = UART1->SR;
  //check if overrun or parity error
        if((sr & 0x08/*OR*/)||(sr & 0x01/*PE*/))
  {
    //receive data to clear error
    *ReceivedData = UART1->DR ;
    //send NACK to host
    //Transmit(NACK);
    //and return error
    return 0;
  }
  //receive data
  *ReceivedData = UART1->DR;
  //and return no error
  return 1;

一周热门 更多>