Skip to main content

GPIO simulator

The GPIO simulator stands in for a board for the programs you run on Windows. Each pin of the program connects to a card: an LED that lights up, a pushbutton you press with the mouse, a potentiometer you turn, a WS2812 LED strip… That way you can test a program that uses the GPIO module or the LED module without having the board at hand.

You open it with Build › Debug › GPIO Sim, on the ribbon. It's an IDE panel like the others: you can dock it or leave it floating (The interface).

  • It only sees programs that run on Windows, with Windows x64 in Build › Target. On a board, the program drives its real pins and the simulator knows nothing about it.
  • You don't need to open it before Run. It connects by itself as soon as the program uses GPIO or LED, and from then on it updates every 30 ms.
The GPIO simulator with four pins in the table and the cards of an 8 × 8 WS2812 matrix, a potentiometer and a signal generator

A walkthrough​

The LED strip of the LedStrip example, as an 8 × 8 matrix.

  1. Create the project. Press Home › Project › New and, in Example Projects, double-click LedStrip (Projects). Its main program, Code/Matrix8x8Plasma.aru, creates a strip of 64 LEDs on GP17 and paints a colour plasma on it.
  2. Open the simulator with Build › Debug › GPIO Sim. The table already has two pins: GP17, connected to WS2812 Strip, and GP19, to Signal generator, which this program doesn't use. The example keeps them in Config/jaru_sim.json.
  3. Pick the shape. On the WS2812 Strip · GP17 card, open Layout and pick 8 x 8.
  4. Run it. Press Run. The card shows the plasma, and below it, 64 LEDs | 8x8 | Bright: 255.
  5. Try the wiring. Change Wiring to Serpentine H: every other row runs backwards and the picture breaks on those rows, because the program counts the LEDs row by row. That's what you would see on a matrix wired in a zigzag.

To use your own pins, add them with Add GPIO Pin and connect them to a device in the Connected to column.

The pin table​

The table on the left holds the pins you are going to use. It doesn't fill itself with the program's pins: you add each pin yourself.

  • Add GPIO Pin asks for the pin number, from 0 to 48. A new pin is a digital input with nothing connected: INPUT, DIGITAL, NONE, LOW and -- Free --. It doesn't let you add the same pin twice.
  • Delete GPIO Pin removes the selected row and its card, without asking.
ColumnWhat it shows
GPIOThe pin: GP2, GP17…
DirectionINPUT or OUTPUT. The program sets it, with GPIO.pinmode or with GPIO.awrite; until then, the pin is an input.
TypeDIGITAL; ADC_IN, with a Potentiometer, a Temperature or a Signal generator; PWM Ch.0 (with its channel) if the program uses GPIO.awrite; DAC_OUT, an analog output with no channel.
PullNONE, PULLUP or PULLDOWN, as set by GPIO.pinmode.
StatusOn a digital pin, HIGH (green dot) or LOW (grey dot). On an analog one, the value and a bar.
Connected toThe device connected to the pin, or -- Free --.

With the mouse:

  • Click Connected to: the list of devices drops down. Pick one and press Enter, or click elsewhere: its card appears on the right. Esc leaves it as it was, and -- Free -- removes the card. Each pin takes one device at most.
  • Click Status, on a digital input, while the program runs: the pin goes from LOW to HIGH or the other way round. It's a quick switch, with no card.
  • Click Status, on an analog pin: a box with the value comes up, from 0 to 4095. Type another one and press Enter (Esc doesn't change it). If the program is running, it reads it with GPIO.aread.

With a PWM of 10 Hz or less, Status makes the pin blink at the PWM's pace, as you would see it on an LED.

Move the controls while the program runs

Every time a program starts, the VM sets all the pins to zero. Whatever you set on the cards beforehand (a turned potentiometer, a switch that's on) doesn't reach the program until you touch it again.

The cards​

On the right there is one card for each pin with a device, in the order you connect them. The title says the device and the pin, like Potentiometer · GP2.

DeviceWhat it isThe program uses it with
Red LED, Green LED, Blue LEDAn LED that lights up with the pin.GPIO.write, GPIO.awrite
PushbuttonA pushbutton: the pin changes while you hold it down.GPIO.read, GPIO.onInterrupt
SwitchA switch: each click turns it on or off.GPIO.read, GPIO.onInterrupt
PotentiometerA knob you turn: from 0 to 4095.GPIO.aread
TemperatureA temperature sensor: from 0 to 4095.GPIO.aread
PhototransistorA light sensor: from 0 to 4095.GPIO.aread
OscilloscopeDraws the pin's PWM signal.GPIO.awrite
Signal generatorGives random voltages or the ones in a CSV file.GPIO.aread
WS2812 StripA strip or a matrix of colour LEDs.LED.new and show()

LEDs​

A round LED that follows the pin, and next to it, its state:

  • With GPIO.awrite (PWM), it shines according to the duty cycle. The card gives the duty, like Duty: 128 / 255 (50%), and below it the channel, the frequency and the resolution, like PWM Ch.0 | 5000Hz | 8bit.
  • With GPIO.write, it lights up with HIGH: ON (HIGH) or OFF (LOW).

Pushbutton and Switch​

A round button you press with the mouse:

  • Pushbutton changes the pin while you hold it down and puts it back when you let go.
  • Switch changes the pin with each click and leaves it that way.

What the program reads depends on the pin mode, as on a board:

  • with GPIO.PULLUP, the pressed button gives 0 (LOW) and released, 1;
  • with GPIO.INPUT or GPIO.PULLDOWN, pressed gives 1 and released, 0.

The card says both things: PRESSED (LOW), Released (HIGH)… The interrupts of GPIO.onInterrupt fire with the button's changes, as on the board.

Potentiometer, Temperature and Phototransistor​

All three give the pin a value from 0 to 4095, the one GPIO.aread reads:

  • Potentiometer: turn the knob by dragging around it, or click a point of the circle to take it there. 0 is at the top, and the value grows clockwise. You can also click the bar below: the value jumps to that point.
  • Temperature: it has no knob; click the bar. The card shows the value in degrees, from 0 °C (0) to 100 °C (4095), and below it, the number (Raw: 2048).
  • Phototransistor: drag up to give it more light and down for less. With Shift, the value moves more slowly.

On the potentiometer and the phototransistor, the mouse wheel moves the value in steps of 1 % (about 41), and with Shift, of 0.1 %. On all three, you can also type the value in the Status column of the table.

Oscilloscope​

It draws the signal of a PWM output (GPIO.awrite): the square wave, with its frequency and its duty cycle. At the top it gives the channel, the frequency, the resolution and the duty, and on the right, the duty in numbers (Duty: 128 / 255).

The - and + buttons, inside the screen, show fewer or more cycles of the wave: from 1 to 20, and 3 by default. With no PWM on the pin, it says No signal.

Signal generator​

It gives the pin a voltage that changes by itself, to test a program that reads a sensor. Its controls:

  • Random or CSV: random voltages or the ones in a file.
  • ▶ Play starts it and ■ Stop stops it. It works even when the program isn't running: the graph below shows what it is giving.
  • Loop: when the CSV ends, it starts over. On by default.
  • The ms box: how many milliseconds between new values, from 10 to 5000. 50 by default.
  • Min and Max: the voltage that gives 0 and the one that gives 4095, from 0 to 3.3 V. 0 and 3.3 by default.
  • CSV... loads a file and switches the generator to CSV.

At the bottom, the card gives the voltage and the value the program reads: 1.99V | ADC: 2465.

With Random, each new value is a random voltage between Min and Max: the program reads a random number between 0 and 4095.

With CSV, the generator plays the file at its own pace: each line is a point, with the time in milliseconds from the start and the voltage in volts, separated by a comma. Between one point and the next, it joins the two with a straight line. Blank lines, lines that start with # and a text header are skipped. This one rises to 3 V in half a second and goes back down:

# time_ms,volts
0,0
500,3
1000,0

If the voltage has decimals, write them the way your Windows writes them: with a point (250,1.5) if Min and Max show as 0.0 and 3.3, and with a comma (250,1,5) if they show as 0,0 and 3,3. When it reaches the last point, it starts over if Loop is on; if not, it stops and keeps the last value.

WS2812 Strip​

It shows the LED strip that the program creates on that pin with LED.new. It is painted every time the program calls show().

  • Layout picks the shape: Strip (a strip, in rows that fill the card) or a matrix of 8 x 8, 16 x 16, 32 x 8, 8 x 32 or 4 x 4 (width by height). The change shows on the program's next show().
  • Wiring says how the matrix is wired, and only matters in a matrix. LED 0 is at the top left:
    • Sequential: row by row, all of them left to right.
    • Serpentine H: row by row, in a zigzag: the first one left to right, the second one right to left, and so on.
    • Serpentine V: column by column, in a zigzag: the first one downwards, the second one upwards, and so on.

LEDs that don't fit in the matrix aren't shown. At the bottom, the card gives how many LEDs the strip has, the shape and the brightness from setBrightness: 64 LEDs | 8x8 | Bright: 255. If there is no strip on that pin, No active strip.

What it saves​

The simulator keeps its pins in Config/jaru_sim.json, inside the project: each pin, with the device it has. This is the one of the LedStrip example:

{
"pins" : [
{
"gpio" : 17,
"connectedTo" : "WS2812 Strip"
},
{
"gpio" : 19,
"connectedTo" : "Signal generator"
}
]
}
  • It saves it when you close the simulator, when you close the project or open another one, and when you close the IDE. With no project open, it saves nothing.
  • It reads it when you open the simulator, and when you open a project with the simulator open.
  • It saves nothing else: Layout, Wiring, the generator settings and the position of the controls go back to their defaults every time.

From code​

On Windows, the GPIO module doesn't touch any hardware: it reads and writes a memory it shares with the simulator. The program doesn't know whether the simulator is open. Without it, nobody moves the inputs: an input pin reads 0 (1 with GPIO.PULLUP), and GPIO.aread, 0.

This program expects a Pushbutton on GP4, a Potentiometer on GP2 and a Red LED on GP5. While you hold the button down, the LED shines according to the potentiometer:

use GPIO

GPIO.pinmode(4, GPIO.PULLUP) // GP4: Pushbutton

while (true)
var value = GPIO.aread(2) // GP2: Potentiometer, from 0 to 4095
if (GPIO.read(4) == 0) then // with PULLUP, pressed is 0
GPIO.awrite(5, value / 16) // GP5: Red LED, brightness from 0 to 255
else
GPIO.awrite(5, 0)
end
pause(50)
end

The LED module drives WS2812 strips. LED.new(pin, n) creates a strip of n LEDs on the pin, from 1 to 1024. You set the colours with setPixel(i, r, g, b), fill(r, g, b), setHSV and fillHSV; the brightness, with setBrightness (from 0 to 255), and clear() sets them all to black. None of that reaches the strip until you call show(). This one lights a red LED that runs along a strip of 64 on GP17:

use LED

var strip = LED.new(17, 64)
strip.setBrightness(128)

var step = 0
while (true)
strip.clear()
strip.setPixel(step % 64, 255, 0, 0)
strip.show() // the card is painted here
step = step + 1
pause(50)
end
  • On Windows there is room for 8 strips and 2,048 LEDs among all of them. Beyond that, LED.new gives an error.
  • The card shows the colours just as the program sets them. setOrder, which on a board says in which order the strip expects the colours, changes nothing here.

The whole GPIO module is in GPIO.

Known issues​

  • The buttons' hints say something else. When you hover over Add GPIO Pin and Delete GPIO Pin, the hint says "New Source Code".
  • The Phototransistor shows as digital in the table. The table shows its pin as DIGITAL and with HIGH/LOW. The value the program reads is the one on the card.
  • A CSV with decimals depends on Windows. A file written with a decimal point doesn't load on a Windows that uses a decimal comma, nor the other way round: the lines it doesn't understand are skipped without a warning.
  • The generator's button stays at Stop. When a CSV ends without Loop, the generator stops, but the button still says ■ Stop. One click starts it again.

All the known issues of JARU, together, are in Known issues.