打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
干货 | DIY 一个 ARM 学习机

我对底层的东西特别感兴趣。十多年前有了自己的电脑,一直保留DOS用了好些年。喜欢汇编,讨厌Java。接触的第一个单片机是AT89S52,下程序是用串口CTS/RTS以及DSR/DTR控制线来模拟SPI,在DOS下把时钟中断调到几十kHz来定时确定时序。后来就用89S52做成了2051的编程器,再后来用2051做了串口转SPI下载器玩起AVR了,玩过最多的还是AVR.

不过51、AVR这类Harvard结构MCU不能干的事情是自己Load程序来运行,只能从ROM执行啊(51可以有办法映射,但是51学习机计划没有实施)。我小时候听说过“中华学习机”,不同于小霸王学习机那样ROM固化死了的,人家是从软盘装载程序的。家里头的旧杂志上介绍过TD-I型8031的学习机,是用开关来二进制编程RAM然后执行的,倘若放到今天……

我生活的时代已经不是穿孔纸带了,DIY还是玩现代的东西吧。言归正传,我的第一个“学习机”作品是ARM7TDMI的,尽管这个核已经早过时了。我选择了NXP的LPC2220作为处理器,它自带64kB的RAM,在单片机中算是大的了。核心比较简单,作为学习机适宜,而且有外部总线,比较方便扩展RAM,类似PC那样来玩。这个PCB做得比较早了,搁置没玩起来(手头没时间玩的板子多了,这是另外的问题),上面除了MCU还有一块16bit*256k的SRAM,一片8bit*128k的NOR Flash ROM,预留16-bit总线插针扩展,具备一个计算机的配置了(除了缺少DMA支持)。下面是线路图:


PCB的顶层图


 
 PCB的底层:


 

作为MCU自带的外设是可以引出来的,所以UART, SPI, I2C基本I/O通信用分组接到插针,再另外放了16个GPIO在一侧。核心部分先焊上就可以玩了。


 
上面介绍的是硬件部分。LPC2220是为数不多的ROMless单片机,里面没有Flash哦,OTP也没有。这也是我选择它的原因,作为学习机不是做任何应用的原型板,烧写Flash尽量避免吧。虽然Flash的烧写次数已经够多了,能省一事算一事。NXP的ARM7 (LPC21xx系列)有个特点是可以从PC直接ISP下载到RAM,然后运行。我在第一次玩ARM (LPC2103)的时候发现Flash工具有这个功能。

读NXP的手册,发现Bootloader是使用串口命令进行交互的,命令也不复杂。



所以,只要连接MCU的UART0到PC的串口,上电或者复位就进入Bootloader里面的ISP程序(因为没有可执行的ROM嘛),就可以从PC把代码直接下载到ROM然后运行了。64kB的SRAM哦,可以实现不少东西了吧。

当然,用NXP官方的FlashMagic来下载的效率太低了,不适应“学习机"要快速载入程序的要求。所以我自己做一个程序:

  1. #include<windows.h>

  2. #include<stdio.h>

  3. #include<string.h>

  4. #include<stdlib.h>

  5. HANDLE dev;

  6. OVERLAPPED oWR = {0}, oRD={0};

  7. void errexit(char *s)

  8. {

  9.   fprintf(stderr,"%s",s);

  10.   exit(1);

  11. }

  12. struct ROM

  13. {

  14.   unsigned char b;

  15.   char oc;

  16. };

  17. int readcomm(unsigned char *buf, int maxlen, int timeout);

  18. int writecomm(unsigned char *buf, int len);

  19. int loadhexfile(char *fn,int szlimit,int *poff,struct ROM *rom);

  20. int showbinary(int szlimit, struct ROM *rom);

  21. int uuencode(int szlimit, struct ROM *rom, char *buf, int slen, int linelen);

  22. int checksum(int szlimit, struct ROM *rom);

  23. main(int argc, char *argv[])

  24. {

  25.    DCB dcb;

  26.    int i,r;

  27.    if(argc<2)

  28.    {

  29.        printf("Supply a HEX file name.\n");

  30.        return;

  31.    }

  32.    dev=CreateFile("COM3", GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,  FILE_FLAG_OVERLAPPED,0);

  33.    if(dev==INVALID_HANDLE_VALUE)

  34.    {

  35.        printf("Cannot open COM3 port.\n");

  36.        exit(1);

  37.    }

  38.    FillMemory(&dcb, sizeof(dcb), 0);

  39.    dcb.DCBlength = sizeof(dcb);

  40.    BuildCommDCB("57600,n,8,1",&dcb);

  41.    if (!SetCommState(dev, &dcb))

  42.    {

  43.        printf("Cannot set port parameters.\n");

  44.        exit(1);

  45.    }

  46.    oWR.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

  47.    oRD.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

  48.    for(i=0;i<1000;i++)

  49.    {

  50.        int len0;

  51.        char c, buf[32];

  52.        char done=0;

  53.        writecomm("?",1);

  54.        r=readcomm(buf,4,20);

  55.        if(r>0)

  56.        {

  57.            int j;

  58.            for(j=0;j<r;j++)

  59.            {

  60.                printf("%c",buf[j]);

  61.                if(buf[j]=='S')

  62.                {

  63.                    r=readcomm(buf+r,14-(4-j),20);

  64.                    if(r==14-(4-j) && strncmp(buf+j,"Synchronized\r\n",14)==0)

  65.                    {

  66.                        printf("SYNC\n");

  67.                        writecomm("Synchronized\r\n",14);

  68.                        r=readcomm(buf,32,50);

  69.                        if(r==18 && strncmp(buf,"Synchronized\r\nOK\r\n",18)==0)

  70.                        {

  71.                            printf("Synchronization done\n");

  72.                            done=1;

  73.                            break;

  74.                        }

  75.                        else

  76.                            printf("(%d) %s",r,buf);

  77.                    }

  78.                }

  79.            }

  80.            if(done) break;

  81.        }

  82.        else

  83.        {

  84.            printf(".");

  85.            continue;

  86.        }

  87.    }

  88.    {

  89.        char c;

  90.        writecomm("11095\r\n",7);

  91.        while(readcomm(&c,1,10)>0)

  92.        {

  93.            printf("%c",c);

  94.        }

  95.    }

  96.    {

  97.        char c;

  98.        writecomm("J\r\n",3);

  99.        while(readcomm(&c,1,10)>0)

  100.        {

  101.            printf("%c",c);

  102.        }

  103.    }

  104.    {

  105.        unsigned int progaddr=0x40000200;

  106.        char c;

  107.        char str[128];

  108.        char buf[512];

  109.        int slen;

  110.        int pgsize;

  111.        struct ROM rom[1024];

  112.        int offset=-1;

  113.        pgsize=loadhexfile(argv[1],1024,&offset,rom);

  114.        printf("Program Size: %d bytes from %X\n", pgsize, offset);

  115.        showbinary(1024,rom);

  116.        sprintf(str,"W %d %d\r\n",progaddr, pgsize);

  117.        slen=strlen(str);

  118.        writecomm(str,slen);

  119.        while(readcomm(&c,1,10)>0)

  120.        {

  121.            printf("%c",c);

  122.        }

  123.        slen=uuencode(1024, rom, buf, 512, 61);

  124.        writecomm(buf,slen);

  125.        sprintf(str,"%d\r\n",checksum(1024,rom));

  126.        slen=strlen(str);

  127.        writecomm(str,slen);

  128.        while(readcomm(&c,1,10)>0)

  129.        {

  130.            printf("%c",c);

  131.        }

  132.        writecomm("U 23130\r\n",9);

  133.        while(readcomm(&c,1,10)>0)

  134.        {

  135.            printf("%c",c);

  136.        }

  137.        sprintf(str,"G %d T\r\n",progaddr);

  138.        slen=strlen(str);

  139.        writecomm(str,slen);

  140.        while(readcomm(&c,1,10)>0)

  141.        {

  142.            printf("%c",c);

  143.        }

  144.    }

  145.    CloseHandle(oWR.hEvent);

  146.    CloseHandle(oRD.hEvent);

  147.    CloseHandle(dev);

  148. }

  149. int writecomm(unsigned char *buf, int len)

  150. {

  151.    int r;

  152.    int len0;

  153.    r=WriteFile(dev,buf,len,&len0, &oWR);

  154.    if(r==0)

  155.    {

  156.        if(GetLastError()!=ERROR_IO_PENDING)

  157.        {

  158.            printf("COM port access error!\n");

  159.            exit(1);

  160.        }

  161.        GetOverlappedResult(dev, &oWR, &len0, TRUE);

  162.    }

  163.    return len0;

  164. }

  165. int readcomm(unsigned char *buf, int maxlen, int tmout)

  166. {

  167.     static unsigned wait=0;

  168.     static unsigned char ch;

  169.     int i, len0, r;

  170.     if(tmout<=0)

  171.         return 0;

  172.     for(i=0;i<maxlen;i++)

  173.     {

  174.         if(!wait)

  175.         {

  176.             if(ReadFile(dev,&ch,1,&len0, &oRD))

  177.             {

  178.                 wait=0;

  179.                 buf[i]=ch;

  180.                 continue;

  181.             }

  182.             if(GetLastError()!=ERROR_IO_PENDING)

  183.             {

  184.                 printf("Read COM port error!\n");

  185.                 exit(1);

  186.             }

  187.         }

  188.         r=WaitForSingleObject(oRD.hEvent,1);

  189.         if(r==WAIT_TIMEOUT)

  190.         {

  191.             wait=1;

  192.             tmout--;

  193.             if(tmout==0)

  194.                 return i;

  195.             else

  196.             {

  197.                 i--;

  198.                 continue;  

  199.             }

  200.         }

  201.         if(r==WAIT_OBJECT_0)

  202.         {

  203.             wait=0;

  204.             buf[i]=ch;

  205.             continue;

  206.         }

  207.     }

  208.     return i;

  209. }

  210. int loadhexfile(char *fn,int szlimit,int *poff,struct ROM *rom)

  211. {

  212.     int i,j,n,count,addr,waddr,bsz;

  213.     char line[512];

  214.     unsigned char bb,sum,hex[256];

  215.     FILE *fp;

  216.     memset(rom,0,sizeof(struct ROM)*szlimit);

  217.     fp=fopen(fn,"r");

  218.     if(fp==NULL)

  219.     {

  220.         printf("Cannot open HEX file %s\n",fn);

  221.         return 0;

  222.     }

  223.     printf("Opening file %s for reading... ",fn);

  224.     count=0;

  225.     sum=0;

  226.     for(n=1;;n++)

  227.     {

  228.         if(!fgets(line,512,fp))

  229.             errexit("read error\n");

  230.         if(line[0]!=':')

  231.             errexit("FORMAT ERROR\n");

  232.         j=0;

  233.         for(i=1;;i+=2)  // convert ASCII to binary

  234.         {

  235.             switch(line[i])

  236.             {

  237.                 case 'A':  bb=0xa0;  break;

  238.                 case 'B':  bb=0xb0;  break;

  239.                 case 'C':  bb=0xc0;  break;

  240.                 case 'D':  bb=0xd0;  break;

  241.                 case 'E':  bb=0xe0;  break;

  242.                 case 'F':  bb=0xf0;  break;

  243.                 case '\0':  case '\r':  case '\n': bb=0x77;  break;

  244.                 default:  if(line[i]>='0' && line[i]<='9')

  245.                               bb=(line[i]-'0')<<4;

  246.                           else

  247.                               bb=0xff;

  248.             }

  249.             if(bb==0x77)

  250.                 break;

  251.             if(bb==0xff)

  252.                 errexit("INVALID CHARACTER\n");

  253.             switch(line[i+1])

  254.             {

  255.                 case 'A':  bb+=0xa;  break;

  256.                 case 'B':  bb+=0xb;  break;

  257.                 case 'C':  bb+=0xc;  break;

  258.                 case 'D':  bb+=0xd;  break;

  259.                 case 'E':  bb+=0xe;  break;

  260.                 case 'F':  bb+=0xf;  break;

  261.                 default:  if(line[i+1]>='0' && line[i+1]<='9')

  262.                               bb+=(line[i+1]-'0');

  263.                           else

  264.                               errexit("BAD BYTE\n");

  265.             }

  266.             sum+=bb;

  267.             hex[j]=bb;

  268.             j++;

  269.         } // converted ASCII to binary

  270.         if(sum!=0)

  271.             errexit("CHECKSUM ERROR\n");

  272.         if(j<5)

  273.             errexit("LINE TOO SHORT\n");

  274.         if(hex[0]!=j-5)

  275.             errexit("FORMAT ERROR\n");

  276.         bsz=j-5;

  277.         switch(hex[3])

  278.         {

  279.             case 0:   addr=hex[1];   addr<<=8;  addr+=hex[2];

  280.                       if(*poff==-1)

  281.                       {

  282.                           *poff=addr;

  283.                       }

  284.                       for(i=0;i<bsz;i++)

  285.                       {

  286.                           int waddr=addr-(*poff);

  287.                           if(waddr>szlimit)

  288.                           {

  289.                               printf("address %X beyond range (base %X) \n",addr, *poff);

  290.                           }

  291.                           else

  292.                           {

  293.                              rom[waddr].b=hex[4+i];

  294.                              rom[waddr].oc=1;

  295.                           }

  296.                           addr++;

  297.                           count++;

  298.                       }

  299.                       break;

  300.             case 1:   if(j!=5)

  301.                           errexit("UNEXPECTED END\n");

  302.                       fclose(fp);

  303.                       return count;

  304.             case 2:   if(hex[1]!=0 || hex[2]!=0 || hex[4]!=0 || hex[5]!=0)

  305.                           printf("UNSUPPORTED PARAGRAPH\n");

  306.                       break;

  307.             case 3:

  308.             default:  printf("UNSUPPORTED RECODE TYPE (%X)\n", hex[3]); break;

  309.         }

  310.     }

  311. }

  312. int showbinary(int szlimit, struct ROM *rom)

  313. {

  314.     int i;

  315.     for(i=0;i<szlimit;)

  316.     {

  317.         int j;

  318.         char blank=1;

  319.         for(j=0;j<16;j++)

  320.         {

  321.             if(rom[i+j].oc)

  322.             {

  323.                 blank=0;

  324.                 break;

  325.             }

  326.         }

  327.         if(blank)

  328.         {

  329.             i+=16;

  330.             continue;

  331.         }

  332.         printf("%04X: ",i);

  333.         for(j=0;j<16;j++)

  334.         {

  335.             if(rom[i+j].oc)

  336.                 printf("%02X",rom[i+j].b);

  337.             else

  338.                 printf("..");

  339.             if(j==7)

  340.                 printf(" - ");

  341.             else

  342.                 printf(" ");

  343.         }

  344.         printf(" | ");

  345.         for(j=0;j<16;j++)

  346.         {

  347.             if(rom[i+j].oc)

  348.             {

  349.                 if(rom[i+j].b>=0x20 && rom[i+j].b<=0x7f)

  350.                     printf("%c",rom[i+j].b);

  351.                 else

  352.                     printf("?");

  353.             }

  354.             else

  355.                 printf(".");

  356.         }

  357.         i+=16;

  358.         printf("\n");

  359.     }

  360. }

  361. int uuencode(int szlimit, struct ROM *rom, char *buf, int slen, int linelen)

  362. {

  363.     int i, sz=0,mem;

  364.     int lmax, lc, brem;

  365.     int index=0;

  366.     for(i=0;i<szlimit;i++)

  367.     {

  368.         if(rom[i].oc)

  369.             sz=i+1;

  370.     }

  371.     lmax=((linelen-1)/4)*3;

  372.     lc=sz/lmax;

  373.     brem=sz%lmax;

  374.     mem=lc*(((linelen-1)/4)*4+3)+3+(brem/3*4)+(brem%3+1);  // include CR LF

  375.     if(mem>=slen)

  376.     {

  377.         printf("UUEncode: buffer too small! need %d bytes\n",mem);

  378.         return 0;

  379.     }

  380.     for(i=0;i<sz;)

  381.     {

  382.         int j, len;

  383.         char r=0;

  384.         unsigned char b, a=0;

  385.         if(i+lmax<sz)

  386.             len=lmax;

  387.         else

  388.             len=brem;

  389.         buf[index++]=0x20+len;

  390.         for(j=0;j<len;j++)

  391.         {

  392.             if(rom[i+j].oc)

  393.                 b=rom[i+j].b;

  394.             else

  395.                 b=0xff;

  396.             a|=(b>>(2+r));

  397.             if(a) buf[index++]=0x20+a; else buf[index++]='`';

  398.             r+=2;

  399.             a=((b&((1<<r)-1))<<(6-r));

  400.             if(r==6)

  401.             {

  402.                 if(a) buf[index++]=0x20+a; else buf[index++]='`';

  403.                 r=0;

  404.                 a=0;

  405.             }

  406.         }

  407.         if(r!=0)

  408.         {

  409.             if(a) buf[index++]=0x20+a; else buf[index++]='`';

  410.         }

  411.         i+=lmax;

  412.         buf[index++]='\r';

  413.         buf[index++]='\n';

  414.     }

  415.     printf("MEM %d, actual %d\n",mem,index);

  416.     return index;

  417. }

  418. int checksum(int szlimit, struct ROM *rom)

  419. {

  420.     int i, sz, sum;

  421.     sz=0;

  422.     for(i=0;i<szlimit;i++)

  423.     {

  424.         if(rom[i].oc)

  425.             sz=i+1;

  426.     }

  427.     sum=0;

  428.     for(i=0;i<sz;i++)

  429.         sum+=rom[i].b;

  430.     return sum;

  431. }

复制代码


这个程序做的工作是打开串口, 和单片机Bootloader ISP命令同步,然后读取指定的HEX文件,下载到LPC2220的RAM地址 0x40000200, 再解除锁定,最后发送执行程序的命令,单片机从 0x40000200 开始运行。如果要重新下载程序,把单片机Reset了,再运行以上的程序即可。命令行一步搞定,容易吧!

注: LPC2220的RAM地址从 0x40000000 开始,但是BootLoader会用一部分RAM,所以为了避免冲突,程序下载从RAM的512字节之后起。NXP的Bootloader是用UUEncode编码传输二进制数据的,上面的程序包含编码的子程序。这个程序也写得不完善,还有比如代码长度检查都没有做进去,目前做到的只是能下载一小段并执行。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
ASCII与十六制字符串互相转换
C语言中可变参数的用法与实例
随想录(做自己代码的测试工程师)
c语言中串比较函数
C语言字符串函数大全
C/C++: 十六进制转10进制源码
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服