关于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条回答
stopshooting
1楼-- · 2019-07-19 22:57
本帖最后由 stopshooting 于 2016-7-28 16:01 编辑

时隔多日再次回到这里,也不知道当时是不是脑抽了,这都没想明白。
0x82  0x9004 是一个语句,要跳到新建的中断向量表处,新建的中断向量表有0x82 IRQHander。
当然是要跳到0x9004了,0x9004刚好就是 0x82  IRQHander 这个语句中0x82的地址。
当时脑抽想着要跳到0x9005才对。。。然而这个0x9005不过是中断函数的地址的地址,而非中断中断函数的地址。。。当然了,也可以直接跳到中断函数的地址,毕竟中断函数地址的地址是已知的,不过还没有试过。
电脑小白
2楼-- · 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;
dgdzov
3楼-- · 2019-07-20 03:29
 精彩回答 2  元偷偷看……
紫气东升
4楼-- · 2019-07-20 03:57
看起来好复杂啊,不懂
电脑小白
5楼-- · 2019-07-20 07:10
dgdzov 发表于 2016-9-1 10:04
bootload里不能中断,如果是usb升级怎么办?

stm8没有这么强大吧,有usb通信接口? stm32见过有自带的usb接口,stm8上没有吧。

一周热门 更多>