rp2040js 1.3.2 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -366,7 +366,7 @@ class RPDMA extends peripheral_js_1.BasePeripheral {
366
366
  return (this.intRaw & this.intEnable1) | this.intForce1;
367
367
  }
368
368
  readUint32(offset) {
369
- if ((offset & 0x7ff) <= CHANNEL_REGISTERS_SIZE) {
369
+ if ((offset & 0x7ff) < CHANNEL_REGISTERS_SIZE) {
370
370
  const channelIndex = (offset & 0x7ff) >> 6;
371
371
  return this.channels[channelIndex].readUint32(offset & CHANNEL_REGISTERS_MASK);
372
372
  }
@@ -399,7 +399,7 @@ class RPDMA extends peripheral_js_1.BasePeripheral {
399
399
  return super.readUint32(offset);
400
400
  }
401
401
  writeUint32(offset, value) {
402
- if ((offset & 0x7ff) <= CHANNEL_REGISTERS_SIZE) {
402
+ if ((offset & 0x7ff) < CHANNEL_REGISTERS_SIZE) {
403
403
  const channelIndex = (offset & 0x7ff) >> 6;
404
404
  this.channels[channelIndex].writeUint32(offset & CHANNEL_REGISTERS_MASK, value);
405
405
  return;
@@ -106,12 +106,15 @@ class PWMChannel {
106
106
  if (value & CSR_EN && !(this.csr & CSR_EN)) {
107
107
  this.updateDoubleBuffered();
108
108
  }
109
+ // PH_ADV and PH_RET are self-clearing, so they never appear in the stored csr value
109
110
  this.csr = value & ~(CSR_PH_ADV | CSR_PH_RET);
110
- if (this.csr & CSR_PH_ADV) {
111
- this.timer.advance(1);
112
- }
113
- if (this.csr & CSR_PH_RET) {
114
- this.timer.advance(-1);
111
+ if (value & CSR_EN) {
112
+ if (value & CSR_PH_ADV) {
113
+ this.timer.advance(1);
114
+ }
115
+ if (value & CSR_PH_RET) {
116
+ this.timer.advance(-1);
117
+ }
115
118
  }
116
119
  this.divMode = (this.csr >> CSR_DIVMODE_SHIFT) & CSR_DIVMODE_MASK;
117
120
  this.setBDirection(this.divMode === PWMDivMode.FreeRunning);
@@ -37,6 +37,12 @@ class Timer32 {
37
37
  */
38
38
  advance(delta) {
39
39
  this.baseValue += delta;
40
+ if (this.topValue !== 0xffffffff) {
41
+ // Keep the base value in range, so that retarding past 0 wraps around to the top
42
+ const topModulo = this.timerMode === TimerMode.ZigZag ? this.topValue * 2 : this.topValue + 1;
43
+ this.baseValue = ((this.baseValue % topModulo) + topModulo) % topModulo;
44
+ }
45
+ this.updated();
40
46
  }
41
47
  get rawCounter() {
42
48
  const { baseFreq, prescalerValue, baseNanos, baseValue, enabled, timerMode } = this;
@@ -362,7 +362,7 @@ export class RPDMA extends BasePeripheral {
362
362
  return (this.intRaw & this.intEnable1) | this.intForce1;
363
363
  }
364
364
  readUint32(offset) {
365
- if ((offset & 0x7ff) <= CHANNEL_REGISTERS_SIZE) {
365
+ if ((offset & 0x7ff) < CHANNEL_REGISTERS_SIZE) {
366
366
  const channelIndex = (offset & 0x7ff) >> 6;
367
367
  return this.channels[channelIndex].readUint32(offset & CHANNEL_REGISTERS_MASK);
368
368
  }
@@ -395,7 +395,7 @@ export class RPDMA extends BasePeripheral {
395
395
  return super.readUint32(offset);
396
396
  }
397
397
  writeUint32(offset, value) {
398
- if ((offset & 0x7ff) <= CHANNEL_REGISTERS_SIZE) {
398
+ if ((offset & 0x7ff) < CHANNEL_REGISTERS_SIZE) {
399
399
  const channelIndex = (offset & 0x7ff) >> 6;
400
400
  this.channels[channelIndex].writeUint32(offset & CHANNEL_REGISTERS_MASK, value);
401
401
  return;
@@ -103,12 +103,15 @@ class PWMChannel {
103
103
  if (value & CSR_EN && !(this.csr & CSR_EN)) {
104
104
  this.updateDoubleBuffered();
105
105
  }
106
+ // PH_ADV and PH_RET are self-clearing, so they never appear in the stored csr value
106
107
  this.csr = value & ~(CSR_PH_ADV | CSR_PH_RET);
107
- if (this.csr & CSR_PH_ADV) {
108
- this.timer.advance(1);
109
- }
110
- if (this.csr & CSR_PH_RET) {
111
- this.timer.advance(-1);
108
+ if (value & CSR_EN) {
109
+ if (value & CSR_PH_ADV) {
110
+ this.timer.advance(1);
111
+ }
112
+ if (value & CSR_PH_RET) {
113
+ this.timer.advance(-1);
114
+ }
112
115
  }
113
116
  this.divMode = (this.csr >> CSR_DIVMODE_SHIFT) & CSR_DIVMODE_MASK;
114
117
  this.setBDirection(this.divMode === PWMDivMode.FreeRunning);
@@ -34,6 +34,12 @@ export class Timer32 {
34
34
  */
35
35
  advance(delta) {
36
36
  this.baseValue += delta;
37
+ if (this.topValue !== 0xffffffff) {
38
+ // Keep the base value in range, so that retarding past 0 wraps around to the top
39
+ const topModulo = this.timerMode === TimerMode.ZigZag ? this.topValue * 2 : this.topValue + 1;
40
+ this.baseValue = ((this.baseValue % topModulo) + topModulo) % topModulo;
41
+ }
42
+ this.updated();
37
43
  }
38
44
  get rawCounter() {
39
45
  const { baseFreq, prescalerValue, baseNanos, baseValue, enabled, timerMode } = this;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rp2040js",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "description": "Raspberry Pi Pico (RP2040) Emulator",
5
5
  "repository": {
6
6
  "type": "git",
@@ -61,7 +61,7 @@
61
61
  },
62
62
  "devDependencies": {
63
63
  "@types/minimist": "^1.2.2",
64
- "@types/node": "^18",
64
+ "@types/node": "^20",
65
65
  "@typescript-eslint/eslint-plugin": "^6.7.3",
66
66
  "@typescript-eslint/parser": "^6.7.3",
67
67
  "eslint": "^8.50.0",
@@ -74,7 +74,7 @@
74
74
  "tsx": "^4.19.3",
75
75
  "typescript": "^5.7.3",
76
76
  "uf2": "^1.0.0",
77
- "vitest": "^3.0.6"
77
+ "vitest": "^4.1.9"
78
78
  },
79
79
  "lint-staged": {
80
80
  "**/*.ts": [