├── .gitignore ├── Makefile ├── README.md ├── icebitsy ├── Makefile ├── README.md ├── blink_count_shift │ ├── Makefile │ ├── README.md │ └── blink_count_shift.v ├── charlieplexing-tomk │ ├── Makefile │ ├── README.md │ └── pmodcharlie.v ├── common │ └── dfu_helper.v ├── dvi-12bit │ ├── Makefile │ ├── README.txt │ ├── dvi-12bit.v │ ├── vga_core.v │ └── vga_timing.v ├── dvi-24bit │ ├── Makefile │ ├── README.txt │ ├── dvi-24bit.v │ ├── vga_core.v │ └── vga_timing.v ├── dvi-4bit │ ├── Makefile │ ├── README.txt │ ├── dvi-4bit.v │ ├── vga_core.v │ └── vga_timing.v ├── icebitsy0.pcf ├── icebitsy1-pmod.pcf ├── icebitsy1.pcf ├── pdm_fade │ ├── COPYING │ ├── Makefile │ └── pdm.v ├── pdm_fade_gamma │ ├── .gitignore │ ├── COPYING │ ├── Makefile │ ├── gamma_pdm.v │ └── gen_gamma_table.c ├── pwm_fade │ ├── COPYING │ ├── Makefile │ └── pwm.v ├── pwm_fade_gamma │ ├── .gitignore │ ├── COPYING │ ├── Makefile │ ├── gamma_pwm.v │ └── gen_gamma_table.c └── sb_rgba_blink │ ├── LICENSE │ ├── Makefile │ └── blink.v ├── icebreaker ├── 7seg_count │ ├── 7seg_count.v │ └── Makefile ├── Makefile ├── blink_count_shift │ ├── Makefile │ ├── README.md │ └── blink_count_shift.v ├── charlieplexing-tomk │ ├── Makefile │ ├── README.md │ └── pmodcharlie.v ├── charlieplexing-twam │ ├── Makefile │ ├── README.md │ └── pmodcharlie.v ├── cmp_1bit │ ├── COPYING │ ├── Makefile │ └── cmp_1bit.v ├── dvi-12bit │ ├── Makefile │ ├── README.txt │ ├── dvi-12bit.v │ ├── vga_core.v │ └── vga_timing.v ├── dvi-24bit │ ├── Makefile │ ├── README.txt │ ├── dvi-24bit.v │ ├── vga_core.v │ └── vga_timing.v ├── dvi-4bit │ ├── Makefile │ ├── README.txt │ ├── dvi-4bit.v │ ├── vga_core.v │ └── vga_timing.v ├── full_adder_1bit │ ├── COPYING │ ├── Makefile │ └── full_adder.v ├── gamepad-audio │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── audio.v │ ├── gen_sin_table.c │ ├── pdm_sine_mod.v │ └── pdm_sine_mod_tb.v ├── gamepad │ ├── COPYING │ ├── Makefile │ ├── README.md │ ├── gamepad.v │ ├── gamepad_mod.v │ ├── gamepad_mod_tb.v │ ├── gamepad_sender_mod.v │ ├── uart_baud_tick_gen.v │ └── uart_tx.v ├── icebreaker-examples.core ├── icebreaker.pcf ├── pdm_fade │ ├── COPYING │ ├── Makefile │ └── pdm.v ├── pdm_fade_gamma │ ├── .gitignore │ ├── COPYING │ ├── Makefile │ ├── gamma_pdm.v │ └── gen_gamma_table.c ├── pll_uart │ ├── COPYING │ ├── Makefile │ ├── pll_uart_mirror.v │ ├── uart_baud_tick_gen.v │ ├── uart_rx.v │ └── uart_tx.v ├── pwm_fade │ ├── COPYING │ ├── Makefile │ └── pwm.v ├── pwm_fade_gamma │ ├── .gitignore │ ├── COPYING │ ├── Makefile │ ├── gamma_pwm.v │ └── gen_gamma_table.c ├── sb_rgba_blink │ ├── LICENSE │ ├── Makefile │ └── blink.v └── ws2812_blink │ ├── Makefile │ ├── README.md │ └── ws2812_blink.v └── main.mk /.gitignore: -------------------------------------------------------------------------------- 1 | *.bin 2 | *.rpt 3 | *.blif 4 | *.asc 5 | *.json 6 | *.log 7 | core 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @printf "Building icebreaker examples\n"; 3 | @$(MAKE) -C icebreaker 4 | @printf "Building icebitsy examples\n"; 5 | @$(MAKE) -C icebitsy 6 | 7 | clean: 8 | @printf "Building icebreaker examples\n"; 9 | @$(MAKE) -C icebreaker clean 10 | @printf "Building icebitsy examples\n"; 11 | @$(MAKE) -C icebitsy clean 12 | 13 | .PHONY: clean 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iCEBreaker examples 2 | 3 | [![Discord](https://img.shields.io/discord/613131135903596547?logo=discord)](https://discord.gg/P7FYThy) [![Support our crowd funding campaign at https://www.crowdsupply.com/1bitsquared/icebreaker-fpga](https://img.shields.io/badge/crowd_supply-support_us-27B1AC.svg)](https://www.crowdsupply.com/1bitsquared/icebreaker-fpga) 4 | 5 | This repository contains examples for the iCEBreaker FPGA educational and development board. 6 | 7 | The goal of this repository is to provide simple examples that can serve as a starting point for the exploration of the iCEBreaker ecosystem. All examples are using the Yosys/nextpnr/icestorm open source flow for ICE40 FPGA. No need for any signups and large downloads of proprietary toolchains necessary. 8 | 9 | ## Dependencies 10 | 11 | ### Manual toolchain build 12 | 13 | For manual icestorm toolcahin flow build instructions follow the steps described on the [icestorm website](http://www.clifford.at/icestorm/#install). 14 | 15 | ### Toolchain build script 16 | 17 | You can automate the build process of the toolchain using the [summon-fpga-tools script](https://github.com/open-tool-forge/summon-fpga-tools). 18 | 19 | ### Toolchain binary releases 20 | 21 | You can download pre-built open source fpga toolchain binary release from [YosysHQ](https://github.com/YosysHQ/oss-cad-suite-build). 22 | 23 | ## Repository structure 24 | 25 | This repository contains examples for multiple iCEBreaker development boards. The examples for each dev board can be found inside their respective subdirectories. 26 | 27 | The default Placement Constraint File (.pcf) for iCEBreaker can be found in the respective dev board directory and contains references to all the default pins on the iCEBreaker development board. This file can be referenced by all the examples that use that board. 28 | 29 | ## Community 30 | 31 | If you have any questions please join the Discord channel and ask away: [1bitsquared.com/pages/chat](https://1bitsquared.com/pages/chat/) 32 | -------------------------------------------------------------------------------- /icebitsy/Makefile: -------------------------------------------------------------------------------- 1 | Q := @ 2 | EXAMPLE_DIRS := $(sort $(dir $(wildcard */Makefile))) 3 | 4 | all: $(EXAMPLE_DIRS) 5 | $(Q)true 6 | 7 | clean: $(EXAMPLE_DIRS:=.clean) 8 | $(Q)true 9 | 10 | $(EXAMPLE_DIRS): 11 | @printf " BUILD $@\n"; 12 | $(Q)$(MAKE) --directory=$@ 13 | 14 | %.clean: 15 | @printf " CLEAN $*\n"; 16 | $(Q)$(MAKE) --directory=$* clean 17 | 18 | .PHONY: $(EXAMPLE_DIRS) clean -------------------------------------------------------------------------------- /icebitsy/README.md: -------------------------------------------------------------------------------- 1 | This directory contains examples for the icebreaker-bitsy also known as icebitsy. 2 | 3 | You are interested in the hardware, you can find the icebreaker-bitsy in the [US 1BitSquared store](https://1bitsquared.com/products/icebreaker-bitsy) as well as the [German 1BitSquared store](https://1bitsquared.de/products/icebreaker-bitsy). 4 | 5 | ## How to build and flash an example 6 | 7 | To build the bitstream, enter the respective example directory and run: 8 | ``` 9 | make 10 | ``` 11 | 12 | To program the bitstream run: 13 | 14 | ``` 15 | make prog 16 | ``` 17 | 18 | ## Notes 19 | If you have more than one icebreaker-bitsy connected to your computer. The programming target will fail with an error indicating that `dfu-util` can not decide which device to program. To list the dfu-devices connected to your system run `dfu-util --list`. You should get an output that is similar to this: 20 | ``` 21 | ❯ dfu-util --list 22 | dfu-util 0.10 23 | 24 | Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc. 25 | Copyright 2010-2020 Tormod Volden and Stefan Schmidt 26 | This program is Free Software and has ABSOLUTELY NO WARRANTY 27 | Please report bugs to http://sourceforge.net/p/dfu-util/tickets/ 28 | 29 | Found Runtime: [1d50:6147] ver=0001, devnum=107, cfg=1, intf=3, path="9-1.1.3", alt=0, name="DFU runtime", serial="e46870a4534c0d22" 30 | Found DFU: [1d50:6146] ver=0005, devnum=112, cfg=1, intf=0, path="9-1.2", alt=1, name="RISC-V firmware", serial="e4692c7367532827" 31 | Found DFU: [1d50:6146] ver=0005, devnum=112, cfg=1, intf=0, path="9-1.2", alt=0, name="iCE40 bitstream", serial="e4692c7367532827" 32 | ``` 33 | 34 | By unplugging and plugging in the icebitsies as needed you should be able to figure out which one is which. When you have figured that out, you can set `DFU_SERIAL` environment variable to tell the makefile which device to program. You can either do that with each invocation of the `make prog` target: 35 | ``` 36 | make prog DFU_SERIAL= 37 | ``` 38 | or you can set the environment variable for the shell session you are using: 39 | ``` 40 | export DFU_SERIAL= 41 | ``` -------------------------------------------------------------------------------- /icebitsy/blink_count_shift/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = blink_count_shift 2 | 3 | ADD_SRC = ../common/dfu_helper.v 4 | PIN_DEF = ../icebitsy1.pcf 5 | DEVICE = up5k 6 | PACKAGE = sg48 7 | 8 | prog: dfuprog 9 | 10 | include ../../main.mk 11 | -------------------------------------------------------------------------------- /icebitsy/blink_count_shift/README.md: -------------------------------------------------------------------------------- 1 | Simple example testing all the LED, Buttons and IO on the iCEBreaker-bitsy FPGA board. 2 | 3 | This example consists of two parts. 4 | 5 | ## Part 1 6 | 7 | Wait for the user button to be pressed for ~2s. After the button was pressed for ~2s the Green LED will go out. 8 | When the button is then released the iCEBreauer-bitsy will reboot into the DFU bootloader. 9 | 10 | ## Part 2 11 | All the iCEBreaker-btisy pins are combined into a 24bit shiftregister and a 1 bit is continously shifted through the outputs. 12 | -------------------------------------------------------------------------------- /icebitsy/blink_count_shift/blink_count_shift.v: -------------------------------------------------------------------------------- 1 | /* Small test design actuating all IO on the iCEBreaker-bitsy dev board. */ 2 | 3 | module top ( 4 | inout USB_P, 5 | inout USB_N, 6 | inout USB_DET, 7 | 8 | input CLK, 9 | 10 | input BTN_N, 11 | 12 | output LEDG_N, 13 | 14 | output P0, P1, P2, P3, P4, P5, P6, P7, 15 | output P8, P9, P10, P11, P12, P13, P14, P15, 16 | output P16, P17, P18, P19, P20, P21, P22, P23 17 | ); 18 | localparam BITS = 24; 19 | localparam LOG2DELAY = 20; 20 | 21 | // Reset to DFU bootloader with a long button press 22 | wire will_reboot; 23 | dfu_helper #( 24 | .BTN_MODE(3) 25 | ) dfu_helper_I ( 26 | .usb_dp (USB_P), 27 | .usb_dn (USB_N), 28 | .usb_pu (USB_DET), 29 | .boot_sel (2'b00), 30 | .boot_now (1'b0), 31 | .btn_in (BTN_N), 32 | .btn_tick (), 33 | .btn_val (), 34 | .btn_press(), 35 | .will_reboot(will_reboot), 36 | .clk (CLK), 37 | .rst (0) 38 | ); 39 | // Indicate when the button was pressed for long enough to trigger a 40 | // reboot into the DFU bootloader. 41 | // (LED turns off when the condition matches) 42 | assign LEDG_N = will_reboot; 43 | 44 | // Delay counter with strobe 45 | // The highest significant bit at position LOG2DELAY will only be 46 | // 'hot' (=1) for one cycle until it is reset to 0 again. 47 | // While the highest significant bit is not hot (0) the counter increments 48 | // with every clock cycle. 49 | reg [LOG2DELAY:0] counter = 0; 50 | always @(posedge CLK) begin 51 | if (counter[LOG2DELAY]) 52 | counter <= 0; 53 | else 54 | counter <= counter + 1; 55 | end 56 | 57 | // Create a bitfield that has one bit high and all the remaining bits low. 58 | // The one bit is rotating through the field. 59 | reg [BITS-1:0] outbitfield = 1 << BITS-1; 60 | always @(posedge CLK) begin 61 | if (counter[LOG2DELAY]) 62 | // Assign the lowest significant bit to the highest significant bit 63 | // assign the remaining bits one bit lower than they were. 64 | // This results in the bit rotating through the field from highest significant bit 65 | // to the lowest significant bit. 66 | outbitfield <= {outbitfield[0], outbitfield[BITS-1:1]}; 67 | end 68 | 69 | assign {P0, P1, P2, P3, P4, P5, P6, P7, 70 | P8, P9, P10, P11, P12, P13, P14, P15, 71 | P16, P17, P18, P19, P20, P21, P22, P23} = outbitfield; 72 | endmodule 73 | -------------------------------------------------------------------------------- /icebitsy/charlieplexing-tomk/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = pmodcharlie 2 | 3 | ADD_SRC = ../common/dfu_helper.v 4 | PIN_DEF = ../icebitsy1-pmod.pcf 5 | DEVICE = up5k 6 | PACKAGE = sg48 7 | 8 | prog: dfuprog 9 | 10 | include ../../main.mk 11 | -------------------------------------------------------------------------------- /icebitsy/charlieplexing-tomk/README.md: -------------------------------------------------------------------------------- 1 | # Charlieplexing 2 | 3 | This example controls the Pmod™ 8-digit 7-segment display ([Blog article](https://www.twam.info/electronics/7-segment-charlieplexing), [Schematic](https://github.com/twam/Pmod7Segment)) using [Charlieplexing](https://en.wikipedia.org/wiki/Charlieplexing). The time since start up is counted and displayed milliseconds in hex. -------------------------------------------------------------------------------- /icebitsy/charlieplexing-tomk/pmodcharlie.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module top( 4 | inout USB_P, 5 | inout USB_N, 6 | inout USB_DET, 7 | 8 | input CLK, 9 | input BTN_N, 10 | output LEDG_N, 11 | output P1_1, P1_2, P1_3, P1_4, P1_7, P1_8, P1_9, P1_10 12 | ); 13 | 14 | localparam CLK_FREQUENCY = 12E6; 15 | localparam COUNTER_MAX = $rtoi(CLK_FREQUENCY/1000); 16 | 17 | wire [7:0] pmodmap; 18 | reg [31:0] milliseconds = 0; 19 | reg [$clog2(COUNTER_MAX)-1:0] counter; 20 | 21 | // Reset to DFU bootloader with a long button press 22 | wire will_reboot; 23 | dfu_helper #( 24 | .BTN_MODE(3) 25 | ) dfu_helper_I ( 26 | .usb_dp (USB_P), 27 | .usb_dn (USB_N), 28 | .usb_pu (USB_DET), 29 | .boot_sel (2'b00), 30 | .boot_now (1'b0), 31 | .btn_in (BTN_N), 32 | .btn_tick (), 33 | .btn_val (), 34 | .btn_press(), 35 | .will_reboot(will_reboot), 36 | .clk (CLK), 37 | .rst (1'b0) 38 | ); 39 | // Indicate when the button was pressed for long enough to trigger a 40 | // reboot into the DFU bootloader. 41 | // (LED turns off when the condition matches) 42 | assign LEDG_N = will_reboot; 43 | 44 | // Count milliseconds 45 | always @(posedge CLK) 46 | begin 47 | if (counter < COUNTER_MAX) 48 | counter <= counter + 1; 49 | else 50 | begin 51 | counter <= 0; 52 | milliseconds <= milliseconds + 1; 53 | end 54 | end 55 | 56 | // map output pins of pmodcharlie module to pins on iCEBreaker 57 | assign pmodmap[0] = P1_1; 58 | assign pmodmap[1] = P1_2; 59 | assign pmodmap[2] = P1_3; 60 | assign pmodmap[3] = P1_4; 61 | assign pmodmap[4] = P1_7; 62 | assign pmodmap[5] = P1_8; 63 | assign pmodmap[6] = P1_9; 64 | assign pmodmap[7] = P1_10; 65 | 66 | pmodcharlie pmodCharlieA( 67 | .clk(CLK), 68 | .pins(pmodmap), 69 | .display_data(milliseconds) 70 | ); 71 | 72 | endmodule 73 | 74 | module pmodcharlie 75 | #( 76 | parameter CLK_FREQUENCY = 12E6, 77 | parameter DISPLAY_FREQUENCY = 1E3 78 | ) 79 | ( 80 | input wire clk, 81 | input wire [31:0] display_data, 82 | output wire [7:0] pins 83 | ); 84 | 85 | localparam NUMBER_OF_DIGITS = 8; 86 | reg [$clog2(NUMBER_OF_DIGITS)-1:0] current_digit; 87 | localparam NUMBER_OF_SEGMENTS = 7; 88 | 89 | reg [7:0] tristate_pins; 90 | reg [7:0] output_pins; 91 | reg [6:0] segments; 92 | reg [6:0] segment_mask = 7'h01; 93 | reg [3:0] digit_data; 94 | 95 | localparam SEGMENT_TIMER_MAX = $rtoi($ceil(CLK_FREQUENCY / (DISPLAY_FREQUENCY * (NUMBER_OF_DIGITS*NUMBER_OF_SEGMENTS)))); 96 | reg [$clog2(SEGMENT_TIMER_MAX)-1:0] segment_timer; 97 | reg [$clog2(NUMBER_OF_SEGMENTS)-1:0] segment_counter; 98 | 99 | // Get current active segment and digit depending on clk 100 | always @(posedge clk) 101 | begin 102 | if (segment_timer != 0) 103 | segment_timer = segment_timer - 1; 104 | else 105 | begin 106 | // Generate a rotating mask that exposes only one 107 | // digit segment at a time 108 | segment_mask <= {segment_mask[5:0], segment_mask[6]}; 109 | 110 | segment_timer <= SEGMENT_TIMER_MAX; 111 | if (segment_counter != 0) 112 | segment_counter <= segment_counter - 1; 113 | else 114 | begin 115 | if (current_digit < NUMBER_OF_DIGITS-1) 116 | current_digit <= current_digit + 1; 117 | else 118 | current_digit <= 0; 119 | segment_counter <= NUMBER_OF_SEGMENTS; 120 | end 121 | end 122 | end 123 | 124 | // Map display_data to digit_data depening on current active digit 125 | always @(*) 126 | begin 127 | case (current_digit) // current_digit 128 | 0: digit_data = display_data[3:0]; 129 | 1: digit_data = display_data[7:4]; 130 | 2: digit_data = display_data[11:8]; 131 | 3: digit_data = display_data[15:12]; 132 | 4: digit_data = display_data[19:16]; 133 | 5: digit_data = display_data[23:20]; 134 | 6: digit_data = display_data[27:24]; 135 | 7: digit_data = display_data[31:28]; 136 | default: digit_data = 4'b0000; 137 | endcase 138 | end 139 | 140 | // Map digit_data to segments 141 | // Also mask segment at a time to prevent brightness 142 | // differences due to higher curret draw depending on 143 | // the amount of segments lit simultaneously 144 | always @(*) begin 145 | case (digit_data) 146 | 'h0: segments = 'b0111111 & segment_mask; 147 | 'h1: segments = 'b0000110 & segment_mask; 148 | 'h2: segments = 'b1011011 & segment_mask; 149 | 'h3: segments = 'b1001111 & segment_mask; 150 | 'h4: segments = 'b1100110 & segment_mask; 151 | 'h5: segments = 'b1101101 & segment_mask; 152 | 'h6: segments = 'b1111101 & segment_mask; 153 | 'h7: segments = 'b0000111 & segment_mask; 154 | 'h8: segments = 'b1111111 & segment_mask; 155 | 'h9: segments = 'b1101111 & segment_mask; 156 | 'hA: segments = 'b1110111 & segment_mask; 157 | 'hB: segments = 'b1111100 & segment_mask; 158 | 'hC: segments = 'b0111001 & segment_mask; 159 | 'hD: segments = 'b1011110 & segment_mask; 160 | 'hE: segments = 'b1111001 & segment_mask; 161 | 'hF: segments = 'b1110001 & segment_mask; 162 | default: segments = 7'b0000000; 163 | endcase 164 | end 165 | 166 | // Configure pins depending on current active digit & segment 167 | always @(posedge clk) begin 168 | 169 | // All pins are set to low except the Anode drive pin 170 | output_pins <= 'h0; 171 | output_pins[7 - current_digit] <= 1; 172 | 173 | // The pins that correspond to the Anode drive pin are always set to output (Hi/VCC) 174 | // The pins that correspond to lit segments are set to output (Low/GND) 175 | // The pins that correspond to unlit segments are set to input (HiZ) 176 | case (current_digit) 177 | 7: tristate_pins <= {segments[6:0], 1'b1}; 178 | 6: tristate_pins <= {segments[6:1], 1'b1, segments[0]}; 179 | 5: tristate_pins <= {segments[6:2], 1'b1, segments[0], segments[1]}; 180 | 4: tristate_pins <= {segments[6:3], 1'b1, segments[1:0], segments[2]}; 181 | 3: tristate_pins <= {segments[6:4], 1'b1, segments[2:0], segments[3]}; 182 | 2: tristate_pins <= {segments[6:5], 1'b1, segments[3:0], segments[4]}; 183 | 1: tristate_pins <= {segments[6], 1'b1, segments[4:0], segments[5]}; 184 | 0: tristate_pins <= { 1'b1, segments[5:0], segments[6]}; 185 | endcase 186 | 187 | end 188 | 189 | SB_IO #( 190 | .PIN_TYPE(6'b 1010_01), 191 | .PULLUP(1'b 0) 192 | ) led_io[7:0] ( 193 | .PACKAGE_PIN(pins), 194 | .OUTPUT_ENABLE(tristate_pins), 195 | .D_OUT_0(output_pins), 196 | ); 197 | 198 | endmodule 199 | -------------------------------------------------------------------------------- /icebitsy/common/dfu_helper.v: -------------------------------------------------------------------------------- 1 | /* 2 | * dfu_helper.v 3 | * 4 | * vim: ts=4 sw=4 5 | * 6 | * - Samples the button every 2^SAMP_TW 7 | * (or every btn_tick if external ticks are used). 8 | * 9 | * - Debounces / flips state when sampled identically 4 times consecutively 10 | * 11 | * - Detect long presses if held active for more than 2^LONG_TW 12 | * 13 | * - Safety against 'boot' presses: buttons need to be inactive for 14 | * 2^(LONG_TW-2) before it is "armed" 15 | * 16 | * - btn_val is the current 'debounced' value of the button 17 | * (possibly already inverted if 'active-low' is set) 18 | * 19 | * For application mode: 20 | * When released after a long press, triggers bootloader image 21 | * When released after a short press, outputs a pulse on btn_press 22 | * 23 | * For bootloader mode: 24 | * Any button presses triggers reboot to application mode image 25 | * 26 | * Copyright (C) 2021 Sylvain Munaut 27 | * SPDX-License-Identifier: CERN-OHL-P-2.0 28 | */ 29 | 30 | `default_nettype none 31 | 32 | module dfu_helper #( 33 | parameter integer DUMMY_USB = 1, // Include dummy USB IOs to avoid false detection 34 | parameter integer SAMP_TW = 7, // Sample button every 128 cycles 35 | parameter integer LONG_TW = 17, // Consider long press after 2^19 sampling 36 | parameter integer BTN_MODE = 3, // [2] Use btn_tick, [1] Include IO buffer, [0] Invert (active-low) 37 | parameter integer BOOTLOADER_MODE = 0, // 0 = For user app, 1 = For bootloader 38 | parameter BOOT_IMAGE = 2'b01, // Bootloader image 39 | parameter USER_IMAGE = 2'b10 // User image 40 | )( 41 | // USB IOs 42 | inout wire usb_dp, 43 | inout wire usb_dn, 44 | inout wire usb_pu, 45 | 46 | // External control 47 | input wire [1:0] boot_sel, 48 | input wire boot_now, 49 | 50 | // Button 51 | input wire btn_in, 52 | input wire btn_tick, 53 | 54 | // Outputs 55 | output wire btn_val, 56 | output reg btn_press, 57 | output wire will_reboot, // goes high when button was pressed for long enough to reboot 58 | 59 | // Clock 60 | input wire clk, 61 | input wire rst 62 | ); 63 | 64 | // Signals 65 | // ------- 66 | 67 | // Input stage 68 | wire btn_raw; 69 | reg btn_cur; 70 | 71 | // Sampling 72 | reg [SAMP_TW:0] samp_cnt = 0; // init only needed for sim 73 | wire samp_now; 74 | 75 | // Debounce 76 | reg [2:0] debounce = 0; // init only needed for sim 77 | reg btn_fall; 78 | 79 | // Long timer 80 | reg [LONG_TW:0] long_cnt; 81 | wire [LONG_TW:0] long_inc; 82 | wire [LONG_TW:0] long_msk; 83 | 84 | reg armed; 85 | 86 | // Boot logic 87 | reg [1:0] wb_sel; 88 | reg wb_req; 89 | reg wb_now; 90 | 91 | 92 | // Dummy USB 93 | // --------- 94 | 95 | if (DUMMY_USB) 96 | SB_IO #( 97 | .PIN_TYPE (6'b10_1000), 98 | .PULLUP (1'b0), 99 | .IO_STANDARD ("SB_LVCMOS") 100 | ) usb[2:0] ( 101 | .PACKAGE_PIN ({usb_dp, usb_dn, usb_pu}), 102 | .OUTPUT_ENABLE (1'b0), 103 | .D_OUT_0 (1'b0) 104 | ); 105 | 106 | 107 | // Button 108 | // ------ 109 | 110 | // IOB 111 | generate 112 | if (BTN_MODE[1]) 113 | SB_IO #( 114 | .PIN_TYPE(6'b000000), // Reg input, no output 115 | .PULLUP(1'b1), 116 | .IO_STANDARD("SB_LVCMOS") 117 | ) btn_iob_I ( 118 | .PACKAGE_PIN(btn_in), 119 | .INPUT_CLK (clk), 120 | .D_IN_0 (btn_raw) 121 | ); 122 | else 123 | assign btn_raw = btn_in; 124 | endgenerate 125 | 126 | // Invert & Synchronize 127 | always @(posedge clk) 128 | btn_cur <= btn_raw ^ BTN_MODE[0]; 129 | 130 | // Sampling tick 131 | always @(posedge clk) 132 | samp_cnt <= ({ 1'b0, samp_cnt[SAMP_TW-1:0] } + 1) & {(SAMP_TW+1){~samp_cnt[SAMP_TW]}}; 133 | 134 | assign samp_now = BTN_MODE[3] ? btn_tick : samp_cnt[SAMP_TW]; 135 | 136 | // Debounce 137 | always @(posedge clk or posedge rst) 138 | if (rst) 139 | debounce <= 3'b000; 140 | else if (samp_now) 141 | casez ({debounce, btn_cur}) 142 | 4'b0zz0: debounce <= 3'b000; 143 | 4'b0001: debounce <= 3'b001; 144 | 4'b0011: debounce <= 3'b010; 145 | 4'b0101: debounce <= 3'b011; 146 | 4'b0111: debounce <= 3'b111; 147 | 4'b1zz1: debounce <= 3'b111; 148 | 4'b1110: debounce <= 3'b110; 149 | 4'b1100: debounce <= 3'b101; 150 | 4'b1010: debounce <= 3'b100; 151 | 4'b1000: debounce <= 3'b000; 152 | default: debounce <= 3'bxxx; 153 | endcase 154 | 155 | assign btn_val = debounce[2]; 156 | 157 | always @(posedge clk) 158 | btn_fall <= (debounce == 3'b100) & ~btn_cur & samp_now; 159 | 160 | 161 | // Long-press / Arming 162 | // ------------------- 163 | 164 | always @(posedge clk or posedge rst) 165 | if (rst) 166 | armed <= 1'b0; 167 | else 168 | armed <= armed | long_cnt[LONG_TW-2]; 169 | 170 | 171 | assign long_inc = { {LONG_TW{1'b0}}, ~long_cnt[LONG_TW] }; 172 | assign long_msk = { (LONG_TW+1){~(armed ^ btn_val)} }; 173 | 174 | always @(posedge clk or posedge rst) 175 | if (rst) 176 | long_cnt <= 0; 177 | else if (samp_now) 178 | long_cnt <= (long_cnt + long_inc) & long_msk; 179 | 180 | 181 | // Command logic 182 | // ------------- 183 | 184 | always @(posedge clk or posedge rst) 185 | if (rst) begin 186 | wb_sel <= 2'b00; 187 | wb_req <= 1'b0; 188 | btn_press <= 1'b0; 189 | end else if (~wb_req) begin 190 | if (boot_now) begin 191 | // External boot request 192 | wb_sel <= boot_sel; 193 | wb_req <= 1'b1; 194 | btn_press <= 1'b0; 195 | end else begin 196 | if (BOOTLOADER_MODE == 1) begin 197 | // We're in a DFU bootloader, any button press results in 198 | // boot to application 199 | wb_sel <= USER_IMAGE; 200 | wb_req <= (armed & btn_fall) | wb_req; 201 | btn_press <= 1'b0; 202 | end else begin 203 | // We're in user application, short press resets the 204 | // logic, long press triggers DFU reboot 205 | wb_sel <= BOOT_IMAGE; 206 | wb_req <= (armed & btn_fall & long_cnt[LONG_TW]) | wb_req; 207 | btn_press <= (armed & btn_fall & ~long_cnt[LONG_TW]); 208 | end 209 | end 210 | end 211 | 212 | assign will_reboot = armed & long_cnt[LONG_TW]; 213 | 214 | // Boot 215 | // ---- 216 | 217 | // Ensure select bits are set before the boot pulse 218 | always @(posedge clk or posedge rst) 219 | if (rst) 220 | wb_now <= 1'b0; 221 | else 222 | wb_now <= wb_req; 223 | 224 | // IP core 225 | SB_WARMBOOT warmboot ( 226 | .BOOT (wb_now), 227 | .S0 (wb_sel[0]), 228 | .S1 (wb_sel[1]) 229 | ); 230 | 231 | endmodule // dfu_helper 232 | -------------------------------------------------------------------------------- /icebitsy/dvi-12bit/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = dvi-12bit 2 | ADD_SRC = vga_core.v vga_timing.v 3 | 4 | ADD_SRC += ../common/dfu_helper.v 5 | PIN_DEF = ../icebitsy1-pmod.pcf 6 | DEVICE = up5k 7 | PACKAGE = sg48 8 | #PNR_SEED = 1 9 | 10 | prog: dfuprog 11 | 12 | include ../../main.mk 13 | 14 | gen_gamma_table: gen_gamma_table.o 15 | gcc $< -o $@ -lm 16 | 17 | gamma_table.hex: gen_gamma_table 18 | ./gen_gamma_table > gamma_table.hex 19 | -------------------------------------------------------------------------------- /icebitsy/dvi-12bit/README.txt: -------------------------------------------------------------------------------- 1 | This is an example design for driving the 3b and 12b HDMI PMOD modules from 2 | Black Mesa Labs. The design drives 800x600 video with a 40 MHz input clock. 3 | The actual video is an alternating display of: 4 | 1) Color Test Pattern bars. 5 | 2) Bouncing dot with changing colors ( Pong'ish ). 6 | 3) Moving lines. 7 | 8 | Original design targets Xilinx Spartan3 FPGA and makes use of 2 Xilinx specific 9 | primitive: 10 | 1) BUFG : Global Clock Tree buffer 11 | 2) FDDRCPE : "ODDR" output flop for mirroring internal clock tree outside. 12 | 13 | top.v : top level for FPGA design. 14 | vga_core.v : Generates color test pattern, bouncing ball and moving lines. 15 | vga_timing.v : Generates low level VGA timing for 800x600 with 40 MHz clock. 16 | 17 | Kevin M. Hubbard @ Black Mesa Labs 2017.12.14 18 | -------------------------------------------------------------------------------- /icebitsy/dvi-24bit/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = dvi-24bit 2 | ADD_SRC = vga_core.v vga_timing.v 3 | 4 | ADD_SRC += ../common/dfu_helper.v 5 | PIN_DEF = ../icebitsy1-pmod.pcf 6 | DEVICE = up5k 7 | PACKAGE = sg48 8 | PNR_SEED = 1 9 | 10 | prog: dfuprog 11 | 12 | include ../../main.mk 13 | 14 | gen_gamma_table: gen_gamma_table.o 15 | gcc $< -o $@ -lm 16 | 17 | gamma_table.hex: gen_gamma_table 18 | ./gen_gamma_table > gamma_table.hex 19 | -------------------------------------------------------------------------------- /icebitsy/dvi-24bit/README.txt: -------------------------------------------------------------------------------- 1 | This is an example design for driving the 3b and 12b HDMI PMOD modules from 2 | Black Mesa Labs. The design drives 800x600 video with a 40 MHz input clock. 3 | The actual video is an alternating display of: 4 | 1) Color Test Pattern bars. 5 | 2) Bouncing dot with changing colors ( Pong'ish ). 6 | 3) Moving lines. 7 | 8 | Original design targets Xilinx Spartan3 FPGA and makes use of 2 Xilinx specific 9 | primitive: 10 | 1) BUFG : Global Clock Tree buffer 11 | 2) FDDRCPE : "ODDR" output flop for mirroring internal clock tree outside. 12 | 13 | top.v : top level for FPGA design. 14 | vga_core.v : Generates color test pattern, bouncing ball and moving lines. 15 | vga_timing.v : Generates low level VGA timing for 800x600 with 40 MHz clock. 16 | 17 | Kevin M. Hubbard @ Black Mesa Labs 2017.12.14 18 | -------------------------------------------------------------------------------- /icebitsy/dvi-4bit/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = dvi-4bit 2 | ADD_SRC = vga_core.v vga_timing.v 3 | 4 | ADD_SRC += ../common/dfu_helper.v 5 | PIN_DEF = ../icebitsy1-pmod.pcf 6 | DEVICE = up5k 7 | PACKAGE = sg48 8 | #PNR_SEED = 1 9 | 10 | prog: dfuprog 11 | 12 | include ../../main.mk 13 | 14 | gen_gamma_table: gen_gamma_table.o 15 | gcc $< -o $@ -lm 16 | 17 | gamma_table.hex: gen_gamma_table 18 | ./gen_gamma_table > gamma_table.hex 19 | -------------------------------------------------------------------------------- /icebitsy/dvi-4bit/README.txt: -------------------------------------------------------------------------------- 1 | This is an example design for driving the 3b and 12b HDMI PMOD modules from 2 | Black Mesa Labs. The design drives 800x600 video with a 40 MHz input clock. 3 | The actual video is an alternating display of: 4 | 1) Color Test Pattern bars. 5 | 2) Bouncing dot with changing colors ( Pong'ish ). 6 | 3) Moving lines. 7 | 8 | Original design targets Xilinx Spartan3 FPGA and makes use of 2 Xilinx specific 9 | primitive: 10 | 1) BUFG : Global Clock Tree buffer 11 | 2) FDDRCPE : "ODDR" output flop for mirroring internal clock tree outside. 12 | 13 | top.v : top level for FPGA design. 14 | vga_core.v : Generates color test pattern, bouncing ball and moving lines. 15 | vga_timing.v : Generates low level VGA timing for 800x600 with 40 MHz clock. 16 | 17 | Kevin M. Hubbard @ Black Mesa Labs 2017.12.14 18 | -------------------------------------------------------------------------------- /icebitsy/dvi-4bit/dvi-4bit.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- (C) Copyright 2017 Kevin M. Hubbard @ Black Mess Labs - All rights reserved. 3 | -- Source file: top.v 4 | -- Date: December 2017 5 | -- Author: khubbard 6 | -- Description: Spartan3 Test Design 7 | -- Language: Verilog-2001 and VHDL-1993 8 | -- Simulation: Mentor-Modelsim 9 | -- Synthesis: Xilinst-XST 10 | -- License: This project is licensed with the CERN Open Hardware Licence 11 | -- v1.2. You may redistribute and modify this project under the 12 | -- terms of the CERN OHL v.1.2. (http://ohwr.org/cernohl). 13 | -- This project is distributed WITHOUT ANY EXPRESS OR IMPLIED 14 | -- WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY QUALITY 15 | -- AND FITNESS FOR A PARTICULAR PURPOSE. Please see the CERN OHL 16 | -- v.1.2 for applicable Conditions. 17 | -- 18 | -- 3b Module - Facing module pins 19 | -- ------------------------------- 20 | -- | 1-GRN 3-CLK 5-HS 7-NC GND 3V | 21 | -- | 0-RED 2-BLU 4-DE 6-VS GND 3V | 22 | -- ___|_______________________________|___ 23 | -- | BML HDMI 3b color PMOD board | 24 | -- --------------------------------------- 25 | -- pmod_*_*<0> = red 26 | -- pmod_*_*<1> = green 27 | -- pmod_*_*<2> = blue 28 | -- pmod_*_*<3> = pixel_clock 29 | -- pmod_*_*<4> = data_enable 30 | -- pmod_*_*<5> = hsync 31 | -- pmod_*_*<6> = vsync 32 | -- pmod_*_*<7> = nc 33 | -- 34 | -- 35 | -- 36 | -- 12b Module - Facing module pins 37 | -- ---------------------------- ---------------------------- 38 | -- | 1-R3 3-R1 5-G3 7-G1 GND 3V | | 1-B3 3-ck 5-B0 7-HS GND 3V | 39 | -- | 0-R2 2-R0 4-G2 6-G0 GND 3V | | 0-B2 2-B1 4-DE 6-VS GND 3V | 40 | -- ___|____________________________|______|____________________________|__ 41 | -- | BML HDMI 12b color PMOD board | 42 | -- ----------------------------------------------------------------------- 43 | -- pmod_*_*<0> = r[2] pmod_*_*<0> = b[2] 44 | -- pmod_*_*<1> = r[3] pmod_*_*<1> = b[3] 45 | -- pmod_*_*<2> = r[0] pmod_*_*<2> = b[1] 46 | -- pmod_*_*<3> = r[1] pmod_*_*<3> = ck 47 | -- pmod_*_*<4> = g[2] pmod_*_*<4> = de 48 | -- pmod_*_*<5> = g[3] pmod_*_*<5> = b[0] 49 | -- pmod_*_*<6> = g[0] pmod_*_*<6> = vs 50 | -- pmod_*_*<7> = g[1] pmod_*_*<7> = hs 51 | -- 52 | -- Revision History: 53 | -- Ver# When Who What 54 | -- ---- -------- -------- --------------------------------------------------- 55 | -- 0.1 12.14.17 khubbard Creation 56 | -- ***************************************************************************/ 57 | `default_nettype none // Strictly enforce all nets to be declared 58 | 59 | module top 60 | ( 61 | inout USB_P, 62 | inout USB_N, 63 | inout USB_DET, 64 | 65 | input CLK, 66 | output LEDG_N, // on board green 67 | input BTN_N, // user button aka reset 68 | 69 | output P1_1, P1_2, P1_3, P1_4, P1_7, P1_8, P1_9, P1_10, 70 | output P2_1, P2_2, P2_3, P2_4, P2_7, P2_8, P2_9, P2_10 71 | 72 | );// module top 73 | 74 | 75 | wire reset_loc; 76 | wire clk_40m_tree; 77 | reg [29:0] led_cnt; 78 | reg [29:0] led_cnt_p1; 79 | wire vga_de; 80 | wire vga_ck; 81 | wire vga_hs; 82 | wire vga_vs; 83 | wire [23:0] vga_rgb; 84 | reg [31:0] random_num; 85 | wire [7:0] r; 86 | wire [7:0] g; 87 | wire [7:0] b; 88 | reg mode_bit; 89 | wire ok_led_loc; 90 | 91 | 92 | //assign reset_loc = ~BTN_N; 93 | 94 | // Reset to DFU bootloader with a long button press 95 | wire will_reboot; 96 | dfu_helper #( 97 | .LONG_TW(19), 98 | .BTN_MODE(3) 99 | ) dfu_helper_I ( 100 | .usb_dp (USB_P), 101 | .usb_dn (USB_N), 102 | .usb_pu (USB_DET), 103 | .boot_sel (2'b00), 104 | .boot_now (1'b0), 105 | .btn_in (BTN_N), 106 | .btn_tick (), 107 | .btn_val (), 108 | .btn_press(reset_loc), 109 | .will_reboot(will_reboot), 110 | .clk (clk_40m_tree), 111 | .rst (0) 112 | ); 113 | // Indicate when the button was pressed for long enough to trigger a 114 | // reboot into the DFU bootloader. 115 | // (LED turns off when the condition matches) 116 | assign LEDG_N = will_reboot; 117 | 118 | //----------------------------------------------------------------------------- 119 | // PLL. 120 | //----------------------------------------------------------------------------- 121 | SB_PLL40_PAD #( 122 | .DIVR(4'b0000), 123 | // 40MHz ish to be exact it is 39.750MHz 124 | .DIVF(7'b0110100), // 39.750MHz 125 | .DIVQ(3'b100), 126 | .FILTER_RANGE(3'b001), 127 | .FEEDBACK_PATH("SIMPLE"), 128 | .DELAY_ADJUSTMENT_MODE_FEEDBACK("FIXED"), 129 | .FDA_FEEDBACK(4'b0000), 130 | .DELAY_ADJUSTMENT_MODE_RELATIVE("FIXED"), 131 | .FDA_RELATIVE(4'b0000), 132 | .SHIFTREG_DIV_MODE(2'b00), 133 | .PLLOUT_SELECT("GENCLK"), 134 | .ENABLE_ICEGATE(1'b0) 135 | ) pll_inst ( 136 | .PACKAGEPIN(CLK), 137 | .PLLOUTCORE(), 138 | .PLLOUTGLOBAL(clk_40m_tree), 139 | .EXTFEEDBACK(), 140 | .DYNAMICDELAY(), 141 | .RESETB(1'b1), 142 | .BYPASS(1'b0), 143 | .LATCHINPUTVALUE(), 144 | //.LOCK(), 145 | //.SDI(), 146 | //.SDO(), 147 | //.SCLK() 148 | ); 149 | 150 | //----------------------------------------------------------------------------- 151 | // Flash an LED. Also control the VGA demos, toggle between color pattern and 152 | // either a bouncing ball or moving lines. 153 | //----------------------------------------------------------------------------- 154 | always @ ( posedge clk_40m_tree or posedge reset_loc ) begin : proc_led 155 | if ( reset_loc == 1 ) begin 156 | random_num <= 32'd0; 157 | led_cnt <= 30'd0; 158 | led_cnt_p1 <= 30'd0; 159 | ok_led_loc <= 0; 160 | mode_bit <= 0; 161 | end else begin 162 | random_num <= random_num + 3; 163 | ok_led_loc <= 0; 164 | led_cnt_p1 <= led_cnt[29:0]; 165 | led_cnt <= led_cnt + 1; 166 | if ( led_cnt[19] == 1 ) begin 167 | ok_led_loc <= 1; 168 | end 169 | if ( led_cnt[29:27] == 3'd0 ) begin 170 | mode_bit <= 0; 171 | end else begin 172 | mode_bit <= 1; 173 | end 174 | 175 | end // clk+reset 176 | end // proc_led 177 | 178 | //assign LEDG_N = ok_led_loc; 179 | 180 | // ---------------------------------------------------------------------------- 181 | // VGA Timing Generator 182 | // ---------------------------------------------------------------------------- 183 | vga_core u_vga_core 184 | ( 185 | .reset ( reset_loc ), 186 | .random_num ( random_num[31:0] ), 187 | .color_3b ( 1'b0 ), 188 | .mode_bit ( mode_bit ), 189 | .clk_dot ( clk_40m_tree ), 190 | .vga_active ( vga_de ), 191 | .vga_hsync ( vga_hs ), 192 | .vga_vsync ( vga_vs ), 193 | .vga_pixel_rgb ( vga_rgb[23:0] ) 194 | ); 195 | assign r = vga_rgb[23:16]; 196 | assign g = vga_rgb[15:8]; 197 | assign b = vga_rgb[7:0]; 198 | 199 | 200 | // ---------------------------------------------------------------------------- 201 | // Assign the PMOD(s) pins 202 | // ---------------------------------------------------------------------------- 203 | // Also add IO registers to minimize timing between lines and ensure we're 204 | // properly aligned to the clock. Clock is output using a DDR flop and 180deg 205 | // out of phase (rising edge in middle of data eye) to maximize setup/hold 206 | // time margin. 207 | 208 | SB_IO #( 209 | .PIN_TYPE(6'b01_0000) // PIN_OUTPUT_DDR 210 | ) dvi_clk_iob ( 211 | .PACKAGE_PIN (P1_2), 212 | .D_OUT_0 (1'b0), 213 | .D_OUT_1 (1'b1), 214 | .OUTPUT_CLK (clk_40m_tree) 215 | ); 216 | 217 | SB_IO #( 218 | .PIN_TYPE(6'b01_0100) // PIN_OUTPUT_REGISTERED 219 | ) dvi_data_iob [6:0] ( 220 | .PACKAGE_PIN ({P1_1, P1_3, P1_4, P1_7, P1_8, P1_9, P1_10}), 221 | .D_OUT_0 ({|g[7:6], vga_hs, |{&r[7:6],&g[7:6],&b[7:6]}, |r[7:6], |b[7:6], vga_de, vga_vs}), 222 | .OUTPUT_CLK (clk_40m_tree) 223 | ); 224 | 225 | endmodule // top.v 226 | -------------------------------------------------------------------------------- /icebitsy/icebitsy0.pcf: -------------------------------------------------------------------------------- 1 | # 12 MHz clock 2 | set_io -nowarn CLK 35 3 | set_frequency CLK 12 4 | 5 | # USB 6 | set_io -nowarn USB_P 43 7 | set_io -nowarn USB_N 42 8 | set_io -nowarn USB_DET 38 9 | 10 | # RS232 - pins on the "programming connector" 11 | set_io -nowarn RX 18 12 | set_io -nowarn TX 19 13 | 14 | # LEDs and Button 15 | set_io -nowarn BTN_N 10 16 | set_io -nowarn LEDR_N 11 17 | set_io -nowarn LEDG_N 37 18 | 19 | # RGB LED Driver 20 | set_io -nowarn LED_RED_N 39 21 | set_io -nowarn LED_GRN_N 40 22 | set_io -nowarn LED_BLU_N 41 23 | set_io -nowarn LED_RGB[0] 39 24 | set_io -nowarn LED_RGB[1] 40 25 | set_io -nowarn LED_RGB[2] 41 26 | 27 | # SPI Flash 28 | set_io -nowarn FLASH_SCK 15 29 | set_io -nowarn FLASH_CS 16 30 | set_io -nowarn FLASH_IO0 14 31 | set_io -nowarn FLASH_IO1 17 32 | set_io -nowarn FLASH_IO2 12 33 | set_io -nowarn FLASH_IO3 13 34 | 35 | # Pins 36 | #set_io -nowarn P1 xx GND 37 | set_io -nowarn P2 44 38 | set_io -nowarn P3 45 39 | set_io -nowarn P4 46 40 | set_io -nowarn P5 47 41 | set_io -nowarn P6 48 42 | set_io -nowarn P7 2 43 | set_io -nowarn P8 3 44 | set_io -nowarn P9 4 45 | set_io -nowarn P10 6 46 | set_io -nowarn P11 9 47 | set_io -nowarn P12 13 48 | set_io -nowarn P13 12 49 | set_io -nowarn P14 17 50 | #set_io -nowarn P15 xx 3v3 51 | #set_io -nowarn P16 xx GND 52 | set_io -nowarn P17 25 53 | set_io -nowarn P18 26 54 | set_io -nowarn P19 27 55 | set_io -nowarn P20 28 56 | set_io -nowarn P21 31 57 | set_io -nowarn P22 32 58 | set_io -nowarn P23 34 59 | set_io -nowarn P24 36 60 | set_io -nowarn P25 39 61 | set_io -nowarn P26 40 62 | set_io -nowarn P27 41 63 | #set_io -nowarn P28 xx 1v2 64 | #set_io -nowarn P29 xx 3v3 65 | #set_io -nowarn P30 xx 5v 66 | set_io -nowarn P31 14 67 | set_io -nowarn P32 18 68 | #set_io -nowarn P33 xx CDONE 69 | set_io -nowarn P34 19 70 | #set_io -nowarn P35 xx CRESET 71 | set_io -nowarn P36 20 72 | #set_io -nowarn P37 xx FLASH_SCK 73 | set_io -nowarn P38 21 74 | #set_io -nowarn P39 xx FLASH_CS 75 | set_io -nowarn P40 23 76 | -------------------------------------------------------------------------------- /icebitsy/icebitsy1-pmod.pcf: -------------------------------------------------------------------------------- 1 | # Defining pins for the iCEBreaker-bitsy 2 | # using the PMOD breakout adapter board 3 | 4 | # 12 MHz clock 5 | set_io -nowarn CLK 35 6 | set_frequency CLK 12 7 | 8 | # USB 9 | set_io -nowarn USB_P 42 10 | set_io -nowarn USB_N 38 11 | set_io -nowarn USB_DET 37 12 | 13 | # RS232 - pin 0 and 1 on the bitsy1 14 | set_io -nowarn RX 47 15 | set_io -nowarn TX 44 16 | 17 | # LEDs and Button 18 | set_io -nowarn BTN_N 2 19 | set_io -nowarn LEDR_N 25 20 | set_io -nowarn LEDG_N 6 21 | 22 | # RGB LED Driver 23 | set_io -nowarn LED_RED_N 39 24 | set_io -nowarn LED_GRN_N 40 25 | set_io -nowarn LED_BLU_N 41 26 | set_io -nowarn LED_RGB[0] 39 27 | set_io -nowarn LED_RGB[1] 40 28 | set_io -nowarn LED_RGB[2] 41 29 | 30 | # SPI Flash 31 | set_io -nowarn FLASH_SCK 15 32 | set_io -nowarn FLASH_CS 16 33 | set_io -nowarn FLASH_IO0 14 34 | set_io -nowarn FLASH_IO1 17 35 | set_io -nowarn FLASH_IO2 18 36 | set_io -nowarn FLASH_IO3 19 37 | 38 | # Pmod 1 39 | set_io -nowarn P1_1 47 40 | set_io -nowarn P1_2 48 41 | set_io -nowarn P1_3 4 42 | set_io -nowarn P1_4 9 43 | set_io -nowarn P1_7 44 44 | set_io -nowarn P1_8 45 45 | set_io -nowarn P1_9 3 46 | set_io -nowarn P1_10 10 47 | 48 | # Pmod 2 49 | set_io -nowarn P2_1 43 50 | set_io -nowarn P2_2 32 51 | set_io -nowarn P2_3 26 52 | set_io -nowarn P2_4 28 53 | set_io -nowarn P2_7 36 54 | set_io -nowarn P2_8 31 55 | set_io -nowarn P2_9 27 56 | set_io -nowarn P2_10 34 57 | 58 | # Pmod 3 59 | set_io -nowarn P3_1 23 60 | set_io -nowarn P3_2 12 61 | set_io -nowarn P3_3 13 62 | set_io -nowarn P3_4 11 63 | set_io -nowarn P3_7 25 64 | set_io -nowarn P3_8 21 65 | set_io -nowarn P3_9 20 66 | set_io -nowarn P3_10 46 67 | 68 | # Pins 69 | set_io -nowarn P0 47 70 | set_io -nowarn P1 44 71 | set_io -nowarn P2 48 72 | set_io -nowarn P3 45 73 | set_io -nowarn P4 4 74 | set_io -nowarn P5 3 75 | set_io -nowarn P6 9 76 | set_io -nowarn P7 10 77 | set_io -nowarn P8 11 78 | set_io -nowarn P9 12 79 | set_io -nowarn P10 21 80 | set_io -nowarn P11 13 81 | set_io -nowarn P12 20 82 | set_io -nowarn P13 25 83 | set_io -nowarn P14 23 84 | set_io -nowarn P15 27 85 | set_io -nowarn P16 26 86 | set_io -nowarn P17 28 87 | set_io -nowarn P18 31 88 | set_io -nowarn P19 32 89 | set_io -nowarn P20 34 90 | set_io -nowarn P21 36 91 | set_io -nowarn P22 43 92 | set_io -nowarn P23 46 93 | -------------------------------------------------------------------------------- /icebitsy/icebitsy1.pcf: -------------------------------------------------------------------------------- 1 | # 12 MHz clock 2 | set_io -nowarn CLK 35 3 | set_frequency CLK 12 4 | 5 | # USB 6 | set_io -nowarn USB_P 42 7 | set_io -nowarn USB_N 38 8 | set_io -nowarn USB_DET 37 9 | 10 | # RS232 - pin 0 and 1 on the bitsy1 11 | set_io -nowarn RX 47 12 | set_io -nowarn TX 44 13 | 14 | # LEDs and Button 15 | set_io -nowarn BTN_N 2 16 | set_io -nowarn LEDR_N 25 17 | set_io -nowarn LEDG_N 6 18 | 19 | # RGB LED Driver 20 | set_io -nowarn LED_RED_N 39 21 | set_io -nowarn LED_GRN_N 40 22 | set_io -nowarn LED_BLU_N 41 23 | set_io -nowarn LED_RGB[0] 39 24 | set_io -nowarn LED_RGB[1] 40 25 | set_io -nowarn LED_RGB[2] 41 26 | 27 | # SPI Flash 28 | set_io -nowarn FLASH_SCK 15 29 | set_io -nowarn FLASH_CS 16 30 | set_io -nowarn FLASH_IO0 14 31 | set_io -nowarn FLASH_IO1 17 32 | set_io -nowarn FLASH_IO2 18 33 | set_io -nowarn FLASH_IO3 19 34 | 35 | # Pins 36 | set_io -nowarn P0 47 37 | set_io -nowarn P1 44 38 | set_io -nowarn P2 48 39 | set_io -nowarn P3 45 40 | set_io -nowarn P4 4 41 | set_io -nowarn P5 3 42 | set_io -nowarn P6 9 43 | set_io -nowarn P7 10 44 | set_io -nowarn P8 11 45 | set_io -nowarn P9 12 46 | set_io -nowarn P10 21 47 | set_io -nowarn P11 13 48 | set_io -nowarn P12 20 49 | set_io -nowarn P13 25 50 | set_io -nowarn P14 23 51 | set_io -nowarn P15 27 52 | set_io -nowarn P16 26 53 | set_io -nowarn P17 28 54 | set_io -nowarn P18 31 55 | set_io -nowarn P19 32 56 | set_io -nowarn P20 34 57 | set_io -nowarn P21 36 58 | set_io -nowarn P22 43 59 | set_io -nowarn P23 46 60 | -------------------------------------------------------------------------------- /icebitsy/pdm_fade/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 Piotr Esden-Tempski 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /icebitsy/pdm_fade/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = pdm 2 | 3 | ADD_SRC = ../common/dfu_helper.v 4 | PIN_DEF = ../icebitsy1.pcf 5 | DEVICE = up5k 6 | PACKAGE = sg48 7 | 8 | prog: dfuprog 9 | 10 | include ../../main.mk 11 | -------------------------------------------------------------------------------- /icebitsy/pdm_fade/pdm.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - pdm demo 3 | * 4 | * Copyright (C) 2018 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | // This example is based on the PDM module by Tommy Thorn 21 | // You can find him on GitHub as @tommythorn 22 | // The original is here: 23 | // https://github.com/tommythorn/yari/blob/master/shared/rtl/soclib/pdm.v 24 | 25 | // This example generates PDM (Pulse Density Modulation) to fade LEDs 26 | // The intended result is opposite pulsating Red and Green LEDs 27 | // on the iCEBreaker. The intended effect is that the two LED "breathe" in 28 | // brigtness up and down in opposite directions. 29 | 30 | module top ( 31 | inout USB_P, 32 | inout USB_N, 33 | inout USB_DET, 34 | input CLK, 35 | output LEDG_N, 36 | input BTN_N, 37 | output [2:0] LED_RGB, 38 | output P2, // Debug pins 39 | output P3, // 40 | output P4, // 41 | output P5 // 42 | ); 43 | 44 | // Reset to DFU bootloader with a long button press 45 | wire will_reboot; 46 | dfu_helper #( 47 | .BTN_MODE(3) 48 | ) dfu_helper_I ( 49 | .usb_dp (USB_P), 50 | .usb_dn (USB_N), 51 | .usb_pu (USB_DET), 52 | .boot_sel (2'b00), 53 | .boot_now (1'b0), 54 | .btn_in (BTN_N), 55 | .btn_tick (), 56 | .btn_val (), 57 | .btn_press(), 58 | .will_reboot(will_reboot), 59 | .clk (CLK), 60 | .rst (0) 61 | ); 62 | // Indicate when the button was pressed for long enough to trigger a 63 | // reboot into the DFU bootloader. 64 | // (LED turns off when the condition matches) 65 | assign LEDG_N = will_reboot; 66 | 67 | 68 | // PDM generator 69 | /* 70 | * Pulse Density Modulation for controlling LED intensity. 71 | * The theory is as follows: 72 | * given a desired target level 0 <= T <= 1, control the output pdm_out 73 | * in {1,0}, such that pdm_out on average is T. Do this by integrating the 74 | * error T - pdm_out over time and switch pdm_out such that the sum of 75 | * (T - pdm_out) is finite. 76 | * 77 | * pdm_sigma = 0, pdm_out = 0 78 | * forever 79 | * pdm_sigma = pdm_sigma + (T - pdm_out) 80 | * if (pdm_sigma >= 0) 81 | * pdm_out = 1 82 | * else 83 | * pdm_out = 0 84 | * 85 | * Check: T = 0, pdm_out is never turned on; T = 1, pdm_out is always on; 86 | * T = 0.5, pdm_out toggles 87 | * 88 | * In fixed point arithmetic this becomes the following (assume N-bit arith) 89 | * pdm_sigma = pdm_sigma_float * 2^N = pdm_sigma_float << N. 90 | * As |pdm_sigma| <= 1, N+2 bits is sufficient 91 | * 92 | * pdm_sigma = 0, pdm_out = 0 93 | * forever 94 | * D = T + (~pdm_out + 1) << N === T + (pdm_out << N) + (pdm_out << (N+1)) 95 | * pdm_sigma = pdm_sigma + D 96 | * pdm_out = 1 & (pdm_sigma >> (N+1)) 97 | */ 98 | reg [16-1:0] pdm_level = 0; 99 | reg [16+1:0] pdm_sigma; 100 | reg pdm_out; 101 | assign pdm_out = ~pdm_sigma[16+1]; 102 | always @(posedge CLK) begin 103 | pdm_sigma <= pdm_sigma + {pdm_out, pdm_out, pdm_level}; 104 | end 105 | 106 | // PDM level generator 107 | // Fading up and down creating a slow sawtooth output 108 | // The fade up down takes about 11.18 seconds 109 | // Note: You will see that the LEDs spend more time being very bright 110 | // than visibly fading, this is because our vision is non linear. Take a look 111 | // at the pwm_fade_gamma example that fixes this issue. :) 112 | reg [13:0] pdm_inc_counter = 0; 113 | reg [16-2:0] pdm_level_value; 114 | reg pdm_dir = 1; 115 | always @(posedge CLK) begin 116 | // Divide clock by 8192 117 | pdm_inc_counter <= pdm_inc_counter + 1; 118 | 119 | // increment/decrement pdm value at 1.5kHz 120 | if (pdm_inc_counter[13]) begin 121 | pdm_inc_counter <= 0; 122 | pdm_level_value <= pdm_level_value + 1; 123 | end 124 | 125 | if (pdm_level_value[16-2]) 126 | pdm_level <= ~pdm_level_value << 2; 127 | else 128 | pdm_level <= pdm_level_value << 2; 129 | end 130 | 131 | SB_RGBA_DRV #( 132 | .CURRENT_MODE("0b1"), // 0: Normal; 1: Half 133 | // Set current to: 4mA 134 | // According to the datasheet the only accepted values are: 135 | // 0b000001, 0b000011, 0b000111, 0b001111, 0b011111, 0b111111 136 | // Each enabled bit increases the current by 4mA in normal CURRENT_MODE 137 | // and 2mA in half CURRENT_MODE. 138 | .RGB0_CURRENT("0b000001"), 139 | .RGB1_CURRENT("0b000001"), 140 | .RGB2_CURRENT("0b000001") 141 | ) rgb_drv_I ( 142 | .RGBLEDEN(1'b1), // Global ON/OFF control 143 | .RGB0PWM(~pdm_out), // Single ON/OFF control that can accept PWM input 144 | .RGB1PWM(1'b0), 145 | .RGB2PWM(pdm_out), 146 | .CURREN(1'b1), // Enable current reference 147 | .RGB0(LED_RGB[0]), 148 | .RGB1(LED_RGB[1]), 149 | .RGB2(LED_RGB[2]) 150 | ); 151 | 152 | assign P2 = pdm_inc_counter[15]; // 50% duty cycle PDM inc clock 153 | assign P3 = pdm_out; // PDM output on a GPIO pin 154 | assign P4 = pdm_inc_counter[15]; // 50% duty cycle PDM inc clock 155 | assign P5 = pdm_out; // PDM output on a GPIO pin 156 | 157 | endmodule 158 | -------------------------------------------------------------------------------- /icebitsy/pdm_fade_gamma/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.hex 3 | gen_gamma_table 4 | -------------------------------------------------------------------------------- /icebitsy/pdm_fade_gamma/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 Piotr Esden-Tempski 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /icebitsy/pdm_fade_gamma/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = gamma_pdm 2 | ADD_DEPS = gamma_table.hex 3 | ADD_CLEAN = *.o gen_gamma_table *.hex 4 | 5 | ADD_SRC = ../common/dfu_helper.v 6 | PIN_DEF = ../icebitsy1.pcf 7 | DEVICE = up5k 8 | PACKAGE = sg48 9 | 10 | prog: dfuprog 11 | 12 | include ../../main.mk 13 | 14 | gen_gamma_table: gen_gamma_table.o 15 | gcc $< -o $@ -lm 16 | 17 | gamma_table.hex: gen_gamma_table 18 | ./gen_gamma_table > gamma_table.hex 19 | -------------------------------------------------------------------------------- /icebitsy/pdm_fade_gamma/gamma_pdm.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - pdm demo 3 | * 4 | * Copyright (C) 2018 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | // This example is based on the PDM module by Tommy Thorn 21 | // You can find him on GitHub as @tommythorn 22 | // The original is here: 23 | // https://github.com/tommythorn/yari/blob/master/shared/rtl/soclib/pdm.v 24 | 25 | // This example generates PDM (Pulse Density Modulation) to fade LEDs 26 | // The intended result is opposite pulsating Red and Green LEDs 27 | // on the iCEBreaker. The intended effect is that the two LED "breathe" in 28 | // brigtness up and down in opposite directions. 29 | 30 | module top ( 31 | inout USB_P, 32 | inout USB_N, 33 | inout USB_DET, 34 | input CLK, 35 | output LEDG_N, 36 | input BTN_N, 37 | output [2:0] LED_RGB, 38 | output P2, // Debug pins 39 | output P3, // 40 | output P4, // 41 | output P5, // 42 | output P6, // 43 | output P7 // 44 | ); 45 | 46 | // Reset to DFU bootloader with a long button press 47 | wire will_reboot; 48 | dfu_helper #( 49 | .BTN_MODE(3) 50 | ) dfu_helper_I ( 51 | .usb_dp (USB_P), 52 | .usb_dn (USB_N), 53 | .usb_pu (USB_DET), 54 | .boot_sel (2'b00), 55 | .boot_now (1'b0), 56 | .btn_in (BTN_N), 57 | .btn_tick (), 58 | .btn_val (), 59 | .btn_press(), 60 | .will_reboot(will_reboot), 61 | .clk (CLK), 62 | .rst (0) 63 | ); 64 | // Indicate when the button was pressed for long enough to trigger a 65 | // reboot into the DFU bootloader. 66 | // (LED turns off when the condition matches) 67 | assign LEDG_N = will_reboot; 68 | 69 | 70 | // Gamma value lookup table parameters 71 | parameter G_PW = 8; // Number of input bits 72 | parameter G_OW = 16; // Number of output bits 73 | 74 | // Load the gamma value lookup table 75 | reg [(G_OW-1):0] gamma_lut [0:((1<<(G_PW))-1)]; 76 | initial $readmemh("gamma_table.hex", gamma_lut); 77 | 78 | // PDM generator 79 | /* 80 | * Pulse Density Modulation for controlling LED intensity. 81 | * The theory is as follows: 82 | * given a desired target level 0 <= T <= 1, control the output pdm_out 83 | * in {1,0}, such that pdm_out on average is T. Do this by integrating the 84 | * error T - pdm_out over time and switch pdm_out such that the sum of 85 | * (T - pdm_out) is finite. 86 | * 87 | * pdm_sigma = 0, pdm_out = 0 88 | * forever 89 | * pdm_sigma = pdm_sigma + (T - pdm_out) 90 | * if (pdm_sigma >= 0) 91 | * pdm_out = 1 92 | * else 93 | * pdm_out = 0 94 | * 95 | * Check: T = 0, pdm_out is never turned on; T = 1, pdm_out is olways on; 96 | * T = 0.5, pdm_out toggles 97 | * 98 | * In fixed point arithmetic this becomes the following (assume N-bit arith) 99 | * pdm_sigma = pdm_sigma_float * 2^N = pdm_sigma_float << N. 100 | * As |pdm_sigma| <= 1, N+2 bits is sufficient 101 | * 102 | * pdm_sigma = 0, pdm_out = 0 103 | * forever 104 | * D = T + (~pdm_out + 1) << N === T + (pdm_out << N) + (pdm_out << (N+1)) 105 | * pdm_sigma = pdm_sigma + D 106 | * pdm_out = 1 & (pdm_sigma >> (N+1)) 107 | */ 108 | reg [G_OW-1:0] pdm_level1; 109 | reg [G_OW+1:0] pdm_sigma1; 110 | reg pdm_out1; 111 | assign pdm_out1 = ~pdm_sigma1[G_OW+1]; 112 | always @(posedge CLK) begin 113 | pdm_sigma1 <= pdm_sigma1 + {pdm_out1, pdm_out1, pdm_level1}; 114 | end 115 | 116 | reg [G_OW-1:0] pdm_level2; 117 | reg [G_OW+1:0] pdm_sigma2; 118 | reg pdm_out2; 119 | assign pdm_out2 = ~pdm_sigma2[G_OW+1]; 120 | always @(posedge CLK) begin 121 | pdm_sigma2 <= pdm_sigma2 + {pdm_out2, pdm_out2, pdm_level2}; 122 | end 123 | 124 | // PDM level generator 125 | // Fading up and down creating a slow sawtooth output 126 | // The fade up down takes about 11.18 seconds 127 | // Note: You will see that the LEDs spend more time being very bright 128 | // than visibly fading, this is because our vision is non linear. Take a look 129 | // at the pwm_fade_gamma example that fixes this issue. :) 130 | reg [17:0] pdm_inc_counter = 0; 131 | reg [G_PW-1+1:0] pdm_level_value; 132 | reg [G_OW-1:0] pdm_gamma_level_p; 133 | reg [G_OW-1:0] pdm_gamma_level_n; 134 | always @(posedge CLK) begin 135 | // Divide clock by 131071 136 | pdm_inc_counter <= pdm_inc_counter + 1; 137 | 138 | // increment/decrement pwm compare value at 91.55Hz 139 | if (pdm_inc_counter[17]) begin 140 | pdm_inc_counter <= 0; 141 | pdm_level_value <= pdm_level_value + 1; 142 | end 143 | 144 | pdm_gamma_level_p <= gamma_lut[ pdm_level_value[G_PW-1:0]]; 145 | pdm_gamma_level_n <= gamma_lut[~pdm_level_value[G_PW-1:0]]; 146 | end 147 | 148 | assign pdm_level1 = pdm_level_value[G_PW-1+1] ? pdm_gamma_level_n : pdm_gamma_level_p; 149 | assign pdm_level2 = pdm_level_value[G_PW-1+1] ? pdm_gamma_level_p : pdm_gamma_level_n; 150 | 151 | SB_RGBA_DRV #( 152 | .CURRENT_MODE("0b1"), // 0: Normal; 1: Half 153 | // Set current to: 4mA 154 | // According to the datasheet the only accepted values are: 155 | // 0b000001, 0b000011, 0b000111, 0b001111, 0b011111, 0b111111 156 | // Each enabled bit increases the current by 4mA in normal CURRENT_MODE 157 | // and 2mA in half CURRENT_MODE. 158 | .RGB0_CURRENT("0b000001"), 159 | .RGB1_CURRENT("0b000001"), 160 | .RGB2_CURRENT("0b000001") 161 | ) rgb_drv_I ( 162 | .RGBLEDEN(1'b1), // Global ON/OFF control 163 | .RGB0PWM(pdm_out1), // Single ON/OFF control that can accept PWM input 164 | .RGB1PWM(1'b0), 165 | .RGB2PWM(pdm_out2), 166 | .CURREN(1'b1), // Enable current reference 167 | .RGB0(LED_RGB[0]), 168 | .RGB1(LED_RGB[1]), 169 | .RGB2(LED_RGB[2]) 170 | ); 171 | 172 | assign P2 = pdm_inc_counter[15]; // 50% duty cycle PDM inc clock 173 | assign P3 = pdm_out1; // PDM output on a GPIO pin 174 | assign P4 = pdm_out2; // PDM output on a GPIO pin 175 | assign P5 = pdm_inc_counter[15]; // 50% duty cycle PDM inc clock 176 | assign P6 = pdm_out1; // PDM output on a GPIO pin 177 | assign P7 = pdm_out2; // PDM output on a GPIO pin 178 | 179 | endmodule 180 | -------------------------------------------------------------------------------- /icebitsy/pdm_fade_gamma/gen_gamma_table.c: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - gamma pwm demo 3 | * 4 | * Copyright (C) 2018 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | // This program generates a gamma correction table. This table is then loaded 21 | // into bram of the FPGA to provide a lookup table. 22 | 23 | #include 24 | #include 25 | 26 | #define GAMMA 2.2 27 | 28 | int main() 29 | { 30 | fprintf(stderr, "Generating the gamma lookup table.\n"); 31 | 32 | for (int i = 0; i < 256; i++) { 33 | double dvalue = pow((1.0 / 255.0) * i, GAMMA); 34 | long lvalue = 0xFFFFl * dvalue; 35 | 36 | fprintf(stderr, "."); 37 | 38 | if ((i % 8) == 0) { 39 | printf("@%08x", i); 40 | } 41 | printf(" %04lX", lvalue); 42 | //printf("%f\n", value); 43 | //printf("%5i | %f\n", i, value); 44 | if ((i % 8) == 7) { 45 | printf("\n"); 46 | } 47 | } 48 | 49 | fprintf(stderr, "\ndone\n"); 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /icebitsy/pwm_fade/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 Piotr Esden-Tempski 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /icebitsy/pwm_fade/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = pwm 2 | 3 | ADD_SRC = ../common/dfu_helper.v 4 | PIN_DEF = ../icebitsy1.pcf 5 | DEVICE = up5k 6 | PACKAGE = sg48 7 | 8 | prog: dfuprog 9 | 10 | include ../../main.mk 11 | -------------------------------------------------------------------------------- /icebitsy/pwm_fade/pwm.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - pwm demo 3 | * 4 | * Copyright (C) 2018 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | // This example generates PWM to fade LEDs 21 | // The intended result is opposite pulsating Red and Blue LEDs 22 | // on the iCEBreaker-bitsy. The intended effect is that the two LEDs 23 | // "breathe" in brigtness up and down in opposite directions. 24 | 25 | module top ( 26 | inout USB_P, 27 | inout USB_N, 28 | inout USB_DET, 29 | input CLK, 30 | output LEDG_N, 31 | input BTN_N, 32 | output [2:0] LED_RGB, 33 | output P2, // Debug pins 34 | output P3 // 35 | ); 36 | 37 | // Reset to DFU bootloader with a long button press 38 | wire will_reboot; 39 | dfu_helper #( 40 | .BTN_MODE(3) 41 | ) dfu_helper_I ( 42 | .usb_dp (USB_P), 43 | .usb_dn (USB_N), 44 | .usb_pu (USB_DET), 45 | .boot_sel (2'b00), 46 | .boot_now (1'b0), 47 | .btn_in (BTN_N), 48 | .btn_tick (), 49 | .btn_val (), 50 | .btn_press(), 51 | .will_reboot(will_reboot), 52 | .clk (CLK), 53 | .rst (0) 54 | ); 55 | // Indicate when the button was pressed for long enough to trigger a 56 | // reboot into the DFU bootloader. 57 | // (LED turns off when the condition matches) 58 | assign LEDG_N = will_reboot; 59 | 60 | // PWM generator 61 | reg [15:0] pwm_counter = 0; 62 | reg [15:0] pwm_compare = 256; 63 | reg pwm_out; 64 | always @(posedge CLK) begin 65 | // Divide clock by 65535 66 | // Results in a 183.11Hz PWM 67 | pwm_counter <= pwm_counter + 1; 68 | 69 | // Set pwm output according to the compare 70 | // Set output high when the counter is smaller than the compare value 71 | // Set output low when the counter is equal or higher than the compare 72 | // value 73 | if (pwm_counter < pwm_compare) begin 74 | pwm_out <= 1; 75 | end else begin 76 | pwm_out <= 0; 77 | end 78 | end 79 | 80 | // PWM compare generator 81 | // Fading up and down creating a slow sawtooth output 82 | // The fade up down takes about 11.18 seconds 83 | // Note: You will see that the LEDs spend more time being very bright 84 | // than visibly fading, this is because our vision is non linear. Take a look 85 | // at the pwm_fade_gamma example that fixes this issue. :) 86 | reg [17:0] pwm_inc_counter = 0; 87 | reg [16-7:0] pwm_compare_value = 0; 88 | always @(posedge CLK) begin 89 | // Divide clock by 131071 90 | pwm_inc_counter <= pwm_inc_counter + 1; 91 | 92 | // increment/decrement pwm compare value at 91.55Hz 93 | if (pwm_inc_counter[17]) begin 94 | pwm_compare_value <= pwm_compare_value + 1; 95 | pwm_inc_counter <= 0; 96 | end 97 | 98 | if (pwm_compare_value[16-7]) 99 | pwm_compare <= ~pwm_compare_value << 7; 100 | else 101 | pwm_compare <= pwm_compare_value << 7; 102 | end 103 | 104 | SB_RGBA_DRV #( 105 | .CURRENT_MODE("0b1"), // 0: Normal; 1: Half 106 | // Set current to: 4mA 107 | // According to the datasheet the only accepted values are: 108 | // 0b000001, 0b000011, 0b000111, 0b001111, 0b011111, 0b111111 109 | // Each enabled bit increases the current by 4mA in normal CURRENT_MODE 110 | // and 2mA in half CURRENT_MODE. 111 | .RGB0_CURRENT("0b000001"), 112 | .RGB1_CURRENT("0b000001"), 113 | .RGB2_CURRENT("0b000001") 114 | ) rgb_drv_I ( 115 | .RGBLEDEN(1'b1), // Global ON/OFF control 116 | .RGB0PWM(~pwm_out), // Single ON/OFF control that can accept PWM input 117 | .RGB1PWM(1'b0), 118 | .RGB2PWM(pwm_out), 119 | .CURREN(1'b1), // Enable current reference 120 | .RGB0(LED_RGB[0]), 121 | .RGB1(LED_RGB[1]), 122 | .RGB2(LED_RGB[2]) 123 | ); 124 | 125 | assign P2 = pwm_counter[15]; // 50% duty cycle PWM clock out 126 | assign P3 = pwm_out; // PWM output on a GPIO pin 127 | 128 | endmodule 129 | -------------------------------------------------------------------------------- /icebitsy/pwm_fade_gamma/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.hex 3 | gen_gamma_table 4 | -------------------------------------------------------------------------------- /icebitsy/pwm_fade_gamma/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 Piotr Esden-Tempski 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /icebitsy/pwm_fade_gamma/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = gamma_pwm 2 | ADD_DEPS = gamma_table.hex 3 | ADD_CLEAN = *.o gen_gamma_table *.hex 4 | 5 | ADD_SRC = ../common/dfu_helper.v 6 | PIN_DEF = ../icebitsy1.pcf 7 | DEVICE = up5k 8 | PACKAGE = sg48 9 | 10 | prog: dfuprog 11 | 12 | include ../../main.mk 13 | 14 | gen_gamma_table: gen_gamma_table.o 15 | gcc $< -o $@ -lm 16 | 17 | gamma_table.hex: gen_gamma_table 18 | ./gen_gamma_table > gamma_table.hex 19 | -------------------------------------------------------------------------------- /icebitsy/pwm_fade_gamma/gamma_pwm.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - gamma pwm demo 3 | * 4 | * Copyright (C) 2018 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | // This example generates PWM with gamma correction 21 | // The intended result is opposite pulsating Red and Green LEDs 22 | // on the iCEBreaker. The intended effect is that the two LED "breathe" evenly 23 | // and don't stay at a perceptable brightness level longer than others. 24 | // 25 | // For more information about gamma correction: 26 | // https://en.wikipedia.org/wiki/Gamma_correction 27 | 28 | module top ( 29 | inout USB_P, 30 | inout USB_N, 31 | inout USB_DET, 32 | input CLK, 33 | output LEDG_N, 34 | input BTN_N, 35 | output [2:0] LED_RGB, 36 | output P2, // Debug pins 37 | output P3, // 38 | output P4 // 39 | ); 40 | 41 | // Reset to DFU bootloader with a long button press 42 | wire will_reboot; 43 | dfu_helper #( 44 | .BTN_MODE(3) 45 | ) dfu_helper_I ( 46 | .usb_dp (USB_P), 47 | .usb_dn (USB_N), 48 | .usb_pu (USB_DET), 49 | .boot_sel (2'b00), 50 | .boot_now (1'b0), 51 | .btn_in (BTN_N), 52 | .btn_tick (), 53 | .btn_val (), 54 | .btn_press(), 55 | .will_reboot(will_reboot), 56 | .clk (CLK), 57 | .rst (0) 58 | ); 59 | // Indicate when the button was pressed for long enough to trigger a 60 | // reboot into the DFU bootloader. 61 | // (LED turns off when the condition matches) 62 | assign LEDG_N = will_reboot; 63 | 64 | // Gamma value lookup table parameters 65 | parameter G_PW = 8; // Number of input bits 66 | parameter G_OW = 16; // Number of output bits 67 | 68 | // Load the gamma value lookup table 69 | reg [(G_OW-1):0] gamma_lut [0:((1<<(G_PW))-1)]; 70 | initial $readmemh("gamma_table.hex", gamma_lut); 71 | 72 | // Very simple dual output PWM generator 73 | // We need two outputs as we can't just invert the gamma corrected PWM output, 74 | // as this would also invert the gamma curve. 75 | reg [15:0] pwm_counter = 0; 76 | reg [15:0] pwm_compare_0; 77 | reg [15:0] pwm_compare_1; 78 | reg pwm_out_0; 79 | reg pwm_out_1; 80 | always @(posedge CLK) begin 81 | pwm_counter <= pwm_counter + 1; 82 | 83 | if (pwm_counter < pwm_compare_0) begin 84 | pwm_out_0 <= 1; 85 | end else begin 86 | pwm_out_0 <= 0; 87 | end 88 | 89 | if (pwm_counter < pwm_compare_1) begin 90 | pwm_out_1 <= 1; 91 | end else begin 92 | pwm_out_1 <= 0; 93 | end 94 | end 95 | 96 | // PWM compare value generator 97 | // Fade through the values using the gamma correction 98 | reg [17:0] pwm_inc_counter = 0; 99 | reg [G_PW:0] pwm_value = 0; 100 | always @(posedge CLK) begin 101 | // Divide clock by 131071 102 | pwm_inc_counter <= pwm_inc_counter + 1; 103 | 104 | // increment/decrement the index 105 | if (pwm_inc_counter[17]) begin 106 | pwm_inc_counter <= 0; 107 | pwm_value <= pwm_value + 1; 108 | end 109 | 110 | // Assign the compare value 111 | // The MSB bit of pwm_value determines the direction of the count 112 | // It is less expensive on an FPGA than doing an up down counter with dir variable 113 | pwm_compare_0 <= gamma_lut[pwm_value[G_PW] ? pwm_value[G_PW-1:0] : ~pwm_value[G_PW-1:0]]; 114 | pwm_compare_1 <= gamma_lut[pwm_value[G_PW] ? ~pwm_value[G_PW-1:0] : pwm_value[G_PW-1:0]]; 115 | end 116 | 117 | SB_RGBA_DRV #( 118 | .CURRENT_MODE("0b1"), // 0: Normal; 1: Half 119 | // Set current to: 4mA 120 | // According to the datasheet the only accepted values are: 121 | // 0b000001, 0b000011, 0b000111, 0b001111, 0b011111, 0b111111 122 | // Each enabled bit increases the current by 4mA in normal CURRENT_MODE 123 | // and 2mA in half CURRENT_MODE. 124 | .RGB0_CURRENT("0b000001"), 125 | .RGB1_CURRENT("0b000001"), 126 | .RGB2_CURRENT("0b000001") 127 | ) rgb_drv_I ( 128 | .RGBLEDEN(1'b1), // Global ON/OFF control 129 | .RGB0PWM(pwm_out_0), // Single ON/OFF control that can accept PWM input 130 | .RGB1PWM(1'b0), 131 | .RGB2PWM(pwm_out_1), 132 | .CURREN(1'b1), // Enable current reference 133 | .RGB0(LED_RGB[0]), 134 | .RGB1(LED_RGB[1]), 135 | .RGB2(LED_RGB[2]) 136 | ); 137 | 138 | assign P2 = pwm_counter[15]; 139 | assign P3 = pwm_out_0; 140 | assign P4 = pwm_out_1; 141 | 142 | endmodule 143 | -------------------------------------------------------------------------------- /icebitsy/pwm_fade_gamma/gen_gamma_table.c: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - gamma pwm demo 3 | * 4 | * Copyright (C) 2018 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | // This program generates a gamma correction table. This table is then loaded 21 | // into bram of the FPGA to provide a lookup table. 22 | 23 | #include 24 | #include 25 | 26 | #define GAMMA 2.2 27 | 28 | int main() 29 | { 30 | fprintf(stderr, "Generating the gamma lookup table.\n"); 31 | 32 | for (int i = 0; i < 256; i++) { 33 | double dvalue = pow((1.0 / 255.0) * i, GAMMA); 34 | long lvalue = 0xFFFFl * dvalue; 35 | 36 | fprintf(stderr, "."); 37 | 38 | if ((i % 8) == 0) { 39 | printf("@%08x", i); 40 | } 41 | printf(" %04lX", lvalue); 42 | //printf("%f\n", value); 43 | //printf("%5i | %f\n", i, value); 44 | if ((i % 8) == 7) { 45 | printf("\n"); 46 | } 47 | } 48 | 49 | fprintf(stderr, "\ndone\n"); 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /icebitsy/sb_rgba_blink/LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /icebitsy/sb_rgba_blink/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = blink 2 | 3 | ADD_SRC = ../common/dfu_helper.v 4 | PIN_DEF = ../icebitsy1.pcf 5 | DEVICE = up5k 6 | PACKAGE = sg48 7 | 8 | prog: dfuprog 9 | 10 | include ../../main.mk 11 | -------------------------------------------------------------------------------- /icebitsy/sb_rgba_blink/blink.v: -------------------------------------------------------------------------------- 1 | /* 2 | * blink.v 3 | * 4 | * CC0 1.0 Universal - See LICENSE in this directory 5 | * 6 | * Copyright (C) 2018 Sylvain Munaut 7 | * 8 | * vim: ts=4 sw=4 9 | */ 10 | 11 | `default_nettype none 12 | 13 | module top ( 14 | inout wire USB_P, 15 | inout wire USB_N, 16 | inout wire USB_DET, 17 | output wire [2:0] LED_RGB, 18 | input wire BTN_N, 19 | output wire LEDG_N, 20 | ); 21 | 22 | reg [27:0] cnt; 23 | wire rgb_pwm[2:0]; 24 | wire clk; 25 | 26 | // Instantiate the internal oscillator 27 | // 48MHz 28 | SB_HFOSC osc_I ( 29 | .CLKHFPU(1'b1), 30 | .CLKHFEN(1'b1), 31 | .CLKHF(clk) 32 | ); 33 | 34 | // Reset to DFU bootloader with a long button press 35 | wire will_reboot; 36 | dfu_helper #( 37 | .BTN_MODE(3), 38 | .LONG_TW(19) 39 | ) dfu_helper_I ( 40 | .usb_dp (USB_P), 41 | .usb_dn (USB_N), 42 | .usb_pu (USB_DET), 43 | .boot_sel (2'b00), 44 | .boot_now (1'b0), 45 | .btn_in (BTN_N), 46 | .btn_tick (), 47 | .btn_val (), 48 | .btn_press(), 49 | .will_reboot(will_reboot), 50 | .clk (clk), 51 | .rst (0) 52 | ); 53 | // Indicate when the button was pressed for long enough to trigger a 54 | // reboot into the DFU bootloader. 55 | // (LED turns off when the condition matches) 56 | assign LEDG_N = will_reboot; 57 | 58 | // Upcount the counter ;) 59 | always @(posedge clk) 60 | cnt <= cnt + 1; 61 | 62 | // Generate PWM for each RGB led depending on the status of counter bits 63 | // cnt[27:25]. When the corresponding cnt bit is high generate a PWM where 64 | // PWM signal is high when cnt[2:0] is equal to 0 and low when it is not 65 | // equal to 0. This results in a PWM duty cycle of 1/8. 66 | assign rgb_pwm[0] = cnt[27] & (cnt[2:0] == 3'b000); 67 | assign rgb_pwm[1] = cnt[26] & (cnt[2:0] == 3'b000); 68 | assign rgb_pwm[2] = cnt[25] & (cnt[2:0] == 3'b000); 69 | 70 | SB_RGBA_DRV #( 71 | .CURRENT_MODE("0b1"), // 0: Normal; 1: Half 72 | // Set current to: 4mA 73 | // According to the datasheet the only accepted values are: 74 | // 0b000001, 0b000011, 0b000111, 0b001111, 0b011111, 0b111111 75 | // Each enabled bit increases the current by 4mA in normal CURRENT_MODE 76 | // and 2mA in half CURRENT_MODE. 77 | .RGB0_CURRENT("0b000001"), 78 | .RGB1_CURRENT("0b000001"), 79 | .RGB2_CURRENT("0b000001") 80 | ) rgb_drv_I ( 81 | .RGBLEDEN(1'b1), // Global ON/OFF control 82 | .RGB0PWM(rgb_pwm[0]), // Single ON/OFF control that can accept PWM input 83 | .RGB1PWM(rgb_pwm[1]), 84 | .RGB2PWM(rgb_pwm[2]), 85 | .CURREN(1'b1), // Enable current reference 86 | .RGB0(LED_RGB[0]), 87 | .RGB1(LED_RGB[1]), 88 | .RGB2(LED_RGB[2]) 89 | ); 90 | 91 | endmodule // blink 92 | 93 | -------------------------------------------------------------------------------- /icebreaker/7seg_count/7seg_count.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | 3 | // Attach 7 segment display PMOD to Icebreaker PMOD1A port. 4 | 5 | module top( 6 | input CLK, 7 | output P1A1, 8 | output P1A2, 9 | output P1A3, 10 | output P1A4, 11 | output P1A7, 12 | output P1A8, 13 | output P1A9, 14 | output P1A10 15 | ); 16 | 17 | // Wiring external pins. 18 | reg [6:0] seg_pins_n; 19 | reg digit_sel; 20 | assign {P1A9, P1A8, P1A7, P1A4, P1A3, P1A2, P1A1} = seg_pins_n; 21 | assign P1A10 = digit_sel; 22 | 23 | // counter increments at CLK = 12 MHz. 24 | // ones digit increments at ~6Hz. 25 | // display refreshes at 375 KHz. 26 | reg [29:0] counter; 27 | wire [3:0] ones = counter[21+:4]; 28 | wire [3:0] tens = counter[25+:4]; 29 | wire [2:0] display_state = counter[2+:3]; 30 | 31 | reg [6:0] ones_segments; 32 | reg [6:0] tens_segments; 33 | 34 | digit_to_segments ones2segs(CLK, ones, ones_segments); 35 | digit_to_segments tens2segs(CLK, tens, tens_segments); 36 | 37 | always @(posedge CLK) begin 38 | counter <= counter + 1; 39 | 40 | // Switch seg_pins_n off during digit_sel transitions 41 | // to prevent flicker. Each digit has 25% duty cycle. 42 | case (display_state) 43 | 0, 1: seg_pins_n <= ~ones_segments; 44 | 2: seg_pins_n <= ~0; 45 | 3: digit_sel <= 0; 46 | 4, 5: seg_pins_n <= ~tens_segments; 47 | 6: seg_pins_n <= ~0; 48 | 7: digit_sel <= 1; 49 | endcase 50 | end 51 | 52 | endmodule // top 53 | 54 | // Get the segments to illuminate to display a single hex digit. 55 | // N.B., This is positive logic. Display needs negative. 56 | module digit_to_segments(input clk, 57 | input [3:0] digit, 58 | output reg[6:0] segments 59 | ); 60 | always @(posedge clk) 61 | case (digit) 62 | 0: segments <= 7'b0111111; 63 | 1: segments <= 7'b0000110; 64 | 2: segments <= 7'b1011011; 65 | 3: segments <= 7'b1001111; 66 | 4: segments <= 7'b1100110; 67 | 5: segments <= 7'b1101101; 68 | 6: segments <= 7'b1111101; 69 | 7: segments <= 7'b0000111; 70 | 8: segments <= 7'b1111111; 71 | 9: segments <= 7'b1101111; 72 | 4'hA: segments <= 7'b1110111; 73 | 4'hB: segments <= 7'b1111100; 74 | 4'hC: segments <= 7'b0111001; 75 | 4'hD: segments <= 7'b1011110; 76 | 4'hE: segments <= 7'b1111001; 77 | 4'hF: segments <= 7'b1110001; 78 | endcase 79 | 80 | endmodule 81 | -------------------------------------------------------------------------------- /icebreaker/7seg_count/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = 7seg_count 2 | 3 | PIN_DEF = ../icebreaker.pcf 4 | DEVICE = up5k 5 | PACKAGE = sg48 6 | 7 | prog: iceprog 8 | 9 | include ../../main.mk 10 | -------------------------------------------------------------------------------- /icebreaker/Makefile: -------------------------------------------------------------------------------- 1 | Q := @ 2 | EXAMPLE_DIRS := $(sort $(dir $(wildcard */Makefile))) 3 | 4 | all: $(EXAMPLE_DIRS) 5 | $(Q)true 6 | 7 | clean: $(EXAMPLE_DIRS:=.clean) 8 | $(Q)true 9 | 10 | $(EXAMPLE_DIRS): 11 | @printf " BUILD $@\n"; 12 | $(Q)$(MAKE) --directory=$@ 13 | 14 | %.clean: 15 | @printf " CLEAN $*\n"; 16 | $(Q)$(MAKE) --directory=$* clean 17 | 18 | .PHONY: $(EXAMPLE_DIRS) clean -------------------------------------------------------------------------------- /icebreaker/blink_count_shift/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = blink_count_shift 2 | 3 | PIN_DEF = ../icebreaker.pcf 4 | DEVICE = up5k 5 | PACKAGE = sg48 6 | 7 | prog: iceprog 8 | 9 | include ../../main.mk 10 | -------------------------------------------------------------------------------- /icebreaker/blink_count_shift/README.md: -------------------------------------------------------------------------------- 1 | Simple example testing all the LED, Buttons and PMOD IO on the iCEBreaker FPGA board. 2 | 3 | This example consists of three parts. 4 | 5 | ## Part 1 6 | 7 | Binary counter displayed on the cluster of 5 LED found on the default PMOD of 8 | the full iCEBreaker board. The LSB is the center red LED and the higher 9 | significant bits are formed by the four green LEDs surrounding. 10 | 11 | ## Part 2 12 | 13 | The count of depressed buttons on the main board and the default PMOD are displayed in binary on the two LEDs mounted on the main board. 14 | 15 | ## Part 3 16 | The remaining PMOD 1A and 1B are combined into a 16bit shiftregister and a 1 bit is continously shifted through the outputs. 17 | -------------------------------------------------------------------------------- /icebreaker/blink_count_shift/blink_count_shift.v: -------------------------------------------------------------------------------- 1 | /* Small test design actuating all IO on the iCEBreaker dev board. */ 2 | 3 | module top ( 4 | input CLK, 5 | 6 | output LED1, 7 | output LED2, 8 | output LED3, 9 | output LED4, 10 | output LED5, 11 | 12 | input BTN_N, 13 | input BTN1, 14 | input BTN2, 15 | input BTN3, 16 | 17 | output LEDR_N, 18 | output LEDG_N, 19 | 20 | output P1A1, P1A2, P1A3, P1A4, P1A7, P1A8, P1A9, P1A10, 21 | output P1B1, P1B2, P1B3, P1B4, P1B7, P1B8, P1B9, P1B10 22 | ); 23 | 24 | localparam BITS = 5; 25 | localparam LOG2DELAY = 22; 26 | 27 | reg [BITS+LOG2DELAY-1:0] counter = 0; 28 | reg [BITS-1:0] outcnt; 29 | 30 | always @(posedge CLK) begin 31 | counter <= counter + 1; 32 | outcnt <= counter >> LOG2DELAY; 33 | end 34 | 35 | assign {LED1, LED2, LED3, LED4, LED5} = outcnt ^ (outcnt >> 1); 36 | 37 | assign {LEDR_N, LEDG_N} = ~(!BTN_N + BTN1 + BTN2 + BTN3); 38 | 39 | assign {P1A1, P1A2, P1A3, P1A4, P1A7, P1A8, P1A9, P1A10, 40 | P1B1, P1B2, P1B3, P1B4, P1B7, P1B8, P1B9, P1B10} = 1 << (outcnt & 15); 41 | endmodule 42 | -------------------------------------------------------------------------------- /icebreaker/charlieplexing-tomk/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = pmodcharlie 2 | 3 | PIN_DEF = ../icebreaker.pcf 4 | DEVICE = up5k 5 | PACKAGE = sg48 6 | 7 | prog: iceprog 8 | 9 | include ../../main.mk 10 | -------------------------------------------------------------------------------- /icebreaker/charlieplexing-tomk/README.md: -------------------------------------------------------------------------------- 1 | # Charlieplexing 2 | 3 | This example controls the Pmod™ 8-digit 7-segment display ([Blog article](https://www.twam.info/electronics/7-segment-charlieplexing), [Schematic](https://github.com/twam/Pmod7Segment)) using [Charlieplexing](https://en.wikipedia.org/wiki/Charlieplexing). The time since start up is counted and displayed milliseconds in hex. -------------------------------------------------------------------------------- /icebreaker/charlieplexing-tomk/pmodcharlie.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module top( 4 | input CLK, 5 | output P2_1, P2_2, P2_3, P2_4, P2_7, P2_8, P2_9, P2_10 6 | ); 7 | 8 | localparam CLK_FREQUENCY = 12E6; 9 | localparam COUNTER_MAX = $rtoi(CLK_FREQUENCY/1000); 10 | 11 | wire [7:0] pmodmap; 12 | reg [31:0] milliseconds = 0; 13 | reg [$clog2(COUNTER_MAX)-1:0] counter; 14 | 15 | // Count milliseconds 16 | always @(posedge CLK) 17 | begin 18 | if (counter < COUNTER_MAX) 19 | counter <= counter + 1; 20 | else 21 | begin 22 | counter <= 0; 23 | milliseconds <= milliseconds + 1; 24 | end 25 | end 26 | 27 | // map output pins of pmodcharlie module to pins on iCEBreaker 28 | assign pmodmap[0] = P2_1; 29 | assign pmodmap[1] = P2_2; 30 | assign pmodmap[2] = P2_3; 31 | assign pmodmap[3] = P2_4; 32 | assign pmodmap[4] = P2_7; 33 | assign pmodmap[5] = P2_8; 34 | assign pmodmap[6] = P2_9; 35 | assign pmodmap[7] = P2_10; 36 | 37 | pmodcharlie pmodCharlieA( 38 | .clk(CLK), 39 | .pins(pmodmap), 40 | .display_data(milliseconds) 41 | ); 42 | 43 | endmodule 44 | 45 | module pmodcharlie 46 | #( 47 | parameter CLK_FREQUENCY = 12E6, 48 | parameter DISPLAY_FREQUENCY = 1E3 49 | ) 50 | ( 51 | input wire clk, 52 | input wire [31:0] display_data, 53 | output wire [7:0] pins 54 | ); 55 | 56 | localparam NUMBER_OF_DIGITS = 8; 57 | reg [$clog2(NUMBER_OF_DIGITS)-1:0] current_digit; 58 | localparam NUMBER_OF_SEGMENTS = 7; 59 | 60 | reg [7:0] tristate_pins; 61 | reg [7:0] output_pins; 62 | reg [6:0] segments; 63 | reg [6:0] segment_mask = 7'h01; 64 | reg [3:0] digit_data; 65 | 66 | localparam SEGMENT_TIMER_MAX = $rtoi($ceil(CLK_FREQUENCY / (DISPLAY_FREQUENCY * (NUMBER_OF_DIGITS*NUMBER_OF_SEGMENTS)))); 67 | reg [$clog2(SEGMENT_TIMER_MAX)-1:0] segment_timer; 68 | reg [$clog2(NUMBER_OF_SEGMENTS)-1:0] segment_counter; 69 | 70 | // Get current active segment and digit depending on clk 71 | always @(posedge clk) 72 | begin 73 | if (segment_timer != 0) 74 | segment_timer = segment_timer - 1; 75 | else 76 | begin 77 | // Generate a rotating mask that exposes only one 78 | // digit segment at a time 79 | segment_mask <= {segment_mask[5:0], segment_mask[6]}; 80 | 81 | segment_timer <= SEGMENT_TIMER_MAX; 82 | if (segment_counter != 0) 83 | segment_counter <= segment_counter - 1; 84 | else 85 | begin 86 | if (current_digit < NUMBER_OF_DIGITS-1) 87 | current_digit <= current_digit + 1; 88 | else 89 | current_digit <= 0; 90 | segment_counter <= NUMBER_OF_SEGMENTS; 91 | end 92 | end 93 | end 94 | 95 | // Map display_data to digit_data depening on current active digit 96 | always @(*) 97 | begin 98 | case (current_digit) // current_digit 99 | 0: digit_data = display_data[3:0]; 100 | 1: digit_data = display_data[7:4]; 101 | 2: digit_data = display_data[11:8]; 102 | 3: digit_data = display_data[15:12]; 103 | 4: digit_data = display_data[19:16]; 104 | 5: digit_data = display_data[23:20]; 105 | 6: digit_data = display_data[27:24]; 106 | 7: digit_data = display_data[31:28]; 107 | default: digit_data = 4'b0000; 108 | endcase 109 | end 110 | 111 | // Map digit_data to segments 112 | // Also mask segment at a time to prevent brightness 113 | // differences due to higher curret draw depending on 114 | // the amount of segments lit simultaneously 115 | always @(*) begin 116 | case (digit_data) 117 | 'h0: segments = 'b0111111 & segment_mask; 118 | 'h1: segments = 'b0000110 & segment_mask; 119 | 'h2: segments = 'b1011011 & segment_mask; 120 | 'h3: segments = 'b1001111 & segment_mask; 121 | 'h4: segments = 'b1100110 & segment_mask; 122 | 'h5: segments = 'b1101101 & segment_mask; 123 | 'h6: segments = 'b1111101 & segment_mask; 124 | 'h7: segments = 'b0000111 & segment_mask; 125 | 'h8: segments = 'b1111111 & segment_mask; 126 | 'h9: segments = 'b1101111 & segment_mask; 127 | 'hA: segments = 'b1110111 & segment_mask; 128 | 'hB: segments = 'b1111100 & segment_mask; 129 | 'hC: segments = 'b0111001 & segment_mask; 130 | 'hD: segments = 'b1011110 & segment_mask; 131 | 'hE: segments = 'b1111001 & segment_mask; 132 | 'hF: segments = 'b1110001 & segment_mask; 133 | default: segments = 7'b0000000; 134 | endcase 135 | end 136 | 137 | // Configure pins depending on current active digit & segment 138 | always @(posedge clk) begin 139 | 140 | // All pins are set to low except the Anode drive pin 141 | output_pins <= 'h0; 142 | output_pins[7 - current_digit] <= 1; 143 | 144 | // The pins that correspond to the Anode drive pin are always set to output (Hi/VCC) 145 | // The pins that correspond to lit segments are set to output (Low/GND) 146 | // The pins that correspond to unlit segments are set to input (HiZ) 147 | case (current_digit) 148 | 7: tristate_pins <= {segments[6:0], 1'b1}; 149 | 6: tristate_pins <= {segments[6:1], 1'b1, segments[0]}; 150 | 5: tristate_pins <= {segments[6:2], 1'b1, segments[0], segments[1]}; 151 | 4: tristate_pins <= {segments[6:3], 1'b1, segments[1:0], segments[2]}; 152 | 3: tristate_pins <= {segments[6:4], 1'b1, segments[2:0], segments[3]}; 153 | 2: tristate_pins <= {segments[6:5], 1'b1, segments[3:0], segments[4]}; 154 | 1: tristate_pins <= {segments[6], 1'b1, segments[4:0], segments[5]}; 155 | 0: tristate_pins <= { 1'b1, segments[5:0], segments[6]}; 156 | endcase 157 | 158 | end 159 | 160 | SB_IO #( 161 | .PIN_TYPE(6'b 1010_01), 162 | .PULLUP(1'b 0) 163 | ) led_io[7:0] ( 164 | .PACKAGE_PIN(pins), 165 | .OUTPUT_ENABLE(tristate_pins), 166 | .D_OUT_0(output_pins), 167 | ); 168 | 169 | endmodule 170 | -------------------------------------------------------------------------------- /icebreaker/charlieplexing-twam/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = pmodcharlie 2 | 3 | PIN_DEF = ../icebreaker.pcf 4 | DEVICE = up5k 5 | PACKAGE = sg48 6 | 7 | prog: iceprog 8 | 9 | include ../../main.mk 10 | -------------------------------------------------------------------------------- /icebreaker/charlieplexing-twam/README.md: -------------------------------------------------------------------------------- 1 | # Charlieplexing 2 | 3 | This example controls the Pmod™ 8-digit 7-segment display ([Blog article](https://www.twam.info/electronics/7-segment-charlieplexing), [Schematic](https://github.com/twam/Pmod7Segment)) using [Charlieplexing](https://en.wikipedia.org/wiki/Charlieplexing). The time since start up is counted and displayed milliseconds in hex. -------------------------------------------------------------------------------- /icebreaker/charlieplexing-twam/pmodcharlie.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module top( 4 | input CLK, 5 | output P2_1, P2_2, P2_3, P2_4, P2_7, P2_8, P2_9, P2_10 6 | ); 7 | 8 | localparam CLK_FREQUENCY = 12E6; 9 | localparam COUNTER_MAX = $rtoi(CLK_FREQUENCY/1000); 10 | 11 | wire [7:0] pmodmap; 12 | reg [31:0] milliseconds = 0; 13 | reg [$clog2(COUNTER_MAX)-1:0] counter; 14 | 15 | // Count milliseconds 16 | always @(posedge CLK) 17 | begin 18 | if (counter < COUNTER_MAX) 19 | counter <= counter + 1; 20 | else 21 | begin 22 | counter <= 0; 23 | milliseconds <= milliseconds + 1; 24 | end 25 | end 26 | 27 | // map output pins of pmodcharlie module to pins on iCEBreaker 28 | assign pmodmap[0] = P2_1; 29 | assign pmodmap[1] = P2_8; 30 | assign pmodmap[2] = P2_4; 31 | assign pmodmap[3] = P2_10; 32 | assign pmodmap[4] = P2_9; 33 | assign pmodmap[5] = P2_2; 34 | assign pmodmap[6] = P2_7; 35 | assign pmodmap[7] = P2_3; 36 | 37 | pmodcharlie pmodCharlieA( 38 | .clk(CLK), 39 | .pins(pmodmap), 40 | .display_data(milliseconds) 41 | ); 42 | 43 | endmodule 44 | 45 | module pmodcharlie 46 | #( 47 | parameter CLK_FREQUENCY = 12E6, 48 | parameter DISPLAY_FREQUENCY = 1E3 49 | ) 50 | ( 51 | input wire clk, 52 | input wire [31:0] display_data, 53 | output wire [7:0] pins 54 | ); 55 | 56 | localparam NUMBER_OF_DIGITS = 8; 57 | reg [$clog2(NUMBER_OF_DIGITS)-1:0] current_digit; 58 | localparam NUMBER_OF_SEGMENTS = 7; 59 | reg [$clog2(NUMBER_OF_SEGMENTS)-1:0] current_segment; 60 | reg [$clog2(NUMBER_OF_DIGITS)-1:0] current_segment2; 61 | 62 | reg [7:0] tristate_pins; 63 | reg [7:0] output_pins; 64 | reg [6:0] segments; 65 | reg [3:0] digit_data; 66 | 67 | localparam SEGMENT_TIMER_MAX = $rtoi($ceil(CLK_FREQUENCY / (DISPLAY_FREQUENCY * (NUMBER_OF_DIGITS*NUMBER_OF_SEGMENTS)))); 68 | reg [$clog2(SEGMENT_TIMER_MAX)-1:0] segment_timer; 69 | reg [$clog2(NUMBER_OF_SEGMENTS)-1:0] segment_counter; 70 | 71 | // Get current active segment and digit depending on clk 72 | always @(posedge clk) 73 | begin 74 | if (segment_timer != 0) 75 | segment_timer = segment_timer - 1; 76 | else 77 | begin 78 | if (current_segment < NUMBER_OF_SEGMENTS-1) 79 | current_segment <= current_segment + 1; 80 | else 81 | current_segment <= 0; 82 | 83 | segment_timer <= SEGMENT_TIMER_MAX; 84 | if (segment_counter != 0) 85 | segment_counter <= segment_counter - 1; 86 | else 87 | begin 88 | if (current_digit < NUMBER_OF_DIGITS-1) 89 | current_digit <= current_digit + 1; 90 | else 91 | current_digit <= 0; 92 | segment_counter <= NUMBER_OF_SEGMENTS; 93 | end 94 | end 95 | end 96 | 97 | // Map display_data to digit_data depening on current active digit 98 | always @(*) 99 | begin 100 | case (current_digit) // current_digit 101 | 0: digit_data = display_data[3:0]; 102 | 1: digit_data = display_data[7:4]; 103 | 2: digit_data = display_data[11:8]; 104 | 3: digit_data = display_data[15:12]; 105 | 4: digit_data = display_data[19:16]; 106 | 5: digit_data = display_data[23:20]; 107 | 6: digit_data = display_data[27:24]; 108 | 7: digit_data = display_data[31:28]; 109 | default: digit_data = 4'b0000; 110 | endcase 111 | end 112 | 113 | // Map digit_data to segments 114 | always @(*) begin 115 | case (digit_data) 116 | 'h0: segments = 'b0111111; 117 | 'h1: segments = 'b0000110; 118 | 'h2: segments = 'b1011011; 119 | 'h3: segments = 'b1001111; 120 | 'h4: segments = 'b1100110; 121 | 'h5: segments = 'b1101101; 122 | 'h6: segments = 'b1111101; 123 | 'h7: segments = 'b0000111; 124 | 'h8: segments = 'b1111111; 125 | 'h9: segments = 'b1101111; 126 | 'hA: segments = 'b1110111; 127 | 'hB: segments = 'b1111100; 128 | 'hC: segments = 'b0111001; 129 | 'hD: segments = 'b1011110; 130 | 'hE: segments = 'b1111001; 131 | 'hF: segments = 'b1110001; 132 | default: segments = 7'b0000000; 133 | endcase 134 | end 135 | 136 | // Configure pins depending on current active digit & segment 137 | always @(posedge clk) begin 138 | output_pins <= 'h0; 139 | output_pins[current_digit] <= 1; 140 | 141 | if (current_segment < current_digit) 142 | current_segment2 <= current_segment; 143 | else 144 | current_segment2 <= current_segment+1; 145 | 146 | tristate_pins <= 'h0; 147 | tristate_pins[current_digit] <= 1; 148 | tristate_pins[current_segment2] <= segments[current_segment]; 149 | end 150 | 151 | SB_IO #( 152 | .PIN_TYPE(6'b 1010_01), 153 | .PULLUP(1'b 0) 154 | ) led_io[7:0] ( 155 | .PACKAGE_PIN(pins), 156 | .OUTPUT_ENABLE(tristate_pins), 157 | .D_OUT_0(output_pins), 158 | ); 159 | 160 | endmodule 161 | -------------------------------------------------------------------------------- /icebreaker/cmp_1bit/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2019 Albin Söderqvist 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /icebreaker/cmp_1bit/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = cmp_1bit 2 | 3 | PIN_DEF = ../icebreaker.pcf 4 | DEVICE = up5k 5 | PACKAGE = sg48 6 | 7 | prog: iceprog 8 | 9 | include ../../main.mk 10 | -------------------------------------------------------------------------------- /icebreaker/cmp_1bit/cmp_1bit.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - 1-bit comparator 3 | * 4 | * Copyright (C) 2019 Albin Söderqvist 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | // Pressing button 1 (A) and/or 2 (B) will compare the two signals 21 | // and enable one of the built-in LEDs: 22 | // A < B: L2 23 | // A = B: L1 24 | // A > B: L3 25 | 26 | module top(BTN1, BTN2, CLK, LED1, LED2, LED3); 27 | input BTN1, BTN2, CLK; 28 | output LED1, LED2, LED3; 29 | wire A, B; 30 | reg [2:0] out; 31 | assign {LED2, LED1, LED3} = out; 32 | assign BTN1 = A; 33 | assign BTN2 = B; 34 | 35 | always @ (posedge CLK) 36 | if (A < B) 37 | out <= 3'b100; 38 | else if (A == B) 39 | out <= 3'b010; 40 | else 41 | out <= 3'b001; 42 | endmodule 43 | -------------------------------------------------------------------------------- /icebreaker/dvi-12bit/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = dvi-12bit 2 | ADD_SRC = vga_core.v vga_timing.v 3 | 4 | PIN_DEF = ../icebreaker.pcf 5 | DEVICE = up5k 6 | PACKAGE = sg48 7 | #PNR_SEED = 1 8 | 9 | prog: iceprog 10 | 11 | include ../../main.mk 12 | 13 | gen_gamma_table: gen_gamma_table.o 14 | gcc $< -o $@ -lm 15 | 16 | gamma_table.hex: gen_gamma_table 17 | ./gen_gamma_table > gamma_table.hex 18 | -------------------------------------------------------------------------------- /icebreaker/dvi-12bit/README.txt: -------------------------------------------------------------------------------- 1 | This is an example design for driving the 3b and 12b HDMI PMOD modules from 2 | Black Mesa Labs. The design drives 800x600 video with a 40 MHz input clock. 3 | The actual video is an alternating display of: 4 | 1) Color Test Pattern bars. 5 | 2) Bouncing dot with changing colors ( Pong'ish ). 6 | 3) Moving lines. 7 | 8 | Original design targets Xilinx Spartan3 FPGA and makes use of 2 Xilinx specific 9 | primitive: 10 | 1) BUFG : Global Clock Tree buffer 11 | 2) FDDRCPE : "ODDR" output flop for mirroring internal clock tree outside. 12 | 13 | top.v : top level for FPGA design. 14 | vga_core.v : Generates color test pattern, bouncing ball and moving lines. 15 | vga_timing.v : Generates low level VGA timing for 800x600 with 40 MHz clock. 16 | 17 | Kevin M. Hubbard @ Black Mesa Labs 2017.12.14 18 | -------------------------------------------------------------------------------- /icebreaker/dvi-12bit/dvi-12bit.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- (C) Copyright 2017 Kevin M. Hubbard @ Black Mess Labs - All rights reserved. 3 | -- Source file: top.v 4 | -- Date: December 2017 5 | -- Author: khubbard 6 | -- Description: Spartan3 Test Design 7 | -- Language: Verilog-2001 and VHDL-1993 8 | -- Simulation: Mentor-Modelsim 9 | -- Synthesis: Xilinst-XST 10 | -- License: This project is licensed with the CERN Open Hardware Licence 11 | -- v1.2. You may redistribute and modify this project under the 12 | -- terms of the CERN OHL v.1.2. (http://ohwr.org/cernohl). 13 | -- This project is distributed WITHOUT ANY EXPRESS OR IMPLIED 14 | -- WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY QUALITY 15 | -- AND FITNESS FOR A PARTICULAR PURPOSE. Please see the CERN OHL 16 | -- v.1.2 for applicable Conditions. 17 | -- 18 | -- 3b Module - Facing module pins 19 | -- ------------------------------- 20 | -- | 1-GRN 3-CLK 5-HS 7-NC GND 3V | 21 | -- | 0-RED 2-BLU 4-DE 6-VS GND 3V | 22 | -- ___|_______________________________|___ 23 | -- | BML HDMI 3b color PMOD board | 24 | -- --------------------------------------- 25 | -- pmod_*_*<0> = red 26 | -- pmod_*_*<1> = green 27 | -- pmod_*_*<2> = blue 28 | -- pmod_*_*<3> = pixel_clock 29 | -- pmod_*_*<4> = data_enable 30 | -- pmod_*_*<5> = hsync 31 | -- pmod_*_*<6> = vsync 32 | -- pmod_*_*<7> = nc 33 | -- 34 | -- 35 | -- 36 | -- 12b Module - Facing module pins 37 | -- ---------------------------- ---------------------------- 38 | -- | 1-R3 3-R1 5-G3 7-G1 GND 3V | | 1-B3 3-ck 5-B0 7-HS GND 3V | 39 | -- | 0-R2 2-R0 4-G2 6-G0 GND 3V | | 0-B2 2-B1 4-DE 6-VS GND 3V | 40 | -- ___|____________________________|______|____________________________|__ 41 | -- | BML HDMI 12b color PMOD board | 42 | -- ----------------------------------------------------------------------- 43 | -- pmod_*_*<0> = r[2] pmod_*_*<0> = b[2] 44 | -- pmod_*_*<1> = r[3] pmod_*_*<1> = b[3] 45 | -- pmod_*_*<2> = r[0] pmod_*_*<2> = b[1] 46 | -- pmod_*_*<3> = r[1] pmod_*_*<3> = ck 47 | -- pmod_*_*<4> = g[2] pmod_*_*<4> = de 48 | -- pmod_*_*<5> = g[3] pmod_*_*<5> = b[0] 49 | -- pmod_*_*<6> = g[0] pmod_*_*<6> = vs 50 | -- pmod_*_*<7> = g[1] pmod_*_*<7> = hs 51 | -- 52 | -- Revision History: 53 | -- Ver# When Who What 54 | -- ---- -------- -------- --------------------------------------------------- 55 | -- 0.1 12.14.17 khubbard Creation 56 | -- ***************************************************************************/ 57 | `default_nettype none // Strictly enforce all nets to be declared 58 | 59 | module top 60 | ( 61 | input CLK, 62 | 63 | output LEDR_N, // on board red 64 | output LEDG_N, // on board green 65 | input BTN_N, // user button aka reset 66 | 67 | output P1A1, P1A2, P1A3, P1A4, P1A7, P1A8, P1A9, P1A10, 68 | output P1B1, P1B2, P1B3, P1B4, P1B7, P1B8, P1B9, P1B10 69 | 70 | 71 | );// module top 72 | 73 | 74 | wire reset_loc; 75 | wire clk_40m_tree; 76 | reg [29:0] led_cnt; 77 | reg [29:0] led_cnt_p1; 78 | wire vga_de; 79 | wire vga_ck; 80 | wire vga_hs; 81 | wire vga_vs; 82 | wire [23:0] vga_rgb; 83 | reg [31:0] random_num; 84 | wire [7:0] r; 85 | wire [7:0] g; 86 | wire [7:0] b; 87 | reg mode_bit; 88 | wire ok_led_loc; 89 | 90 | 91 | assign reset_loc = ~BTN_N; 92 | 93 | //----------------------------------------------------------------------------- 94 | // PLL. 95 | //----------------------------------------------------------------------------- 96 | SB_PLL40_PAD #( 97 | .DIVR(4'b0000), 98 | // 40MHz ish to be exact it is 39.750MHz 99 | .DIVF(7'b0110100), // 39.750MHz 100 | .DIVQ(3'b100), 101 | .FILTER_RANGE(3'b001), 102 | .FEEDBACK_PATH("SIMPLE"), 103 | .DELAY_ADJUSTMENT_MODE_FEEDBACK("FIXED"), 104 | .FDA_FEEDBACK(4'b0000), 105 | .DELAY_ADJUSTMENT_MODE_RELATIVE("FIXED"), 106 | .FDA_RELATIVE(4'b0000), 107 | .SHIFTREG_DIV_MODE(2'b00), 108 | .PLLOUT_SELECT("GENCLK"), 109 | .ENABLE_ICEGATE(1'b0) 110 | ) pll_inst ( 111 | .PACKAGEPIN(CLK), 112 | .PLLOUTCORE(), 113 | .PLLOUTGLOBAL(clk_40m_tree), 114 | .EXTFEEDBACK(), 115 | .DYNAMICDELAY(), 116 | .RESETB(1'b1), 117 | .BYPASS(1'b0), 118 | .LATCHINPUTVALUE(), 119 | //.LOCK(), 120 | //.SDI(), 121 | //.SDO(), 122 | //.SCLK() 123 | ); 124 | 125 | //----------------------------------------------------------------------------- 126 | // Flash an LED. Also control the VGA demos, toggle between color pattern and 127 | // either a bouncing ball or moving lines. 128 | //----------------------------------------------------------------------------- 129 | always @ ( posedge clk_40m_tree or posedge reset_loc ) begin : proc_led 130 | if ( reset_loc == 1 ) begin 131 | random_num <= 32'd0; 132 | led_cnt <= 30'd0; 133 | led_cnt_p1 <= 30'd0; 134 | ok_led_loc <= 0; 135 | mode_bit <= 0; 136 | end else begin 137 | random_num <= random_num + 3; 138 | ok_led_loc <= 0; 139 | led_cnt_p1 <= led_cnt[29:0]; 140 | led_cnt <= led_cnt + 1; 141 | if ( led_cnt[19] == 1 ) begin 142 | ok_led_loc <= 1; 143 | end 144 | if ( led_cnt[29:27] == 3'd0 ) begin 145 | mode_bit <= 0; 146 | end else begin 147 | mode_bit <= 1; 148 | end 149 | 150 | end // clk+reset 151 | end // proc_led 152 | 153 | assign LEDG_N = ok_led_loc; 154 | 155 | // ---------------------------------------------------------------------------- 156 | // VGA Timing Generator 157 | // ---------------------------------------------------------------------------- 158 | vga_core u_vga_core 159 | ( 160 | .reset ( reset_loc ), 161 | .random_num ( random_num[31:0] ), 162 | .color_3b ( 1'b0 ), 163 | .mode_bit ( mode_bit ), 164 | .clk_dot ( clk_40m_tree ), 165 | .vga_active ( vga_de ), 166 | .vga_hsync ( vga_hs ), 167 | .vga_vsync ( vga_vs ), 168 | .vga_pixel_rgb ( vga_rgb[23:0] ) 169 | ); 170 | assign r = vga_rgb[23:16]; 171 | assign g = vga_rgb[15:8]; 172 | assign b = vga_rgb[7:0]; 173 | 174 | 175 | // ---------------------------------------------------------------------------- 176 | // Assign the PMOD(s) pins 177 | // ---------------------------------------------------------------------------- 178 | // Also add IO registers to minimize timing between lines and ensure we're 179 | // properly aligned to the clock. Clock is output using a DDR flop and 180deg 180 | // out of phase (rising edge in middle of data eye) to maximize setup/hold 181 | // time margin. 182 | 183 | SB_IO #( 184 | .PIN_TYPE(6'b01_0000) // PIN_OUTPUT_DDR 185 | ) dvi_clk_iob ( 186 | .PACKAGE_PIN (P1B2), 187 | .D_OUT_0 (1'b0), 188 | .D_OUT_1 (1'b1), 189 | .OUTPUT_CLK (clk_40m_tree) 190 | ); 191 | 192 | SB_IO #( 193 | .PIN_TYPE(6'b01_0100) // PIN_OUTPUT_REGISTERED 194 | ) dvi_data_iob [14:0] ( 195 | .PACKAGE_PIN ({P1A1, P1A2, P1A3, P1A4, P1A7, P1A8, P1A9, P1A10, 196 | P1B1, P1B3, P1B4, P1B7, P1B8, P1B9, P1B10}), 197 | .D_OUT_0 ({r[7], r[5], g[7], g[5], r[6], r[4], g[6], g[4], 198 | b[7], b[4], vga_hs, b[6], b[5], vga_de, vga_vs}), 199 | .OUTPUT_CLK (clk_40m_tree) 200 | ); 201 | 202 | endmodule // top.v 203 | -------------------------------------------------------------------------------- /icebreaker/dvi-24bit/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = dvi-24bit 2 | ADD_SRC = vga_core.v vga_timing.v 3 | 4 | PIN_DEF = ../icebreaker.pcf 5 | DEVICE = up5k 6 | PACKAGE = sg48 7 | PNR_SEED = 1 8 | 9 | prog: iceprog 10 | 11 | include ../../main.mk 12 | 13 | gen_gamma_table: gen_gamma_table.o 14 | gcc $< -o $@ -lm 15 | 16 | gamma_table.hex: gen_gamma_table 17 | ./gen_gamma_table > gamma_table.hex 18 | -------------------------------------------------------------------------------- /icebreaker/dvi-24bit/README.txt: -------------------------------------------------------------------------------- 1 | This is an example design for driving the 3b and 12b HDMI PMOD modules from 2 | Black Mesa Labs. The design drives 800x600 video with a 40 MHz input clock. 3 | The actual video is an alternating display of: 4 | 1) Color Test Pattern bars. 5 | 2) Bouncing dot with changing colors ( Pong'ish ). 6 | 3) Moving lines. 7 | 8 | Original design targets Xilinx Spartan3 FPGA and makes use of 2 Xilinx specific 9 | primitive: 10 | 1) BUFG : Global Clock Tree buffer 11 | 2) FDDRCPE : "ODDR" output flop for mirroring internal clock tree outside. 12 | 13 | top.v : top level for FPGA design. 14 | vga_core.v : Generates color test pattern, bouncing ball and moving lines. 15 | vga_timing.v : Generates low level VGA timing for 800x600 with 40 MHz clock. 16 | 17 | Kevin M. Hubbard @ Black Mesa Labs 2017.12.14 18 | -------------------------------------------------------------------------------- /icebreaker/dvi-4bit/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = dvi-4bit 2 | ADD_SRC = vga_core.v vga_timing.v 3 | 4 | PIN_DEF = ../icebreaker.pcf 5 | DEVICE = up5k 6 | PACKAGE = sg48 7 | #PNR_SEED = 1 8 | 9 | prog: iceprog 10 | 11 | include ../../main.mk 12 | 13 | gen_gamma_table: gen_gamma_table.o 14 | gcc $< -o $@ -lm 15 | 16 | gamma_table.hex: gen_gamma_table 17 | ./gen_gamma_table > gamma_table.hex 18 | -------------------------------------------------------------------------------- /icebreaker/dvi-4bit/README.txt: -------------------------------------------------------------------------------- 1 | This is an example design for driving the 3b and 12b HDMI PMOD modules from 2 | Black Mesa Labs. The design drives 800x600 video with a 40 MHz input clock. 3 | The actual video is an alternating display of: 4 | 1) Color Test Pattern bars. 5 | 2) Bouncing dot with changing colors ( Pong'ish ). 6 | 3) Moving lines. 7 | 8 | Original design targets Xilinx Spartan3 FPGA and makes use of 2 Xilinx specific 9 | primitive: 10 | 1) BUFG : Global Clock Tree buffer 11 | 2) FDDRCPE : "ODDR" output flop for mirroring internal clock tree outside. 12 | 13 | top.v : top level for FPGA design. 14 | vga_core.v : Generates color test pattern, bouncing ball and moving lines. 15 | vga_timing.v : Generates low level VGA timing for 800x600 with 40 MHz clock. 16 | 17 | Kevin M. Hubbard @ Black Mesa Labs 2017.12.14 18 | -------------------------------------------------------------------------------- /icebreaker/dvi-4bit/dvi-4bit.v: -------------------------------------------------------------------------------- 1 | /* **************************************************************************** 2 | -- (C) Copyright 2017 Kevin M. Hubbard @ Black Mess Labs - All rights reserved. 3 | -- Source file: top.v 4 | -- Date: December 2017 5 | -- Author: khubbard 6 | -- Description: Spartan3 Test Design 7 | -- Language: Verilog-2001 and VHDL-1993 8 | -- Simulation: Mentor-Modelsim 9 | -- Synthesis: Xilinst-XST 10 | -- License: This project is licensed with the CERN Open Hardware Licence 11 | -- v1.2. You may redistribute and modify this project under the 12 | -- terms of the CERN OHL v.1.2. (http://ohwr.org/cernohl). 13 | -- This project is distributed WITHOUT ANY EXPRESS OR IMPLIED 14 | -- WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY QUALITY 15 | -- AND FITNESS FOR A PARTICULAR PURPOSE. Please see the CERN OHL 16 | -- v.1.2 for applicable Conditions. 17 | -- 18 | -- 3b Module - Facing module pins 19 | -- ------------------------------- 20 | -- | 1-GRN 3-CLK 5-HS 7-NC GND 3V | 21 | -- | 0-RED 2-BLU 4-DE 6-VS GND 3V | 22 | -- ___|_______________________________|___ 23 | -- | BML HDMI 3b color PMOD board | 24 | -- --------------------------------------- 25 | -- pmod_*_*<0> = red 26 | -- pmod_*_*<1> = green 27 | -- pmod_*_*<2> = blue 28 | -- pmod_*_*<3> = pixel_clock 29 | -- pmod_*_*<4> = data_enable 30 | -- pmod_*_*<5> = hsync 31 | -- pmod_*_*<6> = vsync 32 | -- pmod_*_*<7> = nc 33 | -- 34 | -- 35 | -- 36 | -- 12b Module - Facing module pins 37 | -- ---------------------------- ---------------------------- 38 | -- | 1-R3 3-R1 5-G3 7-G1 GND 3V | | 1-B3 3-ck 5-B0 7-HS GND 3V | 39 | -- | 0-R2 2-R0 4-G2 6-G0 GND 3V | | 0-B2 2-B1 4-DE 6-VS GND 3V | 40 | -- ___|____________________________|______|____________________________|__ 41 | -- | BML HDMI 12b color PMOD board | 42 | -- ----------------------------------------------------------------------- 43 | -- pmod_*_*<0> = r[2] pmod_*_*<0> = b[2] 44 | -- pmod_*_*<1> = r[3] pmod_*_*<1> = b[3] 45 | -- pmod_*_*<2> = r[0] pmod_*_*<2> = b[1] 46 | -- pmod_*_*<3> = r[1] pmod_*_*<3> = ck 47 | -- pmod_*_*<4> = g[2] pmod_*_*<4> = de 48 | -- pmod_*_*<5> = g[3] pmod_*_*<5> = b[0] 49 | -- pmod_*_*<6> = g[0] pmod_*_*<6> = vs 50 | -- pmod_*_*<7> = g[1] pmod_*_*<7> = hs 51 | -- 52 | -- Revision History: 53 | -- Ver# When Who What 54 | -- ---- -------- -------- --------------------------------------------------- 55 | -- 0.1 12.14.17 khubbard Creation 56 | -- ***************************************************************************/ 57 | `default_nettype none // Strictly enforce all nets to be declared 58 | 59 | module top 60 | ( 61 | input CLK, 62 | 63 | output LEDR_N, // on board red 64 | output LEDG_N, // on board green 65 | input BTN_N, // user button aka reset 66 | 67 | output P1A1, P1A2, P1A3, P1A4, P1A7, P1A8, P1A9, P1A10, 68 | output P1B1, P1B2, P1B3, P1B4, P1B7, P1B8, P1B9, P1B10 69 | 70 | 71 | );// module top 72 | 73 | 74 | wire reset_loc; 75 | wire clk_40m_tree; 76 | reg [29:0] led_cnt; 77 | reg [29:0] led_cnt_p1; 78 | wire vga_de; 79 | wire vga_ck; 80 | wire vga_hs; 81 | wire vga_vs; 82 | wire [23:0] vga_rgb; 83 | reg [31:0] random_num; 84 | wire [7:0] r; 85 | wire [7:0] g; 86 | wire [7:0] b; 87 | reg mode_bit; 88 | wire ok_led_loc; 89 | 90 | 91 | assign reset_loc = ~BTN_N; 92 | 93 | //----------------------------------------------------------------------------- 94 | // PLL. 95 | //----------------------------------------------------------------------------- 96 | SB_PLL40_PAD #( 97 | .DIVR(4'b0000), 98 | // 40MHz ish to be exact it is 39.750MHz 99 | .DIVF(7'b0110100), // 39.750MHz 100 | .DIVQ(3'b100), 101 | .FILTER_RANGE(3'b001), 102 | .FEEDBACK_PATH("SIMPLE"), 103 | .DELAY_ADJUSTMENT_MODE_FEEDBACK("FIXED"), 104 | .FDA_FEEDBACK(4'b0000), 105 | .DELAY_ADJUSTMENT_MODE_RELATIVE("FIXED"), 106 | .FDA_RELATIVE(4'b0000), 107 | .SHIFTREG_DIV_MODE(2'b00), 108 | .PLLOUT_SELECT("GENCLK"), 109 | .ENABLE_ICEGATE(1'b0) 110 | ) pll_inst ( 111 | .PACKAGEPIN(CLK), 112 | .PLLOUTCORE(), 113 | .PLLOUTGLOBAL(clk_40m_tree), 114 | .EXTFEEDBACK(), 115 | .DYNAMICDELAY(), 116 | .RESETB(1'b1), 117 | .BYPASS(1'b0), 118 | .LATCHINPUTVALUE(), 119 | //.LOCK(), 120 | //.SDI(), 121 | //.SDO(), 122 | //.SCLK() 123 | ); 124 | 125 | //----------------------------------------------------------------------------- 126 | // Flash an LED. Also control the VGA demos, toggle between color pattern and 127 | // either a bouncing ball or moving lines. 128 | //----------------------------------------------------------------------------- 129 | always @ ( posedge clk_40m_tree or posedge reset_loc ) begin : proc_led 130 | if ( reset_loc == 1 ) begin 131 | random_num <= 32'd0; 132 | led_cnt <= 30'd0; 133 | led_cnt_p1 <= 30'd0; 134 | ok_led_loc <= 0; 135 | mode_bit <= 0; 136 | end else begin 137 | random_num <= random_num + 3; 138 | ok_led_loc <= 0; 139 | led_cnt_p1 <= led_cnt[29:0]; 140 | led_cnt <= led_cnt + 1; 141 | if ( led_cnt[19] == 1 ) begin 142 | ok_led_loc <= 1; 143 | end 144 | if ( led_cnt[29:27] == 3'd0 ) begin 145 | mode_bit <= 0; 146 | end else begin 147 | mode_bit <= 1; 148 | end 149 | 150 | end // clk+reset 151 | end // proc_led 152 | 153 | assign LEDG_N = ok_led_loc; 154 | 155 | // ---------------------------------------------------------------------------- 156 | // VGA Timing Generator 157 | // ---------------------------------------------------------------------------- 158 | vga_core u_vga_core 159 | ( 160 | .reset ( reset_loc ), 161 | .random_num ( random_num[31:0] ), 162 | .color_3b ( 1'b0 ), 163 | .mode_bit ( mode_bit ), 164 | .clk_dot ( clk_40m_tree ), 165 | .vga_active ( vga_de ), 166 | .vga_hsync ( vga_hs ), 167 | .vga_vsync ( vga_vs ), 168 | .vga_pixel_rgb ( vga_rgb[23:0] ) 169 | ); 170 | assign r = vga_rgb[23:16]; 171 | assign g = vga_rgb[15:8]; 172 | assign b = vga_rgb[7:0]; 173 | 174 | 175 | // ---------------------------------------------------------------------------- 176 | // Assign the PMOD(s) pins 177 | // ---------------------------------------------------------------------------- 178 | // Also add IO registers to minimize timing between lines and ensure we're 179 | // properly aligned to the clock. Clock is output using a DDR flop and 180deg 180 | // out of phase (rising edge in middle of data eye) to maximize setup/hold 181 | // time margin. 182 | 183 | SB_IO #( 184 | .PIN_TYPE(6'b01_0000) // PIN_OUTPUT_DDR 185 | ) dvi_clk_iob ( 186 | .PACKAGE_PIN (P1A2), 187 | .D_OUT_0 (1'b0), 188 | .D_OUT_1 (1'b1), 189 | .OUTPUT_CLK (clk_40m_tree) 190 | ); 191 | 192 | SB_IO #( 193 | .PIN_TYPE(6'b01_0100) // PIN_OUTPUT_REGISTERED 194 | ) dvi_data_iob [6:0] ( 195 | .PACKAGE_PIN ({P1A1, P1A3, P1A4, P1A7, P1A8, P1A9, P1A10}), 196 | .D_OUT_0 ({|g[7:6], vga_hs, |{&r[7:6],&g[7:6],&b[7:6]}, |r[7:6], |b[7:6], vga_de, vga_vs}), 197 | .OUTPUT_CLK (clk_40m_tree) 198 | ); 199 | 200 | endmodule // top.v 201 | -------------------------------------------------------------------------------- /icebreaker/full_adder_1bit/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2019 Albin Söderqvist 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /icebreaker/full_adder_1bit/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = full_adder 2 | 3 | PIN_DEF = ../icebreaker.pcf 4 | DEVICE = up5k 5 | PACKAGE = sg48 6 | 7 | prog: iceprog 8 | 9 | include ../../main.mk 10 | -------------------------------------------------------------------------------- /icebreaker/full_adder_1bit/full_adder.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - 1-bit full adder 3 | * 4 | * Copyright (C) 2019 Albin Söderqvist 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | // Pressing the buttons 1-3 (or not) in various combinations 21 | // will represent the two-bit binary numbers 00, 01, 10 and 11 22 | // by enabling some of the built-in LEDs. 23 | 24 | module top(BTN1, BTN2, BTN3, LED1, LED2); 25 | input BTN1, BTN2, BTN3; 26 | output LED1, LED2; 27 | wire [1:0] Sum; 28 | wire A, B, Cin; 29 | assign BTN1 = A, BTN2 = B, BTN3 = Cin; 30 | assign {LED1, LED2} = Sum; 31 | assign Sum = A + B + Cin; 32 | endmodule 33 | -------------------------------------------------------------------------------- /icebreaker/gamepad-audio/.gitignore: -------------------------------------------------------------------------------- 1 | gen_sin_table 2 | gen_sin_table.o 3 | sin_table.hex 4 | -------------------------------------------------------------------------------- /icebreaker/gamepad-audio/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = audio 2 | ADD_SRC = pdm_sine_mod.v 3 | ADD_DEPS = sin_table.hex 4 | ADD_CLEAN = *.o gen_sin_table *.hex 5 | 6 | PIN_DEF = ../icebreaker.pcf 7 | DEVICE = up5k 8 | PACKAGE = sg48 9 | 10 | prog: iceprog 11 | 12 | include ../../main.mk 13 | 14 | gen_sin_table: gen_sin_table.o 15 | gcc $< -o $@ -lm 16 | 17 | sin_table.hex: gen_sin_table 18 | ./gen_sin_table > sin_table.hex 19 | -------------------------------------------------------------------------------- /icebreaker/gamepad-audio/README.md: -------------------------------------------------------------------------------- 1 | This example plays a tone through the stereo audio circuit of the gamepd & audio Pmod. 2 | 3 | ## Hardware requirements 4 | 5 | This example is meant to be used with the gamepad & audio iCEBreaker Pmod attached to Pmod Port A on the iCEBreaker. 6 | 7 | You can find the design files for the gamepad & audio Pmod in the [iCEBreaker Pmod github repository](https://github.com/icebreaker-fpga/icebreaker-pmod/tree/master/gamepad-n-audio) and it might be available from [1BitSquared USA](https://1bitsquared.com/collections/fpga) and [1BitSquared Germany](https://1bitsquared.de/collections/fpga). 8 | 9 | You should be able to connect earphones to the 3.5mm audio jack and hear a sine tone. Be careful and don't hurt your ears!!! 10 | 11 | I don't think this requires mentioning, but you do all of this at your own risk, you can keep the burned pieces. ;) 12 | 13 | ## Software requirements 14 | 15 | No computer side software is needed to run this example. 16 | 17 | ## Building 18 | 19 | Make sure you have the open souce FPGA dev tools installed and in your PATH. The tools you will need are: Yosys, nextpnr-ice40, icestorm. 20 | You will also need GCC and libc installed so you can compile the sin table generator. 21 | 22 | Connect your iCEBreaker and run: 23 | 24 | ``` 25 | make prog 26 | ``` 27 | 28 | ## Testing 29 | 30 | There is a simple testbench available for the gamepad readout core module. 31 | 32 | Make sure you have iverilog installed and in your PATH. You will also need gtkwave or equivalent to read the resulting vcd signal trace file. 33 | 34 | To run the simulation build the testbench target with: 35 | 36 | ``` 37 | make pdm_sine_mod_tb.vcd 38 | ``` 39 | 40 | And then open it in gtkwave with: 41 | ``` 42 | gtkwave pdm_sine_mod_tb.vcd 43 | ``` 44 | 45 | TIP: You can reload the vcd file without restarting gtkwave with Ctrl-Shift-R ;) 46 | -------------------------------------------------------------------------------- /icebreaker/gamepad-audio/audio.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - play audio tones on the gamepad & audio Pmod 3 | * 4 | * Copyright (C) 2020 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | `default_nettype none 21 | 22 | module top ( 23 | input CLK, 24 | input RX, 25 | output TX, 26 | output LEDR_N, 27 | output LEDG_N, 28 | //output P1A1, // CLK 29 | //input P1A2, // GPD0 30 | //input P1A3, // GPD2 31 | output P1A4, // AudioL 32 | //output P1A7, // LATCH 33 | //input P1A8, // GPD1 34 | //input P1A9, // GPD3 35 | output P1A10 // Audio R 36 | ); 37 | 38 | /* Gamepad Pmod pin decoding */ 39 | //wire gp_clk; 40 | //wire gp_latch; 41 | //wire gp_d0; 42 | //wire gp_d1; 43 | //wire gp_d2; 44 | //wire gp_d3; 45 | wire audio_l; 46 | wire audio_r; 47 | 48 | //assign P1A1 = gp_clk; 49 | //assign P1A7 = gp_latch; 50 | //assign {gp_d0, gp_d1, gp_d2, gp_d3} = {P1A2, P1A8, P1A3, P1A9}; 51 | assign P1A4 = audio_l; 52 | assign P1A10 = audio_r; 53 | 54 | /* PLL block instantiation */ 55 | wire clk_42mhz; 56 | //assign clk_42mhz = CLK; 57 | SB_PLL40_PAD #( 58 | .DIVR(4'b0000), 59 | // 42MHz 60 | .DIVF(7'b0110111), 61 | .DIVQ(3'b100), 62 | .FILTER_RANGE(3'b001), 63 | .FEEDBACK_PATH("SIMPLE"), 64 | .DELAY_ADJUSTMENT_MODE_FEEDBACK("FIXED"), 65 | .FDA_FEEDBACK(4'b0000), 66 | .DELAY_ADJUSTMENT_MODE_RELATIVE("FIXED"), 67 | .FDA_RELATIVE(4'b0000), 68 | .SHIFTREG_DIV_MODE(2'b00), 69 | .PLLOUT_SELECT("GENCLK"), 70 | .ENABLE_ICEGATE(1'b0) 71 | ) pll_inst ( 72 | .PACKAGEPIN(CLK), 73 | .PLLOUTCORE(), 74 | .PLLOUTGLOBAL(clk_42mhz), 75 | .EXTFEEDBACK(), 76 | .DYNAMICDELAY(), 77 | .RESETB(1'b1), 78 | .BYPASS(1'b0), 79 | .LATCHINPUTVALUE(), 80 | //.LOCK(), 81 | //.SDI(), 82 | //.SDO(), 83 | //.SCLK() 84 | ); 85 | 86 | /* Generate reset signal */ 87 | reg [15:0] rst_cnt = 16'h0000; 88 | wire rst; 89 | always @(posedge clk_42mhz) begin 90 | if (rst_cnt[15] == 0) begin 91 | rst_cnt <= rst_cnt + 1; 92 | end 93 | end 94 | assign rst = ~rst_cnt[15]; 95 | 96 | // This signal advance should result in 1.024kHz signal 97 | reg [19:0] signal_advance = 20'b00000_00001_00000_00000; 98 | wire pdm_output; 99 | pdm_sine #( 100 | .N_DIV(42) 101 | ) pdm_sine1_I ( 102 | .pdm_pad(pdm_output), 103 | .adv(signal_advance), 104 | .clk(clk_42mhz), 105 | .rst(rst) 106 | ); 107 | 108 | assign audio_l = pdm_output; 109 | assign audio_r = pdm_output; 110 | 111 | endmodule 112 | -------------------------------------------------------------------------------- /icebreaker/gamepad-audio/gen_sin_table.c: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - sine pdm audio demo 3 | * 4 | * Copyright (C) 2020 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | // This program generates a sin correction table. This table is then loaded 21 | // into bram of the FPGA to provide a lookup table. 22 | 23 | #include 24 | #include 25 | 26 | int main() 27 | { 28 | fprintf(stderr, "Generating the sin lookup table.\n"); 29 | fprintf(stderr, "From 0 to PI/2, as the rest are simple transformations\n"); 30 | 31 | for (int i = 0; i < 256; i++) { 32 | double dvalue = sin((M_PI_2 / 255.0) * i); 33 | long lvalue = 0x7FFFFFFFl * dvalue; 34 | 35 | fprintf(stderr, "."); 36 | 37 | if ((i % 8) == 0) { 38 | printf("@%08x", i); 39 | } 40 | printf(" %08lX", lvalue); 41 | //printf("%f\n", value); 42 | //printf("%5i | %f\n", i, value); 43 | if ((i % 8) == 7) { 44 | printf("\n"); 45 | } 46 | } 47 | 48 | fprintf(stderr, "\ndone\n"); 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /icebreaker/gamepad-audio/pdm_sine_mod.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - PDM sine wave generator 3 | * 4 | * Copyright (C) 2020 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | `default_nettype none 20 | 21 | module pdm_sine #( 22 | parameter integer N_DIV = 42000, // clock divider 23 | parameter integer LOG_N_DIV = $clog2(N_DIV) 24 | )( 25 | 26 | // The pdm signal output pad 27 | output wire pdm_pad, 28 | 29 | /* Advance essentially the clock divider. 30 | * Fixed point value with 10.10 bit split. 31 | * The value of b0000000001_0000000000 32 | * will result in a 1.024kHz signal 33 | */ 34 | input [19:0] adv, 35 | 36 | // Clock and reset 37 | input clk, 38 | input rst 39 | ); 40 | 41 | /* Generate strobe */ 42 | reg strobe; 43 | reg [LOG_N_DIV:0] clk_div = N_DIV - 1; 44 | always @(posedge clk) begin 45 | if (rst) begin 46 | clk_div <= N_DIV; 47 | strobe <= 0; 48 | end else 49 | if (clk_div[LOG_N_DIV]) begin 50 | clk_div <= N_DIV - 1; 51 | strobe <= 1; 52 | end else begin 53 | clk_div <= clk_div - 1; 54 | strobe <= 0; 55 | end 56 | end 57 | 58 | /* The Sine value lookup table is meant to cover a 1024 value range 59 | * But we only need to store 1/4 of the values. The remaining ones 60 | * are easy to calculate by simple order reversal and sign change. 61 | * For 1024 values we need 10 bits. For 1/4th we need 8 bits as input. 62 | * The output values are signed 32 bits, but we only need to store half 63 | * of that range so the stored values cover 31 bits. 64 | */ 65 | 66 | // LUT input bit width 67 | localparam SIN_I_BW = 8; 68 | localparam SIN_O_BW = 32; 69 | 70 | // Load the sine value lookup table 71 | reg [(SIN_O_BW - 1):0] sin_lut [0:((1 << (SIN_I_BW)) - 1)]; 72 | initial $readmemh("sin_table.hex", sin_lut); 73 | 74 | // Convert input value to LUT output value 75 | wire [SIN_I_BW + 1:0] lut_in; 76 | wire [SIN_O_BW - 1:0] lut_out; 77 | wire [SIN_I_BW - 1:0] lut_raddr; 78 | reg [SIN_O_BW - 1:0] lut_rdata; 79 | reg lut_inv; 80 | 81 | assign lut_raddr = lut_in[SIN_I_BW] ? ~lut_in[SIN_I_BW - 1:0] : lut_in[SIN_I_BW - 1:0]; 82 | 83 | always @(posedge clk) 84 | lut_rdata <= sin_lut[lut_raddr]; 85 | 86 | always @(posedge clk) 87 | lut_inv <= lut_in[SIN_I_BW + 1]; 88 | 89 | assign lut_out = lut_inv ? ~lut_rdata : lut_rdata; 90 | 91 | // Generate input to the LUT signal generator 92 | reg [19:0] sin_counter; 93 | always @(posedge clk) begin 94 | if (rst) begin 95 | sin_counter <= 0; 96 | end 97 | if (strobe) begin 98 | sin_counter <= sin_counter + adv; 99 | end 100 | end 101 | 102 | assign lut_in = sin_counter[19:10]; 103 | 104 | // PDM signal generator 105 | localparam G_OW = SIN_O_BW; 106 | 107 | reg [G_OW - 1:0] pdm_level; 108 | reg [G_OW + 1:0] pdm_sigma; 109 | wire pdm_out; 110 | reg pdm_strobe = 0; 111 | assign pdm_out = ~pdm_sigma[G_OW + 1]; 112 | always @(posedge clk) begin 113 | if (rst) begin 114 | pdm_level <= 0; 115 | pdm_sigma <= 0; 116 | pdm_strobe <= 0; 117 | end else begin 118 | if(strobe) begin 119 | pdm_level <= lut_out + ((1 << (G_OW - 1))); 120 | pdm_strobe <= 1; 121 | end else if (pdm_strobe) begin 122 | pdm_strobe <= 0; 123 | pdm_sigma <= pdm_sigma + {pdm_out, pdm_out, pdm_level}; 124 | end 125 | end 126 | end 127 | 128 | assign pdm_pad = pdm_out; 129 | 130 | endmodule -------------------------------------------------------------------------------- /icebreaker/gamepad-audio/pdm_sine_mod_tb.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - PDM sine wave generator test bench 3 | * 4 | * Copyright (C) 2020 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | `default_nettype none 20 | `timescale 1ns / 100ps 21 | 22 | module pdm_sine_tb; 23 | 24 | // Signals 25 | reg rst = 1; 26 | reg clk = 1; 27 | 28 | wire pdm_out; 29 | 30 | reg [19:0] signal_advance = 20'b00000_00001_00000_00000; 31 | 32 | // Setup Recording 33 | initial begin 34 | $dumpfile("pdm_sine_mod_tb.vcd"); 35 | $dumpvars(0,pdm_sine_tb); 36 | end 37 | 38 | // Reset Pulse 39 | initial begin 40 | # 31 rst = 0; 41 | # 20000 $finish; 42 | end 43 | 44 | // Clock 45 | always #5 clk = !clk; 46 | 47 | pdm_sine #( 48 | .N_DIV(1) 49 | ) dut_I ( 50 | .pdm_pad(pdm_out), 51 | .adv(signal_advance), 52 | .clk(clk), 53 | .rst(rst) 54 | ); 55 | 56 | endmodule -------------------------------------------------------------------------------- /icebreaker/gamepad/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 Piotr Esden-Tempski 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /icebreaker/gamepad/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = gamepad 2 | ADD_SRC = uart_baud_tick_gen.v uart_tx.v gamepad_mod.v gamepad_sender_mod.v 3 | 4 | PIN_DEF = ../icebreaker.pcf 5 | DEVICE = up5k 6 | PACKAGE = sg48 7 | 8 | prog: iceprog 9 | 10 | include ../../main.mk 11 | -------------------------------------------------------------------------------- /icebreaker/gamepad/README.md: -------------------------------------------------------------------------------- 1 | An example testing the (S)NES type shift register based gamepad readout. 2 | 3 | ## Hardware requirements 4 | 5 | This example is meant to be used with the gamepad & audio iCEBreaker Pmod attached to Pmod Port A on the iCEBreaker. 6 | 7 | You can find the design files for the gamepad & audio Pmod in the [iCEBreaker Pmod github repository](https://github.com/icebreaker-fpga/icebreaker-pmod/tree/master/gamepad-n-audio) and it might be available from [1BitSquared USA](https://1bitsquared.com/collections/fpga) and [1BitSquared Germany](https://1bitsquared.de/collections/fpga). 8 | 9 | You can wire up your gamepads directly to the Pmod connector, but make sure to power your gamepad from the 3v3 power rail. DO NOT HOOK UP 5V SIGNALS DIRECTLY TO THE PMOD PORT!!! You will break things... that is why the dedicated gamepad Pmod has level shifters. 10 | 11 | I don't think this requires mentioning, but you do all of this at your own risk, you can keep the burned pieces. ;) 12 | 13 | ## Software requirements 14 | 15 | The output from this example is printing to the UART interface of the iCEBreaker. Just connect a serial terminal emulator to the second virtual UART port of the iCEBreaker at 115200 baud. 16 | 17 | On Linux this port will be available as `/dev/ttyUSB1` (make sure you are in the dialout group). 18 | 19 | The output should be a following block of text: 20 | 21 | ``` 22 | 1FFFF 23 | 2FFFF 24 | 30000 25 | 40000 26 | ``` 27 | 28 | The first column is the game port ID. The remaining 4 columns show the gamepad 16bit register status as hexadecimal values. 29 | 30 | If a gamepad is connected you should get all 1s aka `FFFF`. If no gamepad is connected you should get all 0s aka `0000`. 31 | 32 | NOTE: The first version of the gamepad & audio Pmod does not have a pulldown resistor on the data lines. So the no gamepad connected state could be anything as those pins are flapping in the wind. You will get the same issue if you decide to wire up the gamepads directly to the Pmod connector. 33 | 34 | The printed text contains an escape sequence (`"\033[4A"`) that causes the cursor to go up 4 lines and keep printing over the previous output. If you are using some software that does not understand terminal escape sequences you will probably see some garbage output and not a nice square block of text. 35 | 36 | For reference here is the serial port configuration in minicom: 37 | 38 | ``` 39 | +------------------------------------------+ 40 | | A - Serial Device : /dev/ttyUSB1 | 41 | | B - Lockfile Location : /var/lock | 42 | | C - Callin Program : | 43 | | D - Callout Program : | 44 | | E - Bps/Par/Bits : 115200 8N1 | 45 | | F - Hardware Flow Control : No | 46 | | G - Software Flow Control : No | 47 | | | 48 | | Change which setting? | 49 | +------------------------------------------+ 50 | ``` 51 | 52 | ## Building 53 | 54 | Make sure you have the open souce FPGA dev tools installed and in your PATH. The tools you will need are: Yosys, nextpnr-ice40, icestorm. 55 | 56 | Connect your iCEBreaker and run: 57 | 58 | ``` 59 | make prog 60 | ``` 61 | 62 | ## Testing 63 | 64 | There is a simple testbench available for the gamepad readout core module. 65 | 66 | Make sure you have iverilog installed and in your PATH. You will also need gtkwave or equivalent to read the resulting vcd signal trace file. 67 | 68 | To run the simulation build the testbench target with: 69 | 70 | ``` 71 | make gamepad_mod_tb.vcd 72 | ``` 73 | 74 | And then open it in gtkwave with: 75 | ``` 76 | gtkwave gamepad_mod_tb.vcd 77 | ``` 78 | 79 | TIP: You can reload the vcd file without restarting gtkwave with Ctrl-Shift-R ;) 80 | -------------------------------------------------------------------------------- /icebreaker/gamepad/gamepad.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - read (S)NES gamepad and send over UART 3 | * 4 | * Copyright (C) 2020 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | `default_nettype none 21 | 22 | module top ( 23 | input CLK, 24 | input RX, 25 | output TX, 26 | output LEDR_N, 27 | output LEDG_N, 28 | output P1A1, // CLK 29 | input P1A2, // GPD0 30 | input P1A3, // GPD2 31 | //output P1A4, // AudioL 32 | output P1A7, // LATCH 33 | input P1A8, // GPD1 34 | input P1A9, // GPD3 35 | //output P1A10, // Audio R 36 | output LED1, 37 | output LED2, 38 | output LED3, 39 | output LED4, 40 | output LED5 41 | ); 42 | 43 | /* Gamepad Pmod pin decoding */ 44 | wire gp_clk; 45 | wire gp_latch; 46 | wire gp_d0; 47 | wire gp_d1; 48 | wire gp_d2; 49 | wire gp_d3; 50 | //wire audio_l; 51 | //wire audio_r; 52 | 53 | assign P1A1 = gp_clk; 54 | assign P1A7 = gp_latch; 55 | assign {gp_d0, gp_d1, gp_d2, gp_d3} = {P1A2, P1A8, P1A3, P1A9}; 56 | //assign P1A4 = audio_l; 57 | //assign P1A10 = audio_r; 58 | 59 | /* PLL block instantiation */ 60 | wire clk_42mhz; 61 | //assign clk_42mhz = CLK; 62 | SB_PLL40_PAD #( 63 | .DIVR(4'b0000), 64 | // 42MHz 65 | .DIVF(7'b0110111), 66 | .DIVQ(3'b100), 67 | .FILTER_RANGE(3'b001), 68 | .FEEDBACK_PATH("SIMPLE"), 69 | .DELAY_ADJUSTMENT_MODE_FEEDBACK("FIXED"), 70 | .FDA_FEEDBACK(4'b0000), 71 | .DELAY_ADJUSTMENT_MODE_RELATIVE("FIXED"), 72 | .FDA_RELATIVE(4'b0000), 73 | .SHIFTREG_DIV_MODE(2'b00), 74 | .PLLOUT_SELECT("GENCLK"), 75 | .ENABLE_ICEGATE(1'b0) 76 | ) pll_inst ( 77 | .PACKAGEPIN(CLK), 78 | .PLLOUTCORE(), 79 | .PLLOUTGLOBAL(clk_42mhz), 80 | .EXTFEEDBACK(), 81 | .DYNAMICDELAY(), 82 | .RESETB(1'b1), 83 | .BYPASS(1'b0), 84 | .LATCHINPUTVALUE(), 85 | //.LOCK(), 86 | //.SDI(), 87 | //.SDO(), 88 | //.SCLK() 89 | ); 90 | 91 | /* Generate reset signal */ 92 | reg [15:0] rst_cnt = 16'h0000; 93 | wire rst; 94 | always @(posedge clk_42mhz) begin 95 | if (rst_cnt[15] == 0) begin 96 | rst_cnt <= rst_cnt + 1; 97 | end 98 | end 99 | assign rst = ~rst_cnt[15]; 100 | 101 | /* Gamepad read module instance. */ 102 | wire [15:0] gp1; 103 | wire [15:0] gp2; 104 | wire [15:0] gp3; 105 | wire [15:0] gp4; 106 | wire gp_data_ready; 107 | gamepads #( 108 | .N_DIV(21) // 21 -> 1MHz shift clock 109 | ) gp_I ( 110 | .gp_clk(gp_clk), 111 | .gp_latch(gp_latch), 112 | .gp_d0(gp_d0), 113 | .gp_d1(gp_d1), 114 | .gp_d2(gp_d2), 115 | .gp_d3(gp_d3), 116 | .gp1(gp1), 117 | .gp2(gp2), 118 | .gp3(gp3), 119 | .gp4(gp4), 120 | .gp_data_ready(gp_data_ready), 121 | .clk(clk_42mhz), 122 | .rst(rst) 123 | ); 124 | 125 | /* Generate gp_data_ready_strobe. */ 126 | reg gp_old_data_ready = 0; 127 | wire gp_data_ready_strobe; 128 | assign gp_data_ready_strobe = gp_data_ready && 129 | (gp_data_ready != gp_old_data_ready); 130 | always @(posedge clk_42mhz) begin 131 | if (gp_data_ready_strobe) begin 132 | gp_old_data_ready <= 1; 133 | end else if (!gp_data_ready) begin 134 | gp_old_data_ready <= 0; 135 | end 136 | end 137 | 138 | /* Store data to display on LEDs. */ 139 | reg [15:0] gp1_reg = 0; 140 | reg [15:0] gp2_reg = 0; 141 | reg [15:0] gp3_reg = 0; 142 | reg [15:0] gp4_reg = 0; 143 | always @(posedge clk_42mhz) begin 144 | if (gp_data_ready_strobe) begin 145 | gp1_reg <= gp1; 146 | gp2_reg <= gp2; 147 | gp3_reg <= gp3; 148 | gp4_reg <= gp4; 149 | end 150 | end 151 | 152 | assign {LEDG_N, LEDR_N, LED5, LED4, LED3, LED2, LED1} = gp1_reg[6:0]; 153 | 154 | /* Instantiate the tx1 module. 155 | * This module will send out hex values representing the 156 | * gamepad values. 157 | */ 158 | reg tx1_start; 159 | reg [7:0] tx1_data; 160 | wire tx1_busy; 161 | uart_tx #(42000000, 115200) utx1 ( 162 | .clk(clk_42mhz), 163 | .tx_start(tx1_start), 164 | .tx_data(tx1_data), 165 | .tx(TX), 166 | .tx_busy(tx1_busy) 167 | ); 168 | 169 | /* Instantiate the gamepad send module. 170 | * This module will take the gamepad 171 | * registers and convert them to a character string 172 | * sequence. 173 | */ 174 | gamepad_sender gp_sender1 ( 175 | .gp_data_ready_strobe(gp_data_ready_strobe), 176 | .gp1(gp1), 177 | .gp2(gp2), 178 | .gp3(gp3), 179 | .gp4(gp4), 180 | .tx_start(tx1_start), 181 | .tx_data(tx1_data), 182 | .tx_busy(tx1_busy), 183 | .clk(clk_42mhz), 184 | .rst(rst) 185 | ); 186 | 187 | endmodule 188 | -------------------------------------------------------------------------------- /icebreaker/gamepad/gamepad_mod.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - read (S)NES gamepad data module 3 | * 4 | * Copyright (C) 2020 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | `default_nettype none 21 | 22 | module gamepads #( 23 | parameter integer N_DIV = 42000, // clock divider 24 | parameter integer LOG_N_DIV = $clog2(N_DIV) 25 | 26 | )( 27 | 28 | // Gamepad Interface Pads 29 | output wire gp_clk, 30 | output wire gp_latch, 31 | input wire gp_d0, 32 | input wire gp_d1, 33 | input wire gp_d2, 34 | input wire gp_d3, 35 | 36 | // User Interface 37 | output wire [15:0] gp1, 38 | output wire [15:0] gp2, 39 | output wire [15:0] gp3, 40 | output wire [15:0] gp4, 41 | output wire gp_data_ready, 42 | 43 | // Clock and reset 44 | input clk, 45 | input rst 46 | ); 47 | 48 | /* Generate strobe */ 49 | reg strobe; 50 | reg [LOG_N_DIV:0] clk_div = N_DIV - 1; 51 | always @(posedge clk) begin 52 | if (rst) begin 53 | clk_div <= N_DIV; 54 | strobe <= 0; 55 | end else 56 | if (clk_div[LOG_N_DIV]) begin 57 | clk_div <= N_DIV - 1; 58 | strobe <= 1; 59 | end else begin 60 | clk_div <= clk_div - 1; 61 | strobe <= 0; 62 | end 63 | end 64 | 65 | /* Gamepad read out state machine */ 66 | localparam 67 | GPS_IDLE = 0, 68 | GPS_LATCH = 1, 69 | GPS_DATA = 2, 70 | GPS_CLOCK = 3; 71 | 72 | reg [15:0] gp1reg; 73 | reg [15:0] gp2reg; 74 | reg [15:0] gp3reg; 75 | reg [15:0] gp4reg; 76 | 77 | reg [1:0] state = GPS_IDLE; 78 | reg [4:0] read_cnt = 15; 79 | reg gp_latch_reg = 0; 80 | reg gp_clk_reg = 0; 81 | reg gp_data_ready_reg = 0; 82 | always @(posedge clk) begin 83 | if (rst) begin 84 | state <= GPS_IDLE; 85 | gp_latch_reg <= 0; 86 | gp_clk_reg <= 0; 87 | gp1reg <= 0; 88 | gp2reg <= 0; 89 | gp3reg <= 0; 90 | gp4reg <= 0; 91 | gp_data_ready_reg <= 0; 92 | end else if (strobe) begin 93 | if (state == GPS_IDLE) begin 94 | gp_latch_reg <= 1; 95 | gp_clk_reg <= 0; 96 | state <= GPS_LATCH; 97 | end 98 | if (state == GPS_LATCH) begin 99 | gp_latch_reg <= 0; 100 | gp_clk_reg <= 0; 101 | gp1reg <= 0; 102 | gp2reg <= 0; 103 | gp3reg <= 0; 104 | gp4reg <= 0; 105 | gp_data_ready_reg <= 0; 106 | state <= GPS_DATA; 107 | end 108 | if (state == GPS_DATA) begin 109 | gp1reg <= {gp_d0, gp1reg[15:1]}; 110 | gp2reg <= {gp_d1, gp2reg[15:1]}; 111 | gp3reg <= {gp_d2, gp3reg[15:1]}; 112 | gp4reg <= {gp_d3, gp4reg[15:1]}; 113 | gp_clk_reg <= 1; 114 | state <= GPS_CLOCK; 115 | end 116 | if (state == GPS_CLOCK) begin 117 | gp_clk_reg <= 0; 118 | if (read_cnt == 0) begin 119 | read_cnt <= 15; 120 | gp_data_ready_reg <= 1; 121 | state <= GPS_IDLE; 122 | end else begin 123 | read_cnt <= read_cnt - 1; 124 | state <= GPS_DATA; 125 | end 126 | end 127 | end 128 | end 129 | 130 | assign gp_latch = gp_latch_reg; 131 | assign gp_clk = gp_clk_reg; 132 | 133 | assign gp1 = gp1reg; 134 | assign gp2 = gp2reg; 135 | assign gp3 = gp3reg; 136 | assign gp4 = gp4reg; 137 | assign gp_data_ready = gp_data_ready_reg; 138 | 139 | endmodule 140 | -------------------------------------------------------------------------------- /icebreaker/gamepad/gamepad_mod_tb.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - read (S)NES gamepad data module test bench 3 | * 4 | * Copyright (C) 2020 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | `default_nettype none 21 | `timescale 1ns / 100ps 22 | 23 | module gamepad_tb; 24 | 25 | // Signals 26 | reg rst = 1; 27 | reg clk = 1; 28 | 29 | wire phy_clk; 30 | wire phy_latch; 31 | reg phy_d0 = 1; 32 | reg phy_d1 = 0; 33 | reg phy_d2 = 1; 34 | reg phy_d3 = 0; 35 | 36 | wire [15:0] gp1; 37 | wire [15:0] gp2; 38 | wire [15:0] gp3; 39 | wire [15:0] gp4; 40 | wire gp_data_ready; 41 | 42 | // Setup Recording 43 | initial begin 44 | $dumpfile("gamepad_mod_tb.vcd"); 45 | $dumpvars(0,gamepad_tb); 46 | end 47 | 48 | // Reset Pulse 49 | initial begin 50 | # 31 rst = 0; 51 | # 20000 $finish; 52 | end 53 | 54 | // Clock 55 | always #5 clk = !clk; 56 | 57 | gamepads #( 58 | .N_DIV(0) 59 | ) dut_I ( 60 | .gp_clk(phy_clk), 61 | .gp_latch(phy_latch), 62 | .gp_d0(phy_d0), 63 | .gp_d1(phy_d1), 64 | .gp_d2(phy_d2), 65 | .gp_d3(phy_d3), 66 | .gp1(gp1), 67 | .gp2(gp2), 68 | .gp3(gp3), 69 | .gp4(gp4), 70 | .gp_data_ready(gp_data_ready), 71 | .clk(clk), 72 | .rst(rst) 73 | ); 74 | 75 | endmodule -------------------------------------------------------------------------------- /icebreaker/gamepad/gamepad_sender_mod.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - Generate hex data out of gamepad registers 3 | * 4 | * Copyright (C) 2020 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module gamepad_sender ( 21 | // Gamepad input 22 | input wire gp_data_ready_strobe, 23 | input wire [15:0] gp1, 24 | input wire [15:0] gp2, 25 | input wire [15:0] gp3, 26 | input wire [15:0] gp4, 27 | 28 | // Serial tx 29 | output reg tx_start, 30 | output reg [7:0] tx_data, 31 | input wire tx_busy, 32 | 33 | // Clock and reset 34 | input clk, 35 | input rst 36 | ); 37 | 38 | /* Sender FSM states. */ 39 | localparam 40 | GPXS_IDLE = 0, 41 | GPXS_SEND_START = 1, 42 | GPXS_WAIT_START = 2, 43 | GPXS_SEND_GP_ID = 3, 44 | GPXS_WAIT_GP_ID = 4, 45 | GPXS_SEND_GP = 5, 46 | GPXS_WAIT_GP = 6, 47 | GPXS_SEND_CR = 7, 48 | GPXS_WAIT_CR = 8, 49 | GPXS_SEND_NL = 9, 50 | GPXS_WAIT_NL = 10; 51 | 52 | /* 4 bit to ascii hex lut */ 53 | wire [7:0] ahex [0:15]; 54 | 55 | assign ahex[0] = "0"; 56 | assign ahex[1] = "1"; 57 | assign ahex[2] = "2"; 58 | assign ahex[3] = "3"; 59 | assign ahex[4] = "4"; 60 | assign ahex[5] = "5"; 61 | assign ahex[6] = "6"; 62 | assign ahex[7] = "7"; 63 | assign ahex[8] = "8"; 64 | assign ahex[9] = "9"; 65 | assign ahex[10] = "A"; 66 | assign ahex[11] = "B"; 67 | assign ahex[12] = "C"; 68 | assign ahex[13] = "D"; 69 | assign ahex[14] = "E"; 70 | assign ahex[15] = "F"; 71 | 72 | /* Start escape sequence for the terminal. */ 73 | wire [7:0] start_seq [0:3]; 74 | 75 | /* Move cursor 4 lines up. Terminal escape sequence. */ 76 | assign start_seq[3] = "\033"; 77 | assign start_seq[2] = "["; 78 | assign start_seq[1] = "4"; 79 | assign start_seq[0] = "A"; 80 | 81 | /* Implementation of the FSM. */ 82 | reg [3:0] gpx_reg[0:15]; 83 | reg [3:0] gpx_state = GPXS_IDLE; 84 | reg [1:0] start_cnt; 85 | reg [4:0] gpx_cnt; 86 | always @(posedge clk) begin 87 | case (gpx_state) 88 | GPXS_IDLE: if(gp_data_ready_strobe) begin 89 | gpx_reg[0] <= gp4[3:0]; 90 | gpx_reg[1] <= gp4[7:4]; 91 | gpx_reg[2] <= gp4[11:8]; 92 | gpx_reg[3] <= gp4[15:12]; 93 | gpx_reg[4] <= gp3[3:0]; 94 | gpx_reg[5] <= gp3[7:4]; 95 | gpx_reg[6] <= gp3[11:8]; 96 | gpx_reg[7] <= gp3[15:12]; 97 | gpx_reg[8] <= gp2[3:0]; 98 | gpx_reg[9] <= gp2[7:4]; 99 | gpx_reg[10] <= gp2[11:8]; 100 | gpx_reg[11] <= gp2[15:12]; 101 | gpx_reg[12] <= gp1[3:0]; 102 | gpx_reg[13] <= gp1[7:4]; 103 | gpx_reg[14] <= gp1[11:8]; 104 | gpx_reg[15] <= gp1[15:12]; 105 | tx_data <= start_seq[3]; 106 | tx_start <= 1; 107 | gpx_state <= GPXS_SEND_START; 108 | gpx_cnt <= 15; 109 | start_cnt <= 2; 110 | end 111 | GPXS_SEND_START: if(tx_busy) begin 112 | tx_start <= 0; 113 | gpx_state <= GPXS_WAIT_START; 114 | end 115 | GPXS_WAIT_START: if(~tx_busy) begin 116 | if (start_cnt == 2'b11) begin 117 | tx_data <= "1"; 118 | tx_start <= 1; 119 | gpx_state <= GPXS_SEND_GP_ID; 120 | end else begin 121 | tx_data <= start_seq[start_cnt]; 122 | tx_start <= 1; 123 | gpx_state <= GPXS_SEND_START; 124 | start_cnt <= start_cnt - 1; 125 | end 126 | end 127 | GPXS_SEND_GP_ID: if(tx_busy) begin 128 | tx_start <= 0; 129 | gpx_state <= GPXS_WAIT_GP_ID; 130 | end 131 | GPXS_WAIT_GP_ID: if(~tx_busy) begin 132 | tx_data <= ahex[gpx_reg[gpx_cnt]]; 133 | tx_start <= 1; 134 | gpx_state <= GPXS_SEND_GP; 135 | gpx_cnt <= gpx_cnt - 1; 136 | end 137 | GPXS_SEND_GP: if(tx_busy) begin 138 | tx_start <= 0; 139 | gpx_state <= GPXS_WAIT_GP; 140 | end 141 | GPXS_WAIT_GP: if(~tx_busy) begin 142 | if (gpx_cnt[1:0] == 2'b11) begin 143 | tx_data <= "\r"; 144 | tx_start <= 1; 145 | gpx_state <= GPXS_SEND_CR; 146 | end else begin 147 | tx_data <= ahex[gpx_reg[gpx_cnt]]; 148 | tx_start <= 1; 149 | gpx_state <= GPXS_SEND_GP; 150 | gpx_cnt <= gpx_cnt - 1; 151 | end 152 | end 153 | GPXS_SEND_CR: if(tx_busy) begin 154 | tx_start <= 0; 155 | gpx_state <= GPXS_WAIT_CR; 156 | end 157 | GPXS_WAIT_CR: if(~tx_busy) begin 158 | tx_data <= "\n"; 159 | tx_start <= 1; 160 | gpx_state <= GPXS_SEND_NL; 161 | end 162 | GPXS_SEND_NL: if(tx_busy) begin 163 | tx_start <= 0; 164 | gpx_state <= GPXS_WAIT_NL; 165 | end 166 | GPXS_WAIT_NL: if(~tx_busy) begin 167 | if (gpx_cnt[3:2] == 2'b11) begin 168 | gpx_state <= GPXS_IDLE; 169 | end else begin 170 | tx_data <= "4" - gpx_cnt[3:2]; 171 | tx_start <= 1; 172 | gpx_state <= GPXS_SEND_GP_ID; 173 | end 174 | end 175 | endcase 176 | end 177 | 178 | endmodule -------------------------------------------------------------------------------- /icebreaker/gamepad/uart_baud_tick_gen.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - Async uart baud tick generator module 3 | * 4 | * Copyright (C) 2018 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | `ifndef _uart_baud_tick_gen_v_ 21 | `define _uart_baud_tick_gen_v_ 22 | 23 | /*** 24 | * This module generates a bit baud tick multiplied by the oversampling parameter. 25 | */ 26 | module baud_tick_gen( 27 | input clk, enable, 28 | output tick); 29 | parameter clk_freq = 12000000; 30 | parameter baud = 115200; 31 | parameter oversampling = 1; 32 | 33 | function integer log2(input integer v); begin log2=0; while(v >> log2) log2 = log2 + 1; end endfunction 34 | 35 | localparam acc_width = log2(clk_freq / baud) + 8; // +/- 2% max timing error over a byte 36 | 37 | reg [acc_width:0] acc = 0; 38 | 39 | localparam shiftlimiter = log2((baud * oversampling) >> (31 - acc_width)); // this makes sure inc calculation doesn't overflow (verilog uses 32bit variables internally) 40 | localparam inc = ((baud * oversampling << (acc_width - shiftlimiter)) + (clk_freq >> (shiftlimiter + 1))) / (clk_freq >> shiftlimiter); // Calculate accumulate increment 41 | //initial $display("acc_width %d, shiftlimit %d, inc %d", acc_width, shiftlimiter, inc); 42 | 43 | always @(posedge clk) if (enable) acc <= acc[acc_width-1:0] + inc[acc_width:0]; else acc <= inc[acc_width:0]; 44 | assign tick = acc[acc_width]; 45 | 46 | endmodule 47 | 48 | `endif // _uart_baud_tick_gen_v_ 49 | -------------------------------------------------------------------------------- /icebreaker/gamepad/uart_tx.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - Async uart tx module 3 | * 4 | * Copyright (C) 2018 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module uart_tx #( 21 | parameter integer clk_freq = 12000000, 22 | parameter integer baud = 115200 23 | )( 24 | input clk, 25 | input tx_start, 26 | input [7:0] tx_data, 27 | output tx, 28 | output tx_busy 29 | ); 30 | 31 | wire bit_tick; 32 | baud_tick_gen #(clk_freq, baud) tickgen(.clk(clk), .enable(tx_busy), .tick(bit_tick)); 33 | 34 | localparam 35 | IDLE = 4'b0000, // tx = high 36 | BIT_START = 4'b0100, // tx = low 37 | BIT0 = 4'b1000, // tx = data bit 0 38 | BIT1 = 4'b1001, // tx = data bit 1 39 | BIT2 = 4'b1010, // tx = data bit 2 40 | BIT3 = 4'b1011, // tx = data bit 3 41 | BIT4 = 4'b1100, // tx = data bit 4 42 | BIT5 = 4'b1101, // tx = data bit 5 43 | BIT6 = 4'b1110, // tx = data bit 6 44 | BIT7 = 4'b1111, // tx = data bit 7 45 | BIT_STOP1 = 4'b0010, // tx = high 46 | BIT_STOP2 = 4'b0011; // tx = high 47 | 48 | reg [3:0] tx_state = IDLE; 49 | wire tx_ready = (tx_state == IDLE); 50 | assign tx_busy = ~tx_ready; 51 | 52 | reg [7:0] tx_shift = 0; 53 | always @(posedge clk) 54 | begin 55 | if (tx_ready & tx_start) 56 | tx_shift <= tx_data; 57 | else 58 | if (tx_state[3] & bit_tick) 59 | tx_shift <= (tx_shift >> 1); 60 | 61 | case (tx_state) 62 | IDLE: if(tx_start) tx_state <= BIT_START; 63 | BIT_START: if(bit_tick) tx_state <= BIT0; 64 | BIT0: if(bit_tick) tx_state <= BIT1; 65 | BIT1: if(bit_tick) tx_state <= BIT2; 66 | BIT2: if(bit_tick) tx_state <= BIT3; 67 | BIT3: if(bit_tick) tx_state <= BIT4; 68 | BIT4: if(bit_tick) tx_state <= BIT5; 69 | BIT5: if(bit_tick) tx_state <= BIT6; 70 | BIT6: if(bit_tick) tx_state <= BIT7; 71 | BIT7: if(bit_tick) tx_state <= BIT_STOP1; 72 | BIT_STOP1: if(bit_tick) tx_state <= BIT_STOP2; 73 | BIT_STOP2: if(bit_tick) tx_state <= IDLE; 74 | default: if(bit_tick) tx_state <= IDLE; 75 | endcase 76 | 77 | end 78 | 79 | // high if state START, STOP1, STOP2 80 | // | high if transmitting bits and bit is 1 81 | // | | 82 | // V V 83 | assign tx = (tx_state < 4) | (tx_state[3] & tx_shift[0]); 84 | 85 | endmodule 86 | -------------------------------------------------------------------------------- /icebreaker/icebreaker-examples.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | 3 | name : :icebreaker:examples:0 4 | 5 | filesets: 6 | pcf: 7 | files: [icebreaker.pcf : {file_type : PCF}] 8 | blink_count_shift: 9 | files: [blink_count_shift/blink_count_shift.v : {file_type : verilogSource}] 10 | pdm_fade: 11 | files: [pdm_fade/pdm.v : {file_type : verilogSource}] 12 | pdm_fade_gamma: 13 | files: [pdm_fade_gamma/gamma_pdm.v : {file_type : verilogSource}] 14 | depend: ["fusesoc:utils:generators"] 15 | pll_uart: 16 | files: 17 | - pll_uart/uart_tx.v : {is_include_file : true} 18 | - pll_uart/uart_rx.v : {is_include_file : true} 19 | - pll_uart/uart_baud_tick_gen.v : {is_include_file : true} 20 | - pll_uart/pll_uart_mirror.v 21 | file_type: verilogSource 22 | pwm_fade: 23 | files: [pwm_fade/pwm.v : {file_type : verilogSource}] 24 | pwm_fade_gamma: 25 | files: [pwm_fade_gamma/gamma_pwm.v : {file_type : verilogSource}] 26 | depend: ["fusesoc:utils:generators"] 27 | 28 | targets: 29 | blink_count_shift: &target 30 | default_tool : icestorm 31 | filesets: [pcf, blink_count_shift] 32 | tools: 33 | icestorm: 34 | pnr : next 35 | nextpnr_options: [--up5k] 36 | toplevel : top 37 | 38 | pdm_fade: 39 | <<: *target 40 | filesets: [pcf, pdm_fade] 41 | 42 | pdm_fade_gamma: 43 | <<: *target 44 | filesets: [pcf, pdm_fade_gamma] 45 | generate : [gamma_table] 46 | 47 | pll_uart: 48 | <<: *target 49 | filesets: [pcf, pll_uart] 50 | 51 | pwm_fade: 52 | <<: *target 53 | filesets: [pcf, pwm_fade] 54 | 55 | pwm_fade_gamma: 56 | <<: *target 57 | filesets: [pcf, pwm_fade_gamma] 58 | generate : [gamma_table] 59 | 60 | 61 | generate: 62 | gamma_table: 63 | generator: custom 64 | parameters: 65 | command: make -C pdm_fade_gamma gamma_table.hex 66 | copy_core : true 67 | run_from_core : true 68 | output: 69 | files: 70 | - pdm_fade_gamma/gamma_table.hex : {file_type : user, copyto: gamma_table.hex} 71 | -------------------------------------------------------------------------------- /icebreaker/icebreaker.pcf: -------------------------------------------------------------------------------- 1 | # 12 MHz clock 2 | set_io -nowarn CLK 35 3 | set_frequency CLK 12 4 | 5 | # RS232 6 | set_io -nowarn RX 6 7 | set_io -nowarn TX 9 8 | 9 | # LEDs and Button 10 | set_io -nowarn BTN_N 10 11 | set_io -nowarn LEDR_N 11 12 | set_io -nowarn LEDG_N 37 13 | 14 | # RGB LED Driver 15 | set_io -nowarn LED_RED_N 39 16 | set_io -nowarn LED_GRN_N 40 17 | set_io -nowarn LED_BLU_N 41 18 | set_io -nowarn LED_RGB[0] 39 19 | set_io -nowarn LED_RGB[1] 40 20 | set_io -nowarn LED_RGB[2] 41 21 | 22 | # SPI Flash 23 | set_io -nowarn FLASH_SCK 15 24 | set_io -nowarn FLASH_SSB 16 25 | set_io -nowarn FLASH_IO0 14 26 | set_io -nowarn FLASH_IO1 17 27 | set_io -nowarn FLASH_IO2 12 28 | set_io -nowarn FLASH_IO3 13 29 | 30 | # PMOD 1A 31 | set_io -nowarn P1A1 4 32 | set_io -nowarn P1A2 2 33 | set_io -nowarn P1A3 47 34 | set_io -nowarn P1A4 45 35 | set_io -nowarn P1A7 3 36 | set_io -nowarn P1A8 48 37 | set_io -nowarn P1A9 46 38 | set_io -nowarn P1A10 44 39 | 40 | # PMOD 1B 41 | set_io -nowarn P1B1 43 42 | set_io -nowarn P1B2 38 43 | set_io -nowarn P1B3 34 44 | set_io -nowarn P1B4 31 45 | set_io -nowarn P1B7 42 46 | set_io -nowarn P1B8 36 47 | set_io -nowarn P1B9 32 48 | set_io -nowarn P1B10 28 49 | 50 | # PMOD 2 51 | set_io -nowarn P2_1 27 52 | set_io -nowarn P2_2 25 53 | set_io -nowarn P2_3 21 54 | set_io -nowarn P2_4 19 55 | set_io -nowarn P2_7 26 56 | set_io -nowarn P2_8 23 57 | set_io -nowarn P2_9 20 58 | set_io -nowarn P2_10 18 59 | 60 | # LEDs and Buttons (PMOD 2) 61 | set_io -nowarn LED1 26 62 | set_io -nowarn LED2 27 63 | set_io -nowarn LED3 25 64 | set_io -nowarn LED4 23 65 | set_io -nowarn LED5 21 66 | set_io -nowarn BTN1 20 67 | set_io -nowarn BTN2 19 68 | set_io -nowarn BTN3 18 69 | -------------------------------------------------------------------------------- /icebreaker/pdm_fade/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 Piotr Esden-Tempski 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /icebreaker/pdm_fade/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = pdm 2 | 3 | PIN_DEF = ../icebreaker.pcf 4 | DEVICE = up5k 5 | PACKAGE = sg48 6 | 7 | prog: iceprog 8 | 9 | include ../../main.mk 10 | -------------------------------------------------------------------------------- /icebreaker/pdm_fade/pdm.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - pdm demo 3 | * 4 | * Copyright (C) 2018 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | // This example is based on the PDM module by Tommy Thorn 21 | // You can find him on GitHub as @tommythorn 22 | // The original is here: 23 | // https://github.com/tommythorn/yari/blob/master/shared/rtl/soclib/pdm.v 24 | 25 | // This example generates PDM (Pulse Density Modulation) to fade LEDs 26 | // The intended result is opposite pulsating Red and Green LEDs 27 | // on the iCEBreaker. The intended effect is that the two LED "breathe" in 28 | // brigtness up and down in opposite directions. 29 | 30 | module top ( 31 | input CLK, 32 | output LEDR_N, 33 | output LEDG_N, 34 | output P1A1, // Debug pins 35 | output P1A2, 36 | output P1A7, 37 | output P1A8 38 | ); 39 | 40 | // PDM generator 41 | /* 42 | * Pulse Density Modulation for controlling LED intensity. 43 | * The theory is as follows: 44 | * given a desired target level 0 <= T <= 1, control the output pdm_out 45 | * in {1,0}, such that pdm_out on average is T. Do this by integrating the 46 | * error T - pdm_out over time and switch pdm_out such that the sum of 47 | * (T - pdm_out) is finite. 48 | * 49 | * pdm_sigma = 0, pdm_out = 0 50 | * forever 51 | * pdm_sigma = pdm_sigma + (T - pdm_out) 52 | * if (pdm_sigma >= 0) 53 | * pdm_out = 1 54 | * else 55 | * pdm_out = 0 56 | * 57 | * Check: T = 0, pdm_out is never turned on; T = 1, pdm_out is olways on; 58 | * T = 0.5, pdm_out toggles 59 | * 60 | * In fixed point arithmetic this becomes the following (assume N-bit arith) 61 | * pdm_sigma = pdm_sigma_float * 2^N = pdm_sigma_float << N. 62 | * As |pdm_sigma| <= 1, N+2 bits is sufficient 63 | * 64 | * pdm_sigma = 0, pdm_out = 0 65 | * forever 66 | * D = T + (~pdm_out + 1) << N === T + (pdm_out << N) + (pdm_out << (N+1)) 67 | * pdm_sigma = pdm_sigma + D 68 | * pdm_out = 1 & (pdm_sigma >> (N+1)) 69 | */ 70 | reg [16-1:0] pdm_level = 0; 71 | reg [16+1:0] pdm_sigma; 72 | reg pdm_out; 73 | assign pdm_out = ~pdm_sigma[16+1]; 74 | always @(posedge CLK) begin 75 | pdm_sigma <= pdm_sigma + {pdm_out, pdm_out, pdm_level}; 76 | end 77 | 78 | // PDM level generator 79 | // Fading up and down creating a slow sawtooth output 80 | // The fade up down takes about 11.18 seconds 81 | // Note: You will see that the LEDs spend more time being very bright 82 | // than visibly fading, this is because our vision is non linear. Take a look 83 | // at the pwm_fade_gamma example that fixes this issue. :) 84 | reg [13:0] pdm_inc_counter = 0; 85 | reg [16-2:0] pdm_level_value; 86 | reg pdm_dir = 1; 87 | always @(posedge CLK) begin 88 | // Divide clock by 8192 89 | pdm_inc_counter <= pdm_inc_counter + 1; 90 | 91 | // increment/decrement pdm value at 1.5kHz 92 | if (pdm_inc_counter[13]) begin 93 | pdm_inc_counter <= 0; 94 | pdm_level_value <= pdm_level_value + 1; 95 | end 96 | 97 | if (pdm_level_value[16-2]) 98 | pdm_level <= ~pdm_level_value << 2; 99 | else 100 | pdm_level <= pdm_level_value << 2; 101 | end 102 | 103 | assign LEDG_N = ~pdm_out; 104 | assign LEDR_N = pdm_out; 105 | assign P1A1 = pdm_inc_counter[15]; // 50% duty cycle PDM inc clock 106 | assign P1A2 = pdm_out; // PDM output on a GPIO pin 107 | assign P1A7 = pdm_inc_counter[15]; // 50% duty cycle PDM inc clock 108 | assign P1A8 = pdm_out; // PDM output on a GPIO pin 109 | 110 | endmodule -------------------------------------------------------------------------------- /icebreaker/pdm_fade_gamma/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.hex 3 | gen_gamma_table 4 | -------------------------------------------------------------------------------- /icebreaker/pdm_fade_gamma/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 Piotr Esden-Tempski 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /icebreaker/pdm_fade_gamma/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = gamma_pdm 2 | ADD_DEPS = gamma_table.hex 3 | ADD_CLEAN = *.o gen_gamma_table *.hex 4 | 5 | PIN_DEF = ../icebreaker.pcf 6 | DEVICE = up5k 7 | PACKAGE = sg48 8 | 9 | prog: iceprog 10 | 11 | include ../../main.mk 12 | 13 | gen_gamma_table: gen_gamma_table.o 14 | gcc $< -o $@ -lm 15 | 16 | gamma_table.hex: gen_gamma_table 17 | ./gen_gamma_table > gamma_table.hex 18 | -------------------------------------------------------------------------------- /icebreaker/pdm_fade_gamma/gamma_pdm.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - pdm demo 3 | * 4 | * Copyright (C) 2018 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | // This example is based on the PDM module by Tommy Thorn 21 | // You can find him on GitHub as @tommythorn 22 | // The original is here: 23 | // https://github.com/tommythorn/yari/blob/master/shared/rtl/soclib/pdm.v 24 | 25 | // This example generates PDM (Pulse Density Modulation) to fade LEDs 26 | // The intended result is opposite pulsating Red and Green LEDs 27 | // on the iCEBreaker. The intended effect is that the two LED "breathe" in 28 | // brigtness up and down in opposite directions. 29 | 30 | module top ( 31 | input CLK, 32 | output LEDR_N, 33 | output LEDG_N, 34 | output P1A1, // Debug pins 35 | output P1A2, 36 | output P1A3, 37 | output P1A7, 38 | output P1A8, 39 | output P1A9 40 | ); 41 | 42 | // Gamma value lookup table parameters 43 | parameter G_PW = 8; // Number of input bits 44 | parameter G_OW = 16; // Number of output bits 45 | 46 | // Load the gamma value lookup table 47 | reg [(G_OW-1):0] gamma_lut [0:((1<<(G_PW))-1)]; 48 | initial $readmemh("gamma_table.hex", gamma_lut); 49 | 50 | // PDM generator 51 | /* 52 | * Pulse Density Modulation for controlling LED intensity. 53 | * The theory is as follows: 54 | * given a desired target level 0 <= T <= 1, control the output pdm_out 55 | * in {1,0}, such that pdm_out on average is T. Do this by integrating the 56 | * error T - pdm_out over time and switch pdm_out such that the sum of 57 | * (T - pdm_out) is finite. 58 | * 59 | * pdm_sigma = 0, pdm_out = 0 60 | * forever 61 | * pdm_sigma = pdm_sigma + (T - pdm_out) 62 | * if (pdm_sigma >= 0) 63 | * pdm_out = 1 64 | * else 65 | * pdm_out = 0 66 | * 67 | * Check: T = 0, pdm_out is never turned on; T = 1, pdm_out is olways on; 68 | * T = 0.5, pdm_out toggles 69 | * 70 | * In fixed point arithmetic this becomes the following (assume N-bit arith) 71 | * pdm_sigma = pdm_sigma_float * 2^N = pdm_sigma_float << N. 72 | * As |pdm_sigma| <= 1, N+2 bits is sufficient 73 | * 74 | * pdm_sigma = 0, pdm_out = 0 75 | * forever 76 | * D = T + (~pdm_out + 1) << N === T + (pdm_out << N) + (pdm_out << (N+1)) 77 | * pdm_sigma = pdm_sigma + D 78 | * pdm_out = 1 & (pdm_sigma >> (N+1)) 79 | */ 80 | reg [G_OW-1:0] pdm_level1; 81 | reg [G_OW+1:0] pdm_sigma1; 82 | reg pdm_out1; 83 | assign pdm_out1 = ~pdm_sigma1[G_OW+1]; 84 | always @(posedge CLK) begin 85 | pdm_sigma1 <= pdm_sigma1 + {pdm_out1, pdm_out1, pdm_level1}; 86 | end 87 | 88 | reg [G_OW-1:0] pdm_level2; 89 | reg [G_OW+1:0] pdm_sigma2; 90 | reg pdm_out2; 91 | assign pdm_out2 = ~pdm_sigma2[G_OW+1]; 92 | always @(posedge CLK) begin 93 | pdm_sigma2 <= pdm_sigma2 + {pdm_out2, pdm_out2, pdm_level2}; 94 | end 95 | 96 | // PDM level generator 97 | // Fading up and down creating a slow sawtooth output 98 | // The fade up down takes about 11.18 seconds 99 | // Note: You will see that the LEDs spend more time being very bright 100 | // than visibly fading, this is because our vision is non linear. Take a look 101 | // at the pwm_fade_gamma example that fixes this issue. :) 102 | reg [17:0] pdm_inc_counter = 0; 103 | reg [G_PW-1+1:0] pdm_level_value; 104 | reg [G_OW-1:0] pdm_gamma_level_p; 105 | reg [G_OW-1:0] pdm_gamma_level_n; 106 | always @(posedge CLK) begin 107 | // Divide clock by 131071 108 | pdm_inc_counter <= pdm_inc_counter + 1; 109 | 110 | // increment/decrement pwm compare value at 91.55Hz 111 | if (pdm_inc_counter[17]) begin 112 | pdm_inc_counter <= 0; 113 | pdm_level_value <= pdm_level_value + 1; 114 | end 115 | 116 | pdm_gamma_level_p <= gamma_lut[ pdm_level_value[G_PW-1:0]]; 117 | pdm_gamma_level_n <= gamma_lut[~pdm_level_value[G_PW-1:0]]; 118 | end 119 | 120 | assign pdm_level1 = pdm_level_value[G_PW-1+1] ? pdm_gamma_level_n : pdm_gamma_level_p; 121 | assign pdm_level2 = pdm_level_value[G_PW-1+1] ? pdm_gamma_level_p : pdm_gamma_level_n; 122 | 123 | assign LEDG_N = ~pdm_out1; 124 | assign LEDR_N = ~pdm_out2; 125 | assign P1A1 = pdm_inc_counter[15]; // 50% duty cycle PDM inc clock 126 | assign P1A2 = pdm_out1; // PDM output on a GPIO pin 127 | assign P1A3 = pdm_out2; // PDM output on a GPIO pin 128 | assign P1A7 = pdm_inc_counter[15]; // 50% duty cycle PDM inc clock 129 | assign P1A8 = pdm_out1; // PDM output on a GPIO pin 130 | assign P1A9 = pdm_out2; // PDM output on a GPIO pin 131 | 132 | endmodule -------------------------------------------------------------------------------- /icebreaker/pdm_fade_gamma/gen_gamma_table.c: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - gamma pwm demo 3 | * 4 | * Copyright (C) 2018 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | // This program generates a gamma correction table. This table is then loaded 21 | // into bram of the FPGA to provide a lookup table. 22 | 23 | #include 24 | #include 25 | 26 | #define GAMMA 2.2 27 | 28 | int main() 29 | { 30 | fprintf(stderr, "Generating the gamma lookup table.\n"); 31 | 32 | for (int i = 0; i < 256; i++) { 33 | double dvalue = pow((1.0 / 255.0) * i, GAMMA); 34 | long lvalue = 0xFFFFl * dvalue; 35 | 36 | fprintf(stderr, "."); 37 | 38 | if ((i % 8) == 0) { 39 | printf("@%08x", i); 40 | } 41 | printf(" %04lX", lvalue); 42 | //printf("%f\n", value); 43 | //printf("%5i | %f\n", i, value); 44 | if ((i % 8) == 7) { 45 | printf("\n"); 46 | } 47 | } 48 | 49 | fprintf(stderr, "\ndone\n"); 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /icebreaker/pll_uart/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 Piotr Esden-Tempski 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /icebreaker/pll_uart/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = pll_uart_mirror 2 | ADD_SRC = uart_baud_tick_gen.v uart_rx.v uart_tx.v 3 | 4 | PIN_DEF = ../icebreaker.pcf 5 | DEVICE = up5k 6 | PACKAGE = sg48 7 | 8 | prog: iceprog 9 | 10 | include ../../main.mk 11 | -------------------------------------------------------------------------------- /icebreaker/pll_uart/pll_uart_mirror.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - Async uart mirror using pll 3 | * 4 | * Copyright (C) 2018 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module top ( 21 | input CLK, 22 | input RX, 23 | output TX, 24 | output LEDR_N, 25 | output LEDG_N 26 | ); 27 | 28 | wire clk_42mhz; 29 | //assign clk_42mhz = CLK; 30 | SB_PLL40_PAD #( 31 | .DIVR(4'b0000), 32 | // 42MHz 33 | .DIVF(7'b0110111), 34 | .DIVQ(3'b100), 35 | .FILTER_RANGE(3'b001), 36 | .FEEDBACK_PATH("SIMPLE"), 37 | .DELAY_ADJUSTMENT_MODE_FEEDBACK("FIXED"), 38 | .FDA_FEEDBACK(4'b0000), 39 | .DELAY_ADJUSTMENT_MODE_RELATIVE("FIXED"), 40 | .FDA_RELATIVE(4'b0000), 41 | .SHIFTREG_DIV_MODE(2'b00), 42 | .PLLOUT_SELECT("GENCLK"), 43 | .ENABLE_ICEGATE(1'b0) 44 | ) usb_pll_inst ( 45 | .PACKAGEPIN(CLK), 46 | .PLLOUTCORE(clk_42mhz), 47 | //.PLLOUTGLOBAL(), 48 | .EXTFEEDBACK(), 49 | .DYNAMICDELAY(), 50 | .RESETB(1'b1), 51 | .BYPASS(1'b0), 52 | .LATCHINPUTVALUE(), 53 | //.LOCK(), 54 | //.SDI(), 55 | //.SDO(), 56 | //.SCLK() 57 | ); 58 | 59 | /* local parameters */ 60 | //localparam clk_freq = 12_000_000; // 12MHz 61 | localparam clk_freq = 42_000_000; // 42MHz 62 | //localparam baud = 57600; 63 | localparam baud = 115200; 64 | 65 | 66 | /* instantiate the rx1 module */ 67 | reg rx1_ready; 68 | reg [7:0] rx1_data; 69 | uart_rx #(clk_freq, baud) urx1 ( 70 | .clk(clk_42mhz), 71 | .rx(RX), 72 | .rx_ready(rx1_ready), 73 | .rx_data(rx1_data), 74 | ); 75 | 76 | /* instantiate the tx1 module */ 77 | reg tx1_start; 78 | reg [7:0] tx1_data; 79 | reg tx1_busy; 80 | uart_tx #(clk_freq, baud) utx1 ( 81 | .clk(clk_42mhz), 82 | .tx_start(tx1_start), 83 | .tx_data(tx1_data), 84 | .tx(TX), 85 | .tx_busy(tx1_busy) 86 | ); 87 | 88 | // Send the received data immediately back 89 | 90 | reg [7:0] data_buf; 91 | reg data_flag = 0; 92 | reg data_check_busy = 0; 93 | always @(posedge clk_42mhz) begin 94 | 95 | // we got a new data strobe 96 | // let's save it and set a flag 97 | if(rx1_ready && ~data_flag) begin 98 | data_buf <= rx1_data; 99 | data_flag <= 1; 100 | data_check_busy <= 1; 101 | end 102 | 103 | // new data flag is set let's try to send it 104 | if(data_flag) begin 105 | 106 | // First check if the previous transmission is over 107 | if(data_check_busy) begin 108 | if(~tx1_busy) begin 109 | data_check_busy <= 0; 110 | end // if(~tx1_busy) 111 | 112 | end else begin // try to send waiting for busy to go high to make sure 113 | if(~tx1_busy) begin 114 | tx1_data <= data_buf; 115 | tx1_start <= 1'b1; 116 | LEDR_N <= ~data_buf[0]; 117 | LEDG_N <= ~data_buf[1]; 118 | end else begin // Yey we did it! 119 | tx1_start <= 1'b0; 120 | data_flag <= 0; 121 | end 122 | end 123 | end 124 | end 125 | 126 | // Loopback the TX and RX lines with no processing 127 | // Useful as a sanity check ;-) 128 | //assign TX = RX; 129 | 130 | endmodule 131 | -------------------------------------------------------------------------------- /icebreaker/pll_uart/uart_baud_tick_gen.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - Async uart baud tick generator module 3 | * 4 | * Copyright (C) 2018 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | /*** 21 | * This module generates a bit baud tick multiplied by the oversampling parameter. 22 | */ 23 | module baud_tick_gen( 24 | input clk, enable, 25 | output tick); 26 | parameter clk_freq = 12000000; 27 | parameter baud = 115200; 28 | parameter oversampling = 1; 29 | 30 | function integer log2(input integer v); begin log2=0; while(v >> log2) log2 = log2 + 1; end endfunction 31 | 32 | localparam acc_width = log2(clk_freq / baud) + 8; // +/- 2% max timing error over a byte 33 | 34 | reg [acc_width:0] acc = 0; 35 | 36 | localparam shiftlimiter = log2((baud * oversampling) >> (31 - acc_width)); // this makes sure inc calculation doesn't overflow (verilog uses 32bit variables internally) 37 | localparam inc = ((baud * oversampling << (acc_width - shiftlimiter)) + (clk_freq >> (shiftlimiter + 1))) / (clk_freq >> shiftlimiter); // Calculate accumulate increment 38 | //initial $display("acc_width %d, shiftlimit %d, inc %d", acc_width, shiftlimiter, inc); 39 | 40 | always @(posedge clk) if (enable) acc <= acc[acc_width-1:0] + inc[acc_width:0]; else acc <= inc[acc_width:0]; 41 | assign tick = acc[acc_width]; 42 | 43 | endmodule 44 | -------------------------------------------------------------------------------- /icebreaker/pll_uart/uart_rx.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - Async uart rx module 3 | * 4 | * Copyright (C) 2018 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module uart_rx( 21 | input clk, 22 | input rx, 23 | output reg rx_ready, 24 | output reg [7:0] rx_data, // data received, valid onli (for one clock cycle) when rx_read is asserted 25 | 26 | // We also detect if a gap occurs in the received stream of characters 27 | // That can be useful if multiple characters are sent in a burst 28 | // This allows us to consider a block of characters as a "packet" 29 | output rx_idle, // asserted when no data has been received for a while 30 | output reg rx_eop = 0 // asserted for one clock cycle when an end of packet has been detected 31 | ); 32 | 33 | parameter clk_freq = 12000000; 34 | parameter baud = 115200; 35 | 36 | parameter oversampling = 8; // needs to be power of 2 37 | // we oversample the rx line at fixed rate to capture each rx data bit 38 | // 8 times oversampling by default, use 16 for higher reception quality. 39 | 40 | localparam 41 | IDLE = 4'b0000, 42 | BIT_START = 4'b0001, 43 | BIT0 = 4'b1000, 44 | BIT1 = 4'b1001, 45 | BIT2 = 4'b1010, 46 | BIT3 = 4'b1011, 47 | BIT4 = 4'b1100, 48 | BIT5 = 4'b1101, 49 | BIT6 = 4'b1110, 50 | BIT7 = 4'b1111, 51 | BIT_STOP = 4'b0010; 52 | 53 | reg [3:0] rx_state = 0; 54 | 55 | wire os_tick; 56 | baud_tick_gen #(clk_freq, baud, oversampling) tickgen(.clk(clk), .enable(1'b1), .tick(os_tick)); 57 | 58 | // sync rx to our clock domain 59 | reg [1:0] rx_sync = 2'b11; 60 | always @(posedge clk) if(os_tick) rx_sync <= {rx_sync[0], rx}; 61 | 62 | // filter/debounce rx 63 | reg [1:0] filter_cnt = 2'b11; 64 | reg rx_bit = 1'b1; 65 | always @(posedge clk) 66 | if(os_tick) begin 67 | // increment/decrement filter_cnt 68 | // the filter_cnt counts up when rx_sync is high until it reaches 2'b11 69 | // the filter_cnt counts down when rx_sync is low until it reaches 2'b00 70 | // this filter will ignore glitches of length up to 2 x oversampling period 71 | // the filter does not provide hold hysteresis 72 | if((rx_sync[1] == 1'b1) && (filter_cnt != 2'b11)) filter_cnt <= filter_cnt + 1'd1; 73 | if((rx_sync[1] == 1'b0) && (filter_cnt != 2'b00)) filter_cnt <= filter_cnt - 1'd1; 74 | 75 | // set rx_bit output high when filter_cnt reaches max and low when min 76 | if(filter_cnt == 2'b11) rx_bit <= 1'b1; 77 | else 78 | if(filter_cnt == 2'b00) rx_bit <= 1'b0; 79 | // XXX: we probably should set rx_bit to some defined value when filter_cnt is not 11 nor 00. 80 | end 81 | 82 | // create an appropriate oversampling counter 83 | // using the counter we generate a sample_now signal offset by 90deg from the rx data clock phase 84 | function integer log2(input integer v); begin log2 = 0; while(v >> log2) log2 = log2 + 1; end endfunction 85 | localparam l2o = log2(oversampling); 86 | reg [l2o-2:0] os_cnt = 0; 87 | always @(posedge clk) if(os_tick) os_cnt <= (rx_state == IDLE) ? 1'd0 : os_cnt + 1'd1; 88 | wire sample_now = os_tick && (os_cnt == ((oversampling / 2) - 1)); 89 | 90 | // rx data finite state machine 91 | always @(posedge clk) 92 | case(rx_state) 93 | IDLE: if(~rx_bit) rx_state <= BIT_START; 94 | BIT_START: if(sample_now) rx_state <= BIT0; 95 | BIT0: if(sample_now) rx_state <= BIT1; 96 | BIT1: if(sample_now) rx_state <= BIT2; 97 | BIT2: if(sample_now) rx_state <= BIT3; 98 | BIT3: if(sample_now) rx_state <= BIT4; 99 | BIT4: if(sample_now) rx_state <= BIT5; 100 | BIT5: if(sample_now) rx_state <= BIT6; 101 | BIT6: if(sample_now) rx_state <= BIT7; 102 | BIT7: if(sample_now) rx_state <= BIT_STOP; 103 | BIT_STOP: if(sample_now) rx_state <= IDLE; 104 | default: rx_state <= IDLE; 105 | endcase 106 | 107 | // accumulate rx data into the rx_data shift register 108 | // rx_state[3] -> this bit is only high when the state machine is in state BIT0:7 109 | always @(posedge clk) begin 110 | if(sample_now && rx_state[3]) begin 111 | rx_data <= {rx_bit, rx_data[7:1]}; 112 | end 113 | end 114 | 115 | // reg rx_error = 0; 116 | always @(posedge clk) 117 | begin 118 | rx_ready <= (sample_now && (rx_state == BIT_STOP) && rx_bit); // Stay high for the duration of stop bit 119 | //rx_error <= (sample_now && (rx_state == BIT_STOP) && ~rx_bit); 120 | end 121 | 122 | // measure gap size between bytes to determine if bus is idle and if the "packet" ended 123 | reg [l2o+1:0] gap_cnt = 0; 124 | always @(posedge clk) 125 | if (rx_state != IDLE) 126 | gap_cnt <= 0; 127 | else 128 | if(os_tick & ~gap_cnt[l2o+1]) gap_cnt <= gap_cnt + 1'd1; 129 | assign rx_idle = gap_cnt[l2o+1]; 130 | always @(posedge clk) rx_eop <= os_tick & ~gap_cnt[l2o+1] & &gap_cnt[l2o:0]; 131 | 132 | endmodule 133 | -------------------------------------------------------------------------------- /icebreaker/pll_uart/uart_tx.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - Async uart tx module 3 | * 4 | * Copyright (C) 2018 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module uart_tx( 21 | input clk, 22 | input tx_start, 23 | input [7:0] tx_data, 24 | output tx, 25 | output tx_busy); 26 | 27 | parameter clk_freq = 12000000; 28 | parameter baud = 115200; 29 | 30 | wire bit_tick; 31 | baud_tick_gen #(clk_freq, baud) tickgen(.clk(clk), .enable(tx_busy), .tick(bit_tick)); 32 | 33 | localparam 34 | IDLE = 4'b0000, // tx = high 35 | BIT_START = 4'b0100, // tx = low 36 | BIT0 = 4'b1000, // tx = data bit 0 37 | BIT1 = 4'b1001, // tx = data bit 1 38 | BIT2 = 4'b1010, // tx = data bit 2 39 | BIT3 = 4'b1011, // tx = data bit 3 40 | BIT4 = 4'b1100, // tx = data bit 4 41 | BIT5 = 4'b1101, // tx = data bit 5 42 | BIT6 = 4'b1110, // tx = data bit 6 43 | BIT7 = 4'b1111, // tx = data bit 7 44 | BIT_STOP1 = 4'b0010, // tx = high 45 | BIT_STOP2 = 4'b0011; // tx = high 46 | 47 | reg [3:0] tx_state = IDLE; 48 | wire tx_ready = (tx_state == 0); 49 | assign tx_busy = ~tx_ready; 50 | 51 | reg [7:0] tx_shift = 0; 52 | always @(posedge clk) 53 | begin 54 | if (tx_ready & tx_start) 55 | tx_shift <= tx_data; 56 | else 57 | if (tx_state[3] & bit_tick) 58 | tx_shift <= (tx_shift >> 1); 59 | 60 | case (tx_state) 61 | IDLE: if(tx_start) tx_state <= BIT_START; 62 | BIT_START: if(bit_tick) tx_state <= BIT0; 63 | BIT0: if(bit_tick) tx_state <= BIT1; 64 | BIT1: if(bit_tick) tx_state <= BIT2; 65 | BIT2: if(bit_tick) tx_state <= BIT3; 66 | BIT3: if(bit_tick) tx_state <= BIT4; 67 | BIT4: if(bit_tick) tx_state <= BIT5; 68 | BIT5: if(bit_tick) tx_state <= BIT6; 69 | BIT6: if(bit_tick) tx_state <= BIT7; 70 | BIT7: if(bit_tick) tx_state <= BIT_STOP1; 71 | BIT_STOP1: if(bit_tick) tx_state <= BIT_STOP2; 72 | BIT_STOP2: if(bit_tick) tx_state <= IDLE; 73 | default: if(bit_tick) tx_state <= IDLE; 74 | endcase 75 | 76 | end 77 | 78 | // high if state START, STOP1, STOP2 79 | // | high if transmitting bits and bit is 1 80 | // | | 81 | // V V 82 | assign tx = (tx_state < 4) | (tx_state[3] & tx_shift[0]); 83 | 84 | endmodule 85 | -------------------------------------------------------------------------------- /icebreaker/pwm_fade/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 Piotr Esden-Tempski 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /icebreaker/pwm_fade/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = pwm 2 | 3 | PIN_DEF = ../icebreaker.pcf 4 | DEVICE = up5k 5 | PACKAGE = sg48 6 | 7 | prog: iceprog 8 | 9 | include ../../main.mk 10 | -------------------------------------------------------------------------------- /icebreaker/pwm_fade/pwm.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - pwm demo 3 | * 4 | * Copyright (C) 2018 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | // This example generates PWM to fade LEDs 21 | // The intended result is opposite pulsating Red and Green LEDs 22 | // on the iCEBreaker. The intended effect is that the two LED "breathe" in 23 | // brigtness up and down in opposite directions. 24 | 25 | module top ( 26 | input CLK, 27 | output LEDR_N, 28 | output LEDG_N, 29 | output P1A7, // Debug pins 30 | output P1A8 // 31 | ); 32 | 33 | // PWM generator 34 | reg [15:0] pwm_counter = 0; 35 | reg [15:0] pwm_compare = 256; 36 | reg pwm_out; 37 | always @(posedge CLK) begin 38 | // Divide clock by 65535 39 | // Results in a 183.11Hz PWM 40 | pwm_counter <= pwm_counter + 1; 41 | 42 | // Set pwm output according to the compare 43 | // Set output high when the counter is smaller than the compare value 44 | // Set output low when the counter is equal or higher than the compare 45 | // value 46 | if (pwm_counter < pwm_compare) begin 47 | pwm_out <= 1; 48 | end else begin 49 | pwm_out <= 0; 50 | end 51 | end 52 | 53 | // PWM compare generator 54 | // Fading up and down creating a slow sawtooth output 55 | // The fade up down takes about 11.18 seconds 56 | // Note: You will see that the LEDs spend more time being very bright 57 | // than visibly fading, this is because our vision is non linear. Take a look 58 | // at the pwm_fade_gamma example that fixes this issue. :) 59 | reg [17:0] pwm_inc_counter = 0; 60 | reg [16-7:0] pwm_compare_value = 0; 61 | always @(posedge CLK) begin 62 | // Divide clock by 131071 63 | pwm_inc_counter <= pwm_inc_counter + 1; 64 | 65 | // increment/decrement pwm compare value at 91.55Hz 66 | if (pwm_inc_counter[17]) begin 67 | pwm_compare_value <= pwm_compare_value + 1; 68 | pwm_inc_counter <= 0; 69 | end 70 | 71 | if (pwm_compare_value[16-7]) 72 | pwm_compare <= ~pwm_compare_value << 7; 73 | else 74 | pwm_compare <= pwm_compare_value << 7; 75 | end 76 | 77 | assign LEDG_N = ~pwm_out; 78 | assign LEDR_N = pwm_out; 79 | assign P1A7 = pwm_counter[15]; // 50% duty cycle PWM clock out 80 | assign P1A8 = pwm_out; // PWM output on a GPIO pin 81 | 82 | endmodule -------------------------------------------------------------------------------- /icebreaker/pwm_fade_gamma/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.hex 3 | gen_gamma_table 4 | -------------------------------------------------------------------------------- /icebreaker/pwm_fade_gamma/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2018 Piotr Esden-Tempski 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /icebreaker/pwm_fade_gamma/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = gamma_pwm 2 | ADD_DEPS = gamma_table.hex 3 | ADD_CLEAN = *.o gen_gamma_table *.hex 4 | 5 | PIN_DEF = ../icebreaker.pcf 6 | DEVICE = up5k 7 | PACKAGE = sg48 8 | 9 | prog: iceprog 10 | 11 | include ../../main.mk 12 | 13 | gen_gamma_table: gen_gamma_table.o 14 | gcc $< -o $@ -lm 15 | 16 | gamma_table.hex: gen_gamma_table 17 | ./gen_gamma_table > gamma_table.hex 18 | -------------------------------------------------------------------------------- /icebreaker/pwm_fade_gamma/gamma_pwm.v: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - gamma pwm demo 3 | * 4 | * Copyright (C) 2018 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | // This example generates PWM with gamma correction 21 | // The intended result is opposite pulsating Red and Green LEDs 22 | // on the iCEBreaker. The intended effect is that the two LED "breathe" evenly 23 | // and don't stay at a perceptable brightness level longer than others. 24 | // 25 | // For more information about gamma correction: 26 | // https://en.wikipedia.org/wiki/Gamma_correction 27 | 28 | module top ( 29 | input CLK, 30 | output LEDR_N, 31 | output LEDG_N, 32 | output P1A7, 33 | output P1A8, 34 | output P1A9 35 | ); 36 | 37 | // Gamma value lookup table parameters 38 | parameter G_PW = 8; // Number of input bits 39 | parameter G_OW = 16; // Number of output bits 40 | 41 | // Load the gamma value lookup table 42 | reg [(G_OW-1):0] gamma_lut [0:((1<<(G_PW))-1)]; 43 | initial $readmemh("gamma_table.hex", gamma_lut); 44 | 45 | // Very simple dual output PWM generator 46 | // We need two outputs as we can't just invert the gamma corrected PWM output, 47 | // as this would also invert the gamma curve. 48 | reg [15:0] pwm_counter = 0; 49 | reg [15:0] pwm_compare_0; 50 | reg [15:0] pwm_compare_1; 51 | reg pwm_out_0; 52 | reg pwm_out_1; 53 | always @(posedge CLK) begin 54 | pwm_counter <= pwm_counter + 1; 55 | 56 | if (pwm_counter < pwm_compare_0) begin 57 | pwm_out_0 <= 1; 58 | end else begin 59 | pwm_out_0 <= 0; 60 | end 61 | 62 | if (pwm_counter < pwm_compare_1) begin 63 | pwm_out_1 <= 1; 64 | end else begin 65 | pwm_out_1 <= 0; 66 | end 67 | end 68 | 69 | // PWM compare value generator 70 | // Fade through the values using the gamma correction 71 | reg [17:0] pwm_inc_counter = 0; 72 | reg [G_PW:0] pwm_value = 0; 73 | always @(posedge CLK) begin 74 | // Divide clock by 131071 75 | pwm_inc_counter <= pwm_inc_counter + 1; 76 | 77 | // increment/decrement the index 78 | if (pwm_inc_counter[17]) begin 79 | pwm_inc_counter <= 0; 80 | pwm_value <= pwm_value + 1; 81 | end 82 | 83 | // Assign the compare value 84 | // The MSB bit of pwm_value determines the direction of the count 85 | // It is less expensive on an FPGA than doing an up down counter with dir variable 86 | pwm_compare_0 <= gamma_lut[pwm_value[G_PW] ? pwm_value[G_PW-1:0] : ~pwm_value[G_PW-1:0]]; 87 | pwm_compare_1 <= gamma_lut[pwm_value[G_PW] ? ~pwm_value[G_PW-1:0] : pwm_value[G_PW-1:0]]; 88 | end 89 | 90 | assign LEDG_N = ~pwm_out_0; 91 | assign LEDR_N = ~pwm_out_1; 92 | assign P1A7 = pwm_counter[15]; 93 | assign P1A8 = pwm_out_0; 94 | assign P1A9 = pwm_out_1; 95 | 96 | endmodule -------------------------------------------------------------------------------- /icebreaker/pwm_fade_gamma/gen_gamma_table.c: -------------------------------------------------------------------------------- 1 | /* 2 | * icebreaker examples - gamma pwm demo 3 | * 4 | * Copyright (C) 2018 Piotr Esden-Tempski 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | // This program generates a gamma correction table. This table is then loaded 21 | // into bram of the FPGA to provide a lookup table. 22 | 23 | #include 24 | #include 25 | 26 | #define GAMMA 2.2 27 | 28 | int main() 29 | { 30 | fprintf(stderr, "Generating the gamma lookup table.\n"); 31 | 32 | for (int i = 0; i < 256; i++) { 33 | double dvalue = pow((1.0 / 255.0) * i, GAMMA); 34 | long lvalue = 0xFFFFl * dvalue; 35 | 36 | fprintf(stderr, "."); 37 | 38 | if ((i % 8) == 0) { 39 | printf("@%08x", i); 40 | } 41 | printf(" %04lX", lvalue); 42 | //printf("%f\n", value); 43 | //printf("%5i | %f\n", i, value); 44 | if ((i % 8) == 7) { 45 | printf("\n"); 46 | } 47 | } 48 | 49 | fprintf(stderr, "\ndone\n"); 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /icebreaker/sb_rgba_blink/LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /icebreaker/sb_rgba_blink/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = blink 2 | 3 | PIN_DEF = ../icebreaker.pcf 4 | DEVICE = up5k 5 | PACKAGE = sg48 6 | 7 | prog: iceprog 8 | 9 | include ../../main.mk 10 | -------------------------------------------------------------------------------- /icebreaker/sb_rgba_blink/blink.v: -------------------------------------------------------------------------------- 1 | /* 2 | * blink.v 3 | * 4 | * CC0 1.0 Universal - See LICENSE in this directory 5 | * 6 | * Copyright (C) 2018 Sylvain Munaut 7 | * 8 | * vim: ts=4 sw=4 9 | */ 10 | 11 | `default_nettype none 12 | 13 | module top ( 14 | output wire [2:0] LED_RGB, 15 | ); 16 | 17 | reg [27:0] cnt; 18 | wire rgb_pwm[2:0]; 19 | wire clk; 20 | 21 | SB_HFOSC osc_I ( 22 | .CLKHFPU(1'b1), 23 | .CLKHFEN(1'b1), 24 | .CLKHF(clk) 25 | ); 26 | 27 | always @(posedge clk) 28 | cnt <= cnt + 1; 29 | 30 | assign rgb_pwm[0] = cnt[27] & (cnt[2:0] == 3'b000); 31 | assign rgb_pwm[1] = cnt[26] & (cnt[2:0] == 3'b000); 32 | assign rgb_pwm[2] = cnt[25] & (cnt[2:0] == 3'b000); 33 | 34 | SB_RGBA_DRV #( 35 | .CURRENT_MODE("0b1"), 36 | .RGB0_CURRENT("0b000001"), 37 | .RGB1_CURRENT("0b000001"), 38 | .RGB2_CURRENT("0b000001") 39 | ) rgb_drv_I ( 40 | .RGBLEDEN(1'b1), 41 | .RGB0PWM(rgb_pwm[0]), 42 | .RGB1PWM(rgb_pwm[1]), 43 | .RGB2PWM(rgb_pwm[2]), 44 | .CURREN(1'b1), 45 | .RGB0(LED_RGB[0]), 46 | .RGB1(LED_RGB[1]), 47 | .RGB2(LED_RGB[2]) 48 | ); 49 | 50 | endmodule // blink 51 | 52 | -------------------------------------------------------------------------------- /icebreaker/ws2812_blink/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = ws2812_blink 2 | 3 | PIN_DEF = ../icebreaker.pcf 4 | DEVICE = up5k 5 | PACKAGE = sg48 6 | 7 | prog: iceprog 8 | 9 | include ../../main.mk 10 | -------------------------------------------------------------------------------- /icebreaker/ws2812_blink/README.md: -------------------------------------------------------------------------------- 1 | Simple example testing the WS2812 "Ear" 2 | 3 | This example blinks a string of up to 64 RGB LEDs with a Magenta, Cyan, Yellow, White repeating color sequence for the LED string. 4 | 5 | Note: This will not work if the RGB LED is installed on the main board. 6 | -------------------------------------------------------------------------------- /icebreaker/ws2812_blink/ws2812_blink.v: -------------------------------------------------------------------------------- 1 | /* Small test design for the WS2812 "Ear" on the iCEBreaker dev board. */ 2 | 3 | module top ( 4 | input CLK, 5 | 6 | output LED_RED_N 7 | ); 8 | 9 | localparam BITS = 5; 10 | localparam LOG2DELAY = 22; 11 | 12 | reg [BITS+LOG2DELAY-1:0] counter = 0; 13 | reg [BITS-1:0] outcnt; 14 | 15 | always @(posedge CLK) begin 16 | counter <= counter + 1; 17 | outcnt <= counter >> LOG2DELAY; 18 | end 19 | 20 | // Generate a ws2812 stream for blinking upto 64 GBR LEDs with a cyclic color 21 | // pattern of Magenta, Cyan. Yellow, and White. 22 | // For an RGBW string it just blinks all LEDs with a light Magenta (Magenta + White) 23 | wire [7:0] byteno = counter[14:7]; // count bytes (3 per pixel) 24 | wire [2:0] bitno = counter[6:4]; // count bits in a byte 25 | wire onbyte = (byteno[1:0] != 0); // turn off every 4th byte to create color cycle 26 | wire onbits = (bitno == 6); // smaller bitno == brighter LED, or MSB to LSB order 27 | wire blink = outcnt[1]; // approx 1 Hz 28 | wire led_red_n; 29 | reg wsbit; 30 | // Output a single WS2812 bit: 31 | // high for 1 of 4 time slots for a 0 bit 32 | // high for 2 of 4 time slots for a 1 bit 33 | // Using counter[3:2] gives us a time slot frequency 34 | // of 12Mhz/4 or 3Mhz (or a 0.333uS slot length). 35 | // This gives an overall bit period of 1.333uS or a bit frequency of 750KHz. 36 | always @(posedge CLK) begin 37 | case (counter[3:2]) 38 | 0: wsbit <= 1'b1; 39 | 1: wsbit <= blink && onbits && onbyte ? 1'b1 : 1'b0; 40 | default: wsbit <= 1'b0; 41 | endcase 42 | end 43 | // Since the WS2812 "Ear" has an inverting output transistor, 44 | // we have to invert the output logic here. 45 | // Note that the default off time between blinks is assumed to 46 | // satisfy the WS2812 reset condition. 47 | assign led_red_n = byteno < 64*3 ? ~wsbit : 1'b1; 48 | 49 | SB_IO #(.PIN_TYPE({4'b1010, 2'b01})) io_led_red_n( // PIN_OUTPUT_TRISTATE, PIN_INPUT 50 | .PACKAGE_PIN(LED_RED_N), 51 | .OUTPUT_ENABLE(1'b1), 52 | .D_OUT_0(led_red_n) 53 | ); 54 | 55 | endmodule 56 | -------------------------------------------------------------------------------- /main.mk: -------------------------------------------------------------------------------- 1 | 2 | all: $(PROJ).bin 3 | 4 | %.json: %.v $(ADD_SRC) $(ADD_DEPS) 5 | yosys -ql $*.log -p 'synth_ice40 -top top -json $@' $< $(ADD_SRC) 6 | 7 | %.asc: $(PIN_DEF) %.json 8 | nextpnr-ice40 --$(DEVICE) \ 9 | $(if $(PACKAGE),--package $(PACKAGE)) \ 10 | --json $(filter-out $<,$^) \ 11 | --pcf $< \ 12 | --asc $@ \ 13 | $(if $(PNR_SEED),--seed $(PNR_SEED)) 14 | 15 | %.bin: %.asc 16 | icepack $< $@ 17 | 18 | %_tb: %_tb.v %.v 19 | iverilog -g2012 -o $@ $^ 20 | 21 | %_tb.vcd: %_tb 22 | vvp -N $< +vcd=$@ 23 | 24 | %_syn.v: %.json 25 | yosys -p 'read_json $^; write_verilog $@' 26 | 27 | %_syntb: %_tb.v %_syn.v 28 | iverilog -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v` 29 | 30 | %_syntb.vcd: %_syntb 31 | vvp -N $< +vcd=$@ 32 | 33 | iceprog: $(PROJ).bin 34 | iceprog $< 35 | 36 | sudo-iceprog: $(PROJ).bin 37 | @echo 'Executing prog as root!!!' 38 | sudo iceprog $< 39 | 40 | # The default DFU device is the no2bootloader used by icebreaker-bitsy 41 | DFU_DEVICE ?= 1d50:6146 42 | 43 | dfuprog: $(PROJ).bin 44 | dfu-util$(if $(DFU_DEVICE), -d $(DFU_DEVICE))$(if $(DFU_SERIAL), -S $(DFU_SERIAL)) -a 0 -D $< -R 45 | 46 | sudo-dfuprog: $(PROJ).bin 47 | @echo 'Executing dfu-util as root!!!' 48 | sudo dfu-util$(if $(DFU_DEVICE), -d $(DFU_DEVICE))$(if $(DFU_SERIAL), -S $(DFU_SERIAL)) -a 0 -D $< -R 49 | 50 | clean: 51 | rm -f $(PROJ).blif $(PROJ).asc $(PROJ).bin $(PROJ).json $(PROJ).log $(ADD_CLEAN) 52 | 53 | .SECONDARY: 54 | .PHONY: all prog clean 55 | .DEFAULT_GOAL := all 56 | --------------------------------------------------------------------------------