|
| 1 | +# 🧮 4-Bit Up/Down Counter on Vicharak Shrike-Lite |
| 2 | + |
| 3 | + |
| 4 | + |
| 5 | +## 1. Project Overview & Objective |
| 6 | + |
| 7 | +This project implements a **4-bit up/down counter in Verilog** on the **Vicharak Shrike-Lite** FPGA dev board and demonstrates how the **RP2040 microcontroller reads FPGA-generated data in real time** using MicroPython. |
| 8 | + |
| 9 | +The goal is to help the readers understand: |
| 10 | + |
| 11 | +- Synchronous digital logic design in Verilog |
| 12 | +- FPGA pin-level signal exposure |
| 13 | +- Parallel data transfer from FPGA to MCU |
| 14 | +- Hardware–software co-design using MCU + FPGA boards |
| 15 | + |
| 16 | +This counter is intentionally simple so the **communication mechanism** is easy to observe and reason about. |
| 17 | + |
| 18 | +--- |
| 19 | + |
| 20 | +## 2. System Description (FPGA ↔ RP2040) |
| 21 | + |
| 22 | +### FPGA |
| 23 | +- Implements a **4-bit synchronous counter** |
| 24 | +- Supports **up and down counting** |
| 25 | +- Uses a clock divider to slow the count rate (~1 Hz) |
| 26 | +- Continuously drives the counter value on GPIO pins |
| 27 | + |
| 28 | +### RP2040 |
| 29 | +- Programs the FPGA bitstream |
| 30 | +- Samples FPGA GPIO outputs |
| 31 | +- Reconstructs the counter value |
| 32 | +- Displays output in **binary and hexadecimal** |
| 33 | + |
| 34 | +--- |
| 35 | + |
| 36 | +## 3. FPGA Verilog Design (Go Configure Software Hub) |
| 37 | + |
| 38 | +> The bitstream for the Renesas FPGA in Shrike-Lite can only be generated in the Go Configure Software hub for now. So once it is installed in your pc, Select the appropriate fpga part [`SLG47910V (Rev BB)`] and create new project. Once created, double click on the fpga core square to open ForgeFPGA Workshop window and paste the verilog code from `./ffpga/src/counter.v` into main.v and click on synthesize button. |
| 39 | +
|
| 40 | +### Top-Level Module |
| 41 | + |
| 42 | +~~~verilog |
| 43 | +(* top *) module counter( |
| 44 | + (* iopad_external_pin, clkbuf_inhibit *) input clk, |
| 45 | + (* iopad_external_pin *) input nreset, |
| 46 | + (* iopad_external_pin *) input up_down, |
| 47 | + (* iopad_external_pin *) output [3:0] out_oe, |
| 48 | + (* iopad_external_pin *) output osc_en, |
| 49 | + (* iopad_external_pin *) output [3:0] count |
| 50 | +); |
| 51 | +~~~ |
| 52 | + |
| 53 | + |
| 54 | +- `clk` : Clock input to the FPGA |
| 55 | +- `nreset` : **Synchronous active-low reset** |
| 56 | +- `up_down`: Controls counting direction |
| 57 | +- `count` : 4-bit counter output |
| 58 | + |
| 59 | +Output control: |
| 60 | + |
| 61 | +~~~verilog |
| 62 | +assign out_oe = 4'b1111; // to configure count signal pins as outputs |
| 63 | +assign osc_en = 1'b1; // to enable clock |
| 64 | +assign count = counter_reg; // Counter Output |
| 65 | +~~~ |
| 66 | + |
| 67 | +--- |
| 68 | + |
| 69 | +### Timing & Counter Logic |
| 70 | + |
| 71 | +A **26-bit register (`time_steps`)** is used as a clock divider: |
| 72 | + |
| 73 | +~~~verilog |
| 74 | +if (time_steps >= 26'd49_999_999) |
| 75 | +~~~ |
| 76 | + |
| 77 | +- Counter updates roughly **once per second** |
| 78 | +- `up_down = 1` → increment |
| 79 | +- `up_down = 0` → decrement |
| 80 | +- 4-bit width naturally causes wrap-around |
| 81 | + |
| 82 | +This demonstrates clean **synchronous sequential logic**. |
| 83 | + |
| 84 | +--- |
| 85 | + |
| 86 | +## 4. Pin Connections |
| 87 | + |
| 88 | +### Counter Data Lines (FPGA → RP2040) |
| 89 | + |
| 90 | +| Signal | FPGA Pin | RP2040 Pin | |
| 91 | +|-----------|----------|------------| |
| 92 | +| `count[0]` | GPIO3 | GPIO2 | |
| 93 | +| `count[1]` | GPIO4 | GPIO1 | |
| 94 | +| `count[2]` | GPIO5 | GPIO3 | |
| 95 | +| `count[3]` | GPIO6 | GPIO0 | |
| 96 | + |
| 97 | +These four lines form a **4-bit parallel data bus** from FPGA → RP2040. |
| 98 | + |
| 99 | + |
| 100 | + |
| 101 | +### Control Signals |
| 102 | + |
| 103 | +| Signal | FPGA Pin | Description | |
| 104 | +|--------|----------|-------------| |
| 105 | +| `nreset` | GPIO2 | Synchronous active-low reset | |
| 106 | +| `up_down` | GPIO7 | Controls up/down counting | |
| 107 | + |
| 108 | + |
| 109 | +### I/O Planner (in Go Configure Software Hub) |
| 110 | +>Tick the following check boxes in I/O Planner after synthesizing the verilog code. |
| 111 | +
|
| 112 | +- [x] CLK |
| 113 | +- [x] GPIO |
| 114 | +- [x] OSC_ctrl |
| 115 | + |
| 116 | +>Then, configure the ports as shown below. Finally, save all files and click on Generate Bitstream. |
| 117 | +
|
| 118 | +| FUNCTION | DIRECTION | PORT | |
| 119 | +|--------|----------|-------------| |
| 120 | +| `OSC_CLK` | Input | clk | |
| 121 | +| `GPIO02_IN` | Input | updown | |
| 122 | +| `GPIO03_OUT` | Output | count[0] | |
| 123 | +| `GPIO03_OE` | Output | out_oe[0] | |
| 124 | +| `GPIO04_OUT` | Output | count[1] | |
| 125 | +| `GPIO04_OE` | Output | out_oe[1] | |
| 126 | +| `GPIO05_OUT` | Output | count[2] | |
| 127 | +| `GPIO05_OE` | Output | out_oe[2] | |
| 128 | +| `GPIO06_OUT` | Output | count[3] | |
| 129 | +| `GPIO06_OE` | Output | out_oe[4] | |
| 130 | +| `GPIO07_IN` | Input | nreset | |
| 131 | +| `OSC_EN` | Output | osc_en | |
| 132 | + |
| 133 | +> The Bitstream file can be found in the project root folder as `.\ffpga\build\bitstream\FPGA_bitstream_MCU.bin`. You can rename it to any name but make sure to keep the `.bin` file extension. Don't forget to upload the bitstream file to shrike's rp2040 file system either by copy-pasting it through file explorer or by uploading using thonny directly. |
| 134 | +
|
| 135 | +## 5. RP2040 MicroPython Implementation |
| 136 | + |
| 137 | +### Flashing the FPGA |
| 138 | + |
| 139 | +~~~python |
| 140 | +import shrike |
| 141 | +shrike.flash("4bit_counter.bin") |
| 142 | +~~~ |
| 143 | + |
| 144 | +--- |
| 145 | + |
| 146 | +### Reading and Decoding Counter Value |
| 147 | + |
| 148 | +~~~python |
| 149 | +cntr_pins = [2, 1, 3, 0] |
| 150 | +counter = [Pin(pin, Pin.IN) for pin in cntr_pins] |
| 151 | +~~~ |
| 152 | + |
| 153 | +Each pin corresponds to one counter bit. |
| 154 | +The RP2040 reconstructs the value using bit shifts: |
| 155 | + |
| 156 | +~~~python |
| 157 | +value += (1 << i) |
| 158 | +~~~ |
| 159 | + |
| 160 | +Formatted output: |
| 161 | + |
| 162 | +~~~python |
| 163 | +binary_str = "{:04b}".format(value) |
| 164 | +hex_str = "{:X}".format(value) |
| 165 | +print(f"Binary: {binary_str} | Hex: 0x{hex_str}") |
| 166 | +~~~ |
| 167 | + |
| 168 | +>Connect the Shrike board and Open Thonny. Select MicroPython (RP2040) Interpreter along with correct COM Port at the bottom right corner of the Thonny window. Create a new file and paste the code from `.\firmware\micropython\counter_test.py` into it. Save it and click on run button in the top row to run the code on the Shrike board. Output is printed to the Shell. |
| 169 | +
|
| 170 | +--- |
| 171 | + |
| 172 | +## 6. Hardware Diagram & Significance |
| 173 | + |
| 174 | + |
| 175 | + |
| 176 | + |
| 177 | +*Block-level view of the Up/Down Counter showing the FPGA-generated 4-bit counter, parallel data bus to RP2040, and control signals.* |
| 178 | + |
| 179 | +### Result: |
| 180 | + |
| 181 | + |
| 182 | + |
| 183 | +*Serial Output from RP2040 showing the up-counting, reset, and down-counting functionality of the counter.* |
| 184 | + |
| 185 | +>Note: Noise and Interference on the GPIO input pins of the FPGA is also considered as a logic high (1). Thus, Physical connection of input pins to 3.3V to stay in up-counting mode or to stay out of reset is simply not required in this scenario. |
0 commit comments