ws2811.v (15067B)
1 /* 2 * Copyright 2022 Gerd Beuster (gerd@frombelow.net). This is free 3 * soft-/hardware under the GNU GPL v3 license or any later 4 * version. See COPYING in the root directory for details. 5 */ 6 7 `ifndef ws2811_v 8 `define ws2811_v 9 10 // Module led_monitor uses a number of sub-modules: 11 // 12 // - Module vram listens to the CPU internals and the busses in order 13 // to keep track of the system state, including memory value. (System 14 // memory is not tapped but mirrored by listening to the busses and 15 // write operations.) 16 // 17 // - Module bit2pixel converts 3 bit GRB data to 24 bits GRB data 18 // suitable for the WS2811 LED matrix. 19 // 20 // - Module ws2811 sends the sequence of 24 bits GRB data to the LED 21 // matrix in WS2811 protocol. 22 23 module led_monitor(input fast_clk, 24 // Memory content is mirrored for monitoring 25 // purposes by listening to data and address bus 26 input [7:0] data_bus, 27 input [7:0] address_bus, 28 input mem_set, 29 // Input of CPU debugging output 30 input [15:0] control_logic, 31 input [7:0] reg_a, 32 input [7:0] alu, 33 input [7:0] pc, 34 input [7:0] dp, 35 // Data line of WS2811 matrix 36 output ws2811_dout); 37 38 // Each row of the 16x16 matrix represents two bytes, 39 // therefore the size of the video RAM of the matrix 40 // is 32 bytes 41 parameter vram_size = 32; 42 // WS2811 timing 43 parameter cycles_t0h = 4; // 0: Cycles for high 44 parameter cycles_t0l = 13; // 0: Cycles for low 45 parameter cycles_t1h = 13; // 1: Cycles for high 46 parameter cycles_t1l = 4; // 1: Cycles for low 47 parameter cycles_reset = 4000; // Cycles for rest 48 49 // The output of the video RAM is fed into bit2pixel in order to 50 // convert video RAM data into pixel values for the LED matrix. 51 wire [2:0] vram_dout; 52 // vram_next requests the next bit from video ram. Video ram sets 53 // vram_eod when video ram transfer is completed. 54 wire vram_next, vram_eod; 55 vram #(.size(vram_size)) 56 vram_mem (.din(data_bus), 57 .ain(address_bus), 58 .mem_set(mem_set), 59 .control_logic(control_logic), 60 .reg_a(reg_a), 61 .alu(alu), 62 .pc(pc), 63 .dp(dp), 64 .vclk(fast_clk), 65 .veod(vram_eod), .vnext(vram_next), 66 .vout(vram_dout)); 67 // bs_next requests to set bs_dout to the next pixel. bs_eod 68 // indicates that all pixels have been transmitted. 69 wire bs_next, bs_dout, bs_eod; 70 bit2pixel b2p (.clk(fast_clk), 71 .vram_din(vram_dout), .vram_eod(vram_eod), 72 .vram_next(vram_next), 73 .dout_next(bs_next), .dout(bs_dout), 74 .dout_eod(bs_eod)); 75 // ws2811 translates the bit values of pixels to the high/low 76 // signals of the WS2811 protocol. 77 ws2811 #(.cycles_t0h(cycles_t0h), .cycles_t0l(cycles_t0l), 78 .cycles_t1h(cycles_t1h), .cycles_t1l(cycles_t1l), 79 .cycles_reset(cycles_reset)) 80 ws (.clk(fast_clk), 81 .din(bs_dout), 82 .next(bs_next), 83 .eod(bs_eod), .dout(ws2811_dout)); 84 endmodule 85 86 // The input interface of the VRAM connects to the databus, the output 87 // interface to WS2811. The output interface is not random access but 88 // provides a bitstream. 89 module vram(// VRAM input interfaces to read internal state 90 input [7:0] din, 91 input [7:0] ain, 92 input mem_set, // Write din to memory cell 93 input [15:0] control_logic, // All control logic flags 94 input [7:0] reg_a, 95 input [7:0] alu, 96 input [7:0] pc, 97 input [7:0] dp, 98 // VRAM interface for video output 99 input vclk, 100 input vnext, // Dump next bit 101 output reg veod, 102 output reg [2:0] vout // Stream output 103 ); 104 105 parameter size = 32; 106 107 reg [7:0] mem [0:size-1]; 108 reg [$clog2(size)-1:0] v_byte_ptr = 0; 109 reg [2:0] v_bit_ptr = 0; 110 reg [7:0] byte_out; 111 112 // The LED matrix is wired in snake wiring, ain_snake allows us to 113 // access memory cells in the usual left-to-right, row-by-row 114 // order. We still have to remember that the order of LEDs in the 115 // memory cells in every other row is reversed. 116 wire [7:0] ain_snake; 117 assign ain_snake = (((ain % 4) == 0) ? 118 (ain + 9) 119 : (((ain % 4) == 1) ? 120 (ain + 7) 121 : (ain + 8))); 122 wire [$clog2(size)-1:0] v_byte_ptr_snake; 123 assign v_byte_ptr_snake = (((v_byte_ptr % 4) == 0) ? 124 (v_byte_ptr - 7) 125 : (((v_byte_ptr % 4) == 1) ? 126 (v_byte_ptr - 9) 127 : (v_byte_ptr - 8))); 128 129 // When using BRAM, we can only write one cell on each 130 // cycle. Therefore we have to split VRAM updates into a number of 131 // cycles. The output will only be accurate if the bus clock is 132 // much slower than the VRAM clock that all VRAM parts are updated 133 // in one bus clock cycle. 134 `define state_update_control_logic_0 0 135 `define state_update_control_logic_1 1 136 `define state_update_address_bus 2 137 `define state_update_data_bus 3 138 `define state_update_accumulator 4 139 `define state_update_alu 5 140 `define state_update_pc 6 141 `define state_update_dp 7 142 `define state_update_mem 8 143 reg [3:0] state = `state_update_control_logic_0; 144 always @(posedge(vclk)) 145 case (state) 146 `state_update_control_logic_0: 147 begin 148 mem[0] <= control_logic[7:0]; 149 state <= `state_update_control_logic_1; 150 end 151 `state_update_control_logic_1: 152 begin 153 mem[1] <= { 1'b0, control_logic[15:8] }; 154 state <= `state_update_address_bus; 155 end 156 `state_update_address_bus: 157 begin 158 mem[2] <= { ain[0], ain[1], ain[2], ain[3], ain[4], ain[5], ain[6], ain[7] }; 159 state <= `state_update_data_bus; 160 end 161 `state_update_data_bus: 162 begin 163 mem[3] <= { din[0], din[1], din[2], din[3], din[4], din[5], din[6], din[7] }; 164 state <= `state_update_accumulator; 165 end 166 `state_update_alu: 167 begin 168 mem[4] <= alu; 169 state <= `state_update_pc; 170 end 171 `state_update_accumulator: 172 begin 173 mem[5] <= reg_a; 174 state <= `state_update_alu; 175 end 176 `state_update_pc: 177 begin 178 mem[6] <= { pc[0], pc[1], pc[2], pc[3], pc[4], pc[5], pc[6], pc[7] }; 179 state <= `state_update_dp; 180 end 181 `state_update_dp: 182 begin 183 mem[7] <= { dp[0], dp[1], dp[2], dp[3], dp[4], dp[5], dp[6], dp[7] }; 184 state <= `state_update_mem; 185 end 186 `state_update_mem: 187 begin 188 if (mem_set && (ain <= (size - 9))) 189 // We are in the phase for updating memory, and 190 // the memory in the range shown is written. Therefore we update it. 191 if ((ain % 4) > 1) 192 // While ain_snake de-mangles the order of memory cells, we still have 193 // to reverse the bit order of the memory cells in every other row due 194 // to the snake wiring. 195 mem[ain_snake] <= {din[0], din[1], din[2], din[3], 196 din[4], din[5], din[6], din[7] }; 197 else 198 mem[ain_snake] <= din; 199 state <= `state_update_control_logic_0; 200 end 201 endcase 202 203 204 // Output interface: Dump memory as bitstream for output on LED array. 205 always @(posedge(vclk)) 206 begin 207 byte_out <= mem[v_byte_ptr]; 208 vout <= ((v_byte_ptr < 2) ? 209 // First row shows bits of control logic 210 ((v_bit_ptr % 2 == 0) ? 211 // Alternate colors when showing control logic bits 212 { 1'b0, byte_out[v_bit_ptr], 1'b0 } 213 : { 1'b0, 1'b0 , byte_out[v_bit_ptr] }) 214 : ((v_byte_ptr < 8) ? 215 // Registers & busses 216 ((v_byte_ptr % 2 == 0) ? 217 // In alternating colors 218 { 1'b0, byte_out[v_bit_ptr], 1'b0 } 219 : { 1'b0, 1'b0, byte_out[v_bit_ptr] }) 220 : 221 // Memory content shown in blue. In order to 222 // indicate the location of the PC and the DP, 223 // non-set bits of the memory cell pointed to by 224 // the PC and DP are colored in the respective 225 // color. 226 { byte_out[v_bit_ptr], 227 ((v_byte_ptr_snake == pc) && (byte_out[v_bit_ptr] == 1'b0)) ? 1'b1 : 1'b0, 228 ((v_byte_ptr_snake == dp) && (byte_out[v_bit_ptr] == 1'b0)) ? 1'b1 : 1'b0 229 })); 230 veod <= ((v_bit_ptr == 7) && (v_byte_ptr == (size - 1))); 231 // Advance to next output bit 232 if (vnext) 233 begin 234 // Memory is organized as bytes, so we may have to 235 // advance to the next byte when all bits of the current 236 // bit have been output. 237 // Note that we do not set v_byte_ptr and v_bit_ptr explicitly 238 // back to 0 when a complete byte has been output; we simply let 239 // it overflow. 240 if (v_bit_ptr == 7) 241 v_byte_ptr <= v_byte_ptr + 1; 242 v_bit_ptr <= v_bit_ptr + 1; 243 end 244 end // always @ (posedge(vclk)) 245 endmodule 246 247 // Takes a stream of bit triples representing 3 bit GRB color values. 248 // These triplets are translated to a 24 bit GRB value as input for 249 // the ws2811 input stream by module ws2811. 250 module bit2pixel(input clk, 251 // Interface to VRAM 252 input [2:0] vram_din, 253 input vram_eod, 254 output reg vram_next, 255 // Interface to WS2811 256 output reg dout, 257 output reg dout_eod, 258 input dout_next); 259 260 parameter LED_INTENSITY = 3; // Intensity of LED; range [1..7] 261 reg init = 0; 262 // Color of output bit 263 reg [1:0] dout_color; 264 // Position of output bit in output byte 265 reg [2:0] dout_bit; 266 267 always @(posedge(clk)) 268 if (init == 0) 269 begin 270 init <= 1; 271 dout_eod <= 0; 272 dout <= 0; 273 dout_color <= 0; 274 dout_bit <= 0; 275 end 276 else 277 begin 278 // Each input bit is translated to 3 colors of 8 bits 279 // intensity. We output 0 unless we output the desired color 280 // in the desired intensity. 281 dout <= (dout_bit == 8-LED_INTENSITY) ? vram_din[dout_color] : 0; 282 dout_eod <= ((vram_eod) && (dout_color == 2) && 283 (dout_bit == 7)); 284 if (dout_next) 285 begin 286 if (dout_bit == 7) 287 // 8 bit have been output. Switch to next color 288 // channel. 289 if(dout_color == 2) 290 begin 291 dout_color <= 0; 292 // Since all colors have been output, the output 293 // for this bit from VRAM is complete and we 294 // request the next one. 295 vram_next <= 1; 296 end 297 else 298 dout_color <= dout_color + 1; 299 // Since width of dout_bit is 3 bit, it runs 300 // over bits 0..7 301 dout_bit <= dout_bit + 1; 302 end // if (dout_next) 303 else 304 vram_next <= 0; 305 end 306 307 endmodule 308 309 module ws2811(input clk, input din, input eod, output reg next, output reg dout); 310 311 // One clock cycle @ 12 Mhz: 312 // 83.3333 ns 313 314 // Protocol 315 316 // https://www.tme.eu/Document/26d574b43ad9ddaffa4d5bcd140ec145/WS2811.pdf 317 // Send order: GRB, MSB First 318 // 0: High 220 ns ~ 380 ns | Low 580 ns ~ 1600 ns 319 // 1: High 580 ns ~ 1600 ns | Low 220 ns ~ 420 ns 320 // Frame length: 800 ns ~ 1980 ns 321 // Reset: > 280000 ns 322 parameter cycles_t0h = 4; // 0: Cycles for high 323 parameter cycles_t0l = 13; // 0: Cycles for low 324 parameter cycles_t1h = 13; // 1: Cycles for high 325 parameter cycles_t1l = 4; // 1: Cycles for low 326 parameter cycles_reset = 4000; // Cycles for rest 327 328 `define state_reset 0 329 `define state_high 1 330 `define state_low 2 331 reg [1:0] state_ptr; 332 reg [15:0] cycles_counter; 333 334 reg init = 0; 335 336 always @(posedge(clk)) 337 if (init == 0) 338 begin 339 init <= 1; 340 state_ptr <= `state_reset; 341 cycles_counter <= cycles_reset; 342 dout <= 0; 343 next <= 0; 344 end 345 else 346 begin 347 cycles_counter <= cycles_counter + 1; 348 next <= 0; 349 // In state_reset, dout is kept low in order to initate 350 // a new transmission of color values for all LEDs. After 351 // that, we alternate between state_high and state_low, 352 // sending each color value bit by PWM. Each cycle 353 // represents a bit: The length of the high/low phases 354 // depends on the bit value. 355 case (state_ptr) 356 `state_reset: 357 if (cycles_counter == cycles_reset) 358 begin 359 state_ptr <= `state_high; 360 cycles_counter <= 0; 361 dout <= 1; 362 end 363 `state_high: 364 if (cycles_counter == ((din == 1'b1) ? 365 cycles_t1h-1 : cycles_t0h-1)) 366 begin 367 state_ptr <= `state_low; 368 cycles_counter <= 0; 369 dout <= 0; 370 end 371 `state_low: 372 if (cycles_counter == ((din == 1'b1) ? 373 cycles_t1l-1 : cycles_t0l-1)) 374 begin 375 if (eod) 376 // When all bits are send, we are done and start over. 377 begin 378 state_ptr <= `state_reset; 379 cycles_counter <= 0; 380 dout <= 0; 381 end 382 else 383 // Transmit next bit 384 begin 385 state_ptr <= `state_high; 386 cycles_counter <= 0; 387 dout <= 1; 388 end // else: !if(eod) 389 next <= 1; 390 end 391 endcase // case (state_ptr) 392 end 393 394 endmodule 395 396 `endif