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
463 stars 73 forks source link

Implemenet serial port (USART) RX #11

Closed urish closed 3 years ago

urish commented 4 years ago

USART transmit implemented in #6, we need to implement RX as well!

yiivon commented 3 years ago

Consider following please, maybe it will help a bit

usart.ts


export class AVRUSART {
public onByteTransmit: USARTTransmitCallback | null = null;
public onLineTransmit: USARTLineTransmitCallback | null = null;

private lineBuffer = ''; private outBuffer = [];

constructor(private cpu: CPU, private config: USARTConfig, private freqMHz: number) { ... this.cpu.readHooks[config.UDR] = (v) => { const d: u8 = this.outBuffer.shift(); return (this.cpu.data[this.config.UDR] = d); }; }

tick() { if (this.cpu.interruptsEnabled) { const ucsra = this.cpu.data[this.config.UCSRA]; const ucsrb = this.cpu.data[this.config.UCSRB]; ... if (ucsra & UCSRA_UDRE && this.outBuffer.length > 0) { avrInterrupt(this.cpu, this.config.rxCompleteInterrupt); } } }

write(b: u8) { this.outBuffer.push(b); }

writeString(s: string) { for (let i = 0; i < s.length; i++) { this.outBuffer.push(s.charCodeAt(i)); } }

writeln(s: string) { s += '\n'; this.writeString(s); } ... }

urish commented 3 years ago

That is helpful, thank you!

yiivon commented 3 years ago

In fact, I am very eager for avr8js to run grbl firmware completely and accurately.

GRBL is a firmware implemented in pure C language running on arduino uno (ATmega328P).

I use the latest version of Proteus to run grbl for arduino simulation, and I can get the correct result. But the current avr8js does not seem to be able to achieve the same, I guess it may be that some implementations of timer are not perfect.

If you also want to make avr8js run like real chips, you can try to run grbl firmware in emulation, which may solve this problem and make avr8js close to real chips again. At the same time, it also helped me a lot.

Ask for your help and thank you sincerely!

urish commented 3 years ago

Thanks for the feedback @yiivon! Can you please open a new issue for this?

urish commented 3 years ago

Until this is implemented, here is a quick hackish workaround. The code assumes that you have a list of bytes pending for Serial RX inside the serialBuffer array:

  1. When initializing the simulation, add the following code:
cpu.readHooks[usart0Config.UDR] = () => serialBuffer.shift() || 0;
  1. Then, add this inside your execute() loop:
const ucsra = cpu.data[usart0Config.UCSRA];
if (cpu.interruptsEnabled && ucsra & 0x20 && serialBuffer.length > 0) {
  avrInterrupt(cpu, usart0Config.rxCompleteInterrupt);
}
urish commented 3 years ago

Ok, so this is now released!

Usage example: https://stackblitz.com/edit/avr8js-serial-rx?file=index.ts