EEWorld 电子工程世界

文章数:10804 被阅读:13623255

账号入驻

干货 | DIY 一个 ARM 学习机

最新更新时间:2018-02-26
    阅读数:

我对底层的东西特别感兴趣。十多年前有了自己的电脑,一直保留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

  2. #include

  3. #include

  4. #include


  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.    

  28.    if(argc<2)

  29.    {

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

  31.        return;

  32.    }

  33.    

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

  35.    if(dev==INVALID_HANDLE_VALUE)

  36.    {

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

  38.        exit(1);

  39.    }

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

  41.    dcb.DCBlength = sizeof(dcb);

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

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

  44.    {

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

  46.        exit(1);

  47.    }

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

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


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

  51.    {

  52.        int len0;

  53.        char c, buf[32];

  54.        char done=0;


  55.        writecomm("?",1);

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

  57.        if(r>0)

  58.        {

  59.            int j;

  60.            for(j=0;j

  61.            {

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

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

  64.                {

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

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

  67.                    {

  68.                        printf("SYNC\n");

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

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

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

  72.                        {

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

  74.                            done=1;

  75.                            break;

  76.                        }

  77.                        else

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

  79.                    }

  80.                }

  81.            }

  82.            if(done) break;

  83.        }

  84.        else

  85.        {

  86.            printf(".");

  87.            continue;

  88.        }

  89.    }


  90.    {

  91.        char c;

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

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

  94.        {

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

  96.        }

  97.    }


  98.    {

  99.        char c;

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

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

  102.        {

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

  104.        }

  105.    }


  106.    {

  107.        unsigned int progaddr=0x40000200;

  108.        char c;

  109.        char str[128];

  110.        char buf[512];

  111.        int slen;

  112.        int pgsize;

  113.        struct ROM rom[1024];

  114.        int offset=-1;

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


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


  117.        showbinary(1024,rom);


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

  119.        slen=strlen(str);

  120.        writecomm(str,slen);

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

  122.        {

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

  124.        }


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

  126.        writecomm(buf,slen);

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

  128.        slen=strlen(str);

  129.        writecomm(str,slen);


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

  131.        {

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

  133.        }


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

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

  136.        {

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

  138.        }


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


  140.        slen=strlen(str);

  141.        writecomm(str,slen);

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

  143.        {

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

  145.        }


  146.    }


  147.    CloseHandle(oWR.hEvent);

  148.    CloseHandle(oRD.hEvent);

  149.    CloseHandle(dev);


  150. }




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

  152. {

  153.    int r;

  154.    int len0;


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

  156.    if(r==0)

  157.    {

  158.        if(GetLastError()!=ERROR_IO_PENDING)

  159.        {

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

  161.            exit(1);

  162.        }

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

  164.    }

  165.    return len0;


  166. }



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

  168. {


  169.     static unsigned wait=0;

  170.     static unsigned char ch;

  171.     int i, len0, r;

  172.     if(tmout<=0)

  173.         return 0;


  174.     for(i=0;i

  175.     {

  176.         if(!wait)

  177.         {

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

  179.             {

  180.                 wait=0;

  181.                 buf[i]=ch;

  182.                 continue;

  183.             }

  184.             if(GetLastError()!=ERROR_IO_PENDING)

  185.             {

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

  187.                 exit(1);

  188.             }

  189.         }

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

  191.         if(r==WAIT_TIMEOUT)

  192.         {

  193.             wait=1;

  194.             tmout--;

  195.             if(tmout==0)

  196.                 return i;

  197.             else

  198.             {

  199.                 i--;

  200.                 continue;  

  201.             }

  202.         }

  203.         if(r==WAIT_OBJECT_0)

  204.         {

  205.             wait=0;

  206.             buf[i]=ch;

  207.             continue;

  208.         }

  209.     }

  210.     return i;

  211. }




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

  213. {

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

  215.     char line[512];

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

  217.     FILE *fp;


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


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

  220.     if(fp==NULL)

  221.     {

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

  223.         return 0;

  224.     }

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


  226.     count=0;

  227.     sum=0;

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

  229.     {

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

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

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

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

  234.         j=0;

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

  236.         {

  237.             switch(line[i])

  238.             {

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

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

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

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

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

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

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

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

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

  248.                           else

  249.                               bb=0xff;

  250.             }

  251.             if(bb==0x77)

  252.                 break;

  253.             if(bb==0xff)

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

  255.             switch(line[i+1])

  256.             {

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

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

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

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

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

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

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

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

  265.                           else

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

  267.             }

  268.             sum+=bb;

  269.             hex[j]=bb;

  270.             j++;

  271.         } // converted ASCII to binary

  272.         if(sum!=0)

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

  274.         if(j<5)

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

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

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

  278.         bsz=j-5;

  279.         switch(hex[3])

  280.         {

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

  282.                       if(*poff==-1)

  283.                       {

  284.                           *poff=addr;

  285.                       }

  286.                       for(i=0;i

  287.                       {

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

  289.                           if(waddr>szlimit)

  290.                           {

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

  292.                           }

  293.                           else

  294.                           {

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

  296.                              rom[waddr].oc=1;

  297.                           }

  298.                           addr++;

  299.                           count++;

  300.                       }

  301.                       break;

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

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

  304.                       fclose(fp);

  305.                       return count;

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

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

  308.                       break;

  309.             case 3:

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

  311.         }

  312.     }

  313. }



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

  315. {

  316.     int i;

  317.     for(i=0;i

  318.     {

  319.         int j;

  320.         char blank=1;


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

  322.         {

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

  324.             {

  325.                 blank=0;

  326.                 break;

  327.             }

  328.         }

  329.         if(blank)

  330.         {

  331.             i+=16;

  332.             continue;

  333.         }


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

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

  336.         {

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

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

  339.             else

  340.                 printf("..");

  341.             if(j==7)

  342.                 printf(" - ");

  343.             else

  344.                 printf(" ");

  345.         }

  346.         printf(" | ");

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

  348.         {

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

  350.             {

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

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

  353.                 else

  354.                     printf("?");

  355.             }

  356.             else

  357.                 printf(".");

  358.         }


  359.         i+=16;

  360.         printf("\n");


  361.     }

  362. }



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

  364. {

  365.     int i, sz=0,mem;

  366.     int lmax, lc, brem;

  367.     int index=0;

  368.     for(i=0;i

  369.     {

  370.         if(rom[i].oc)

  371.             sz=i+1;

  372.     }

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

  374.     lc=sz/lmax;

  375.     brem=sz%lmax;

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

  377.     if(mem>=slen)

  378.     {

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

  380.         return 0;

  381.     }


  382.     for(i=0;i

  383.     {

  384.         int j, len;

  385.         char r=0;

  386.         unsigned char b, a=0;


  387.         if(i+lmax

  388.             len=lmax;

  389.         else

  390.             len=brem;

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

  392.         for(j=0;j

  393.         {

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

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

  396.             else

  397.                 b=0xff;

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

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

  400.             r+=2;

  401.             a=((b&((1<

  402.             if(r==6)

  403.             {

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

  405.                 r=0;

  406.                 a=0;

  407.             }

  408.         }

  409.         if(r!=0)

  410.         {

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

  412.         }

  413.         i+=lmax;

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

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


  416.     }


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

  418.     return index;

  419. }



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

  421. {

  422.     int i, sz, sum;

  423.     sz=0;

  424.     for(i=0;i

  425.     {

  426.         if(rom[i].oc)

  427.             sz=i+1;

  428.     }

  429.     sum=0;

  430.     for(i=0;i

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

  432.     return sum;

  433. }

复制代码


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

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

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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

站点相关: TI培训

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

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