6486|0

1381

帖子

2

TA的资源

五彩晶圆(初级)

楼主
 

用命令行工具简化 STM8 程序的编译流程 [复制链接]

本帖最后由 cruelfox 于 2017-12-30 23:32 编辑

我购买STM8S Discovery开发板的时间比买STM32开发板还早,但反而用了几年STM32后也没用起来STM8,偶尔用到的8位MCU还是AVR. 其中一个原因是我工惯了GCC,stm32, AVR都有gcc编译器工具链的支持,但STM8没有,我就没有花时间去折腾编译工具了。

ST官方提供了STM8的开发工具叫STVD,"Visual Develop"的缩写,从ST网站上可以下到。链接进去,下载的安装包其实是 st_toolset, 它支持STM8,还有更老的ST7,安装后其实还包含了ST Visual Programmer软件等。STVD的界面很像老的MS Visual Studio 6.0,它只是一个工程管理器、编辑器加调试器,并不包含汇编、编译工具。st_toolset安装后带了一套汇编工具,在 st_toolset\asm 目录下面,也包含了MCU寄存器描述使用的汇编头文件(.inc, .asm)

很难再纯用汇编来开发MCU程序了,st_toolset\include 下面提供了给C编译器用的 .h 头文件,但是没有编译器。在STVD上面新建工程的时候,可以选择 COSMIC 或者 Raisonace 的C编译器,需要指定第三方工具的路径;STVD会生成一个什么也不做的C程序模板。配置好后STVD会去调用这两家的工具来完成编译和链接。下载和调试则是STVD自己内带的功能。

本人的喜好还是用命令行工具,所以抛开STVD这个图形界面,直接找COSMIC的工具来用吧。从COSMIC的网站上可以下载到32k代码限制的免费版编译器(申请一个免费license)。IAR好象也提供有限制的免费编译器EWSTM8,我没有试过。除此之外就是著名的开源软件 SDCC 了。

好,如何从 C 代码得到最终下载到单片机的 HEX/BIN 文件呢?除了编译工具程序,还需要哪些支持的资源?
(A) 寄存器描述的文件,一般是 .h 形式。这个需要由单片机厂商提供,也就是给每个寄存器的地址起一个名字,在C语言里面能直接操作。不过定义方式又跟编译器有一定关系,因为它不是普通的内存地址。
(B) 中断向量表的定义,也是需要单片机厂商提供,不同型号不一样。它也需要结合编译器特性来书写。
(C) 初始化代码,也就是从RESET中断入口开始执行的程序。一般是一段汇编代码。
(D) C运行代码,包括标准库函数的头文件、编译好的库函数代码,以及软件开发时没有明写但会隐含地调用的库函数代码。这个通常是C编译工具一起提供的,也不一定全部由编译器厂商提供,例如GCC和newlib是两部分的软件。
(E) 地址空间的说明,ROM, RAM的大小和位置。

下面以我写的一个 LED 数码管显示循环计数的简单程序为例子. C源程序是这样的:
  1. #include "stm8s003f3.h"

  2. void myDelay(unsigned int value)
  3. {
  4.      unsigned int i,j;
  5.      for(i=0;i<40;i++)
  6.      {
  7.          for(j=0;j<value;j++);
  8.      }
  9. }

  10. void GPIO_Config(void)
  11. {
  12.      PA_DDR = 1<<3|1<<2|1<<1;   // LED COMx ctrl
  13.      PA_CR1 = 1<<3|1<<2|1<<1;   // LED COMx ctrl
  14.      PA_ODR = 1<<3|1<<2|1<<1;   // initial High
  15.      PC_DDR = 0xf0; // PC4..7 LED seg (open drain)
  16.      PD_DDR = 1<<6|1<<5|1<<4|1<<3; // PD3..6 LED seg (open drain)
  17. }

  18. void translate(short d, char *dig)
  19. {
  20.     const char table[10]={24, 95, 104, 73, 15, 137, 136, 93, 8, 9};
  21.     const char segdp=247;
  22.     d%=1000;
  23.     dig[0]=table[d/100];
  24.     d%=100;
  25.     dig[1]=table[d/10];
  26.     d%=10;
  27.     dig[2]=table[d];
  28. }

  29. int main(void)
  30. {
  31.     char dig[3];
  32.     GPIO_Config();
  33.     while(1)
  34.     {
  35.         int i;
  36.         static unsigned short count=0;
  37.         translate(count, dig);
  38.         count++;
  39.         if(count>999)
  40.             count=0;
  41.         for(i=0;i<100;i++)
  42.         {
  43.             PC_ODR = dig[0]&0xf0;
  44.             PD_ODR = dig[0]<<3;
  45.             PA_ODR = 1<<3|1<<2;
  46.             myDelay(10);
  47.             PC_ODR = dig[1]&0xf0;
  48.             PD_ODR = dig[1]<<3;
  49.             PA_ODR = 1<<3|1<<1;
  50.             myDelay(10);
  51.             PC_ODR = dig[2]&0xf0;
  52.             PD_ODR = dig[2]<<3;
  53.             PA_ODR = 1<<2|1<<1;
  54.             myDelay(10);
  55.         }
  56.     }
  57. }
复制代码


程序里面用到 STM8 的寄存器只有 GPIO 控制的几个寄存器,它们的定义包含在 stm8s003f3.h 这个头文件中。前面提过,这个头文件在 st_toolset\include 目录下。弄到之后就可以编译这个文件(count.c)得到目标文件(count.obj)了。 COSMIC C 编译器的编译工具叫做 cxstm8, 它的命令行参数说明在COSMIC的Docs目录下用户手册里面。我用如下命令来执行编译:
cxstm8 +mods0 -i../st_toolset/include count.c
其中 +mods0 是指定Memory model(mods0 对我这个小程序使用合适),-i参数是头文件搜索路径。

接下来需要链接操作,COSMIC的链接工具叫做 clnk, 它和常见的linker用法有所不同,需要在命令行上指定一个 .lkf 文件,而不是指定刚才编译得到的 .o 文件。起初我很不习惯,思索过觉得这样也和用GNU ld需要指定一个脚本类似的。这个 .lkf 文件怎么写,找个例子参考再改改就可以了。在用STVD编译的时候,它会对应Debug和Release版本各生成一个.lkf文件,其实在 st_toolset 目录下搜索可以找到几个范本。

我改写的一个 test.lkf 文件内容是这样:
#   LINK COMMAND FILE FOR TEST PROGRAM

+seg .text -b 0x8080 -n .text       # program start address
+seg .const -a .text -n .const      # constants follow vector
+seg .bsct -b 0x0 -m 0x100      # zero page start address
+seg .data -b 0x100 -n .data
+seg .bss -a .data -n .bss

crts0.sm8               # startup routine
count.o                 # application program

libis0.sm8
libm0.sm8

+seg .const -b 0x8000 -m 0x80       # vectors start address
stm8_interrupt_vector.o             # interrupt vectors

# define these symbols if crtsi is used
+def __endzp=@.ubsct            # end of uninitialized zpage
+def __memory=@.bss         # end of bss segment
+def __stack=0x1ff

上面 count.o,  stm8_interrupt_vector.o 是C文件编译得到的,另外几个 crts0.sm8, libis0.sm8, libm0.sm8 都是COSMIC提供的初始化代码及函数库。 代码段、数据段的地址安排在这个文件中定义。中断向量表由 stm8_interrupt_vector.c 文件编译产生,它在 st_toolset\stvd\builder 目录下面,内容如下
  1. /*  BASIC INTERRUPT VECTOR TABLE FOR STM8 devices
  2. *  Copyright (c) 2007 STMicroelectronics
  3. */

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

  5. struct interrupt_vector {
  6.     unsigned char interrupt_instruction;
  7.     interrupt_handler_t interrupt_handler;
  8. };

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

  16. extern void _stext();     /* startup routine */

  17. struct interrupt_vector const _vectab[] = {
  18.     {0x82, (interrupt_handler_t)_stext}, /* reset */
  19.     {0x82, NonHandledInterrupt}, /* trap  */
  20.     {0x82, NonHandledInterrupt}, /* irq0  */
  21.     {0x82, NonHandledInterrupt}, /* irq1  */
  22.     {0x82, NonHandledInterrupt}, /* irq2  */
  23.     {0x82, NonHandledInterrupt}, /* irq3  */
  24.     {0x82, NonHandledInterrupt}, /* irq4  */
  25.     {0x82, NonHandledInterrupt}, /* irq5  */
  26.     {0x82, NonHandledInterrupt}, /* irq6  */
  27.     {0x82, NonHandledInterrupt}, /* irq7  */
  28.     {0x82, NonHandledInterrupt}, /* irq8  */
  29.     {0x82, NonHandledInterrupt}, /* irq9  */
  30.     {0x82, NonHandledInterrupt}, /* irq10 */
  31.     {0x82, NonHandledInterrupt}, /* irq11 */
  32.     {0x82, NonHandledInterrupt}, /* irq12 */
  33.     {0x82, NonHandledInterrupt}, /* irq13 */
  34.     {0x82, NonHandledInterrupt}, /* irq14 */
  35.     {0x82, NonHandledInterrupt}, /* irq15 */
  36.     {0x82, NonHandledInterrupt}, /* irq16 */
  37.     {0x82, NonHandledInterrupt}, /* irq17 */
  38.     {0x82, NonHandledInterrupt}, /* irq18 */
  39.     {0x82, NonHandledInterrupt}, /* irq19 */
  40.     {0x82, NonHandledInterrupt}, /* irq20 */
  41.     {0x82, NonHandledInterrupt}, /* irq21 */
  42.     {0x82, NonHandledInterrupt}, /* irq22 */
  43.     {0x82, NonHandledInterrupt}, /* irq23 */
  44.     {0x82, NonHandledInterrupt}, /* irq24 */
  45.     {0x82, NonHandledInterrupt}, /* irq25 */
  46.     {0x82, NonHandledInterrupt}, /* irq26 */
  47.     {0x82, NonHandledInterrupt}, /* irq27 */
  48.     {0x82, NonHandledInterrupt}, /* irq28 */
  49.     {0x82, NonHandledInterrupt}, /* irq29 */
  50. };
复制代码

因为我这个例子程序不用到中断,所以只处理 RESET入口就够了,这是用默认的。
链接命令执行:
clink -o count.sm8 test.lkf
就得到整个程序机器代码文件了。不过,还要转换下格式,才可以给烧写工具用。生成HEX文件执行:
chex -fi -o count.hex count.sm8
这样得到了STVP可以用的 count.hex 文件。

对于简单的程序,可以把 cxstm8, clink, chex 这几步命令写成批一个处理文件。复杂一点可以写一个Makefile,然后用make命令来处理编译过程。

汇总一下,开发 STM8 需要的(免费)软件:
1. COSMIC C STM8 编译器
2. st toolset 这个开发工具集合,但只用到其中一部分东西
  (1)  st_toolset\include 下面的STM8型号相关头文件
  (2) st_toolset\stvd\Example 里面能找到的 stm8_interrupt_vector.c 文件
  (3) st_toolset\stvd\Example 里面能找到的 .lkf 文件
  (4) STVP 烧写工具,有GUI和命令行版本

其中2 部分(1)(2)(3)也不是唯一的,比如可以下载 STM8 Standard Periphral Library 软件包,能找到功能相似,支持更丰富的代码。

此内容由EEWORLD论坛网友cruelfox原创,如需转载或用于商业用途需征得作者同意并注明出处

此帖出自单片机论坛
点赞 关注
 

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表