Tutorial
Litex
fjullien migen_litex_tutorials <-- Best Litex tutorial
ICEStorm Install icestorm_install.md
Migen Simulation
Counter
from migen import *
class DPLL(Module):
def __init__(self):
self.count = Signal(4)
self.sync += self.count.eq(self.count + 1)
def dpll_test(dut):
for i in range(20):
print((yield dut.count))
yield
if __name__ == "__main__":
dut = DPLL()
run_simulation(dut, dpll_test(dut), vcd_name="dpll.vcd")
Migen Selection of Signal from Signal as Index
shiftout = Array({} for i in range(REG_Number))
for i in range(16):
shiftout[0][i] = [self.spi_miso1.eq(Regsiters[0][i] & ~self.spi_cs)]
shiftout[1][i] = [self.spi_miso2.eq(Regsiters[1][i] & ~self.spi_cs)]
for i in range(REG_Number):
self.comb += [
Case(shift_count, shiftout[i])
]
Migen Case
self.comb += Case(word_cound,{
0: self.uart_tx.eq(start_b0),
1: self.uart_tx.eq(start_b1),
2: self.uart_tx.eq(timestamp_b0),
3: self.uart_tx.eq(timestamp_b1),
4: self.uart_tx.eq(timestamp_b2),
5: self.uart_tx.eq(timestamp_b3),
"default": self.uart_tx.eq(0),
})
Migen Module
Migen Reset FSM
fsm = FSM(reset_state="WAIT")
fsm = ClockDomainsRenamer("icap")(fsm)
fsm = ResetInserter()(fsm)
self.submodules += fsm
self.comb += fsm.reset.eq(~(self.write | self.read))
IceStorm toolset for ICE40 FPGA
# Project setup
PROJ = blinky
BUILD = ./build
DEVICE = 8k
FOOTPRINT = ct256
# Files
FILES = top.v
.PHONY: all clean burn timing
all $(BUILD)/$(PROJ).asc $(BUILD)/$(PROJ).bin:
# if build folder doesn't exist, create it
mkdir -p $(BUILD)
# synthesize using Yosys
yosys -p "synth_ice40 -top top -blif $(BUILD)/$(PROJ).blif -json $(BUILD)/$(PROJ).json" $(FILES)
# Place and route using arachne
#arachne-pnr -d $(DEVICE) -P $(FOOTPRINT) -o $(BUILD)/$(PROJ).asc -p pinmap.pcf $(BUILD)/$(PROJ).blif
nextpnr-ice40 --hx$(DEVICE) --json build/$(PROJ).json --pcf pinmap.pcf --asc build/$(PROJ).asc
# Convert to bitstream using IcePack
icepack $(BUILD)/$(PROJ).asc $(BUILD)/$(PROJ).bin
burn: $(BUILD)/$(PROJ).bin
iceprog $(BUILD)/$(PROJ).bin
timing: $(BUILD)/$(PROJ).asc
icetime -tmd hx$(DEVICE) $(BUILD)/$(PROJ).asc
clean:
rm build/*
Chisel FPGA開発日記
https://msyksphinz.hatenablog.com/
Agile Hardware Design Video 2024

Amaranth
Verilog
https://verilogguide.readthedocs.io/en/latest/
The Art of FPGA Design - element14 Community
The Art of FPGA Design - element14 Community
Digital Signal Processing, from Algorithm to FPGA Bitstream - element14 Community
Digital Signal Processing, from Algorithm to FPGA Bitstream
Linux and Programming
Linux Thread
Linuxとpthreadsによる マルチスレッドプログラミング入門|サポート|秀和システム Book Link
Linux Kernel Module Programming Guide
https://sysprog21.github.io/lkmpg/
Tutorial 1 https://linux-kernel-labs.github.io/refs/heads/master/#
SSH Turnnel
ssh -f -N -L 127.0.0.1:8888:127.0.0.1:8888 -i pemKey user@ipaddress
For Jupyter notebook
PICO
PICO Programming Tutorial
Digital Systems Design Using Microcontrollers - V. Hunter Adams
Raspberry Pi Pico Lectures 2025 YT
RP2040 + FPGA RISC-V AXIS Communication
PICO PIO Programming
PICO PIO Programming Youtube Video
PICO PIO Programming Youtube Video Github Code
Web Reference
A Practical Look at PIO on the Raspberry Pi Pico URL
Introduction to the PIO (Programmable Input Output) of the RP2040
programmable-io-programming @ circuitcellar URL
RP2040 PICO DMA
Playing with the Pico Part 4 - Getting Acquainted with PIO
RP2040 LVGL
http://bbs.eeworld.com.cn/thread-1227666-1-1.html
RP2040 Arduino How to Make 2 PWM Start at the same time
#define _PWM_LOGLEVEL_ 0
#include "RP2040_PWM.h"
//creates pwm instance
RP2040_PWM* PWM_Instance1;
RP2040_PWM* PWM_Instance2;
#define FREQ1 2000000
#define FREQ2 2000000
int updated = 0;
void setup() {
Serial.begin(115200);
PWM_Instance1 = new RP2040_PWM(10, FREQ1, 0);
PWM_Instance1->setPWM(10, FREQ1, 0);
turn_on_pwm1();
}
void turn_on_pwm1()
{
rp2040.fifo.push(1);
PWM_Instance1->setPWM(10, FREQ1, 50);
}
void turn_on_pwm2()
{
while(1) {
if (rp2040.fifo.available()) {
PWM_Instance2->setPWM(12, FREQ2, 50);
rp2040.fifo.pop();
return;
}
}
}
void setup1() {
PWM_Instance2 = new RP2040_PWM(12, FREQ2, 0);
PWM_Instance2->setPWM(12, FREQ2, 0);
turn_on_pwm2();
}
void loop() {
delay(1000);
}
void loop1() {
delay(1000);
}
SPI Master and Slave on Pico
// Shows how to use SPISlave on a single device.
// Core0 runs as an SPI master and initiates a transmission to the slave
// Core1 runs the SPI Slave mode and provides a unique reply to messages from the master
//
// Released to the public domain 2023 by Earle F. Philhower, III <earlephilhower@yahoo.com>
#include <SPI.h>
#include <SPISlave.h>
// Wiring:
// Master RX GP0 <-> GP11 Slave TX
// Master CS GP1 <-> GP9 Slave CS
// Master CK GP2 <-> GP10 Slave CK
// Master TX GP3 <-> GP8 Slave RX
SPISettings spisettings(1000000, MSBFIRST, SPI_MODE0);
// Core 0 will be SPI master
void setup() {
SPI.setRX(0);
SPI.setCS(1);
SPI.setSCK(2);
SPI.setTX(3);
SPI.begin(true);
delay(5000);
}
int transmits = 0;
void loop() {
char msg[42];
memset(msg, 0, sizeof(msg));
sprintf(msg, "What's up? This is transmission %d", transmits);
Serial.printf("\n\nM-SEND: '%s'\n", msg);
SPI.beginTransaction(spisettings);
SPI.transfer(msg, sizeof(msg));
SPI.endTransaction();
Serial.printf("M-RECV: '%s'\n", msg);
transmits++;
delay(5000);
}
// Core 1 will be SPI slave
volatile bool recvBuffReady = false;
char recvBuff[42] = "";
int recvIdx = 0;
void recvCallback(uint8_t *data, size_t len) {
memcpy(recvBuff + recvIdx, data, len);
recvIdx += len;
if (recvIdx == sizeof(recvBuff)) {
recvBuffReady = true;
recvIdx = 0;
}
}
int sendcbs = 0;
// Note that the buffer needs to be long lived, the SPISlave doesn't copy it. So no local stack variables, only globals or heap(malloc/new) allocations.
char sendBuff[42];
void sentCallback() {
memset(sendBuff, 0, sizeof(sendBuff));
sprintf(sendBuff, "Slave to Master Xmission %d", sendcbs++);
SPISlave1.setData((uint8_t*)sendBuff, sizeof(sendBuff));
}
// Note that we use SPISlave1 here **not** because we're running on
// Core 1, but because SPI0 is being used already. You can use
// SPISlave or SPISlave1 on any core.
void setup1() {
SPISlave1.setRX(8);
SPISlave1.setCS(9);
SPISlave1.setSCK(10);
SPISlave1.setTX(11);
// Ensure we start with something to send...
sentCallback();
// Hook our callbacks into the slave
SPISlave1.onDataRecv(recvCallback);
SPISlave1.onDataSent(sentCallback);
SPISlave1.begin(spisettings);
delay(3000);
Serial.println("S-INFO: SPISlave started");
}
void loop1() {
if (recvBuffReady) {
Serial.printf("S-RECV: '%s'\n", recvBuff);
recvBuffReady = false;
}
}
Python
使用 uv 管理 Python 環境
PySerial
PySerial Example Code pyserial_sample.md
Python FTDI for SPI
from pyftdi.ftdi import Ftdi
Ftdi.show_devices()
from pyftdi.spi import SpiController
spi.configure('ftdi://ftdi:2232h:1:7b/1')
slave = spi.get_port(cs=1, freq=10E6, mode=2)
write_buf = b'\x01\x02\x03'
read_buf = slave.exchange(write_buf, duplex=True)
FTDI SPI DDS AD9833
from pyftdi.spi import SpiController
############user changes these###############
user_freq = 1000
#pinout from H232 for SPI
'''
ad0 SCLK to UNO pin 13
ad1 MOSI to UNO pin 11
ad2 MISO to UNO pin 12 (not used)
ad3 CS0 to UNO pin 10
ad4 cs1 ... ad7 CS4.
'''
#WE WANT TO BE ABLE TO ENTER A FREQ TO SHOW ON SCOPE.
# Instantiate a SPI controller
# We need want to use A*BUS4 for /CS, so at least 2 /CS lines should be
# reserved for SPI, the remaining IO are available as GPIOs.
def get_dec_freq(freq):
bignum = 2**28
f = freq
clock=25000000 #if your clock is different enter that here./
dec_freq = f*bignum/clock
return int(dec_freq)
padded_binary = 0
bits_pushed = 0
d = get_dec_freq(user_freq)
print("freq int returned is: " + str(d))
#turn into binary string.
str1 = bin(d)
#print(str1)
#get rid of first 2 chars.
str2 = str1[2:]
#print(str2)
#pad whatever we have so far to 28 bits:
longer = str2.zfill(28)
#print("here is 28 bit version of string")
#print(str(longer))
#print("here is length of that string")
#print(len(str(longer)))
lm1 = "01" + longer[:6]
lm2 = longer[6:14]
rm1 = "01" + longer[14:20]
rm2 = longer[20:]
# print(lm1 + " " + lm2 + " " + rm1 + " " + rm2)
def str_2_int(strx):
numb = int(strx, 2)
return numb
lm1x = str_2_int(lm1)
lm2x = str_2_int(lm2)
rm1x = str_2_int(rm1)
rm2x = str_2_int(rm2)
print(str(lm1x) + " " + str(lm2x) + " " + str(rm1x) + " " + str(rm2x))
##########
#freq0_loadlower16 = [80,199]
#freq0_loadupper16 = [64,0]
#64 0 80 198
spi = SpiController(cs_count=2)
device = 'ftdi://ftdi:232h:0:1/1'
# Configure the first interface (IF/1) of the FTDI device as a SPI master
spi.configure(device)
# Get a port to a SPI slave w/ /CS on A*BUS4 and SPI mode 2 @ 10MHz
slave = spi.get_port(cs=1, freq=8E6, mode=2)
freq0_loadlower16 = [rm1x,rm2x]
freq0_loadupper16 = [lm1x,lm2x]
cntrl_reset = [33,0]
phase0 = [192,0]
cntrl_write = [32,0]
send2_9833 = cntrl_reset + freq0_loadlower16 + freq0_loadupper16 + phase0 + cntrl_write
print(send2_9833)
qq = bytearray(send2_9833)
# Synchronous exchange with the remote SPI slave
#write_buf = qq
#read_buf = slave.exchange(write_buf, duplex=False)
slave.exchange(out=qq, readlen=0, start=True, stop=True, duplex=False, droptail=0)
slave.flush()
Virtual Enviroment
Other Solution https://python-poetry.org/
Makefile for Python
Makefile for Python project
# 預設目標,當直接執行 make 時會執行的目標
.PHONY: all
all: install test build
# 安裝相依性
.PHONY: install
install:
pip install -r requirements.txt
# 執行測試
.PHONY: test
test:
python -m unittest discover tests
# 打包程式碼 (使用 setuptools)
.PHONY: build
build:
python setup.py sdist bdist_wheel
# 清理
.PHONY: clean
clean:
rm -rf build dist *.egg-info
Python Import Module from Parent Folder
import os
import sys
current_dir = os.path.dirname(os.path.abspath(__file__))
parent_dir = os.path.join(current_dir, '..')
sys.path.append(os.path.abspath(parent_dir))
Python for PDF
from pypdf import PdfReader, PdfWriter
reader = PdfReader("input.pdf")
writer = PdfWriter()
for page in reader.pages:
# Define new crop box coordinates (adjust as needed)
# Example: crop 10 units from each side
left = page.mediabox.left + 10
bottom = page.mediabox.bottom + 10
right = page.mediabox.right - 10
top = page.mediabox.top - 10
page.mediabox.lower_left = (left, bottom)
page.mediabox.upper_right = (right, top)
writer.add_page(page)
with open("output_cropped.pdf", "wb") as fp:
writer.write(fp)
Micropython
Pyboard Sleep and Wakeup
import pyb, stm
from pyb import Pin
# wakeup callback
wakeup = False
def cb(exti):
nonlocal wakeup
wakeup = True
# configure switch to generate interrupt on press
sw = pyb.Switch()
sw.callback(lambda:cb(0))
# function to flash an LED
def flash(led):
led.on()
pyb.delay(100)
led.off()
while True:
# standby (need to exit by pressing RST, or wait 15s)
if stm.mem32[stm.RTC + stm.RTC_BKP1R] == 0:
flash(led1)
stm.mem32[stm.RTC + stm.RTC_BKP1R] = 1
rtc.wakeup(15000, cb)
pyb.standby()
else:
stm.mem32[stm.RTC + stm.RTC_BKP1R] = 0
# stop
flash(led2)
led_off()
pyb.stop()
led_on()
# idle
flash(led3)
wakeup = False
while not wakeup:
pyb.wfi()
# run
flash(led4)
wakeup = False
while not wakeup:
pass
Micropython pyBoard DAC use DMA
import math
from array import array
from pyb import DAC
# create a buffer containing a sine-wave, using half-word samples
buf = array('H', 2048 + int(2047 * math.sin(2 * math.pi * i / 128)) for i in range(128))
# output the sine-wave at 400Hz
dac = DAC(1, bits=12)
dac.write_timed(buf, 400 * len(buf), mode=DAC.CIRCULAR)
Micropython Debounce
import pyb
def wait_pin_change(pin):
# wait for pin to change value
# it needs to be stable for a continuous 20ms
cur_value = pin.value()
active = 0
while active < 20:
if pin.value() != cur_value:
active += 1
else:
active = 0
pyb.delay(1)
pin_x1 = pyb.Pin('X1', pyb.Pin.IN, pyb.Pin.PULL_DOWN)
while True:
wait_pin_change(pin_x1)
pyb.LED(4).toggle()
Micropython json
Micropython USB UART Passthrough
import pyb
import select
def pass_through(usb, uart):
usb.setinterrupt(-1)
while True:
select.select([usb, uart], [], [])
if usb.any():
uart.write(usb.read(256))
if uart.any():
usb.write(uart.read(256))
pass_through(pyb.USB_VCP(), pyb.UART(1, 9600, timeout=0))
Micropython GPIO IRQ
# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-interrupts-micropython/
from machine import Pin
button = Pin(21, Pin.IN, Pin.PULL_DOWN)
def button_pressed(pin):
print("Button Pressed!")
# Attach the interrupt to the button's rising edge
button.irq(trigger=Pin.IRQ_RISING, handler=button_pressed)
Micropython Timer IRQ
# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-interrupts-micropython/
from machine import Pin, Timer
from time import sleep
# LED pin
led_pin = 20
led = Pin(led_pin, Pin.OUT)
# Callback function for the timer
def toggle_led(timer):
led.value(not led.value()) # Toggle the LED state (ON/OFF)
# Create a periodic timer
blink_timer = Timer()
blink_timer.init(mode=Timer.PERIODIC, period=500, callback=toggle_led) # Timer repeats every half second
# Main loop (optional)
while True:
print('Main Loop is running')
sleep(2)
Micrpython IRQ
raspberry-pi-pico-interrupts-micropython
Arduino Pico
UART to USB Passthrough as FT232
void setup() {
// Initialize USB Serial communication (to computer)
Serial.begin(115200);
while (!Serial); // Wait for Serial Monitor to open (optional)
// Initialize hardware UART (e.g., UART0 on Pico, connected to external device)
Serial1.begin(115200);
}
void loop() {
// Read from hardware UART and send to USB Serial
if (Serial1.available()) {
Serial.write(Serial1.read());
}
// Read from USB Serial and send to hardware UART
if (Serial.available()) {
Serial1.write(Serial.read());
}
}
Chromebook
Install Desktop GUI in chromebook chromebookDesktop.md
DSP
Wavelet
Neuro Science
Neuroscience exploration Video
Topological Data Analysis (TDA)