搜索
bottom↓
回复: 16

【求助】请教ATMEGA128高64k空间如何正确读取使用

[复制链接]

出0入0汤圆

发表于 2012-8-1 18:04:51 | 显示全部楼层 |阅读模式
本帖最后由 blackhorse21 于 2012-8-1 18:25 编辑

各位大侠好,小弟学习使用ATMEGA128制作一个非常简单的MP3,编译环境是ICCAVR7.22,用AVR STUDIO JTAG烧录和调试。目前已经完成MP3基本的播放功能了,想开始做一个单界面的GUI。用户界面的图片数组不大,是176*220*16bit的数据,大约为75Kbyte,因此我想放在单片机内部。然而遇上了种种问题,描述如下:
一开始我直接声明了一个数组,然后报错:
'lit' area size too large(>64K bytes)
经过查阅相关帖子之后我认为是因为单个文件的lit区域不能大于64K所致

为此,我将数据分成了176*110*16bit的两个数组(因为液晶屏填充数据的时候是行扫描,所以我就按行分割了),分别放在了两个c文件中,然后在GUI的头文件中声明如下:
  1. extern flash unsigned char backpic1[110][352];
  2. extern flash unsigned char backpic2[110][352];
复制代码
在main函数中便正常调用了,编译通过,烧录之后发现图像在显示后一半时刚开始还是正常的,但是在越五分之一的位置开始有一行乱了,随后便是重新显示最开始的图像数据,而且平移了。

经过思考,我确认是因为16位寻址空间只能找到64K数据,而RAMPZ寄存器没有置1,所以Z指针在归零之后,并没有访问到高64K数据,而是错误地将代码误认为是图像数据显示了一会儿,然后因为接着就是上半部分的图像数据,所以重新开始显示上半部分的图像。由于不是从一行的第一个像素开始显示的,所以图像发生了平移。

我想,只要在Z寄存器归零的时候将RAMPZ置1就好了嘛,但是因为ICCAVR的声明中我没有找到Z寄存器,所以我仿照其声明对Z寄存器进行了声明:
  1. //定义Z寄存器
  2. #define Zpointer_H        (*(volatile unsigned char *)0x1F)
  3. #define Zpointer_L        (*(volatile unsigned char *)0x1E)
复制代码
然后在循环送数的语句中加上了判断语句,并在送数完成之后将RAMPZ归零:
  1. for (i=0;i<40;i++)
  2.         {
  3.        
  4.            for (j=0;j<176;j++)
  5.                {
  6.                    if(Zpointer_H==0x00&&Zpointer_L==0x00){RAMPZ=0x01;}
  7.                    write_data(backpic2[i][j*2],backpic2[i][j*2+1]);
  8.                    }

  9.         }
  10. RMAPZ=0x00;
复制代码
这样做确实完成了图片显示的任务,但是根据我老师的问题倍增定律:“解决一个问题会出来十个问题”,确实带来了两个问题:
1、首先,我原来正常的MP3功能木有了,它不唱歌了 。为了解决这个问题,我在使用JTAG进行DEBUG时(请勿吐槽……串口调试我知道,只是这块板子的串口转USB芯片坏了……)发现在主程序在没有进入子程序,或者进入子程序之后返回时没有正常返回,而是跑飞了。
2、要求在ICCAVR中,两个图片数据文件的排列顺序不能反,反了之后我添加的那条指令就得跟着换到另外一次调用中去。而且最恐怖的是,将来怎么办?如果程序越变越大,到底那个64K的分界在哪里我怎么闹得清楚……这是多大的一个隐患……

我认为,首先这个问题估计还是跟RAMPZ有关,因为它影响着长跳转指令访问的是哪一页数据,是低64K还是高64k。其次,我不知道咋办……

后来我想能不能将接近64K的数据放在高64K的FLASH里,将剩下的一部分图像数据放在低64kFLASH的比较高的部分。为此我进行了尝试,想要使用ICCAVR的内部指令:
#pragma abs_address:<address>
这个指令会将函数与全局数据不使用浮动定位(重定位)进行放置,而是从 <address>开始分配绝对地址,这在访问中断向量和其它硬件项目时特别有用,可不可以用在我的项目里呢?
不行……因为伦家是字节地址了啦,限制寻址空间只有64K字节了啦啦啦,伦家ICCAVR不能强制帮你把数据放到ATMEGA128的下半身的~
肿么会这样~最后一丝希望啊~
所以,我来了……求救&求教……

PS.这是一个学习型项目,老师想让我先不要考虑外置FLASH DATA存储器,看看能不能做出来,这样省钱啊……但是我深切地觉得,还是外部Data Flash芯片靠谱啊~而且ATMEGA128如何使用高64K的空间是个好神奇的课题啊~貌似ICCAVR7.22没有太支持这个玩意儿。

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

 楼主| 发表于 2012-8-1 18:27:09 | 显示全部楼层
自己顶一下~~~

出200入2554汤圆

发表于 2012-8-1 19:26:04 | 显示全部楼层
本帖最后由 t3486784401 于 2012-8-1 19:30 编辑

之前也干过这种事情,闲的蛋疼非要用M128存音频,8位数据在8ksps下,128kB也就16s;

当时也在纠结怎么用高64k,后来还是用了C和汇编的混编(ICC还是很给力的),涉及内存大数组访问时,用汇编写,主构架用C写。

ICCAVR里有个选项就是空出R20-R23,这么里边刚好可以构成一个DWORD来存地址,调用的时候把 R22:R20->RAMPZ:Z,然后ELPM就行了。

当然编译器里边没法编译超过64k的数组,这个无妨,最后把要用的数据定位到固定的绝对地址(程序里与之呼应),直接生成HEX文件续接到源HEX文件后边即可。

祝LZ成功咯!


P.S. 附上当年的那个工程,PWM实现的DA,8M主频,OC2脚输出(直接接耳机,樱桃小丸子乱入)。里边从0x00200地址开始就是音频数据,是用记事本粘进去的。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2012-8-1 19:36:33 | 显示全部楼层
t3486784401 发表于 2012-8-1 19:26
之前也干过这种事情,闲的蛋疼非要用M128存音频,8位数据在8ksps下,128kB也就16s;

当时也在纠结怎么用高 ...

哎呀,好感谢啊~我好好看看,这个编写的方式好纠结啊~

出0入0汤圆

 楼主| 发表于 2012-8-1 21:22:55 | 显示全部楼层
刚刚3楼童鞋的方法不太可行啊……我的程序已经大了,这样嵌入汇编好乱……

出0入296汤圆

发表于 2012-8-1 21:34:00 | 显示全部楼层
先关闭全局中断响应,然后再访问RAMPZ,弄到想要得数据以后,改回RAMPZ,然后再开启中断响应。

出0入0汤圆

 楼主| 发表于 2012-8-1 21:36:52 | 显示全部楼层
Gorgon_Meducer 发表于 2012-8-1 21:34
先关闭全局中断响应,然后再访问RAMPZ,弄到想要得数据以后,改回RAMPZ,然后再开启中断响应。 ...

好的!中断!这个问题我确实忘了,马上试试去!

出0入296汤圆

发表于 2012-8-1 21:41:29 | 显示全部楼层
blackhorse21 发表于 2012-8-1 21:36
好的!中断!这个问题我确实忘了,马上试试去!

在线等你好消息

出0入0汤圆

 楼主| 发表于 2012-8-1 21:56:23 | 显示全部楼层
Gorgon_Meducer 发表于 2012-8-1 21:41
在线等你好消息

额,尝试失败,我再自己仔细梳理梳理问题吧……我的中断其实在绘制这个背景的时候应该是没有中断请求的,所以关了中断故障现象依然。另外想问一下,在ICCAVR里,没有办法强制将数据放在FLASH 的高64k空间里吗?#pragma abs_address:<address>指令不行了,因为只支持16位寻址空间。在数组前直接嵌入汇编语句:
  1. asm(".org 0x10000");
复制代码
则会提示我不能对一个重定位的变量进行强制定位。

出0入296汤圆

发表于 2012-8-1 22:01:07 | 显示全部楼层
blackhorse21 发表于 2012-8-1 21:56
额,尝试失败,我再自己仔细梳理梳理问题吧……我的中断其实在绘制这个背景的时候应该是没有中断请求的, ...

我之前做过很多努力,无法通过绝对定位的方法将数据放到高64K。但是你可以通过修改HEX文件的方法将原本定位在低64位空间的代码定位到高64K。

出0入296汤圆

发表于 2012-8-1 22:04:02 | 显示全部楼层
本帖最后由 Gorgon_Meducer 于 2012-8-1 22:06 编辑
Gorgon_Meducer 发表于 2012-8-1 22:01
我之前做过很多努力,无法通过绝对定位的方法将数据放到高64K。但是你可以通过修改HEX文件的方法将原本定 ...


这段经过检验的代码应该能给你启示,ICC下的

  1. #if BL_USE_PAGE_VERIFY == ENABLE
  2. /***********************************************************
  3. *   函数说明:  页面校验函数                               *
  4. *   输入:      源页面缓冲区,目标地址                     *
  5. *   输出:      校验是否成功                               *
  6. *   调用函数:  无                                         *
  7. ***********************************************************/
  8. BOOL Bootloader_Flash_Page_Verify
  9.         (
  10.             BYTE *pchDataBuffer,
  11.             #if BL_USE_EXTEND_ADDRESS_SPACE == ENABLE
  12.             UINT32 dwAddress
  13.             #else
  14.             UINT16 wAddress
  15.             #endif
  16.         )
  17. {
  18.     UINT16 wCounter = FLASH_PAGE_SIZE;
  19.     UINT8 chDataA;
  20.     UINT8 chDataB;
  21.    
  22.     #if BL_USE_EXTEND_ADDRESS_SPACE == ENABLE
  23.     UINT8 TRAMPZ = RAMPZ;
  24.     #endif
  25.     if (pchDataBuffer == NULL)
  26.     {
  27.         //! have nothing to do with...
  28.         return FALSE;
  29.     }
  30.     #if BL_USE_EXTEND_ADDRESS_SPACE == ENABLE
  31.     RAMPZ = dwAddress >> 16;
  32.     #endif
  33.     //! load the address to z register
  34.     asm("movw r30,r18");
  35.     //! load the buffer address to x register
  36.     asm("movw r26,r16");
  37.     #if BL_USE_EXTEND_ADDRESS_SPACE == ENABLE
  38.     if (RAMPZ)
  39.     {
  40.         while(wCounter--)
  41.         {
  42.             //! load a byte from flash (addressed by z register)
  43.             asm("elpm r0,z+");
  44.             //! employ a temporary variable chDataA
  45.             asm("mov %chDataA,r0");
  46.             //! load a byte from sram (addressed by x register)
  47.             asm("ld r0,x+");
  48.             //! employ a temporary variable chDataB
  49.             asm("mov %chDataB,r0");
  50.             //! checking...
  51.             if (chDataA != chDataB)
  52.             {
  53.                 RAMPZ = TRAMPZ;
  54.                 return FALSE;        
  55.             }
  56.             WDR();
  57.         }
  58.     }
  59.     else
  60.     {
  61.         while(wCounter--)
  62.         {
  63.             //! load a byte from flash (addressed by z register)
  64.             asm("lpm r0,z+");
  65.             //! employ a temporary variable chDataA
  66.             asm("mov %chDataA,r0");
  67.             //! load a byte from sram (addressed by x register)
  68.             asm("ld r0,x+");
  69.             //! employ a temporary variable chDataB
  70.             asm("mov %chDataB,r0");
  71.             //! checking...
  72.             if (chDataA != chDataB)
  73.             {
  74.                 RAMPZ = TRAMPZ;
  75.                 return FALSE;        
  76.             }
  77.             WDR();
  78.         }
  79.     }
  80.     RAMPZ = TRAMPZ;
  81.     #else
  82.     while(wCounter--)
  83.     {
  84.         //! load a byte from flash (addressed by z register)
  85.         asm("lpm r0,z+");
  86.         //! employ a temporary variable chDataA
  87.         asm("mov %chDataA,r0");
  88.         //! load a byte from sram (addressed by x register)
  89.         asm("ld r0,x+");
  90.         //! employ a temporary variable chDataB
  91.         asm("mov %chDataB,r0");
  92.         //! checking...
  93.         if (chDataA != chDataB)
  94.         {
  95.             return FALSE;        
  96.         }
  97.     }
  98.     #endif
  99.     return TRUE;
  100. }
  101. #endif
复制代码
这是一段ICC里面读取任意Flash并通过串口发送出来的代码
  1. #if IAP_ENABLE_FLASH_READ == ENABLE
  2.                 else if (chMemoryType == IAP_MEM_TYPE_FLASH)
  3.                 {
  4.                     UINT8 chData = FRAME_HEAD;
  5.                     UINT16 wCRC = CRC_INIT;
  6.                     #if BL_USE_EXTEND_ADDRESS_SPACE == ENABLE
  7.                     UINT16 wCounter = wSize;
  8.                     UINT32 dwAddressCounter = dwAddress;
  9.                     UINT8 chTempRAMPZ;
  10.                     #else
  11.                     UINT16 wCounter = wSize;
  12.                     #endif
  13.                     wSize++;
  14.                     CRC(wCRC,((BYTE *)&wSize)[0])
  15.                     CRC(wCRC,((BYTE *)&wSize)[1])
  16.                     CRC(wCRC,IAP_CMD_READ_MEMORY)
  17.                     
  18.                     while(!SERIAL_OUT(chData));             //发送头部
  19.                     while(!SERIAL_OUT(wSize));              //发送数据包长度
  20.                     chData = IAP_CMD_READ_MEMORY;
  21.                     while(!SERIAL_OUT(chData));             //发送指令
  22.                     
  23.                     
  24.                     #if BL_USE_EXTEND_ADDRESS_SPACE == ENABLE
  25.                     chTempRAMPZ = RAMPZ;
  26.                     while(wCounter--)
  27.                     {
  28.                         UINT16 wAddress = dwAddressCounter;
  29.                         RAMPZ = dwAddressCounter >> 16;
  30.                         asm("movw r30,%wAddress");
  31.                         asm("elpm r24,z");
  32.                         asm("std  Y+6,r24");
  33.                         while(!SERIAL_OUT(chData));                        
  34.                         CRC(wCRC,chData);
  35.                         dwAddressCounter++;
  36.                         
  37.                         WDR();
  38.                     }
  39.                     RAMPZ = chTempRAMPZ;
  40.                     #else
  41.                     //开始发送数据
  42.                     asm("movw r30,%wAddress");
  43.                     while(wCounter--)
  44.                     {
  45.                         asm("lpm r24,z+");
  46.                         asm("std  Y+6,r24");
  47.                         while(!SERIAL_OUT(chData));
  48.                         WDR();
  49.                         CRC(wCRC,chData)
  50.                     }
  51.                     #endif
复制代码

出0入0汤圆

 楼主| 发表于 2012-8-1 22:06:09 | 显示全部楼层
Gorgon_Meducer 发表于 2012-8-1 22:01
我之前做过很多努力,无法通过绝对定位的方法将数据放到高64K。但是你可以通过修改HEX文件的方法将原本定 ...

看来是不行,您的意思是和3楼网友的思路一致,在程序中不直接声明数据,而是在编程之后直接在HEX文件中的指定位置利用ULTRAEDIT将数据放入?

出0入0汤圆

 楼主| 发表于 2012-8-1 22:09:06 | 显示全部楼层
Gorgon_Meducer 发表于 2012-8-1 22:04
这段经过检验的代码应该能给你启示,ICC下的这是一段ICC里面读取任意Flash并通过串口发送出来的代码 ...

谢谢,我研读一下!

出0入296汤圆

发表于 2012-8-1 22:09:37 | 显示全部楼层
本帖最后由 Gorgon_Meducer 于 2012-8-1 22:11 编辑
blackhorse21 发表于 2012-8-1 22:06
看来是不行,您的意思是和3楼网友的思路一致,在程序中不直接声明数据,而是在编程之后直接在HEX文件中的 ...

  1.                     chTempRAMPZ = RAMPZ;
  2.                     while(wCounter--)
  3.                     {
  4.                         UINT16 wAddress = dwAddressCounter;
  5.                         UINT8 chData;
  6.                         RAMPZ = dwAddressCounter >> 16;
  7.                         asm("movw r30,%wAddress");
  8.                         asm("elpm r24,z");
  9.                         asm("std  Y+6,r24");

  10.                         //! chData就是你可以用的
  11.                         while(!SERIAL_OUT(chData));                        
  12.                         CRC(wCRC,chData);

  13.                         dwAddressCounter++;                        
  14.                         WDR();
  15.                     }
  16.                     RAMPZ = chTempRAMPZ;
复制代码

出0入0汤圆

 楼主| 发表于 2012-8-5 21:43:29 | 显示全部楼层
Gorgon_Meducer 发表于 2012-8-1 22:09

非常感谢傻孩子大侠的指导,经过试验,虽然在汇编语言条件下能实现图片数据的存放,但是由于我的工程中还涉及到好多图片,使用片内程序寄存器已然不靠谱,经过与老师反复说明后,已经改为在系统内增加data flash了,这下工作好做多了。
总结一下,ATmega128的程序存储器是128K的,而且程序计数器PC是一个16位的指针,而且一次是取回两个字节的数据并作为指令来执行。所以对其单片机内核而言,不存在需要改变RAMPZ的问题,正好能够寻址128K字节的空间。但是作为我们的程序,却只能通过16位的Z寄存器,一次一个字节的形式来读取数据或者执行跳转,所以受到了寻址空间为64K的限制,在访问高64K数据时,需要改变RAMPZ寄存器的内容。这是一个瓶颈。其次,ICCAVR设定程序段起始位置的预编译指令寻址空间也只有16位=64K,无法直接指定将数据放置在高64K的程序存储器中,这是瓶颈二。受到这两方面的限制,在C语言环境下,我们很难将ATmega128的高64K程序存储器作为单纯的存储空间来存放数据并加以利用。该做程序存储器的地方,还是让他老老实实放程序吧。

出0入0汤圆

发表于 2014-11-28 09:03:23 | 显示全部楼层
记号学习

出0入4汤圆

发表于 2014-11-28 09:56:12 | 显示全部楼层
如果用gcc,直接使用pgm_read_byte_far(address) 或 pgm_read_word_far(address)即可。address是32位地址。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-16 02:40

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表