[FPGA] Overkill WS2812 AXI controller – Enlight your Zynq !


Recently got a WS2812 LED Strip, I can’t really remember why but I thought it would be a good idea to make a Verilog controller for it, and it would even better to make it AXI Lite Compliant :) It’s also for me the occasion to start my new « Friday Evening Fun Project » politic, I’ll try to make a short and fast project each Friday evening and publish it (it’ll allow me to take a break with bigger project)

IMG_20170121_123202.jpg

If you don’t know how to start creating a new IP you could use in Vivado diagram follow this link, it’s well explained. I’ll just precise few more point about the way your code and the « generic » AXI Lite wrapper are interacting.

BE REALLY CAREFUL: if you don’t want to loose your source file when editing IP with Vivado you should explicitly create your file in the hdl directory of the original project of the IP or in a path outside of the temporary project created for editing !

When you generate an AXI wrapper with 4 registers (it’s the default settings used in Vivado) you’ll have 5 registers to interact with the BUS. 4 of them are dedicated for data reception, slv_reg0 to slv_reg3, and 1 will be dedicated to transfer of data to master reg_data_out. In our case we will make it simple and don’t use Interrupts. The WS2812 driver has a really simple interface:

In AXIWS2812Strip_v1_0_S00_AXI.v | Line 392
ws2812_driver striptease(
    .clk(S_AXI_ACLK),
    .reset(slv_reg0[2]),
    .write(slv_reg0[0]),
    .addr(slv_reg1),
    .value(slv_reg2),
    .display(slv_reg0[1]),

    .busy(busy),
    .led_out(led_out)
);

As you can see we will use 3 registers, slv_reg0 will be the Command register, slv_reg1 will be the address of the LED to write and slv_reg2 is the 24bit LED value. You’ll have to remember that when writing code in the SDK. Our only BUS output will be a busy flag allowing the code to know if we are resetting or displaying the RAM array. This busy flag need to be linked to the reg_data_out

In AXIWS2812Strip_v1_0_S00_AXI.v | Line 360
case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
    2'h0   : reg_data_out <= {{31{0}}, busy}; //slv_reg0;
    2'h1   : reg_data_out <= slv_reg1;
    2'h2   : reg_data_out <= slv_reg2;
    2'h3   : reg_data_out <= slv_reg3;
    default : reg_data_out <= 0;
endcase

This part allows to map 4 different registers to the BUS interface, in our case the busy flag will be presented on the address 0. So in brief to use our controller, we will need to write the LED Index in the register 1 (the number of the LED you want to configure, 0 indexed), and we will need to write the 24bit RGB Value to register 2. After that we will need to write the value 1 to the register 0 to trigger the writing. Finally you’ll need to write the value 2 to the register 0 to trigger the refresh of the strip. In case you need to reset all the array value write value 4 to the register 0. All those values are the bit number used in the instantiation above !

You’ll find an example in the helloworld.c in the SDK directory. Obviously the controller and the code could be heavily optimized (everything was done in 2 or 3 hours), it’s just a first version to play with. You can also use the controller without using the AXI Part :)

Link to the Github project.

Publicités

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s