2025年2月12日水曜日

AVR128DBxxのPROGMEMについて

AVR128DxxxのArduinoでPROGMEMを安易に使うためのメモ。AVR128DxxxってめっちゃFlash領域あるのでデータ領域として有効活用したい。

普通Arduinoでは、PROGMEMしてpgm_read_byteとかで読み込んで使ってたけど、AVR128Dxxxではどうもそうはいかないらしい。リンカスクリプトをいじるとかいろんな検討をした投稿があるけど、難しい。安易にやりたいわけよ。で、AVR128DxxxでArduinoするってことはボードマネージャーでSpence Konde氏のDxCore(https://github.com/SpenceKonde/DxCore)を入れているわけで、そのライブラリ(https://github.com/SpenceKonde/DxCore/blob/master/megaavr/libraries/Flash/README.md)を使う。今回は読み出しだけってことで使う関数は
uint8_t Flash.readByte(uint32_t address);
が、ポインタが16bitなんだろうことが原因で、正しいuint32_tのアドレスを知るすべがない。いや、わかってはいるんだけど、、、で、こういう設定
であることを前提にすると、
PROGMEM_SECTION1は0x00008000から
PROGMEM_SECTION2は0x00010000から
PROGMEM_SECTION3は0x00018000から
なので、これを信じてこんなコードを書く。
  1. #include <Flash.h>
  2.  
  3. const uint8_t test1[] PROGMEM_SECTION1={
  4.     0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
  5. };
  6.  
  7. const uint8_t test2[] PROGMEM_SECTION2={
  8.     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
  9. };
  10.  
  11. const uint8_t test3[] PROGMEM_SECTION3={
  12.     0x69, 0xC4, 0xE0, 0xD8, 0x6A, 0x7B, 0x04, 0x30, 0xD8, 0xCD, 0xB7, 0x80, 0x70, 0xB4, 0xC5, 0x5A
  13. };
  14.  
  15. uint8_t v[16];
  16.  
  17. void setup(){
  18.     uint8_t i;
  19.     uint32_t adr1,adr2,adr3;
  20.     adr1=0x00008000;
  21.     adr2=0x00010000;
  22.     adr3=0x00018000;
  23.     char buf[80];
  24.     Serial2.begin(115200);
  25.     while (!Serial2 && millis() < 5000);
  26.     Serial2.println((uint32_t)(&test1[0]),HEX);
  27.     Serial2.println((uint32_t)(&test2[0]),HEX);
  28.     Serial2.println((uint32_t)(&test3[0]),HEX);
  29.     for(i=0;i<16;i++){
  30.         v[i]=Flash.readByte(adr1+i);
  31.     }
  32.     sprintf(buf,"%08lX : ",adr1);Serial2.print(buf);
  33.     for(i=0;i<16;i++){
  34.         sprintf(buf,"%02X ",v[i]);Serial2.print(buf);
  35.     }
  36.     Serial2.println("");
  37.  
  38.     for(i=0;i<16;i++){
  39.         v[i]=Flash.readByte(adr2+i);
  40.     }
  41.     sprintf(buf,"%08lX : ",adr2);Serial2.print(buf);
  42.     for(i=0;i<16;i++){
  43.         sprintf(buf,"%02X ",v[i]);Serial2.print(buf);
  44.     }
  45.     Serial2.println("");
  46.  
  47.     for(i=0;i<16;i++){
  48.         v[i]=Flash.readByte(adr3+i);
  49.     }
  50.     sprintf(buf,"%08lX : ",adr3);Serial2.print(buf);
  51.     for(i=0;i<16;i++){
  52.         sprintf(buf,"%02X ",v[i]);Serial2.print(buf);
  53.     }
  54.     Serial2.println("");
  55.  
  56. }
  57. void loop(){
  58.      
  59. }
で、.vscode/arduino.jsonにoutputパスを追加しておく。
  1. {
  2.     "configuration": "chip=avr128db28,clock=16crystal,bodvoltage=1v9,bodmode=disabled,resetpin=reset,entrycond=default,millis=tcb2,printf=default,attach=allenabled,mvioopti=enabled,startuptime=64,wiremode=mors,bootloaderusart=ser2,WDTtimeout=disabled,WDTwindow=disabled,flmap=lockdefault",
  3.     "output": "./build",
  4.     "board": "DxCore:megaavr:avrdbopti",
  5.     "sketch": "upperpgmtry1.ino",
  6.     "port": "/dev/ttyUSB0"
  7. }
まぁこんな感じ。
一旦コンパイルする。
で、buildフォルダになんじゃかんじゃできるので、.mapファイルを開いて、test1, test2, test3を探すと、
って感じで、確かに思った通りになっている。
で、実行してみると、
こんな感じで期待通りに値を取得できている。いくつかの配列を確保してアドレスがわからない場合や、mapファイルが期待と違っていた場合は、それに合わせてコードのadr?を変えて、もう一度確認して、ってことを一致するまでやればいいんじゃないかな、、、決して正しいやり方とは思わないけど、安易にやることを目標にしています。ちなみに、Serialに出力したポインタの値はやっぱりおかしい。たぶんSECTION1は(uint32_t)(test1)x0000FFFF, SECTION2は(uint32_t)(test2)x0000FFFF+0x00010000, SECTION3は(uint32_t)(test3)x0000FFFF+0x00010000なんだろうけど、実行中のコードがこれを判別することは難しい。プログラマわかっていることなので記述しとけばいいんだけど、だったらmapファイル見てやっちまうのも巨悪ではないよね。

0 件のコメント:

コメントを投稿