PICPIO logoPICPIO
PICPIO

How to use PICPIO

From install to a blinking LED, and everything after.

1. Install PICPIO

PICPIO is a VS Code extension. Install it like any other:

  1. Open VS Code (free from code.visualstudio.com).
  2. Open the Extensions panel (Ctrl+Shift+X).
  3. Search PICPIO and click Install on the one by CURIOUS WORM.

Or press Ctrl+P and run:

ext install picpio.picpio
PICPIO is self-contained: the build engine, device support and libraries all come inside the extension. Nothing else to download.

2. Add Microchip's free tools

To build and flash real hardware, you also install Microchip's free tools (one time). PICPIO opens the right download pages for you on first run.

  • XC8 compiler: required to build (PIC10/12/16/18). Choose the free license during setup.
  • MPLAB X (IPE + MDB): required to flash and debug over a PICkit/Snap/ICD.
  • XC16: only if you target PIC24 / dsPIC.
The built-in simulator needs none of these. You can write and run logic with nothing but the extension.

Check everything is found anytime by running picpio doctor in the PICPIO terminal.

3. Create a project

  1. Click the PICPIO chip icon in the left sidebar.
  2. Choose New Project.
  3. Pick a name, your chip (e.g. PIC18F27K40), the programmer, and the framework:
    • picpio: the friendly high-level API (recommended).
    • bare-metal: raw registers (TRISx/LATx/PORTx).
  4. PICPIO scaffolds the project: src/main.c, a picpio.ini, and a REFERENCE.md with your chip's pin map and API.

4. Anatomy of a sketch

A PICPIO program has two functions: init() runs once at boot, and run() repeats forever.

#include <Picpio.h>

void init() {              // runs once at startup
  gpio_mode(BUILTIN_LED, GPIO_OUT);
}

void run() {               // repeats forever
  gpio_write(BUILTIN_LED, GPIO_HIGH);
  sys_delay(500);
  gpio_write(BUILTIN_LED, GPIO_LOW);
  sys_delay(500);
}

That's a complete blink program. Pins are named D0Dn, A0An for analog, and BUILTIN_LED for the on-board LED.

5. The PICPIO API

Simple, consistent functions across every supported chip. It's plain C, compiled by XC8/XC16/XC32/XC-DSC exactly like any other library, not a custom language. The uart1.begin(...)-style calls work because each peripheral is a struct of function pointers under the hood.

Digital I/O

FunctionWhat it does
gpio_mode(pin, mode)GPIO_IN, GPIO_OUT, or GPIO_PULLUP
gpio_write(pin, val)GPIO_HIGH or GPIO_LOW
gpio_read(pin)Returns GPIO_HIGH or GPIO_LOW

Pins are named D0Dn and A0An (the exact range depends on your chip), plus BUILTIN_LED for the on-board LED. Prefer the chip's own pin names (RA0, RC2…)? Put #define PICPIO_PIN_ALIASES before #include <Picpio.h> and those work too.

Analog & PWM

FunctionWhat it does
adc_read(pin)Reads an analog pin. Resolution depends on the chip (10-bit on most PIC16/PIC32, 12-bit on dsPIC33A…), your project's REFERENCE.md has the exact range.
pwm_write(pin, duty)PWM duty cycle, 0–255, at each chip's fixed default frequency
pwm_config(pin, freq_hz, resolution_bits)Set a specific PWM frequency (Hz) and duty resolution (up to 16 bits) before using pwm_write16(), ESP32 ledcSetup()-style. On chip families where one timer drives several PWM pins, this sets the frequency for all of them at once, not just the pin you passed, your project's REFERENCE.md says which.
pwm_write16(pin, duty)Duty scaled to whatever resolution the last pwm_config() call asked for on that pin
adc_pwm_write(adc_read(pin), pwm_pin, ascending)Scales an ADC reading onto pwm_pin's configured duty range and writes it. ascending nonzero: ADC low → duty low. Zero: inverted (ADC low → duty high). A potentiometer or light sensor can drive an LED/motor/buzzer in one call.
Frequency-configurable PWM is new and hasn't been checked against every supported chip on real hardware yet. Verify the actual output frequency with a scope before relying on it for anything timing-critical, and open an issue if it's off.

Timing

FunctionWhat it does
sys_delay(ms)Block for whole milliseconds
sys_delay_us(us)Block for whole microseconds
sys_millis()Milliseconds since boot
sys_micros()Microseconds since boot

Serial (UART)

uart1, and uart2 on chips with a second hardware UART:

FunctionWhat it does
uart1.begin(baud) / uart1.end()Start or stop the port
uart1.print(x) / uart1.println(x)Send a string, number or float, same call for every type
uart1.write(byte)Send one raw byte
uart1.available() / uart1.read()Bytes waiting, and read one
uart1.flush()Wait for the send buffer to empty

I2C

FunctionWhat it does
i2c1.begin()Start the bus as controller
i2c1.beginTransmission(addr) / i2c1.endTransmission()Wrap a write to a device address
i2c1.requestFrom(addr, len)Ask a device for len bytes
i2c1.write(byte)Queue a byte inside a transmission
i2c1.available() / i2c1.read()Bytes waiting, and read one

SPI

FunctionWhat it does
spi1.begin() / spi1.end()Start or stop the bus
spi1.transfer(byte)Send a byte, returns the byte read back
spi1.setBitOrder(...)SPI_MSB or SPI_LSB
spi1.setDataMode(...)SPI_MODE0SPI_MODE3
spi1.setClockDivider(...)SPI_CLOCK_DIV2SPI_CLOCK_DIV128
Most libraries call spi1/i2c1 for you. You'll rarely touch these directly, except when writing your own driver.

Interrupts

Global enable/disable only, there's no attach-a-callback API:

sys_irq_on();   // enable
sys_irq_off();  // disable

Handy extras

Familiar helpers ship too: byte/word/boolean typedefs, PI, min/max/constrain/map, and bit_read/bit_set/bit_clr/bit_write.

Example: read a sensor and print it:

void init() {
  uart1.begin(115200);
}

void run() {
  int v = adc_read(A0);     // range depends on your chip
  uart1.println(v);
  sys_delay(200);
}
Every project's REFERENCE.md lists the exact pin map, ADC resolution, and the full API for your chip, open it anytime.

6. Build & flash

Use the PICPIO toolbar buttons, or the terminal:

  • Build: compile with XC8/XC16. picpio build
  • Upload: build and flash to your board. picpio upload
  • Upload & Monitor: flash, then open the serial monitor.

Connect your board with a PICkit (or Snap/ICD), hit Upload, and watch it flash:

$ picpio upload
Compiling main.c with XC8...
Program: 3.1%  Data: 1.4%
 Flashed to PIC18F27K40
 Done in 4.2s

7. Examples browser

Every one of PICPIO's 130+ libraries ships a complete, runnable example, the same code picpio lib add drops into your sketch. Read it before you commit to a library, not after installing it.

  1. Open Examples from the PICPIO sidebar.
  2. Pick a library to read its full example, exactly as it would be inserted into your sketch.
  3. Like what you see? Add the library, see below.

8. Add a library

PICPIO ships 130+ ready-made drivers: OLED/TFT displays, sensors, motor & stepper drivers, RTCs, ADC/DAC expanders, RF/CAN/LoRa, USB CDC serial, GPS/GSM, keypads, SD card (FAT16/32), EEPROM, WS2812 LEDs, servos, PID and more.

  1. Open the Library Manager from the PICPIO sidebar (or run picpio lib add SSD1306).
  2. PICPIO copies the driver in and drops working example code into your sketch.
  3. It also writes the device's wiring + protocol into REFERENCE.md.
$ picpio lib add SSD1306
 Added SSD1306 (I2C OLED)
 Example inserted into src/main.c
PICPIO warns if a library needs a peripheral (I2C, SPI…) your chosen chip doesn't have, before you build.

9. Wiring diagram

Once you've added a library, PICPIO already knows what you're using. Open Wiring Diagram from the sidebar and it reads your src/main.c to draw exactly how to connect it, no datasheet hunting.

Detected from main.c:
 BME280 → I2C1 (RC3 SCL, RC4 SDA)
 ILI9341 → SPI1, CS on RC0
 XPT2046 touch → SPI1, CS on RC1

It updates as you add more libraries, and the same wiring gets written into your project's REFERENCE.md, so it's there even with the panel closed.

10. Pin map

Open Pin Map from the sidebar to see every pin on your exact chip package, DIP or QFP, labeled with both its friendly PICPIO name (D0, A0…) and its native port pin (RB0, RA0…).

The same mapping is also in your project's REFERENCE.md as plain text, alongside the full API for your chip.

11. Display Designer

Building a UI on a TFT or OLED? Open Display Designer from the sidebar:

  1. Pick your display and drag on labels, gauges, buttons and images.
  2. See the layout live, matched to your display's real resolution.
  3. Store pictures on an SD card or a W25Q flash chip so they cost no program memory.
  4. Press Code and PICPIO writes the wiring and drawing code straight into your sketch.
Pictures staged for a W25Q flash chip get uploaded to the real chip over serial from the same panel, once your firmware is built, flashed, and running.

12. Simulate before hardware

No board yet? Run your logic in the built-in simulator and watch it work.

  1. Open src/main.c.
  2. Click Simulate in the PICPIO toolbar.
  3. Watch pin states, PWM waveforms, and Serial / I2C / SPI traffic update live as your code runs.

Great for teaching, for checking logic, and for working without hardware in hand.

Share it on your network

Run Simulate Network (server + clients) to host the simulator as a server, then use Share Simulator Pages on My Network to open it from any other device on your network, no PICPIO install needed on that device. Handy for a classroom, or showing someone a demo without sending them a file.

13. Serial monitor

See live output from your board and send data back:

  1. Click Serial Port Monitor in the PICPIO sidebar.
  2. Pick the COM port and baud rate (match your uart1.begin(...)).
  3. Read incoming lines; type in the box to send data to the board.
COM3 @ 115200
Temp: 24.6 C
Temp: 24.7 C
Humidity: 48%

14. Bare-metal (registers)

Teaching or learning register-level PIC programming? Pick the bare-metal framework when creating a project. You write a normal main() against the chip's real SFRs, with full IntelliSense (autocomplete on TRISB, PORTAbits, …).

// bare-metal blink
void main(void) {
  TRISBbits.TRISB0 = 0;        // RB0 output
  while (1) {
    LATBbits.LATB0 ^= 1;       // toggle
    __delay_ms(500);
  }
}

15. Your project's reference

Every project includes a REFERENCE.md generated for your exact chip:

  • The full pin map (which physical pin is D0, A0, the I2C/SPI/UART pins…).
  • The complete API available on that chip.
  • For each library you add, the device's wiring and communication protocol.

It's read-only and always matches your hardware, keep it open as you build.

16. Troubleshooting

XC8/XC16/XC32 error messages are often cryptic. PICPIO recognizes the common ones and shows what actually happened and what to do about it, in plain English, right in the Problems panel and the terminal, no error-code lookup needed.

If a build or upload fails, run picpio doctor: it checks your whole toolchain and tells you what's missing:

$ picpio doctor
 XC8 compiler   v2.46
 PICkit 3 detected
 Device pack installed
 130+ libraries
All systems go.
  • "Compiler not found" → install XC8 from Microchip, then reopen VS Code.
  • "No programmer detected" → check the PICkit/Snap is plugged in and MPLAB X is installed.
  • "no device-support files found" → PICPIO downloads your chip's support pack automatically on first build (needs internet). If it can't, run picpio install-dfp once, then build again.
  • Autocomplete missing → reopen the folder so IntelliSense reloads.
Still stuck? Email picpiosupport@gmail.com or visit curiousworm.in.

Install PICPIO   Back to home