aboutsummaryrefslogtreecommitdiff
path: root/src/peripherals/usart.ts
diff options
context:
space:
mode:
authorUri Shaked2021-02-19 23:43:34 +0200
committerUri Shaked2021-02-19 23:43:34 +0200
commitcf13e06ace0a132cc370e80a7dc87ea3f311bfb2 (patch)
tree60f6460b04bee54b5c08bcf18b88e2acf4a24fa4 /src/peripherals/usart.ts
parentfeat(demo): web worker support (diff)
downloadavr8js-cf13e06ace0a132cc370e80a7dc87ea3f311bfb2.tar.gz
avr8js-cf13e06ace0a132cc370e80a7dc87ea3f311bfb2.tar.bz2
avr8js-cf13e06ace0a132cc370e80a7dc87ea3f311bfb2.zip
feat(usart): implement RX #11
close #11
Diffstat (limited to 'src/peripherals/usart.ts')
-rw-r--r--src/peripherals/usart.ts63
1 files changed, 58 insertions, 5 deletions
diff --git a/src/peripherals/usart.ts b/src/peripherals/usart.ts
index f9b0f87..f55fef3 100644
--- a/src/peripherals/usart.ts
+++ b/src/peripherals/usart.ts
@@ -65,13 +65,31 @@ const UCSRC_UCSZ0 = 0x2; // Character Size 0
const UCSRC_UCPOL = 0x1; // Clock Polarity
/* eslint-enable @typescript-eslint/no-unused-vars */
+const rxMasks = {
+ 5: 0x1f,
+ 6: 0x3f,
+ 7: 0x7f,
+ 8: 0xff,
+ 9: 0xff,
+};
export class AVRUSART {
public onByteTransmit: USARTTransmitCallback | null = null;
public onLineTransmit: USARTLineTransmitCallback | null = null;
+ public onRxComplete: (() => void) | null = null;
+ private rxBusyValue = false;
+ private rxByte = 0;
private lineBuffer = '';
// Interrupts
+ private RXC: AVRInterruptConfig = {
+ address: this.config.rxCompleteInterrupt,
+ flagRegister: this.config.UCSRA,
+ flagMask: UCSRA_RXC,
+ enableRegister: this.config.UCSRB,
+ enableMask: UCSRB_RXCIE,
+ constant: true,
+ };
private UDRE: AVRInterruptConfig = {
address: this.config.dataRegisterEmptyInterrupt,
flagRegister: this.config.UCSRA,
@@ -90,19 +108,29 @@ export class AVRUSART {
constructor(private cpu: CPU, private config: USARTConfig, private freqHz: number) {
this.reset();
this.cpu.writeHooks[config.UCSRA] = (value) => {
- cpu.data[config.UCSRA] = value;
- cpu.clearInterruptByFlag(this.UDRE, value);
+ cpu.data[config.UCSRA] = value & (UCSRA_MPCM | UCSRA_U2X);
cpu.clearInterruptByFlag(this.TXC, value);
return true;
};
this.cpu.writeHooks[config.UCSRB] = (value, oldValue) => {
+ cpu.updateInterruptEnable(this.RXC, value);
cpu.updateInterruptEnable(this.UDRE, value);
cpu.updateInterruptEnable(this.TXC, value);
+ if (value & UCSRB_RXEN && oldValue & UCSRB_RXEN) {
+ cpu.clearInterrupt(this.RXC);
+ }
if (value & UCSRB_TXEN && !(oldValue & UCSRB_TXEN)) {
// Enabling the transmission - mark UDR as empty
cpu.setInterruptFlag(this.UDRE);
}
};
+ this.cpu.readHooks[config.UDR] = () => {
+ const mask = rxMasks[this.bitsPerChar] ?? 0xff;
+ const result = this.rxByte & mask;
+ this.rxByte = 0;
+ this.cpu.clearInterrupt(this.RXC);
+ return result;
+ };
this.cpu.writeHooks[config.UDR] = (value) => {
if (this.onByteTransmit) {
this.onByteTransmit(value);
@@ -116,12 +144,10 @@ export class AVRUSART {
this.lineBuffer += ch;
}
}
- const symbolsPerChar = 1 + this.bitsPerChar + this.stopBits + (this.parityEnabled ? 1 : 0);
- const cyclesToComplete = (this.UBRR * this.multiplier + 1) * symbolsPerChar;
this.cpu.addClockEvent(() => {
cpu.setInterruptFlag(this.UDRE);
cpu.setInterruptFlag(this.TXC);
- }, cyclesToComplete);
+ }, this.cyclesPerChar);
this.cpu.clearInterrupt(this.TXC);
this.cpu.clearInterrupt(this.UDRE);
};
@@ -131,6 +157,33 @@ export class AVRUSART {
this.cpu.data[this.config.UCSRA] = UCSRA_UDRE;
this.cpu.data[this.config.UCSRB] = 0;
this.cpu.data[this.config.UCSRC] = UCSRC_UCSZ1 | UCSRC_UCSZ0; // default: 8 bits per byte
+ this.rxBusyValue = false;
+ this.rxByte = 0;
+ this.lineBuffer = '';
+ }
+
+ get rxBusy() {
+ return this.rxBusyValue;
+ }
+
+ writeByte(value: number) {
+ const { cpu, config } = this;
+ if (this.rxBusyValue || !(cpu.data[config.UCSRB] & UCSRB_RXEN)) {
+ return false;
+ }
+ this.rxBusyValue = true;
+ cpu.addClockEvent(() => {
+ this.rxByte = value;
+ this.rxBusyValue = false;
+ cpu.setInterruptFlag(this.RXC);
+ this.onRxComplete?.();
+ }, this.cyclesPerChar);
+ return true;
+ }
+
+ private get cyclesPerChar() {
+ const symbolsPerChar = 1 + this.bitsPerChar + this.stopBits + (this.parityEnabled ? 1 : 0);
+ return (this.UBRR * this.multiplier + 1) * symbolsPerChar;
}
private get UBRR() {