Raspberry Pi 500 Library for Proteus: a CAN bus dashboard with an MCP2515 on SPI and a web page

Raspberry Pi 500 Library for Proteus: MCP2515 CAN Bus Dashboard

2.5K Views
40
700
60
25
60
PCBWay

Hello friends, I hope you all are doing great. Today, I am going to share the Raspberry Pi 500 Library for Proteus. The Raspberry Pi 500 is a Raspberry Pi 5 built into a keyboard: the BCM2712 at 2.4 GHz with 8 GB of RAM, the RP1 I/O controller, Gigabit Ethernet, Wi-Fi, two micro-HDMI outputs and the usual 40-pin GPIO header at the back. With this library the keyboard runs your Python program against the circuit in Proteus 8.5, on our virtual network.

Updates

Raspberry Pi 500 Library for Proteus

Latest version: V1.0 (October 2026, this tutorial)

Helping Tools

Every library of our board series connects the board to a different module and serves a web page. This time the Pi 500 joins a CAN bus - the network of cars, trucks and factory machines. An MCP2515 CAN module on the Pi's SPI bus talks to a second node, an Arduino UNO playing the engine, which sends the engine speed, the coolant temperature and the road speed twice a second. The Pi decodes the frames, watches the health of the bus, switches a lamp on the engine node, and shows everything on a dashboard page on a laptop and a phone.

NOTICE: this library does not run Raspberry Pi OS. It runs your Python program, with the same Python libraries a Pi uses for its pins, its buses and its network, in step with the simulation. Your feedback is the fuel that keeps us going, so please tell us what you think in the comments below or in the Raspberry Pi 500 board of our forum. And if our free libraries help you, you can buy us a coffee. So, let's get started with the Raspberry Pi 500 Library for Proteus:

Raspberry Pi 500 Library for Proteus: a CAN bus dashboard with an MCP2515 on SPI and a web page
Figure: The Raspberry Pi 500 Library for Proteus: PI1 runs can_dashboard.py - the power LED on, the MCP2515 on SPI0, its INT on GPIO25.

What is the Raspberry Pi 500?

In December 2024 Raspberry Pi did for the Pi 5 what the Pi 400 had done for the Pi 4: it put the whole computer inside a compact keyboard. The case, the keys and the row of sockets at the back are the Pi 400's, but inside sits the Pi 5's BCM2712 - four Cortex-A76 cores at 2.4 GHz - with 8 GB of RAM and the RP1 chip that drives the GPIO header, USB and Ethernet. The keyboard also gained a power key, which works like the Pi 5's power button.

For electronics the important part is still at the back: the 40-pin GPIO header, the same pins with the same numbers as on every Pi since the B+. Because the pins belong to the RP1, a Pi 500 program drives them the Pi 5 way - through the Linux gpiochip, with lgpio and gpiozero on top of it.

The Raspberry Pi 400 and the Raspberry Pi 500
Raspberry Pi 400 (2020)Raspberry Pi 500 (2024)
ProcessorBCM2711, four Cortex-A72 cores at 1.8 GHzBCM2712, four Cortex-A76 cores at 2.4 GHz
RAM4 GB8 GB
GPIO controllerinside the BCM2711the RP1 I/O controller
GPIO libraryRPi.GPIO or gpiozerolgpio, gpiozero on lgpio, rpi-lgpio
NetworkGigabit Ethernet, dual-band Wi-Fi, Bluetooth 5.0the same
USBtwo USB 3.0, one USB 2.0the same
Power key-yes, on the keyboard
Sizea 286 x 122 mm keyboardthe same case

In Proteus, our Raspberry Pi Model B Library for Proteus covers how the board runs a Python program: the program and Proteus work in lockstep, every sleep, pin wait and bus transfer moves the simulation clock, and the Python libraries for the pins answer as on a Pi. The Raspberry Pi 4 Model B Library for Proteus, the Raspberry Pi 5 Library for Proteus and the Raspberry Pi 400 Library for Proteus are the Pi 500's closest relatives: it borrows the Pi 400's keyboard and the Pi 5's runtime.

Features of the Raspberry Pi 500 Library for Proteus

  • The keyboard as it looks: the Pi 500 from above with its keys, the power key, the raspberry key, the power LED, and the back with the Ethernet jack, the USB sockets, the USB-C, the two micro-HDMI, the microSD slot, the 40-pin header and the Kensington slot.
  • The Pi 5 inside: /proc/cpuinfo says Revision d04190, the device tree "Raspberry Pi 500 Rev 1.0", and gpiozero names the board 500; the GPIOs are lines of gpiochip 0, as on a real Pi 500.
  • lgpio and gpiozero: gpiochip_open, claims, reads and writes, alerts with callbacks, PWM and servo pulses, and gpiozero's devices on the lgpio pin factory - with the timing of the Pi 500, about 1 us a GPIO call.
  • Ethernet and Wi-Fi: eth0 with the cable in (the default), wlan0 on our router TEP-WiFi with the cable out - 192.168.1.51 either way; sockets and http.server work on both.
  • SPI and the other buses: spidev on SPI0 for the CAN controller - plus smbus2, pyserial, 1-Wire and the DHT sensors, as on the earlier boards.
  • The Pi Terminal: the output, the errors, a line for input(), and a Board tab with the GPIOs, the LED and the supply pins - with our TEP header, no Windows title bar.
  • A complete package: about 14.1 MB with the board, Python, the runtime, the MCP2515 and Arduino UNO libraries, the monitors and the demo, without the source code of the models.

The Raspberry Pi 500 in Proteus

Raspberry Pi 500 in Proteus: the keyboard computer with its 40-pin GPIO header at the back
Figure: The part as the library draws it: the keys with the power key (F10) and the raspberry key, the power LED lit at the top right, and along the back the Ethernet jack, the USB sockets, the USB-C, the two micro-HDMI, the microSD slot, the 40-pin header with a colour-coded tag on each pin, and the Kensington slot.

Search RASPBERRY in Pick Devices; the device RASPBERRY PI 500 is in TEPRPI500.LIB (Microprocessor ICs, Raspberry Pi), with the prefix PI. The keyboard is drawn at half its real size - a 286 mm keyboard would fill the sheet - but the header keeps the real 0.1 in pitch, so its 40 pins leave the top edge as one comb, as on every Pi of the series, each with a tag in the colour of its kind: 5V red, 3V3 orange, GND black, GPIO green, I2C blue, SPI pink, UART purple and the ID pins grey. Click a micro-HDMI socket or the raspberry key to open the Pi Terminal, and the Ethernet jack to plug or unplug the cable.

Raspberry Pi 500 in Proteus with seven header pins wired to net labels for the MCP2515
Figure: PI1 in the demo: seven header pins go up to net labels - 5V and GND, and MOSI, MISO, INT, SCLK and CE0 for the CAN module.

The 40-Pin Header

The 40 pins with their BCM numbers
PinsNamePinsName
13V325V
3GPIO2 (SDA)45V
5GPIO3 (SCL)6GND
7GPIO48GPIO14 (TXD)
9GND10GPIO15 (RXD)
11GPIO1712GPIO18
13GPIO2714GND
15GPIO2216GPIO23
173V318GPIO24
19GPIO10 (MOSI)20GND
21GPIO9 (MISO)22GPIO25
23GPIO11 (SCLK)24GPIO8 (CE0)
25GND26GPIO7 (CE1)
27ID_SD28ID_SC
29GPIO530GND
31GPIO632GPIO12
33GPIO1334GND
35GPIO1936GPIO16
37GPIO2638GPIO20
39GND40GPIO21

The GPIOs work at 3.3 V; GPIO2 and GPIO3 have the Pi's 1.8 k pull-ups. The 5V and 3V3 pins power the modules wired to them. ID_SD and ID_SC are kept for a HAT's ID EEPROM, so leave them free, as on a real Pi.

Download Raspberry Pi 500 Library for Proteus

Click the button below to download Raspberry-Pi-500-Library-for-Proteus-v1.0.zip (about 14.1 MB with Python included, without the source code of the models):

Raspberry Pi 500 Library for Proteus V1.0
  • README.txt: the device, the network, installation, the demo, the header, the properties, troubleshooting and the limits.
  • Proteus Library Files: TEPRPI500.LIB (the Raspberry Pi 500) and the demo's parts: TEPMCP2515.LIB (the CAN modules), ArduinoV4TEP.LIB (the engine node's Arduino UNO V4.0), TEPLAPTOP.LIB and TEPMOBILE.LIB.
  • Proteus Model Files: TEPNET.DLL (the Pi, the laptop, the phone and the network), TEPMCP2515.DLL, TEPARDUINO.DLL and the TEPPi folder - Python 3.11 and the TEP Pi runtime.
  • Python Code: blink.py and can_dashboard.py.
  • Arduino Code: CAN_Node1.ino, the engine node.
  • Proteus Simulation: the demo project, its program, the engine node's HEX file and copies of the DLLs.

No Proteus yet? Read How to Download and Install Proteus 7 and 8. New to libraries? Follow How to Install a New Library in Proteus.

How to Install Raspberry Pi 500 Library for Proteus

  1. Close Proteus and extract the whole zip file, for example to your Desktop.
  2. Copy the files from Proteus Library Files into the LIBRARY folder of Proteus (usually C:\Program Files (x86)\Labcenter Electronics\Proteus 8 Professional\LIBRARY).
  3. Copy everything from Proteus Model Files - the DLLs and the TEPPi folder - into the MODELS folder, replacing an older TEPNET.DLL and TEPPi folder (these are the newest; they also run every earlier Pi of the series).
  4. Delete TEPRPI500.IDX from the LIBRARY folder if it is there.
  5. Start Proteus, press P and search for RASPBERRY.

There is nothing else to install: Python comes in the TEPPi folder, so you need no Python on your PC.

Demo: a CAN Bus Dashboard

CAN (Controller Area Network) was made by Bosch for cars: instead of a wire from every sensor to every gauge, all the control units share one twisted pair, CANH and CANL, and send short frames - an identifier and up to eight data bytes. The identifier says what the frame is about and also sets its priority: when two nodes start at once, the lower identifier wins, without either frame being lost. Every receiver checks the CRC and acknowledges a good frame in the same bit time, so a sender always knows whether anybody heard it.

Open Pi-500-CAN-Dashboard.pdsprj. PI1 runs can_dashboard.py on Ethernet with U1, an MCP2515 CAN module from our MCP2515 CAN Bus Module Library for Proteus, on its SPI0 pins. ARD1 is an Arduino UNO V4.0 from our Arduino UNO Library for Proteus V4.0 with its own MCP2515, U2: it runs CAN_Node1.hex, the engine node of the MCP2515 library, and has an LED on D7. The two modules' CANH and CANL pins are joined. Both modules are the Advance versions: each opens a pop-up window at Run with the frames on the bus. PC1 is the Laptop WiFi Monitor and MOB1 the Mobile WiFi Monitor.

Raspberry Pi 500 Proteus simulation: an MCP2515 on SPI, an Arduino UNO engine node, a laptop and a phone
Figure: The whole demo: PI1 with seven header pins going to net labels, U1 on the Pi's SPI, ARD1 with U2 and the LED, the CAN bus labels between the modules, and the laptop and the phone.
The wiring of the Pi's CAN node
MCP2515 pinNet labelPi 500 pinWhat it does
VCC, GND5V, GND2, 6the module's supply
CSCE024 (GPIO8)LOW for every SPI transfer
SOMISO21 (GPIO9)the MCP2515's answers
SIMOSI19 (GPIO10)the Pi's instructions
SCKSCLK23 (GPIO11)the SPI clock
INTINT22 (GPIO25)LOW while a received frame waits
CANH, CANLCANH_BUS, CANL_BUS-the bus to the engine node's module

The MCP2515 Over SPI

The MCP2515 is a complete CAN controller: it builds and checks the frames, the CRC, the bit stuffing and the acknowledgements, and keeps the error counters. The Pi only talks to it over SPI with a handful of instructions - read and write a register, change some bits, read a received frame, load a frame to send and ask for it to be sent. The program wraps them in a small class:

    def read(self, reg):
        return self.spi.xfer2([self.READ, reg, 0])[2]

    def write(self, reg, *values):
        self.spi.xfer2([self.WRITE, reg] + list(values))

    def modify(self, reg, mask, value):
        self.spi.xfer2([self.BITMOD, reg, mask, value])

After a RESET the chip waits in configuration mode. The bit timing comes from the CNF1 to CNF3 registers and the module's 8 MHz crystal: for 500 kbps a bit is 8 time quanta of 0.25 us. The receive buffers are told to take every frame, the INT pin to fall when one arrives, and then the chip goes to normal mode - which CANSTAT confirms:

    def begin(self):
        """RESET (configuration mode), 500 kbps with the 8 MHz crystal (CNF1 0x00, CNF2 0x90, CNF3 0x82: 8 time quanta of 0.25 us, the
        sample point at 62.5 %), both RX buffers take every frame (filters off, RXB0 rolls over to RXB1), INT on a received frame, then
        normal mode. True when CANSTAT confirms it."""
        self.spi.xfer2([self.RESET])
        time.sleep(0.01)
        self.write(self.CNF3, 0x82, 0x90, 0x00)                     # CNF3, CNF2, CNF1 (the addresses count down: 0x28 .. 0x2A)
        self.write(self.RXB0CTRL, 0x64)                             # RXM = 11 (any frame), BUKT (roll over to RXB1)
        self.write(self.RXB1CTRL, 0x60)
        self.write(self.CANINTE, 0x03)                              # RX0IE, RX1IE
        self.modify(self.CANCTRL, 0xE0, 0x00)                       # REQOP = 000: normal mode
        for _ in range(10):
            if self.read(self.CANSTAT) & 0xE0 == 0x00:
                return True
            time.sleep(0.01)
        return False

Receiving and Sending Frames

When INT is LOW, CANINTF says which buffer holds a frame. The READ RX BUFFER instruction reads it in one go - the identifier, the length and the data - and clears the buffer's flag when CS goes high, so INT goes back up by itself:

    def receive(self):
        """The frames waiting in RXB0 / RXB1: [(id, data)]. READ RX BUFFER clears the buffer's flag when CS goes high."""
        frames = []
        flags = self.read(self.CANINTF)
        for bit, cmd in ((0x01, self.READ_RX0), (0x02, self.READ_RX0 | 0x04)):
            if flags & bit:
                r = self.spi.xfer2([cmd] + [0] * 13)[1:]
                ident = r[0] << 3 | r[1] >> 5
                if r[1] & 0x08:                                     # IDE: an extended (29-bit) identifier
                    ident = (ident << 2 | r[1] & 0x03) << 16 | r[2] << 8 | r[3]
                frames.append((ident, bytes(r[5:5 + min(r[4] & 0x0F, 8)])))
        return frames

Sending is the other way round: LOAD TX BUFFER writes the identifier, the length and the data into TXB0, and RTS starts the transmission. If the last frame is still waiting - nobody has acknowledged it yet - the program does not overwrite it:

    def send(self, ident, data):
        """A standard frame through TXB0; False while the last one still waits (no other node acknowledges it)."""
        if self.read(self.TXB0CTRL) & 0x08:
            return False
        self.spi.xfer2([self.LOAD_TX0, ident >> 3 & 0xFF, (ident & 0x07) << 5, 0, 0, len(data)] + list(data))
        self.spi.xfer2([self.RTS_TX0])
        return True

The chip also counts the errors it sees. Every failed transmission adds 8 to TEC and every success takes 1 away; above 127 a node becomes error passive and above 255 it goes bus-off and stops. EFLG tells the state:

    def errors(self):
        """(TEC, REC, the error state from EFLG)."""
        tec, rec, eflg = self.read(self.TEC), self.read(self.REC), self.read(self.EFLG)
        state = 'BUS-OFF' if eflg & 0x20 else 'ERROR PASSIVE' if eflg & 0x18 else 'ERROR ACTIVE'
        return tec, rec, state

The Bus Loop

A thread watches the INT pin with lgpio - the Pi 500 way to read a GPIO - every 5 ms. ID 0x100 carries the engine data; once a second the Pi sends ID 0x200 with the LED state for the engine node and reads the error counters, and every 2 s it prints a status line:

def can_loop():
    """Every 5 ms: INT LOW means a frame waits - read it; every second: ID 0x200 with the LED, the error counters, a status line."""
    next_tx = next_status = time.time()
    shown = None
    while True:
        if lgpio.gpio_read(chip, INT_PIN) == 0:
            for ident, data in can.receive():
                if ident == 0x100 and len(data) >= 4:
                    with lock:
                        first = state['frames'] == 0
                        state.update(rpm=data[0] << 8 | data[1], coolant=data[2], kmh=data[3], last=time.time())
                        state['frames'] += 1
                    if first:
                        note('first frame from the engine node: ID 0x100 %s' % data.hex(' ').upper())
                else:
                    note('frame ID 0x%X: %s' % (ident, data.hex(' ').upper()))

The dashboard's warnings come from the data and from time: HIGH RPM from 2800 rpm, COOLANT HOT from 85 C, and ENGINE NODE SILENT when no frame has arrived for 2 s - a cut wire, a crashed node or a dead bus all look like that:

def warnings(s):
    if not s['frames']:
        return 'waiting for the engine node'
    if time.time() - s['last'] > 2:
        return 'ENGINE NODE SILENT - no frame for %.0f s' % (time.time() - s['last'])
    w = []
    if s['rpm'] >= RPM_HIGH: w.append('HIGH RPM')
    if s['coolant'] >= COOLANT_HOT: w.append('COOLANT HOT')
    return ', '.join(w) or 'OK'

The Web Page

The page shows the engine, the status, the bus and the LED, with REFRESH, LED ON and LED OFF; /json gives the same values for a program:

PAGE = """<html><head><title>Pi 500 CAN dashboard</title></head><body>
<h1>CAN Dashboard</h1>
<p>Engine: <b>{rpm} rpm</b>, {kmh} km/h</p>
<p>Coolant: {coolant} C</p>
<p>Status: <b>{warning}</b></p>
<p>Bus: {bus}, TEC {tec}, REC {rec}; frames {frames}, sent {sent}</p>
<p>Engine node LED: {led}</p>
<p><a href="/">REFRESH</a> <a href="/led?on=1">LED ON</a> <a href="/led?on=0">LED OFF</a></p>
<p>{log}</p>
</body></html>"""

At the start the program opens gpiochip 0 and claims GPIO25 as an input with a pull-up, sets up the MCP2515, waits for the network, starts the bus thread and serves on port 8000:

print('can_dashboard.py - CAN bus dashboard on the Raspberry Pi 500')
chip = lgpio.gpiochip_open(0)
lgpio.gpio_claim_input(chip, INT_PIN, lgpio.SET_PULL_UP)
can = MCP2515()
if can.begin():
    print('MCP2515 ready: 500 kbps, 8 MHz crystal, normal mode; INT on GPIO%d' % INT_PIN)
else:
    print('MCP2515 not answering - check CS (GPIO8), SCK, SI, SO and 5 V')
print('waiting for the network ...')
while my_ip() == '0.0.0.0':
    time.sleep(0.5)
threading.Thread(target=can_loop, daemon=True).start()
print('dashboard on http://%s:%d/' % (my_ip(), PORT))
HTTPServer(('', PORT), Handler).serve_forever()

Run the Demo

Press Run. The MCP2515 answers, eth0 comes up and the first frame from the engine node arrives within a second:

pi@raspberrypi:~ $ python3 can_dashboard.py
can_dashboard.py - CAN bus dashboard on the Raspberry Pi 500
MCP2515 ready: 500 kbps, 8 MHz crystal, normal mode; INT on GPIO25
waiting for the network ...
dashboard on http://192.168.1.51:8000/
16:43:34  first frame from the engine node: ID 0x100 03 52 3C 15
16:43:34  dashboard: OK
16:43:34   900 rpm  coolant 60 C   22 km/h  frames 2  LED off  ERROR ACTIVE
16:43:36  1100 rpm  coolant 60 C   27 km/h  frames 6  LED off  ERROR ACTIVE
Pi Terminal in Proteus: the Raspberry Pi 500 CAN dashboard starts
Figure: The Pi Terminal: the MCP2515 ready at 500 kbps, the first frame from the engine node, the page's address and the status lines.
Raspberry Pi 500 in Proteus running the CAN dashboard with its power LED on
Figure: The running Pi 500 with its power LED on, the header wired to the CAN module.
Raspberry Pi 500 CAN bus dashboard running in Proteus
Figure: The demo running: PI1 on Ethernet, U1 and U2 on the bus, ARD1 sending, the laptop and the phone.
MCP2515 Advance pop-up in Proteus: the Raspberry Pi 500 node on the CAN bus
Figure: U1's pop-up: 500 kbps measured on the bus, this node's traffic, and the frames - ID 0x100 from the engine, ID 0x200 from the Pi.
Arduino UNO serial monitor in Proteus: the CAN engine node sends ID 0x100
Figure: The engine node's monitor: ID 0x100 sent with the rpm, the coolant and the speed every 500 ms.

Open the Page

On the laptop click Browser and Go (its home page is http://192.168.1.51:8000/json); on the phone the same with http://192.168.1.51:8000/:

Laptop WiFi Monitor in Proteus showing the Raspberry Pi 500 CAN dashboard JSON
Figure: The laptop: the JSON - rpm, coolant, km/h, the frames, the LED and the bus.
Mobile WiFi Monitor in Proteus showing the Raspberry Pi 500 CAN dashboard
Figure: The phone: the engine, the status, the bus, the LED, and REFRESH, LED ON and LED OFF as buttons.

A Lamp on the Other Node

Tap LED ON on the phone. From the next second the Pi's ID 0x200 frames carry a 1 in byte 0, and the engine node switches the LED on its D7 - a command crossing from a web page, through the Pi and the CAN bus, to another microcontroller:

Mobile WiFi Monitor in Proteus after LED ON on the Raspberry Pi 500 dashboard
Figure: The phone after LED ON: the engine node LED ON.
Arduino UNO engine node in Proteus with its LED lit by a CAN frame from the Raspberry Pi 500
Figure: Closer: ARD1 with U2, and the LED on D7 lit.
Arduino UNO serial monitor in Proteus: from node 2: LED ON
Figure: The engine node's monitor: from node 2: LED ON.

High Revs

The engine node sweeps the rpm between 800 and 3000. At 2800 rpm the dashboard switches to HIGH RPM:

Mobile WiFi Monitor in Proteus: HIGH RPM on the Raspberry Pi 500 CAN dashboard
Figure: The phone after REFRESH: HIGH RPM.
Laptop WiFi Monitor in Proteus: the CAN dashboard JSON at high rpm
Figure: The laptop after Go: the rpm and the warning in the JSON.

A Cut Cable

Now click CABLE on U1's pop-up: the Pi's node is off the bus. No more frames reach it, so after 2 s the dashboard says ENGINE NODE SILENT. And its own ID 0x200 frames find nobody to acknowledge them: the MCP2515 sends them again and again, TEC climbs by 8 each time, and at 128 the node is error passive. The engine node, now alone on its side of the cut, gets no acknowledgements either:

MCP2515 Advance pop-up in Proteus with the cable cut: ACK errors
Figure: U1's pop-up with the cable cut: the node alone, ACK errors and TEC rising.
Mobile WiFi Monitor in Proteus: ENGINE NODE SILENT on the Raspberry Pi 500 dashboard
Figure: The phone after REFRESH: ENGINE NODE SILENT and the bus error passive.
Pi Terminal in Proteus: the Raspberry Pi 500 CAN node goes error passive
Figure: The Pi Terminal: the engine node silent, then bus: ERROR PASSIVE.

Click CABLE again: the frames come back, the next acknowledged ID 0x200 takes TEC below 128, and the node is error active again. Then tap LED OFF:

Mobile WiFi Monitor in Proteus after LED OFF on the Raspberry Pi 500 dashboard
Figure: The phone after LED OFF: the bus error active again, the LED off.
MCP2515 Advance pop-up in Proteus: the engine node after the test
Figure: U2's pop-up at the end: the engine node's traffic and its error counters back to normal.

The Pi Terminal logs every event:

16:43:49  the page: LED ON - sent in ID 0x200
16:43:50  2500 rpm  coolant 64 C   62 km/h  frames 34  LED ON  ERROR ACTIVE
16:43:54  dashboard: HIGH RPM
16:43:54  2900 rpm  coolant 65 C   72 km/h  frames 42  LED ON  ERROR ACTIVE
16:43:58  dashboard: OK
16:44:44  2550 rpm  coolant 77 C   63 km/h  frames 141  LED ON  ERROR ACTIVE
16:44:45  bus: ERROR PASSIVE (TEC 128, REC 0)
16:44:46  dashboard: ENGINE NODE SILENT - no frame for 3 s
16:44:48  2550 rpm  coolant 77 C   63 km/h  frames 141  LED ON  ERROR PASSIVE
16:44:50  bus: ERROR ACTIVE (TEC 127, REC 0)
16:44:50  dashboard: OK
16:44:50  1850 rpm  coolant 79 C   46 km/h  frames 145  LED ON  ERROR ACTIVE
16:44:53  the page: LED OFF - sent in ID 0x200
16:44:54  1450 rpm  coolant 80 C   36 km/h  frames 153  LED off  ERROR ACTIVE

The Pi Terminal

The Pi Terminal opens at Run, in the look of our TEP Serial Monitor Advance for Proteus - our own TEP header, no Windows title bar. Its Monitor tab shows the program's output (OUT), errors (ERR) and the lines you type for input() (IN). The Board tab shows the board live - the SPI pins, CE0 and INT - the power LED and the supply pins, and RESTART PROGRAM starts the program again:

Pi Terminal in Proteus: the Raspberry Pi 500 CAN dashboard log
Figure: The Pi Terminal after the run: the status lines, the warnings, the LED commands and the bus states.
Pi Terminal Board tab in Proteus: the Raspberry Pi 500 GPIOs, LED and supply pins
Figure: The Board tab: the BCM2712 at 2.4 GHz, the GPIOs by BCM number, the PWR LED, 5V and 3V3, can_dashboard.py and the speed.

Properties of the Raspberry Pi 500

Double-click the Pi to change them
PropertyWhat it does
PROGRAMthe Python program (default blink.py; a name next to the project or a full path)
AUTOOPENthe Pi Terminal at Run: YES (default) or NO
ETHERNETthe cable at Run: IN (default, eth0) or OUT (the network on wlan0)
WIFISSID, WIFIPASSthe network wlan0 joins and its password (default TEP-WiFi, 12345678)
PYTHON, RUNTIMEa python.exe and a runtime folder of your own (empty: the TEPPi folder)

Your own programs go next to your project; set PROGRAM to the file's name. The default blink.py blinks an LED on GPIO17 with gpiozero - which runs on lgpio on the Pi 500:

from time import sleep
from gpiozero import LED

led = LED(17)
while True:
    led.on()
    print('LED on')
    sleep(0.5)
    led.off()
    print('LED off')
    sleep(0.5)

Troubleshooting

  • "MCP2515 not answering": CS on GPIO8 (CE0), SCK, SI to MOSI and SO to MISO, the module's VCC on 5V.
  • No frames: CANH to CANH and CANL to CANL; both nodes at 500 kbps with the 8 MHz crystal - the pop-up shows the bit rate it measures on the bus.
  • TEC climbs and the bus goes error passive: nobody acknowledges the frames - the other node is off the bus or not running.
  • The page does not open: the address is http://192.168.1.51:8000/ and the program must have printed "dashboard on". A monitor sometimes needs Go a second time; use REFRESH to see new values.
  • The TEPPi folder was not found: copy it from Proteus Model Files into MODELS, or next to your project.

Things to Know Before Using a Real Raspberry Pi 500

  • The header: it points backwards out of the case; a HAT hangs down behind the keyboard, so a 40-way ribbon cable to a breadboard or a CAN HAT on a short cable is the comfortable way.
  • SocketCAN: on a real Pi the usual way is the kernel's driver - dtoverlay=mcp2515-can0 with the crystal and the interrupt pin in config.txt, then python-can on can0. Our runtime does not model the kernel's drivers, so the demo drives the chip itself over spidev; both ways use the same chip and the same frames.
  • 3.3 V on SO: many cheap MCP2515 modules run the MCP2515 on 5 V, so its SO pin swings to 5 V - too much for the Pi's GPIO9. Pick a module with a 3.3 V MCP2515 and a 5 V TJA1050, or add a level shifter on SO.
  • Terminators: a CAN bus needs 120 ohm at both ends; the modules have a J1 jumper for theirs.
  • The power key: the Pi 500 shuts down from its keyboard; a program that must keep a bus alive should run as a service that starts again after boot.

Limitations of the Simulation

  • The board does not run Raspberry Pi OS: there is no desktop, no shell commands, no kernel drivers such as SocketCAN and no apt. It runs one Python program; its threads take turns, so the four cores are not modelled.
  • The keys are drawn, not pressed - no key reaches the program, the power key included - and the Num Lock and Caps Lock LEDs stay off.
  • Bluetooth, the 5 GHz band, the Gigabit speed and Wi-Fi scanning are not modelled; the network is the same TEP network.
  • The micro-HDMI outputs, USB, the microSD card's files and the RP1's PIO are drawn or named but not simulated.
  • The 5V and 3V3 pins are logic levels: a module that reads its own supply sees 5 V on either.
  • C programs and Python packages with C code do not run. Pure Python code takes no simulation time; only the pin, bus, sleep and network calls move the clock.
  • The router, the board's address, the boot time and the Pi Terminal are TEP additions.
  • Raspberry Pi is a trademark of Raspberry Pi Ltd; this library is not made or endorsed by Raspberry Pi Ltd or Labcenter.
  • Tested in Proteus 8.5 in October 2026 (the demo as shipped, about 86 s of simulation in 457 s on our PC with the two pop-ups, the monitors and the Pi Terminal open). Proteus 7 is not supported.

So, that was all about the Raspberry Pi 500 Library for Proteus. I hope it helps you try the keyboard computer with real modules before you touch the hardware - a CAN controller driven over SPI, frames from another microcontroller decoded, a command sent back across the bus, the error counters watched, and a dashboard on a laptop or a phone. The next boards of our series bring other modules and more web pages. If you use the library in a project, please share it in the comments or in our forum, and if you have any questions, ask in the comments and I will help you out. Till the next tutorial, take care and have fun!


Comments

0

Join the conversation