Wokwi Simulator Custom Chips

This thread is for listing Wokwi Custom Chips. If you use or know of any interesting ones, please post them here.

I use a couple Wokwi "custom chips" to test code by posters on the forum.

Two of my favorites are:,

They are both demonstrated in:

I often pull up that simulation up as a testbed and drop a poster's code in to see how things run.

Frequency Counter

I've just written my own Frequency Counter custom chip, as demonstrated here:

image https://wokwi.com/projects/406518140295703553

but I haven't yet packaged it in Github. It is packaged in Github here:

The Frequency Counter can detect up to 8MHz from an simulated Uno, and the code in the sketch demonstrates a few methods of pulse generation.

code
/*
  Custom Frequency Counter chip example for Wokwi.
  https://wokwi.com/projects/406518140295703553 -- Using https://github.com/drf5n/Wokwi-Chip-FrequencyCounter
  https://wokwi.com/projects/406335146945275905 -- Using tabbed files
  built from https://wokwi.com/projects/327458636089524820

  Start the simulation. The green LED shows the output of the inverter.
  The frequency counts show up in the Serial monitor.

  For more information on custom chips: https://docs.wokwi.com/chips-api/getting-started
*/

#include "TimerHelpers.h" // https://gammon.com.au/timers // to configure PWM

const int scheme = 6; // 0..8 Choose one 0 is slowest range, 6 is fastest, 8 is variable
const unsigned long Period = 1000; // 0..? keep lower than 16k for delayMicrosecond() modes
unsigned long varPeriod = Period; // 
const byte PIN = 9;  // this is OC1A (timer 1 output compare A) for sharing with PWM modes

void setup() {
  pinMode(PIN, OUTPUT);
}

void loop() {
  switch (scheme) {
    case 0: // millisecond period with divided delay()
      digitalWrite(PIN, LOW);
      delay(Period / 2); // 50%
      digitalWrite(PIN, HIGH);
      delay(Period - Period / 2); // Compliment of 50% to deal with odd numbers and zeros
      break;
    case 1: // microsecond period with divided delayMicroseconds()
      digitalWrite(PIN, LOW);
      delayMicroseconds(Period / 2);
      digitalWrite(PIN, HIGH);
      delayMicroseconds(Period - Period / 2);
      break;
    case 2: // microsecond period direct port manipulation
      PORTB &= ~bit(1);
      delayMicroseconds(Period / 2);
      PORTB |= bit(1);
      delayMicroseconds(Period - Period / 2);
      break;
    case 3: // PINx toggle in loop()
      PINB = bit(1);
      break;
    case 4: // PINx toggle, one cycle unrolled per loop()
      PINB = bit(1);
      PINB = bit(1);
      break;
    case 5: // unrolled PINx toggle to reduce loop() overhead
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      PINB = bit(1);
      break;
    case 6: // PWM output
      static bool init6 = false;
      if (!init6 ) {
        init6 = true;
        set8MHz(0);
      }
      delay(10);
      break;
    case 7: // broken PWM output
      static bool init7 = false;
      if (!init7 ) {
        init7 = true;
        set8MHz(1); // alternate
      }
      delay(10);
      break;
    case 8: // variable 0-Period millis
      static int lastA0 = -1;
      int potVal = analogRead(A0);
      if (potVal != lastA0) { // change detect pot
        varPeriod = map(potVal, 1023, 0, 0, Period);
        lastA0 = potVal;
      }
      digitalWrite(PIN, LOW);
      delay(varPeriod / 2);
      digitalWrite(PIN, HIGH);
      delay(varPeriod - varPeriod / 2);
      break;
    default:
      static bool initDefault = false;
      if (!initDefault) {
        initDefault = true;
        Serial.begin(115200);
        Serial.print("unsuppored scheme: ");
        Serial.print(scheme);
      }
  }
}

void set8MHz(const byte scheme) {
  TCCR1A = 0;        // reset timer 1
  TCCR1B = 0;
  // set up Timer 1
  TCNT1 = 0;  // reset counter
  if (scheme == 0) { // 8MHz one way:
    OCR1A = 1;  // compare A register value //
    // WGM 15: FastPWM with TOP=OCR1A
    Timer1::setMode (15, Timer1::PRESCALE_1, Timer1::SET_A_ON_COMPARE);
  }
  else if (scheme == 1) { // 8MHz the other way // Doesn't work on Wokwi
    OCR1A = 0;  // compare A register value //
    // WGM 15: FastPWM with TOP=OCR1A
    Timer1::setMode (15, Timer1::PRESCALE_1, Timer1::TOGGLE_A_ON_COMPARE);
    /*
      Page 103 of https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf

      A frequency (with 50% duty cycle) waveform output in fast PWM mode can be achieved by setting OC1A to toggle its logical
      level on each compare match (COM1A1:0 = 1). This applies only if OCR1A is used to define the TOP value
      (WGM13:0 = 15). The waveform generated will have a maximum frequency of fOC1A = fclk_I/O/2 when OCR1A is set to zero
      (0x0000). This feature is similar to the OC1A toggle in CTC mode, except the double buffer feature of the output compare
      unit is enabled in the fast PWM mode.
    */
  }
}

The Wokwi custom chip API is documented in the:

...which has lots of examples. However, if you're looking for a non-official custom chip, it can be hard to find. Googling for them, you can often find broken implementations, or old implementations of them.

If you've written or use interesting Wokwi custom chips, feel free to post about them here.

See also:

1 Like

These are a straight cut and paste from Custom Chips Getting Started:

Basics

Communication

  • SPI Chip - A basic ROT13 cipher over SPI
  • UART Chip - A basic ROT13 cipher over UART
  • I2C Chip - Simple counter with interrupt output
  • EEPROM Chip - Simple I2C memory with 256 kbits by Benny Meisels

Displays

Sensors

Complex chips

1 Like

Up/Down counter limit switches

Here's a Wokwi custom chip with an up/down counter and upper/lower limit/threshold outputs:

  • Wokwi limitCounter -- up/down counter with NO/NC high/low limit outputs.

It isn't a custom chip, but I also learned that you can use the Wokwi stepper motor inputs or A4988 outputs as quadrature signals that work as an encoder:

Stepper quadrature output as encoder input

And another with an A4988 driver and clearer quadrature output/input signals.

(With that, you could read a couple of the motor's quadrature signals with an Arduino and with a function on the Arduino, simulate motor feedback.)

GPS

Luxometer BH1750

1 Like

Sample chips from this tutorial video: https://www.youtube.com/watch?v=yzdCS3A4DvU

And from the getting started, the plain hello-world chip: