Giter Site home page Giter Site logo

fujprog's Introduction

Travis (.org)

ULX2S / ULX3S JTAG programmer

This is FPGA JTAG programmer for ULX2/3S boards. You need to have bitstream ready.

Usage

FPGA ULX2S / ULX3S JTAG programmer command line options:

Usage: fujprog [option(s)] [bitstream_file]

 Valid options:
  -p PORT	Select USB JTAG / UART PORT (default is 0)
  -P TTY	Select TTY port (valid only with -t or -a)
  -T TYPE	Select TYPE of input (svf, img, bit or jed)
  -i 		identify and exit
  -j TARGET	Select bitstream TARGET as SRAM (default) or FLASH
  -f ADDR	Start writing to SPI flash at ADDR, optional with -j flash
  -s FILE	Convert bitstream to SVF FILE and exit
  -r		Reload FPGA configuration from FLASH
  -t		Enter terminal emulation mode after completing JTAG operations
  -b SPEED	Set baudrate to SPEED (300 to 3000000 bauds)
  -e FILE	Send and execute a f32c (MIPS/RISCV) binary FILE
  -x SPEED	Set binary transfer speed, optional with -e
  -a FILE	Send a raw FILE
  -d 		debug (verbose)
  -D DELAY	Delay transmission of each byte by DELAY ms
  -V 		display version and exit
  -z 		Force action
  -h 		This help message
  -l X		Display messages in log fashion every <X> times
  -S serial 	Select FTDI by serial to support multiple boards
  -q 		Suppress messages

Example usage

Upload bitstream:

fujprog bitstream.bit

Upload bitstream to flash:

fujprog -j flash bitstream.bit

Upload bitstream from curl:

curl https://www.site.com/bitstream.bit | fujprog

Upload flash image from curl:

curl https://www.site.com/bitstream.img | fujprog -T img -j flash

Building

It is standard CMake procedure:

mkdir build
cd build
cmake ..
make
make install

You can also pass optional parameters:

cmake -DBUILD_STATIC=ON -DLIBFTDISTATIC=/opt/libftdi/lib/libftdi.a -DLIBUSB0STATIC=/opt/libusb0/lib/libusb.a ..
make install/strip

Linux requirements

You need following packages in order to build on Debian/Ubuntu systems:

sudo apt-get install libftdi1-dev libusb-dev cmake make build-essential

MacOS X build

You need to install following dependencies (tested with homebrew):

brew install libftdi libftdi0

And then it is standard build with -DSTATICLIB=ON:

mkdir build
cd build
cmake -DBUILD_STATICLIB=ON ..
make
make install/strip

Note that full static binary is not supported by Apple.

Windows build

You need to download ftdi dependency lib:

wget https://www.ftdichip.com/Drivers/CDM/CDM%20v2.12.28%20WHQL%20Certified.zip

Then you can just open folder inside Visual Studio and build Release versions.

Windows cross-compile

You need to download ftdi dependency lib:

wget https://www.ftdichip.com/Drivers/CDM/CDM%20v2.12.28%20WHQL%20Certified.zip

Cross compiling is done using standard cmake toolchain file:

mkdir build
cd build
cmake -DCMAKE_TOOLCHAIN_FILE=`pwd`/../cmake/Toolchain-cross-mingw32.cmake ..
make

FreeBSD build

You need to install dependencies:

pkg install libftdi1 pkgconf git cmake

And then it is standard CMake procedure:

mkdir build
cd build
cmake ..
make
make install

If you need static binary version, you need to perform following cmake command:

cmake -E env CFLAGS="-pthread" cmake -DBUILD_STATIC=ON ..

Windows Notes

You may need to disable windows security block

windows security block

Windows Drivers

The JTAG features of this fujprog cannot be used concurrently with OpenOCD.

In order to use OpenOCD with the ULX3S, the libusbK dirvers are needed. One way of manually changing the drivers is to use Zadig. The problem with using the libusbK drivers is that this fujprog will no longer work, as it needs the FTDI drivers.

Change ULX3S Driver to libusbK using Zadig

The ULX3S is using the FTDI drivers if it shows up in the Device Manager - Ports (COM & LPT)

ULX3S-as-FTDI-device

Launch Zadig and click on Options - List all Devices. Select the ULX3S device from the dropdown:

Zadig-FTDI-to-libusbK

Press the Replace Driver button and after a few moments you should see a message that the drivers were installed successfully:

Zadig-success

The driver change typically works immediately and no reboot is needed.

Change ULX3S Driver to FTDI

The FTDI drivers should already be installed. If so, Windows will automatically use these drivers when a new ULXS3 is plugged in. If the FTDI Drivers are not installed, they can be downloaded from https://www.ftdichip.com/Drivers/D2XX.htm (the setup executable noted in the comments column may be the easiest way to install the drivers).

The ULX3S is using the libusbK drivers if it shows up in Device Manager - libusbK USB Devices. (typically when using OpenOCD)

ULX3S-as-libusbK-device

To remove the libusbK drivers, right click on your ULX3S device in Device Manager and select Uninstall Device:

Uninstall-libusbK-device

Then click the Uninstall button (don't check the box unless you want to actually uninstall the drivers from Windows and then reinstall the drivers later; we are only uninstalling the device):

Uninstall-libusbK-device-step2

After clicking the Uninstall button, Device Manager may flicker a bit, but no message is typically shown. If the device was removed it will no longer be visible. If there are no other libusbK devices, then then entire libusbK USB Devices container will also be gone.

To complete the process of installing the FDTI drivers: Unplug the ULX3S, wait 30 seconds and plug it back in. Windows should automatically use the FTDI drivers and a new COM port will appear in Device Manager - Ports (COM & LPT) as shown above.

Troubleshooting

WINDOWS

Most issues come from windows platform. In some cases fujprog doesn't work. Sometimes it is just a matter of dynamic linking (DLL file "ftd2xx.dll" or "ftd2xx64.dll", easiest is just to copy this file from FTDI D2XX CDM driver to the same directory where fujprog.exe is)

On VoIFS there is strange problem related with fujprog.exe compiled with mingw. fujprog.exe, if started from "wrong" directory doesn't work. When started from "wrong" directory, fujprog.exe will exit without printing any error or any other message while it should print help/usage message shown on top of this page. Possible cause of this problem is that "ftd2xx64.dll" (for win64) is found copied to System32 directory under name "ftd2xx.dll" (for win32).

Possible solution would be to remove all ftd2xx copies and copy fujprog.exe and dll to another directory and try again.

LINUX

Here we have much better success, fujprog is statically linked and doesn't depend on any other file. Most issues come from user permissions so fujprog should be either run as root or the user should be given permissions to access USB and serial device, that's usually done easily with some udev rule:

# /etc/udev/rules.d/80-fpga-ulx3s.rules
# this is for usb-serial tty device
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", \
  MODE="664", GROUP="dialout"
# this is for fujprog libusb access
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", \
  GROUP="dialout", MODE="666"

APPLE

Make sure that FTDI driver is not loaded. For example:

sudo kextstat | grep -i ftdi

Should not return com.FTDI.driver.FTDIUSBSerialDriver when ulx3s is connected to USB port like this:

195 0 0xffffff7f85521000 0x7000 0x7000 com.FTDI.driver.FTDIUSBSerialDriver (2.4.4)

If does, try to run fujprog as root as it will try to automatically handle kexts. Also, you can temporarily remove them by running following commands:

/sbin/kextunload -bundle-id com.FTDI.driver.FTDIUSBSerialDriver
/sbin/kextunload -bundle-id com.apple.driver.AppleUSBFTDI

Feel free to report any problems. If you have problems running released binary try to compile your own version.

Credits

Fujprog is based on ujprog originally authored by Marko Zec. Contributions from EMARD, gojimmypi and kost.

Copyright (C), 2008-2018 Marko Zec, University of Zagreb

Copyright (c), 2014-2019 EMARD

Copyright (c), 2020 kost

fujprog's People

Contributors

blitz avatar dpavlin avatar kost avatar pnrhub avatar vmedea avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

fujprog's Issues

flash write protection and segfault

To protect bootloader, first 2MB of flash can be
write protected by flash vendor specific commands.

fujprog segfaults trying to write over write protected range.

some reporting of current flash protection status and reason
why it can't flash would be nice to users,
and of course options to set and remove write protection too

For Winbond and ISSI on ULX3S boards, here is esp32
micropython code, it's simple and can be used as reference
for fujprog https://github.com/emard/esp32ecp5/blob/master/ecp5wp.py

fujprog always fails the first time with icestation32

While trying to write to flash with fujprog while icestation32 is running it always fails the first time with Received and expected data do not match! and a mismatch. The second time it always works:

ubuntu@build:~/icestation-32/software/sprites$ make ulx3s_prog
Building gfx_convert if needed
Building header_gen if needed
../common/../../utilities/gfx_convert/gfx_convert -f png -o crystal_ crystal.png
Found paletted image
Palette size: 16
../common/../../utilities/header_gen/header_gen -t uint16_t -s -i crystal_tiles -o ./crystal_tiles crystal_tiles.bin
../common/../../utilities/header_gen/header_gen -t uint16_t -s -i crystal_palette -o ./crystal_palette crystal_palette.bin
riscv-none-embed-cpp -P -o sections_p.lds ../common/sections.lds
riscv-none-embed-gcc -std=c11 -Wall -Os -MMD -MP -flto -march=rv32i -mabi=ilp32 -I../common/../common/ -I../common/../lib/ -I./ -ffreestanding -nostdlib -DASSERT_ENABLED -c main.c -o main.o
riscv-none-embed-gcc -std=c11 -Wall -Os -MMD -MP -flto -march=rv32i -mabi=ilp32 -I../common/../common/ -I../common/../lib/ -I./ -ffreestanding -nostdlib -DASSERT_ENABLED -c crystal_tiles.c -o crystal_tiles.o
riscv-none-embed-gcc -std=c11 -Wall -Os -MMD -MP -flto -march=rv32i -mabi=ilp32 -I../common/../common/ -I../common/../lib/ -I./ -ffreestanding -nostdlib -DASSERT_ENABLED -c crystal_palette.c -o crystal_palette.o
riscv-none-embed-gcc -std=c11 -Wall -Os -MMD -MP -flto -march=rv32i -mabi=ilp32 -I../common/../common/ -I../common/../lib/ -I./ -ffreestanding -nostdlib -DASSERT_ENABLED -Wl,-Bstatic,-T,sections_p.lds,--strip-debug main.o crystal_tiles.o crystal_palette.o ../lib/vdp.o ../lib/math_util.o ../common/font.o     ../common/vectors.o ../common/start.o -o prog.elf -lgcc
riscv-none-embed-objcopy -O binary prog.elf prog.bin

fujprog -j flash -f 0x200000 prog.bin
ULX2S / ULX3S JTAG programmer v4.8 (git f498967 built Oct  8 2020 16:06:36)
Copyright (C) Marko Zec, EMARD, gojimmypi, kost and contributors
Using USB cable: ULX3S FPGA 85K v3.0.8
Erasing sectors, please wait.
Type, paste or pipe your bitstream.
Programming: 0% \ Received and expected data do not match!
TDO: 0000 Expected: 4000 mask: C100
Line 26: Operation not permitted

Failed.
ubuntu@build:~/icestation-32/software/sprites$ make ulx3s_prog
Building gfx_convert if needed
Building header_gen if needed

fujprog -j flash -f 0x200000 prog.bin
ULX2S / ULX3S JTAG programmer v4.8 (git f498967 built Oct  8 2020 16:06:36)
Copyright (C) Marko Zec, EMARD, gojimmypi, kost and contributors
Using USB cable: ULX3S FPGA 85K v3.0.8
Erasing sectors, please wait.
Type, paste or pipe your bitstream.
Programming: 100%
Completed in 80.57 seconds.

It does nothing special with regard to arguments (-j flash -f 0x200000, fwiw it also happens at offset 0x0).

It appears to me that something is interfering with programming. After the first time the device is in a reset state, and so the second time it works.

This is on a ULX3S 85F v3.0.8, with commit f498967.

Procedure entry point CloseHandle could not be located

Having some compile problems. On a new system when attempting to run a freshly compiled fujprog.exe:

image

The only difference from a working system seems to be the compiler version: 9.3.0 on the problem system, 7.3.0 on an older, working system.

0 $ cmake -DCMAKE_TOOLCHAIN_FILE=`pwd`/../cmake/Toolchain-cross-mingw32.cmake ..
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Check for working C compiler: /usr/bin/i686-w64-mingw32-gcc
-- Check for working C compiler: /usr/bin/i686-w64-mingw32-gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/i686-w64-mingw32-g++
-- Check for working CXX compiler: /usr/bin/i686-w64-mingw32-g++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found PkgConfig: /usr/bin/pkg-config (found version "0.29.1")
-- Checking for module 'libftdi1'
--   Found libftdi1, version 1.4
-- Checking for module 'libusb-1.0'
--   Found libusb-1.0, version 1.0.23
-- Found Git: /usr/bin/git (found version "2.25.1")
-- GIT hash: cc3ea93
-- Configuring done
-- Generating done
-- Build files have been written to: /mnt/c/workspace-test/fujprog/build

both systems do report the same warning:

0 $ make
Scanning dependencies of target fujprog
[ 50%] Building C object CMakeFiles/fujprog.dir/fujprog.c.obj
/mnt/c/workspace-test/fujprog/fujprog.c: In function ‘setup_usb’:
/mnt/c/workspace-test/fujprog/fujprog.c:745:57: warning: passing argument 4 of ‘FT_GetDeviceInfo’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
  745 |  res = FT_GetDeviceInfo(ftHandle, &ftDevice, &deviceID, serial,
      |                                                         ^~~~~~
In file included from /mnt/c/workspace-test/fujprog/fujprog.c:97:
/mnt/c/workspace-test/fujprog/ftd2xx.h:1057:9: note: expected ‘PCHAR’ {aka ‘char *’} but argument is of type ‘const char *’
 1057 |   PCHAR SerialNumber,
      |   ~~~~~~^~~~~~~~~~~~
[100%] Linking C executable fujprog.exe
[100%] Built target fujprog

I tried copying DLL's to same directory (not needed on working system) - no change.

Could this problem really be compiler version specific?

A pre-existing, already compiled fujprog.exe does otherwise work fine on the new system (and old system).

The file generated on the new system when compiled however is 396,951 bytes. On the older working system the file is 465,847 bytes at compile time. Perhaps the new compiler optimizes something away?

ecppack --spimode problem

if any of ecppack --spimode (fast-read, dual-spi, qspi)
is used, then fujprog will fail

LANG=C ecppack --compress --freq 62.0 --spimode fast-read --input ulx3s_12f_passthru.config --bit ulx3s_12f_passthru.bit; fujprog -z -j flash ulx3s_12f_passthru.bit

ULX2S / ULX3S JTAG programmer v4.6 (git 0a4cc36 built Jul 23 2020 04:07:33)
Copyright (C) Marko Zec, EMARD, gojimmypi, kost and contributors
Using USB cable: ULX3S FPGA 12K v3.0.8
can't find IDCODE, invalid bitstream

this will work (note the small difference in "<" redirection)

LANG=C ecppack --compress --freq 62.0 --spimode fast-read --input ulx3s_12f_passthru.config --bit ulx3s_12f_passthru.bit; fujprog -z -j flash < ulx3s_12f_passthru.bit

long path failure in WSL

when programming a bitstream with a long file source path with WSL, an open ... failed message occurs, for example as shown in my FuseSoC example:

In WSL:

0 $  ls /mnt/c/workspace/myFuseSoC/build/fusesoc_utils_blinky_1.0/ulx3s_85-trellis/fusesoc_utils_blinky_1.0.bit -al
-rwxrwxrwx 1 gojimmypi gojimmypi 1927725 Jun 12 13:10 /mnt/c/workspace/myFuseSoC/build/fusesoc_utils_blinky_1.0/ulx3s_85-trellis/fusesoc_utils_blinky_1.0.bit
gojimmypi@DESKTOP(WSL): /mnt/c/workspace/myFuseSoC ()

0 $  /mnt/c/workspace/fujprog/build/fujprog-v48-win64.exe /mnt/c/workspace/myFuseSoC/build/fusesoc_utils_blinky_1.0/ulx3s_85-trellis/fusesoc_utils_blinky_1.0.bit
ULX2S / ULX3S JTAG programmer v4.8 (git 96ebb45 built Oct  7 2020 22:42:00)
Copyright (C) Marko Zec, EMARD, gojimmypi, kost and contributors
Using USB cable: ULX3S FPGA 12K v3.0.3
open(/mnt/c/workspace/myFuseSoC/build/fusesoc_utils_blinky_1.0/ulx3s_85-trellis/fusesoc_utils_blinky_1.0.bit) failed

Failed.
Programming: 0% - gojimmypi@DESKTOP(WSL): /mnt/c/workspace/myFuseSoC ()

0 $  cp /mnt/c/workspace/myFuseSoC/build/fusesoc_utils_blinky_1.0/ulx3s_85-trellis/fusesoc_utils_blinky_1.0.bit ./fuse_blinky.bit
gojimmypi@DESKTOP(WSL): /mnt/c/workspace/myFuseSoC ()

0 $  /mnt/c/workspace/fujprog/build/fujprog-v48-win64.exe ./fuse_blinky.bit
ULX2S / ULX3S JTAG programmer v4.8 (git 96ebb45 built Oct  7 2020 22:42:00)
Copyright (C) Marko Zec, EMARD, gojimmypi, kost and contributors
Using USB cable: ULX3S FPGA 12K v3.0.3
Programming: 100%
Completed in 61.91 seconds.
gojimmypi@DESKTOP(WSL): /mnt/c/workspace/myFuseSoC ()

Curiously, this is not a problem when calling the same executable from DOS to to same path:

C:\workspace>cd myFuseSoC

C:\workspace\myFuseSoC>dir c:\workspace\myFuseSoC\build\fusesoc_utils_blinky_1.0\ulx3s_85-trellis\fusesoc_utils_blinky_1.0.bit
 Volume in drive C is OS
 Volume Serial Number is [omit]

 Directory of c:\workspace\myFuseSoC\build\fusesoc_utils_blinky_1.0\ulx3s_85-trellis

06/12/2021  01:10 PM         1,927,725 fusesoc_utils_blinky_1.0.bit
               1 File(s)      1,927,725 bytes

C:\workspace\myFuseSoC>c:\workspace\fujprog\build\fujprog-v48-win64.exe c:\workspace\myFuseSoC\build\fusesoc_utils_blinky_1.0\ulx3s_85-trellis\fusesoc_utils_blinky_1.0.bit
ULX2S / ULX3S JTAG programmer v4.8 (git 96ebb45 built Oct  7 2020 22:42:00)
Copyright (C) Marko Zec, EMARD, gojimmypi, kost and contributors
Using USB cable: ULX3S FPGA 12K v3.0.3
Programming: 100%
Completed in 61.88 seconds.

C:\workspace\myFuseSoC>

I tried to duplicate in a real Linux environment, well - actually a VM, but I was unable to get the ULX3S to be recognized from within the VM:
image

Hangs on Mac M1 Monterey

Seems to hang just before starting programming. I rebuilt using the instructions in the README and it worked. Not sure why.

feature request --showall

TIL from @goran-mahovlic that when testing the new @RadionaOrg ULX3S boards, the FTDI firmware version will change and some old versions of fujprog and ujprog will NO LONGER WORK. This could make for a really horrible first time user experience.

So my feature request: add something to fujprog that shows all the interesting characteristics of the board (versions, etc), with a warning as to which respective minimum versions of fujprog and ujprog are needed.

I'm thinking something like: fujprog --showall

This first step should prominently be displayed in all tutorials for the ULX3S to avoid potentially countless hours of frustration in trying the program the ULX3S with an out-of-date bitstream uploader tool.

See also: Warning: New batch - or just testing .

Thanks!

Broken on OpenBSD

Hi,
I have gotten fujprog to compile on OpenBSD,
but it fails with the following message log when running doas ./fujprog ulx3s.bit

ULX2S / ULX3S JTAG programmer v4.8 (git cc3ea93 built Oct 23 2023 22:45:54)
Copyright (C) Marko Zec, EMARD, gojimmypi, kost and contributors
Using USB cable: ULX3S FPGA 85K v3.0.8
ftdi_write_data() failed
ftdi_write_data() failed
ftdi_write_data() failed
Line 7: Operation not permitted
ftdi_write_data() failed
ftdi_write_data() failed

Failed.
ftdi_write_data() failed
ftdi_write_data() failed
ftdi_disable_bitbang() failed

I have already tested it on Arch Linux and it works perfectly fine.
To get it to compile I had to add || defined(__OpenBSD__) to the isnumber() ifdef.
Why is isnumber() even defined, if isdigit(3) exists?
And you also forgot to put x in (). Macros can be dangerous.
I have already tried adding __OpenBSD__ to where __FreeBSD__ is checked (except USE_PPI),
but no help.

make log:

[ 50%] Building C object CMakeFiles/fujprog.dir/fujprog.c.o
/tmp/test/fujprog/fujprog.c:3471:3: warning: 'ftdi_usb_purge_buffers' is deprecated [-Wdeprecated-declarations]
                ftdi_usb_purge_buffers(&fc);
                ^
/usr/local/include/libftdi1/ftdi.h:566:9: note: 'ftdi_usb_purge_buffers' has been explicitly marked deprecated here
    int DEPRECATED(ftdi_usb_purge_buffers(struct ftdi_context *ftdi));
        ^
/usr/local/include/libftdi1/ftdi.h:247:42: note: expanded from macro 'DEPRECATED'
#define DEPRECATED(func) __attribute__ ((deprecated)) func
                                         ^
/tmp/test/fujprog/fujprog.c:4069:4: warning: 'ftdi_usb_purge_buffers' is deprecated [-Wdeprecated-declarations]
                        ftdi_usb_purge_buffers(&fc);
                        ^
/usr/local/include/libftdi1/ftdi.h:566:9: note: 'ftdi_usb_purge_buffers' has been explicitly marked deprecated here
    int DEPRECATED(ftdi_usb_purge_buffers(struct ftdi_context *ftdi));
        ^
/usr/local/include/libftdi1/ftdi.h:247:42: note: expanded from macro 'DEPRECATED'
#define DEPRECATED(func) __attribute__ ((deprecated)) func
                                         ^
2 warnings generated.
[100%] Linking C executable fujprog
fujprog.c(CMakeFiles/fujprog.dir/fujprog.c.o:(exec_bit_file)): warning: sprintf() is often misused, please use snprintf()
fujprog.c(CMakeFiles/fujprog.dir/fujprog.c.o:(exec_svf_mem)): warning: strcpy() is almost always misused, please use strlcpy()
[100%] Built target fujprog

Support gzip-ed bit files or disable flashing of unknown files

fujprog/fujprog.c

Line 3112 in e0cedeb

/* Execute flash target automatically */

Why is good idea to flash random unknown files instead of loading them to ram? This is sure way to corrupt your flashed image if you specify gziped bit file (which is supporetd by esp32ecp5).

On that note, I would love to have support of bziped bit files. Sure, I can do something like

gzip -cd ulx3s_85f_minimig_ps2kbd.bit.gz | fujprog

But it would be nice to at least warn me that file is gziped instead of flashing it to fpga board.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.