继乌克兰大神搞定f1c100s的裸奔usb主机之后我借网络工具翻译了musb编程指南供大家参考,文件在这里:musb_programming_guide(译文).pdf
@LinjieGuo
加载用户APP的详细准备工作代码如下:
void * LoadBin(char * buf, int vir_offset, char * file_start, process * pro)//vir_offset填0
{
void * stack;
app_hdr * phdr;
uint32_t vir_start;
int page;
CopyFile(buf, 0, file_start, 0, sizeof(app_hdr));
// spl_print32((u32)(file_start));spl_prints(" \r\n \r\n", 0);
// show_data((void*)buf);
phdr = (void*)buf;
vir_start = (phdr->load_addr) >> 20;
if(0x2e617070 != phdr->magic) return (void*)0xffffffff;
//准备虚拟空间
//需要适应phdr->load_addr - phdr->stack虚拟地址段
page = ((phdr->stack) >> 20) - (vir_start) + 1;//计算页数
while(page --)
{
PagePrepare(pro, vir_start << 20);
//拷贝映射关系到临时页表
*(Get_pgt_base(-1) + (int32_t)(vir_start)) = *(Get_pgt_base(pro->id_pro) + (int32_t)(vir_start));
vir_start ++;
}
//拷贝代码
vir_offset = 0;//这个使用0很有必要
CopyFile((char*)(phdr->load_addr), vir_offset, file_start, phdr->code_offset, phdr->code_size);
//清bss
FillData((char*)phdr->bss_addr, 0, phdr->bss_size);
//准备堆栈数据
stack = StackAlign((void*)(phdr->stack));
PrepareStack(stack, (void*)phdr->entry);
return stack;
}
@LinjieGuo
大佬你好!你的疑问1答案如下:
loader在运行os之前已为os部署好了虚拟环境,当然os在运行过程中也有部署虚拟环境的能力,各用户进程虚拟地址空间是严格分开的,loader中相关部署代码如下
uint32_t fill_table(void)
{
uint32_t* base_addr;
base_addr = (uint32_t*)PAGE_TABLE_ADDR;//第一个内核进程的页表地址//?物理地址,(至少16k对齐)
//4G空间全部归0(不可访问),页表项全0会产生错误
InitPageTable(base_addr);
// 起始向量表在此,第一阶段代码在此CNB,SRAM处物理和虚拟地址均可回收
map_l1_section(base_addr, 0x00000000, 0x00000000, 1 * SIZE_1M, PRI_RW_USR_RW, USE_CACHE);
// SDRAM空间,CB
map_l1_section(base_addr, 0xc0000000, 0x80000000, 16 * SIZE_1M, PRI_RW_USR_NOT, USE_CACHE|USE_BUFFER);
//任务SP、显示缓冲区放在用户空间
//内核堆栈、向量
map_l1_section(base_addr, 0xfff00000, 0x83f00000, 1 * SIZE_1M, PRI_RW_USR_NOT, USE_CACHE);
//页表
map_l1_section(base_addr, 0xffc00000, 0x83c00000, 3 * SIZE_1M, PRI_RW_USR_NOT, USE_CACHE);
map_l1_section(base_addr, 0xff900000, 0x01e00000, 1 * SIZE_1M, PRI_RW_USR_NOT, 0); // 外设
map_l1_section(base_addr, 0xff800000, 0x01c00000, 1 * SIZE_1M, PRI_RW_USR_NOT, 0); // 外设
return (uint32_t)base_addr;
/*
* 虚拟地址0xffc00000-0xfff00000 对应物理地址0x83c00000-0x83f00000 存放页表+内核栈、向量表(其中内核栈、向量表在最后一页)
*
*虚拟地址0xff800000-0xffb00000 分给外设使用
*
*虚拟地址0xc0000000开始分给内核代码+内核堆使用
*/
}
断电重启后需要重新下载OS吗,略麻烦
你也可以用常规方法通过USB口将arm9os.bin下载到spiflash的0x8000处,这样就固化了。我自己是因为要一直更新OS,一直在调试OS,所以保存OS到spiflash的功能没打开,其实我的OS有个头,当其中某字段设为1(该字段决定OS自己是否被保存)时,loader发现这个1,就会保存OS到spiflash。头如下:
typedef struct {// 80字节
uint32_t magic; // 文件标记0x27190556
uint32_t struct_size; // 自身尺寸
uint32_t entry; // 程序入口
uint32_t kernel_addr; // header的加载地址
uint32_t kernel_size; // header的长度
uint32_t kernel_crc; // header的校验值
uint32_t bss_addr; // BSS地址
uint32_t bss_size; // BSS大小
uint32_t isr_addr; // 中断服务程序地址数组首地址
uint32_t isr_nbr; // 地址个数
uint32_t rsv1; // 保留(最低位为1表示程序加载到SDRAM之后还要烧到spi flash)
uint32_t rsv2; // 保留
uint8_t name[32]; // 字符串
} kernel_header_t;
事情是这样的:随着大家都在玩f1c100s,作为一直玩GUI的我也注意到了该芯片,性价比比较高适合驱屏,该芯片CPU内核为ARM9,刚好是我比较熟悉的核,自己写的GUI一直用ucos在树莓派上跑,ucos我玩了太多年了,也翻译过ucos的代码,毕竟这个os并不免费,只能作为学习用途。单纯的多线程OS玩了太久,最近萌生了要自己写个多进程多线程OS,于是在网上搜集整理相关资料,感谢前辈们无私奉献、辛苦踩坑,尤其是xboot这样的大佬,以及其他一系列的大佬(不一一点名),最终它来了:基于tiny200 r3(f1c200s)板子的bootloader固件+多进程多线程OS镜像+APP开发模板。
大家都知道OS这个玩意相当复杂,请允许我详细介绍玩它的步骤,对,就是玩它...玩它...玩它...,详细步骤如下:
1、用传统方法通过usb口烧写boot.bin到spiflash的0x0位置;
2、用传统方法通过usb口烧写loader.bin到spiflash的0x3000位置;
3、注意因为loader有串口下载功能,完成以上两步之后,就再也不需要从usb口下载了;
4、数据线连接tiny200 r3的串口,并连接到电脑,打开串口工具(XCOM),选择正确串口,设置波特率115200;
5、轻按tiny200的RST键,松开后,迅速通过串口工具发送字符'2'~'6'中的一个,这时进入下载APP模式;
6、使用串口工具的文件发送功能,选择APP0.bin,点击发送,发送完毕后,该APP就保存到了spiflash中;
7、重复4到6步可以下载不同的APP,分别选择字符'2'到'6'一共允许下载5个APP到spiflash中;
8、轻按tiny200的RST键,松开后,迅速通过串口工具发送字符'1',这时进入下载OS模式;
9、使用串口工具的文件发送功能,选择arm9os.bin,点击发送,发送完毕后,OS开始运行;
10、使用串口的多条发送功能,发送字符串"run app02",这时OS会加载第一个APP并运行它,如果发送字符串"run app03",这时OS加载第二个APP并运行它,以此类推......
注释:字符'2'~字符'6'是下载APP的指令,字符'1'是下载操作系统的指令,下载时不要选错文件;"run app"是加载并运行APP的指令。
相关文件如下:
串口工具:XCOM V2.0.exe
boot:boot.rar
loader:_loader.rar
arm9os:arm9os.rar
APP模板:APP0.rar
为了方便玩f1c100s/f1c200s的小伙伴能实现串口下载程序,我自己实现了write—spiflash功能
代码使用如下:
p = (kernel_header_t *)0xc0000000;//起始位置放的是程序头
if(p->rsv1 & 0x1)//判断是否需要将程序存入spiflash
{
//从0xc0000000搬到spiflash的0x8000处,然后重新上电运行(方案1)
sys_spi_flash_init();
n = size / 4096;//1扇区4k(4096)
if(size % 4096) n ++;
cnt = 0;
while(n --)
{
sys_spi_EraseSector(0x8000 + cnt*4096);//根据size计算擦除扇区数
cnt ++;
}
n = size / 256;//1页256字节
if(size % 256) n ++;
cnt = 0;
while(n --)
{
sys_spi_WritePage(0x8000 + cnt*256, (void*)0xc0000000 + cnt*256);//根据size计算写入页数
cnt ++;
}
sys_spi_flash_exit();
}
相关底层代码主要是擦除和写flash,可点击下面链接下载:
IAP很方便,不需要每次使用工具从usb口烧写。
祝你使用我的代码很愉快!
下面这个验证是好的
准备自己搞个多进程OS,大伙要不要试试这个loader,我也在测试中,望提宝贵意见
编译方法:
1、使用eclipse打开工程,直接编译生成bin文件
2、编译makesunxi工具
3、使用makesunxi工具对bin文件头部进行处理
4、按照usb下载方法下载loader到spiflash0x000000处
5、新建一个工程,编译下载到spiflash0x100000处
系统上点之后,loader被加载,之后loader初始化硬件,并把你下载到flash的代码前1024字节加载到0x80000000处,并跳到这里。你需要确保跳到0x80000000之后不要跑飞了
由于我不会在linux下烧程序到板子,我都是在windows下操作。所以我找了宿主机和客户机之间互换文件的方法,希望把编译的文件拿倒windows下烧写。具体方法见这个网页: https://www.cnblogs.com/sunev/archive/2012/03/16/2400887.html
分享一个链接,韦东山讲得不错,你要快速知道Linux是如何被启动的,请看以下链接,uboot太大了不方便。
链接在此:
http://blog.chinaunix.net/uid-22072065-id-5111239.html
另附一堆韦哥的免费视频:
https://v.youku.com/v_show/id_XNjMxNDUwNjMy.html?f=20746515&from=y1.2-3.4.23
业余花了一段时间破解三菱PLC,暂支持27条基本指令,后续继续完善。如有想玩的朋友,可以搭个硬件试试。
我是三哥,QQ58223001
https://whycan.cn/files/members/1056/chengju_plc20191016.rar