原创 vsprog之S51部分源代码(RC4)以及大致解说

2008-11-17 00:31 3598 4 5 分类: MCU/ 嵌入式
  RC4版本大致已经搞定,也应该提供一个USB_TO_XXX的示例程序。按照原计划,公开S51的支持程序(包括USB_TO_XXX的底层驱动代码)。我也尽可能地附加一些说明(包括底层的代码和协议)。S51部分的代码,目前由网友hyy维护。

注意:所有的这些代码只是用于提供一个示例,不得用于商业应用。

vsprog之S51源代码:https://static.assets-stash.eet-china.com/album/old-resources/2008/11/17/c464ee70-0f41-4b0f-b9de-e41a1f937bec.zip

这里用进入编程模式的代码做一个说明。

S51进入编程模式的算法如下:
  芯片复位后,从SPI接口发送0xAC,0x53,0x00,0x00,然后,SPI接收的第四字节为0x69,这样就说明正常进入编程模式了。用这个算法举例是因为同时用到了USB_TO_GPIO(控制复位信号)、USB_TO_DELAY(控制延时)和USB_TO_SPI(执行操作)。

代码:



spi_init();<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


reset_init();



// use s5x_isp_frequency


spi_conf(s5x_isp_frequency);



// toggle reset


reset_output();


reset_set();


delay_ms(100);


reset_input();


delay_ms(30);


reset_output();


reset_set();


delay_ms(10);



// enter into program mode command


cmd_buf[0] = 0xAC;


cmd_buf[1] = 0x53;


cmd_buf[2] = 0x00;


cmd_buf[3] = 0x00;


tmp8 = 0;


// ret[3] should be 0x69


spi_io(cmd_buf, 4, &tmp8, 3, 1);


if((ERROR_OK != commit()) || (tmp8 != 0x69)) { LOG_ERROR("fail to enter into program mode, try a slower speed\n"); ret = ERROR_FAIL; goto leave_program_mode; }


按照算法,应该基本都看得懂,这里只是简单的作一下说明:
1.所有这些调用(spi_ini,reset_init,spi_conf,reset_output,reset_input,delay_ms,spi_io等),都是宏定义,通过宏来把应用层的函数格式转换成编程器统一驱动层的函数格式。代码如下:




#define spi_init() p->spi_init()


#define spi_fini() p->spi_fini()


#define spi_conf(speed) p->spi_config((speed), SPI_CPOL_LOW, SPI_CPHA_1EDGE, SPI_MSB_FIRST)


#define spi_io(out, outlen, in, inpos, inlen) p->spi_io((out), (in), (outlen), (inpos), (inlen))


#define reset_init() p->gpio_init()


#define reset_fini() p->gpio_fini()


#define reset_output() p->gpio_config(GPIO_SRST, 1)


#define reset_input() p->gpio_config(GPIO_SRST, 0)


#define reset_set() p->gpio_out(GPIO_SRST, GPIO_SRST)


#define reset_clr() reset_input()


#define delay_ms(ms) p->delayms((ms) | 0x8000)


#define delay_us(us) p->delayus((us) & 0x7FFF)



#define commit() p->peripheral_commit()


其中,p是传递给目标芯片的编程函数的编程器数据结构的指针,vsprog理论上是可以支持一些其他的编程器的,需要增加对应的驱动和数据结构即可。这里的宏就是调用编程器的数据结构里的对应函数,并做参数转换。
2.有一些函数需要返回数据的,是通过设置返回数据的大小,起始位置,并提供数据指针来实现的。比如这里的spi_io,第一和第二个参数是发送数据的指针和数据的字节大小,第三个参数是接收数据的指针(不接收就设置为NULL),第四个参数是指从返回数据的第n个字节开始复制,第五个参数是复制的字节数。这样spi_io(cmd_buf, 4, &tmp8, 3, 1);就是发送4个进入编程模式的命令,并接收第四个字节(序号是3,一个字节)的返回数据,并放入tmp8变量。这里需要注意的是,这些函数调用并不涉及到实际的操作,而只是记录下要发送的命令,在调用commit的时候,才会发送命令并接收执行结果(这样可以得到最高的USB带宽的利用率)。所以,需要保证调用commit时候,传递的指针可访问(如果在一个子函数中,传递一个auto变量的指针(位于堆栈上),而在子函数返回后才调用commit,这样就出问题了,因为在执行实际的操作的时候,会把返回的数据复制到未知的堆栈上)。
3.S51的复位是高电平有效,所以输出高电平是使芯片复位。而释放并不是输出低电平,而是把复位控制信号设置为输入。


  对于高层的代码,一切似乎都很简单,但是对于底层的驱动代码,就可能不是非常容易理解了。当然,如果对底层不感兴趣的话,可以直接忽略,而只是看一下接口部分提供的函数即可(在编程器的数据结构中定义的,可以被应用层调用的函数)。而且,我也不确定,我是否可以清楚地描述。
1.编程器的数据结构(programmer_info_t,位于programmer.h文件中),对于一些基本的应用,编程器的数据接口定义了应用层需要调用的函数。比如,对于SPI接口:




// spi


RESULT (*spi_init)(void);


RESULT (*spi_fini)(void);


RESULT (*spi_config)(uint16 kHz, uint8 cpol, uint8 cpha, uint8 first_bit);


RESULT (*spi_io)(uint8 *out, uint8 *in, uint16 len, uint16 inpos, uint16 inlen);


这里,spi_config的kHZ是SPI频率,cpol和cpha可以组合成SPI的4种模式,first_bit用于定义MSB_First还是LSB_First。spi_io前面已经说明过了(可能和应用层调用的方式不同,所以通过宏来转换了)。
2.数据结构的初始化
编程器的数据结构由编程器的驱动自己初始化,数据结构位于最前面的3个成员需要在结构定义时初始化:




programmer_info_t programmers_info[] = 


{


// versaloon


{


VERSALOON_STRING, // name


versaloon_check_argument, // check_argument


versaloon_init_capability, // init_capability


},


{ NULL }


};


versaloon_check_argument用来解析传递给编程器的命令行参数(注意不能和其他命令行参数的名字(一个字节)冲突),versaloon_init_capability用于初始化编程器的各种能力:




RESULT versaloon_init_capability(void *p)


{


((programmer_info_t *)p)->init = versaloon_init;


((programmer_info_t *)p)->fini = versaloon_fini;



((programmer_info_t *)p)->interfaces = (SPI | GPIO | ISSP | JTAG);



// SPI


((programmer_info_t *)p)->spi_init = versaloon_spi_init;


((programmer_info_t *)p)->spi_fini = versaloon_spi_fini;


((programmer_info_t *)p)->spi_config = versaloon_spi_config;


((programmer_info_t *)p)->spi_io = versaloon_spi_io;
......
}


其中,interfaces为该编程器支持的硬件接口(USB_TO_DELAY不算,因为这个延时也可以在上位机实现)。这样,主程序就可以判断需要的功能是否都具备。其他就是各个接口函数指针的初始化了。
3.命令的收集
USB_TO_XXX之所以可以简化很多操作,是因为由于协议通用,所以很多代码都可以通用。比如:




RESULT usbtospi_init(void)


{


return usbtoxxx_init_command(USB_TO_SPI, &usbtospi_num_of_interface);


}


RESULT usbtospi_io(uint8 interface_index, uint8 *out, uint8 *in, uint16 outlen, uint16 inpos, uint16 inlen)


{


#ifdef PARAM_CHECK


if(interface_index > 7) { LOG_BUG("invalid inteface_index %d\n", interface_index); return ERROR_FAIL; }


#endif



return usbtoxxx_inout_command(USB_TO_SPI, interface_index, out, outlen, outlen, in, inpos, inlen, 1);


}



想不到这2个函数竟然可以这么简单吧?
usbtoxxx_init_command设置对应的接口的USB_TO_XXX_INIT命令,该命令返回一个字节的数据,表明当前编程器支持的该种接口的数量,这里把这个数量放在usbtospi_num_of_interface变量中。
usbtoxxx_inout_command也类似,对应接口的USB_TO_XXX_INOUT命令。
更加想不到的是,这些usbtoxxx_xxxx_command实质上都是调用同一个函数(usbtoxxx_add_command):




RESULT usbtoxxx_add_command(uint8 type, uint8 cmd, uint8 *cmdbuf, uint16 cmdlen, uint16 retlen, uint8 *wantbuf, uint16 wantpos, uint16 wantlen, uint8 collect);


#define usbtoxxx_init_command(type, interface_num) usbtoxxx_add_command((type), (USB_TO_XXX_INIT), &null_char, 1, 1, interface_num, 0, 1, 0)


#define usbtoxxx_fini_command(type) usbtoxxx_add_command((type), (USB_TO_XXX_FINI), &null_char, 1, 0, NULL, 0, 0, 0)


#define usbtoxxx_conf_command(type, port, cmdbuf, cmdlen) usbtoxxx_add_command((type), (USB_TO_XXX_CONFIG | (port)), (cmdbuf), (cmdlen), 0, NULL, 0, 0, 0)


#define usbtoxxx_inout_command(type, port, cmdbuf, cmdlen, retlen, wantbuf, wantpos, wantlen, c) usbtoxxx_add_command((type), (USB_TO_XXX_IN_OUT | (port)), (cmdbuf), (cmdlen), retlen, wantbuf, wantpos, wantlen, (c))


#define usbtoxxx_in_command(type, port, cmdbuf, cmdlen, retlen, wantbuf, wantpos, wantlen, c) usbtoxxx_add_command((type), (USB_TO_XXX_IN | (port)), (cmdbuf), (cmdlen), retlen, wantbuf, wantpos, wantlen, (c))


#define usbtoxxx_out_command(type, port, cmdbuf, cmdlen, c) usbtoxxx_add_command((type), (USB_TO_XXX_OUT | (port)), (cmdbuf), (cmdlen), 0, NULL, 0, 0, (c))


#define usbtoxxx_poll_command(type, port, cmdbuf, cmdlen) usbtoxxx_add_command((type), (USB_TO_XXX_POLL | (port)), (cmdbuf), (cmdlen), 0, NULL, 0, 0, 0)

usbtoxxx_add_command就是把需要发送的命令放在USB发送数据的缓冲中,并且最后通过调用versaloon_add_pending设置对应的等待结构(versaloon_pending_result),这个结构在下面会说明,用于记录当接收的返回数据的时候,把需要的数据保存的方法(从第几个字节开始保存,并保存多少个字节等)。
4.命令的收发以及返回数据的解析
调用commit的时候,会把发送缓冲中的命令发送出去,并等待接收返回数据。然后根据versaloon_pending_result中的设置,解析返回数据(部分关键代码):




for(i = 0; i < versaloon_pending_idx; i++)


{


// get result data


if((versaloon_pending_result.want_data_size > 0) && (versaloon_pending_result.data_buffer != NULL))


{


memcpy(versaloon_pending_result.data_buffer, versaloon_buf + usbtoxxx_buffer_index + versaloon_pending_result.want_data_pos, versaloon_pending_result.want_data_size);


}



usbtoxxx_buffer_index += versaloon_pending_result.actual_data_size;



}


5.组合命令
为了高效的操作,有些命令是可以支持组合命令的,比如:
spi_io的几次连续的调用,是可以组合成一个单一的USB_TO_XXX_INOUT命令的。usbtoxxx_add_command的最后一个参数collect提供了这个支持,如果命令支持组合功能,并且调用时希望使用这个功能,就传递1。经测试,这个功能对速度有一定的影响。并且,目前SPI、ISSP、JTAG接口都支持这个功能。

PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

用户131114 2008-11-17 13:03

bug修正: vsprog.c的free_all_and_exit函数中: static void free_all_and_exit(int exit_code) { if((cur_programmer != NULL) && (cur_programmer->fini != NULL)) { cur_programmer->fini(); } // free buffer if(program_info.boot != NULL) { free(program_info.boot); program_info.boot = NULL; } ......
相关推荐阅读
用户131114 2010-12-25 22:43
征集各种单片机/存储器的支持
先随便列几个:Actel FPGA,Renesas R8C,Nuvoton Cortex。当然,Versaloon已经支持的就不需要了。当然,一些简单的比如SPI Flash,可以都可以。合作(或者交...
用户131114 2010-12-11 17:06
STM32F207 demo板原理图
这个硬件是VersaloonHandy平台的第一个测试评估硬件。资源:1. usb device + host, LTC41602. 3路可控电压,分别用于SD供电、TFT背光、对外供电,IIC接口控...
用户131114 2010-09-13 15:13
Versaloon 平台硬件规划
按照计划,几个平台都进行的非常顺利。第二批的生产也在进行中。 抽空规划了一下Versaloon平台的下一个硬件。1。使用120M STM32F203系列100脚芯片,USB 2.0 HS OTG2。2...
用户131114 2010-09-11 01:04
USBDM也成为浮云了。。。。。
HSC08/HCS12(X)的调试支持也基本按时完成了。。。。。。碰到的困难比预想的多,8过仍旧只是浮云。。。。。。coldfireV1应该也可以支持,不过需要有demo板测试并做相应的调整。 上图:...
用户131114 2010-09-02 02:28
Versaloon平台发展规划
最近发布的Versaloon调试仿真平台计划,相信很快就能完成第一阶段,有人怀疑不? Versaloon在实现的理念上,有其先进性,在同一个简单的硬件上,能够实现这么多种芯片的支持,并且具备不错的性能...
用户131114 2010-09-01 17:40
STLink简单的像浮云一样
原来计划花2天时间,没想到一天就搞定了。。。。。。在STM8S103F2上测试通过。STVP在下载STM8S103F2的速度并不是一般的慢啊,每次64字节。。。。。。OMG。。。。 下一步准备OSBD...
EE直播间
更多
我要评论
1
4
关闭 站长推荐上一条 /3 下一条