wokwi / avr8js

Arduino (8-bit AVR) simulator, written in JavaScript and runs in the browser / Node.js
https://blog.wokwi.com/avr8js-simulate-arduino-in-javascript/
MIT License
461 stars 73 forks source link

Is It Possible to Run UNO's Hex with Greater Memory? #142

Closed yusongone closed 1 year ago

yusongone commented 1 year ago

Project Background:

  1. Edit and run the actual effect of the WS2812 matrix in the web browser.
  2. Use FastLED as an animation library in the Arduino project.
  3. Call the server-side arduino-cli through the API to compile the hex, and run the hex file in the browser through avr8js.

To satisfy this need, I tried the following ways:

  1. UNO: Because there are more fastLed light columns, UNO's 2048-byte sram gradually cannot meet the memory demand. Is there a way to expand the memory space of avr8js? I tried to expand the memory to 4KB using this.cpu = new CPU(this.program, 0x1000); but it doesn't seem to work.

  2. Mega2560: In order to solve the memory problem, I had to switch to the Mega2560 compilation method when UNO couldn't be used. I referred to the following two articles: https://github.com/wokwi/avr8js/issues/67https://stackblitz.com/edit/avr8js-mega-ws2812-xl?file=index.ts But other problems arose: When using Serial.print("a b"), or Serial.println("a") in the firmware, the runner.usart.onByteTransmit function of the simulator will trigger non-stop. When using Serial.write("a"); it can output normally. That is to say, as long as the content of the print is longer than 1 byte, this error will occur.

  3. RP2040: To circumvent this issue, I saw that there is another simulator engine available, rp2040: https://github.com/wokwi/rp2040js. So I started referring to https://stackblitz.com/edit/rp2040js-blink-fqaunq?file=index.ts,compile.ts,package.json and used rp2040, but I encountered the following problems: a). Currently testing, only when the version of arduino-cli core mbed_rp2040 = 3.0.0 and the version of rp2040js = 0.10.1 can it run normally. b). It seems that the timer in Arduino is not accurate. When I use FastLED's EVERY_N_MILLISECONDS(16){ // refresh rate 60Hz to execute the code, its execution frequency is much lower.

In summary, I only need a simulator with enough memory to run hex. However, due to the lack of simulation technology and hardware knowledge, I have spent a lot of time on this issue and still have not found a good solution. If there is an ideal choice, I still hope to have a running environment of UNO simulator with 4KB, or 8KB or even higher. What should I do?

urish commented 1 year ago

Hello, thanks for taking the time to explain the background of your project.

Here are some pointers:

  1. Regarding Uno with more memory - you'd also need to tell the compiler there's additional memory available, and potentially move the stack pointer out of the way. How do you compile your code?
  2. Have you remembered calling Serial.begin() prior to using Serial.print()? Also, which version of avr8js are you using? the one from the stackbliz example is pretty old.
  3. RP2040 uses inaccurate clocking. We intend to publish a new version in a few weeks which will use a more accurate clock, similar to what AVR8js does.
yusongone commented 1 year ago

Thank you for taking the time to respond to my queries, it has been of great help to me.

1: I've researched previously, asking whether something needs to be done during compilation if one wants to expand the run space of Uno. However, due to my unfamiliarity with this field, I haven't received a precise answer. Currently, I'm using arduino-cli as a compile service, with the compile command being arduino-cli compile --fqbn arduino:avr:uno ./avr_sim --library ./lib/normal. I'm unsure how to inform the compiler about the extra available memory and I would appreciate your guidance.

2:Before using Serial.println, I always use Serial.begin(115200); However, I'm uncertain whether additional code configurations are required on the avr8js end. I haven't seen related code in various examples, and have tried to find answers within the source code of avr8js. However, due to my limited technical skills, I have yet to find a solution. Below is the code to create Mega2560

const FLASH = 0x40000; // ATmega2560 params
  export class AVRRunner {
    program = new Uint16Array(FLASH);
    cpu;
    timer;
    portB;
    portC;
    portD;
    stopped = false;
    constructor(hex ) {
      loadHex(hex, new Uint8Array(this.program.buffer));
      this.cpu = new CPU(this.program, 0x8200);
      this.freqHz = 16e6;
      this.timer = new AVRTimer(this.cpu, {
        ...timer0Config,
        compAInterrupt: 0x02a,
        compBInterrupt: 0x02c,
        ovfInterrupt: 0x02e,
      });
      // this.timer= new AVRTimer(this.cpu, timer0Config);
      this.portB = new AVRIOPort(this.cpu, portBConfig);
      this.portC = new AVRIOPort(this.cpu, portCConfig);
      this.portD = new AVRIOPort(this.cpu, portDConfig);
      this.usart = new AVRUSART(this.cpu, usart0Config, this.freqHz);
    }

3: I'm delighted to hear about a more accurate clock version for rp2040 and look forward to it. I find the API for rp2040 more convenient to use, for instance:

rp2040.gpio[13].addListener((state) => {});
rp2040.uart[0].onByte=()=>{}

Also, the logger functionality of rp2040 allows easier monitoring of firmware run errors, which is incredibly convenient

urish commented 1 year ago
  1. To tell the Arduino CLI about the extra memory use the --build-property upload.maximum_data_size= flags, e.g.:

    arduino-cli compile --fqbn arduino:avr:uno --build-property upload.maximum_data_size=8192 ./avr_sim --library ./lib/normal
  2. For the ATmega2560, the interrupt numbers are different. So you'd want to configure the UART with the relevant interrupt numbers, e.g.:

    this.usart = new AVRUSART(this.cpu, {
      ...usart0Config,
        rxCompleteInterrupt: 0x32,
        dataRegisterEmptyInterrupt: 0x34,
        txCompleteInterrupt: 0x36,
    }, this.freqHz);

I hope this helps!

yusongone commented 1 year ago

Thank you very much, the Serial of the mega2560 is working perfectly now. I'll take some time to test the memory expansion of Uno. Your assistance has been of paramount importance to me, and I want to express my gratitude once again. Once my project is completed, I'll provide you with the online address as soon as possible to share my joy.

urish commented 1 year ago

Awesome! Closing this issue for now, and looking forward to seeing what you are building