ARM s3c2410 中 断 问 题 的 解 决 popsonic@126.com QQ:52179095 sonyer 赵 海 涛 一 状 况 7 月 的 某 一 天, 一 时 兴 起 觉 得 ARM 9 应 该 比 较 好 玩 于 是 跑 到 淘 宝 上 去 逛 逛, 搜 了 半 天 发 现 开 发 板 基 本 上 是 44B0 和 2410 2 种 难 道 三 星 的 东 西 最 便 宜? 工 业 级 的 philips 和 atmel 半 个 影 子 都 没 有 看 到 没 有 办 法, 就 买 块 2410 先 玩 着 吧 心 里 想 着 也 应 该 没 有 太 大 的 关 系 就 是 大 家 手 头 可 能 有 的 那 块 mc2410e, 接 口 丰 富 功 能 强 大 说 实 在 的 板 子 挺 好, 成 本 嘛 估 计 也 就 是 350 左 右 吧 问 题 就 此 开 始 了, 以 前 用 的 是 philips 的 21XX 还 有 22XX, 三 星 的 玩 意 一 直 没 有 碰 过 学 ARM 这 东 西 就 是 要 和 底 层 打 交 道 才 会 体 验 到 乐 趣 于 是 到 三 星 的 网 站 找 了 半 天 down 下 了 她 的 数 据 手 册 和 测 试 代 码 TEST2410 其 实 测 试 代 码 在 买 的 时 候 的 那 张 光 盘 里 也 有 解 压, 新 建 工 程 文 件, 添 加 源 文 件 编 译, 运 行 AXD 跑 起 来 了! 但 是 我 测 试 到 59 项 就 是 Timer Interrupt 的 时 候 死 机 了 没 有 任 何 错 误 二 交 涉 出 现 这 个 状 况, 第 一 个 反 应 就 是 板 子 有 问 题 毕 竟 人 家 是 三 星 网 站 上 的 代 码, 专 门 做 这 个 板 子 测 试 的, 当 然 了 官 方 的 班 子 上 还 带 了 红 外 和 gps 等 模 块 不 过 只 要 不 去 测 试 那 些 就 没 有 问 题 打 开 QQ 询 问 猎 人 大 哥, 态 度 是 不 错, 然 后 给 我 个 QQ 号, 说 是 开 发 这 块 板 子 的 那 个 人 的 号 码 其 实 这 块 板 子 我 似 曾 相 识, 后 来 发 现 和 立 宇 泰 的 板 子 很 象 其 实 这 块 板 子 的 技 术 含 量 最 高 的 就 是 那 块 6 层 核 心 板, 因 为 频 率 很 高, 所 以 布 线 的 时 候 都 需 要 等 长 线 来 连 到 flash 和 Ram 布 线 工 具 protel 是 不 行 的, 一 般 用 cadence, 后 来 也 证 实 了 我 的 想 法 跑 题 了, 不 好 意 思 总 之, 我 想 传 达 的 信 息 是 能 做 出 这 快 板 子 的 人, 还 是 很 牛 的! 联 系 到 那 个 牛 人 之 后, 牛 人 告 诉 我 : 我 们 的 板 子, 肯 定 是 没 有 问 题 的, 要 不 然 操 作 系 统 怎 么 跑 起 来 的? 对 啊, 能 跑 linux 啊, 操 作 系 统 能 够 支 持 多 任 务 是 因 为 时 间 片 分 配 的 原 理, 而 时 间 片 是 由 时 间 中 断 支 持 的, 不 然 跑 不 起 来 啊 但 是 其 他 的, 这 位 牛 人 什 么 也 没 有 说 郁 闷 ing.. 三 求 救 剩 下 的 时 间 就 是 跑 论 坛, 去 各 个 群 问 高 手 然 后 得 到 的 答 案, 要 么 是 这 帮 人 就 喜 欢 搞 linux 和 ce. 要 么 就 是 咬 定 我 的 程 序 有 问 题 真 奇 怪, 他 们 玩 linux 和 ce 主 要 玩 的 是 什 么 如 果 只 是 把 arm 上 装 个 linux 然 后 就 每 天 开 开 玩 玩 游 戏 上 上 网, 他 们 为 什 么 不 去 玩 xp? 这 样 要 好 玩 的 多!ce 上 的 嵌 入 我 也 玩 过, 用 的 是 c#.net 写 的 控 制 程 序 做 的 是 车 载 上 面 的 东 西 并 体 会 不 到 什 么 乐 趣 啊 还 有 牛 人 们, 上 论 坛 就 是 谈 USB 驱 动 怎 么 写, 说 实 话 那 个 太 高 深 了! 我 真 的 还 不 知 道 怎 么 写, 不 过 最 简 单 的 东 西 我 还 没 有 搞 定 呢! 足 足 郁 闷 了 2 个 月 后, 我 决 定 自 己 搞 定 它! 四 从 BootLoader 开 始 众 所 周 之,BootLoader 是 开 发 嵌 入 系 统 的 难 点 以 前 用 philips 的 arm 的 时 候 启 动 代 码 使 用 的 是 周 立 功 提 供 的 除 了 改 变 一 下 锁 向 环 的 设 置 来 改 变 主 频, 基 本 上 没 有 用 过 其 他 的 功 能 端 口 的 配 置 一 般 都 是 到 了 main() 函 数 之 后 再 加 一 个 LowlevelInital() 来 初 始 化 端 口, 毕 竟 c 写 起 来 比 那 些 汇 编 要 方 便 的 多! 不 过 要 解 决 现 在 的 问 题 真 的 是 要 看 BootLoader 了
打 开 测 试 程 序 的 2410init.s AREA Init,CODE,READONLY ; 这 个 表 示 只 读 段 的 代 码 区 域 Init 是 这 个 段 的 名 称 ENTRY ; 这 个 表 示 入 口 ;1)The code, which converts to Big-endian, should be in little endian code. ;2)The following little endian code will be compiled in Big-Endian mode. ; The code byte order should be changed as the memory bus width. ;3)The pseudo instruction,dcd can't be used here because the linker generates error. ASSERT :DEF:ENDIAN_CHANGE [ ENDIAN_CHANGE ASSERT :DEF:ENTRY_BUS_WIDTH [ ENTRY_BUS_WIDTH=32 b ChangeBigEndian ;DCD 0xea000007 [ ENTRY_BUS_WIDTH=16 andeq r14,r7,r0,lsl #20 ;DCD 0x0007ea00 [ ENTRY_BUS_WIDTH=8 streq r0,[r0,-r10,ror #1 ;DCD 0x070000ea b ResetHandler b HandlerUndef ;handler for Undefined mode b HandlerSWI ;handler for SWI interrupt b HandlerPabort ;handler for PAbort b HandlerDabort;handler for DAbort b. ;reserved b HandlerIRQ ;handler for IRQ interrupt b HandlerFIQ ;handler for FIQ interrupt 这 个 是 异 常 向 量 表, 注 意 很 多 人 认 为 是 中 断 向 量 表, 其 实 不 是, 是 异 常 向 量 表! 这 个 地 址 是 0x00000000 开 始 的 不 过, 不 一 定 是 物 理 地 址 的 0x0000000 而 是 逻 辑 上 的 0x00000000 用 过 arm7 的 朋 友 应 该 知 道 在 arm7 中 有 一 个 Remap 的 寄 存 器 用 来 将 逻 辑 地 址 映 射 到 地 址 0 因 为 我 们 普 通 调 试 的 时 候, 一 般 都 直 接 在 RAM 里 而 运 行 的 时 候 则 放 到 flash 里 去 让 它 运 行! 当 系 统 重 启 之 后 系 统 会 从 0x00000000 开 始 运 行, 也 就 是 b ResetHandler: ;======= ; ENTRY ;======= ResetHandler
ldr r0,=wtcon ;watch dog disable ldr r1,=0x0 ldr r0,=intmsk ldr r1,=0xffffffff ;all interrupt disable ldr r0,=intsubmsk ldr r1,=0x7ff ;all sub interrupt disable, 2002/04/10 [ {FALSE} ; rgpfdat = (rgpfdat & ~(0xf<<4)) ((~data & 0xf)<<4); ; Led_Display ldr r0,=gpfcon ldr r1,=0x5500 ldr r0,=gpfdat ldr r1,=0x10 ;To reduce PLL lock time, adjust the LOCKTIME register. ldr r0,=locktime ldr r1,=0xffffff [ PLL_ON_START ;Configure MPLL ldr r0,=mpllcon ldr r1,=((m_mdiv<<12)+(m_pdiv<<4)+m_sdiv) ;Fin=12MHz,Fout=50MHz ;Check if the boot is caused by the wake-up from POWER_OFF mode. ldr r1,=gstatus2 ldr r0,[r1 tst r0,#0x2 ;In case of the wake-up from POWER_OFF mode, go to POWER_OFF_WAKEUP handler. bne WAKEUP_POWER_OFF EXPORT StartPointAfterPowerOffWakeUp
StartPointAfterPowerOffWakeUp 0 ;Set memory control registers ldr r0,=smrdata ldr r1,=bwscon ;BWSCON Address add r2, r0, #52 ;End address of SMRDATA ldr r3, [r0, #4 str r3, [r1, #4 cmp r2, r0 bne %B0 bl ;Initialize stacks InitStacks ; Setup IRQ handler ldr r0,=handleirq ldr r1,=isrirq ;This routine is needed ;if there isn't 'subs pc,lr,#4' at 0x18, 0x1c ;Copy and paste RW data/zero initialized data ldr r0, = Image$$RO$$Limit ; Get pointer to ROM data ldr r1, = Image$$RW$$Base ; and RAM copy ldr r3, = Image$$ZI$$Base 1 2 3 ;Zero init base => top of initialised data cmp r0, r1 ; Check that they are different beq %F2 cmp r1, r3 ; Copy init data ldrccr2, [r0, #4 ;--> LDRCC r2, [r0 + ADD r0, r0, #4 strcc r2, [r1, #4 ;--> STRCC r2, [r1 + ADD r1, r1, #4 bcc %B1 ldr r1, = Image$$ZI$$Limit ; Top of zero init segment mov r2, #0 cmp r3, r1 ; Zero init strcc r2, [r3, #4 bcc %B3 [ :LNOT:THUMBCODE
bl Main ;Don't use main() because... b. [ THUMBCODE ;for start-up code for Thumb mode orr lr,pc,#1 bx lr CODE16 bl Main ;Don't use main() because... b. CODE32 这 段 代 码 是 进 行 堆 栈 的 设 置, 然 后 还 有 copy 一 些 数 据 到 RAM 中 去, 这 些 我 们 先 不 说 最 后 bl Main 跳 到 主 函 数 中 去 执 行 你 的 代 码! 0x18 b HandlerIRQ ;handler for IRQ interrupt 当 中 断 发 生 的 时 候 就 会 到 0x18 去 执 行 代 码, 然 后 跳 入 到 中 断 向 量 表 去 判 断 发 生 的 什 么 中 断 最 后 根 据 中 断 号 找 到 中 断 服 务 程 序 的 入 口 地 址, 然 后 执 行 中 断 服 务 程 序, 最 后 再 跳 回 到 原 先 的 地 方 继 续 执 行! 关 于 中 断 的 执 行 过 程 请 参 靠 其 他 书 籍!( 我 这 里 不 太 好 画 图 ) 仔 细 研 究 过 这 些 代 码 后 发 现 没 有 什 么 问 题, 因 为 既 然 程 序 能 够 跑 到 主 函 数 去 说 明 前 面 的 初 始 化 是 对 的 但 是 为 什 么 中 断 执 行 不 了 呢? 五 希 望 我 决 定 打 开 AXD 然 后 去 调 试 看 看 到 底 是 哪 里 出 了 错! 这 个 是 在 AXD 里 的 信 息 可 以 看 到 0x18 出 是 跳 转 到 了 0x2e4 这 个 是 一 个 非 条 件 跳 转! b 0x2e4! 灵 魂 附 体! 怎 么 回 事? 一 个 死 循 环? 这 个 和 我 想 的 可 不 一 样 啊! 怪 不 到 一 进 中 断 就 什 么 反 应 都 没 有 了, 人 家 死 循 环 着 呢! 该 死 的 问 题, 纠 缠 了 我 2 个 月 原 来 是 死 循 环 了 转 身 回 厨 房 泡 了 杯 茶, 点 了 支 烟 在 想 那 里 出 了 问 题 5 分 钟 后, 我 决 定 还 是 看 看 编 译 出 来 的 东 西 Test.bin 是 我 代 码 里 编 译 出 来 的 二 进 制 代 码!
这 个 和 编 译 器 里 的 不 一 样 啊, 难 道 我 编 译 的 东 西 一 直 没 有 在 里 面 运 行? 这 次 我 猜 对 了, 确 实 是 这 样 的 我 前 面 说 过 2410 是 没 有 Remap 机 制 的 我 把 二 进 制 代 码 放 到 了 0x30000000 的 地 方. 但 是 我 原 先 的 想 法 是 既 然 没 有 Remap 机 制, 那 么 肯 定 有 其 他 的 机 制 将 开 头 的 那 个 向 量 表, 放 到 0x00000000 但 是 其 实 我 错 了 那 么 开 始 的 那 段 代 码 是 谁 的 呢? 其 实 是 vivi 的 于 是 我 把 代 码 的 R0 Base 的 值 改 为 0x00000000 想 直 接 放 到 0x00000000 的 地 方 把 原 先 的 改 了 然 后 我 执 行, 这 次 我 乖 了, 先 看 看 内 存 里 面 的 值, 这 次 里 面 的 值 是 对 的 了 于 是 我 再 往 下 执 行, 执 行 到 入 了 main 函 数 之 后 没 有 执 行 几 条 然 后 就 报 错 了 然 后 pc 指 针 就 跑 到 了 一 个 很 奇 怪 的 地 址, 很 后 面! 俗 语 程 序 跑 飞 了! 六 真 相 我 打 开 地 址 然 后 看 内 存 空 间, 发 现 到 了 oxff0 后 面 的 地 址 里 面 的 内 容 是 乱 的, 不, 是 太 一 致 了! 到 了 这 个 份 上 我 算 是 醒 悟 过 来 了, 查 数 据 手 册 啊! 查 了 若 干 资 料 后,( 不 是 数 据 手 册 ) 找
到 了 2410 的 启 动 机 制 原 来 2410 是 有 一 个 4K 的 片 内 RAM, 启 动 之 后 会 将 NAND FLASH 中 前 面 4K 的 内 容 拷 贝 到 这 个 叫 做 stepping stone 的 4k RAM 中 执 行 ( 其 实 你 可 以 发 现 0x00000000 和 0x40000000 的 内 容 是 一 样 的!) 然 后 由 这 4k 的 代 码 copy flash 中 的 代 码 到 RAM 中 去 然 后 把 pc 指 到 RAM 中 的 某 个 开 始 的 地 方 来 运 行! 其 实 超 过 0xff0 后 面 的 数 据 是 乱 的,NAND FLASH 的 内 容 你 是 看 不 到 的! 知 道 了 这 个 原 因 我 就 变 聪 明 了, 写 了 以 下 代 码 : void copy_data(void) { char * p_tag,* p_src; int i=0; p_tag=0; p_src=(char *)0x30000000; for (i=0;i<4096;i++) { *p_tag++=*p_src++; } } 然 后 程 序 就 跑 OK 了!( 代 码 的 作 用 是 把 0x30000000 开 始 的 4k 内 容 放 到 0x00000000 去 ) 但 是 这 个 只 是 个 治 标 不 治 本 的 方 法, 也 只 是 适 合 于 调 试, 我 现 在 知 道 问 题 出 在 vivi 上! 于 是 打 开 vivi vivi\arch\s3c2410\head.s: 在 第 720 行 找 到 了 处 理 中 断 的 代 码 HandleIRQ: #ifdef CONFIG_DEBUG_LL mov r12, r14 ldr r0, STR_IRQ ldr r1, SerBase bl PrintWord bl PrintFaultAddr #endif 1: b 1b @ infinite loop 牛 人 让 中 断 自 己 玩 了! 至 此 想 必 大 家 知 道 如 何 处 理 了! 七 尾 声 现 在 我 已 经 做 在 电 脑 前 面 开 始 写 一 些 比 较 好 玩 点 的 代 码 了 收 获 是 知 道 如 何 去 解 决 这 些 问 题 教 训 是 : 数 据 手 册 啊, 一 定 要 看! 而 且 要 认 真 看!