This project builds from several other HacksterIO projects
The goal of this series of projects is to show how to control several LED targets via serial port. The LED hardware targets are:
- The 6 LEDs on the Tang9K Nano
- NeoPix Stick 8 x 5050 LEDs Cool White
- Blinkt! Pimoroni board
To access each LED hardware board the design leverages an open standard bus architecture: WishBone Each LED hardware board is a wishbone peripheral which can be accessed at a unique bus address. From the serial port, each LED hardware board can be accessed via simple bus write commands.
Here is a block diagram showing the basic components of the verilog code in the Tang9k Nano
- TX/RX serial: Serial stream coming from BL702. The maximum serial rate is 8Mbps, for this design will be using 3Mbps
- Serial: decode/encode serial stream info an Axis data stream. Axis stream is a byte interface with ready/data signals.
- Wishbone master takes the byte stream and converts it into wishbone bus commands. Read/Write bus transactions.
- MUX: is a bus multiplexer that sections the address space into chunks for each LED HW. Each LED HW interface is a wishbone peripheral.
- Tang9LEDs: Wishbone bus peripheral that exposes, each LED as a bit in the data. 3 Different Addresses are exposed:
- 0: Direct access to the LEDs. The data will reflect what the LEDs are
- 4: OR operation. The LEDs current status is OR'ed with the data. This is a toggle on.
- 8: NOT operation: Toggle the LEDs off if the data is 1.
Here is the verilog code:
module wb_leds
#(
parameter DATA_WIDTH = 32, // width of data bus in bits (8, 16, 32, or 64)
parameter ADDR_WIDTH = 32, // width of address bus in bits
parameter SELECT_WIDTH = (DATA_WIDTH/8)
)
(
input i_clk,
input i_rst, // master side
input wire [ADDR_WIDTH-1:0] wb_adr_i, // ADR_I() address
input wire [DATA_WIDTH-1:0] wb_dat_i, // DAT_I() data in
output wire [DATA_WIDTH-1:0] wb_dat_o, // DAT_O() data out
input wire wb_we_i, // WE_I write enable input
input wire [SELECT_WIDTH-1:0] wb_sel_i, // SEL_I() select input
input wire wb_stb_i, // STB_I strobe input
output wire wb_ack_o, // ACK_O acknowledge output
output wire wb_err_o, // ERR_O error output
output wire wb_rty_o, // RTY_O retry output
input wire wb_cyc_i, // CYC_I cycle input
output [5:0] o_led);
reg ack;
reg [5:0] led_reg;
initial begin
ack = 0;
led_reg = 6'h2F;
end
assign wb_ack_o = ack;
always @(posedge i_clk) begin
if (i_rst) begin
ack <= 1'b0;
end
else begin
if ((~ack & wb_cyc_i & wb_stb_i)) begin
if (wb_we_i) begin
case(wb_adr_i[3:0])
8'h0 : led_reg<= wb_dat_i;
8'h4 : led_reg<= led_reg | wb_dat_i;
8'h8 : led_reg<= led_reg & ~wb_dat_i;
default: begin end
endcase
end
ack <= 1'b1;
end
if (ack) begin
ack <= 1'b0;
end
end
end
//always return led settings
assign wb_dat_o= {26'h0, led_reg };
assign wb_err_o = 0;
assign wb_rty_o = 0;
assign o_led = ~led_reg;
endmodule
Serial protocolIn the project there is a python script, ledTester.py. This tests the LEDs on Tang9K nano.
The tang9K nano exposes two serial ports, the first one is for programming the FPGA. The second serial port allows the FPGA to access the RX/TX pins.
The example uses baud rate of 3Mbps. The onboard PLL was needed to create a 130Mhz clock to decode the serial stream and generate clocks for other LED blocks.
Looking the python code:
def writeLEDTang9K(ser, led_0_5):
led_val = led_0_5 & 0xFF
msg = [0xA2,
0,0,0,0,
0, 4 ,
led_val,0,0,0 ]
reply = ser.write(msg)
while (ser.in_waiting == 0):
pass
if (ser.in_waiting):
inmsg = ser.read(ser.in_waiting )led_val,0,0,0 ]
A2: is a write command
0, 0, 0, 0: is the address. This is a 32 bit address
0, 4: is the count of how many data bytes follow
led_val, 0, 0, 0: is the 32 bit data the led_val
def toggleOffLEDTang9K(ser, led_0_5 ):
led_val = led_0_5 & 0xFF
msg = [0xA2,
0,0,0,8,
0,4,
led_val,0 ,0,0 ]
reply = ser.write(msg)
while (ser.in_waiting == 0):
pass
if (ser.in_waiting):
inmsg = ser.read(ser.in_waiting )
def toggleOnLEDTang9K(ser, led_0_5 ):
led_val = led_0_5 & 0xFF
msg = [0xA2,
0,0,0,4,
0,4,
led_val,0 ,0,0 ]
reply = ser.write(msg)
while (ser.in_waiting == 0):
pass
if (ser.in_waiting):
inmsg = ser.read(ser.in_waiting )
The two other functions access the OR and the NOT
Comments
Please log in or sign up to comment.