stefanrueger / urboot Goto Github PK
View Code? Open in Web Editor NEWSmall AVR bootloader using urprotocol
License: GNU General Public License v3.0
Small AVR bootloader using urprotocol
License: GNU General Public License v3.0
It may be a good idea to create github action CI for urboot, probably just for Linux as the toolchain in the repo is only for Linux.
One possibility is to use Docker container in the CI.
I looked through the MightyCore boards.txt file and realized that I had to handle the CLKPR register "manually" in the bootloader when the microcontroller is configured to run at either 4 or 2 MHz internal oscillator.
When the user selects 4MHz or 2MHz internal oscillator when using MightyCore (1 MHz is handled by setting the CKDIV8 fuse), the CLKPR register is set (in the user application) to divide the clock speed down. However, when the chip receives a hardware reset, the CLKPR register doesn't get cleared but keeps the microcontroller running at 4 or 2 MHz. This is now a problem since the baud rate the bootloader will accept is now changed due to the CLKPR register.
Have you thought of this issue? With Optiboot flash, I always cleared the CLKPR so that the microcontroller was running at a known, 8 MHz speed.
I just stumbled across this while looking into #5.
I've successfully flashed a vector bootloader, but for some reason, I'm getting a verification mismatch when flashing the user program. It's just a simple blink program compiled using ATTinyCore. What is happening, and why am I getting a verification mismatch?
$ ./avrdude -cusbasp -pattiny2313 -Uflash:w:/Users/hans/Downloads/urboot/bootloaders/attiny2313/autobaud/attiny2313_autobaud_ee_lednop_fr_ce_ur_vbl.hex:i
avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e910a (probably t2313)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file /Users/hans/Downloads/urboot/bootloaders/attiny2313/autobaud/attiny2313_autobaud_ee_lednop_fr_ce_ur_vbl.hex for flash
with 346 bytes in 2 sections within [0x6a0, 0x7ff]
using 11 pages and 6 pad bytes
avrdude: writing 346 bytes flash ...
Writing | ################################################## | 100% 0.00 s
avrdude: 346 bytes of flash written
avrdude: verifying flash memory against /Users/hans/Downloads/urboot/bootloaders/attiny2313/autobaud/attiny2313_autobaud_ee_lednop_fr_ce_ur_vbl.hex
Reading | ################################################## | 100% 0.00 s
avrdude: 346 bytes of flash verified
avrdude done. Thank you.
$ ./avrdude -curclock -pattiny2313 -P /dev/cu.SLAB_USBtoUART -Uflash:w:/var/folders/6l/ypg6qbw172v1s4vtt6g990tw0000gn/T/arduino_build_534228/Blink.ino.hex:i
avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e910a (probably t2313)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file /var/folders/6l/ypg6qbw172v1s4vtt6g990tw0000gn/T/arduino_build_534228/Blink.ino.hex for flash
with 456 bytes in 1 section within [0, 0x1c7]
using 15 pages and 24 pad bytes
avrdude: preparing flash input for device bootloader
avrdude: writing 456 bytes flash ...
Writing | ################################################## | 100% 0.06 s
avrdude: 456 bytes of flash written
avrdude: verifying flash memory against /var/folders/6l/ypg6qbw172v1s4vtt6g990tw0000gn/T/arduino_build_534228/Blink.ino.hex
Reading | | 0% 0.00 s avrdude: en passant forcing reset vector to point to vector bootloader
Reading | ################################################## | 100% 0.06 s
avrdude error: verification mismatch, first encountered at addr 0x0002
device 0xff != input 0x21
avrdude error: verification mismatch
avrdude done. Thank you.
$ cat /var/folders/6l/ypg6qbw172v1s4vtt6g990tw0000gn/T/arduino_build_534228/Blink.ino.hex
:1000000014C021C020C01FC01EC01DC07FC01BC0A7
:100010001AC019C018C017C016C015C014C013C02C
:1000200012C011C010C00FC00EC011241FBECFEDF2
:10003000CDBF20E0A0E6B0E001C01D92A936B20716
:10004000E1F7AED0BFC0DCCF3FB7F8948091650038
:1000500090916600A0916700B091680022B708B641
:1000600001FE05C02F3F19F00196A11DB11D3FBF34
:10007000BA2FA92F982F8827BC01CD01620F711DBF
:10008000811D911D42E0660F771F881F991F4A95B9
:10009000D1F70895CF92DF92EF92FF92CF93DF9343
:1000A000D3DFEB0188EEC82E83E0D82EE12CF12CB3
:1000B000CBDF6C1B7D0B683E7340A0F0C114D104F4
:1000C000E104F10439F4DF91CF91FF90EF90DF90DC
:1000D000CF90089581E0C81AD108E108F108C8510D
:1000E000DC4FE6CFC114D104E104F10409F7EBCFF2
:1000F00090B79F7D90BF811105C08FB7F8949598F8
:100100008FBF08958FB7F894959AFACF1F920F92E8
:100110000FB60F9211242F933F938F939F93AF931A
:10012000BF938091610090916200A0916300B091B3
:1001300064003091600023E0230F2D3768F126E83A
:10014000230F0296A11DB11D2093600080936100D2
:1001500090936200A0936300B09364008091650067
:1001600090916600A0916700B09168000196A11D72
:10017000B11D8093650090936600A0936700B093D3
:100180006800BF91AF919F918F913F912F910F90F8
:100190000FBE0F901F9018950196A11DB11DD4CFD1
:1001A00083E080BF83BF789489B7826089BF8FB7AF
:1001B000F8948D9A8FBF81E09BDF6CDF80E098DF41
:0801C00069DFF9CFF894FFCFCD
:00000001FF
It is good to have some documentation for the users to build their own firmware.
The comments here are a good start.
urboot-gcc
make MCU=atmega328p F_CPU=16000000L WDTO=1S AUTOBAUD=1 LED=AtmelPB5 DUAL=0 EEPROM=1 URPROTOCOL=1 FRILLS=7 MOVETO=atmega328p_autobaud_ee_led+b5_fr_ce_ur_vbl
2. Using avr-gcc directly
./avr-toolchain/5.4.0/bin/avr-gcc -DSTART=0x7e80UL -DRJMPWP=0xcfd6 -Wl,--section-start=.text=0x7e80 -Wl,--section-start=.version=0x7ffa -D_urboot_AVAILABLE=22 -g -Wundef -Wall -Os -fno-split-wide-types -mrelax -mmcu=atmega328p -DF_CPU=16000000L -Wno-clobbered -DWDTO=1S -DAUTOBAUD=1 -DLED=AtmelPB5 -DDUAL=0 -DEEPROM=1 -DURPROTOCOL=1 -DFRILLS=7 -DVBL=1 -Wl,--relax -nostartfiles -nostdlib -o atmega328p_16mhz_auto_115200bps_ev1f7_ledPB5_wdto1s_ur.elf urboot.c
./avr-toolchain/5.4.0/bin/avr-objcopy -j .text -j .data -j .version --set-section-flags .version=alloc,load -O ihex atmega328p_16mhz_auto_115200bps_ev1f7_ledPB5_wdto1s_ur.elf atmega328p_16mhz_auto_115200bps_ev1f7_ledPB5_wdto1s_ur.hex
./avr-toolchain/5.4.0/bin/avr-objdump -h -S atmega328p_16mhz_auto_115200bps_ev1f7_ledPB5_wdto1s_ur.elf > atmega328p_16mhz_auto_115200bps_ev1f7_ledPB5_wdto1s_ur.lst
mv atmega328p_16mhz_auto_115200bps_ev1f7_ledPB5_wdto1s_ur.hex atmega328p_autobaud_ee_led+b5_fr_ce_ur_vbl.hex
Today I encountered some issues from the hex files generated by ATtinyCore. I have no issues with other optiboot bootloaders so far, like those from optiboot_x (MegaCoreX and megaTinyCore) and DxCore.
Just an example:
$ ./hexls optiboot_attiny88_8000000UL.hex
Argument "--" isn't numeric in addition (+) at ./hexls line 221.
Argument "----h--" isn't numeric in addition (+) at ./hexls line 221.
610 640 u7.3 0 optiboot_attiny88_8000000UL.hex
$ cat optiboot_attiny88_8000000UL.hex
:101D800001C025C1112484B7882379F0982F9A7057
:101D9000923059F081FF03C094B7977F94BF282EEB
:101DA00080E000D1E1E1FF27099485E08093810084
:101DB0008EE0F8D0259A569A86E028E13EEF91E031
:101DC000309385002093840096BBB09BFECF1D9A74
:101DD000A8958150A9F793E0D92ECC24C39425E08F
:101DE000922E32ECE32E3EE0F32E8F2D806C882E67
:101DF000C5D0813479F4C2D0182FDAD0123811F45A
:101E000080E004C08BE3113809F083E0A8D080E1C2
:101E1000A6D0EECF823419F484E1D2D0F8CF853445
:101E200011F485E0FACF853541F4A8D0C82FA6D0AB
:101E3000D82FCC0FDD1FBCD0EACF863519F484E053
:101E4000BFD0DECF843609F052C098D097D0782E1C
:101E500095D0682E00E011E05801EFEFAE1ABE0AEF
:101E60008DD0F801808385017A10F6CFA1D020971C
:101E7000F1F430910001309384012091010120930D
:101E80008501E0920001809201014091220140937E
:101E900086014091230140938701832F922F419720
:101EA00080932201892F8F70806C80932301F5E449
:101EB0006F1201C0FFCFFE01D7BEE89507B600FC48
:101EC000FDCFFE01A0E0B1E0CD0102962D913C9145
:101ED0000901C7BEE89511243296DC017812F4CFCF
:101EE000FE0197BEE89507B600FCFDCF90CF843782
:101EF00039F544D043D0B82E41D05AD08E010115C7
:101F0000110549F4809184012AD0BA940F5F1F4FC4
:101F1000B110F5CF7CCF0130110519F48091850106
:101F2000F3CF0232110519F480918601EDCF03320F
:101F3000110519F480918701E7CFF8018491E4CF6E
:101F4000853739F435D08EE10AD083E908D081E1B4
:101F50005DCF813509F06FCF88E024D06CCF2AE0C7
:101F600030E08095089410F45E9802C05E9A0000FC
:101F700015D014D086952A95B1F70895A89529E033
:101F800030E04F99FECF0AD009D008D088944F99FD
:101F900008942A9511F08795F7CF08959AE29A95BB
:101FA000F1F70895E0E6F0E098E1908380830895EA
:101FB000E5DF803219F088E0F5DFFFCF84E1CFCF95
:101FC000CF93C82FDBDFC150E9F7CF91F1CFFC01F0
:101FD0000A0167BFE895112407B600FCFDCF0895FC
:021FFE00003BA6
:0400000300001D805C
:00000001FF
Ref: as of now urboot does not work for the LGT8F328P. It will be good to have the support.
More info about typical LGT8F328P board. It seems to me the most common one is the Nano style, followed by the Pro Mini style and the Uno style.
https://github.com/dbuezas/lgt8fx
So far only the vendor provided Optiboot bootloader firmware works on my Nano LGT8F328P board.
https://github.com/LGTMCU/Larduino_HSP/tree/master/hardware/LGT/avr/bootloaders/lgt8fx8p
https://github.com/dbuezas/lgt8fx/tree/master/lgt8f/bootloaders/lgt8fx8p (same as above)
For people who want to try different bootloaders, they can use Nano or Uno to burn the bootloaders with the following projects.
https://github.com/LGTMCU/LarduinoISP (from the vendor)
https://github.com/brother-yan/LGTISP
urboot for AVR xMega will be interesting.
From here.
I'd be interested in handling XMEGA parts (They have a huge bootloader section that I think could be made available for ordinary applications)
Hi Stefan,
I'm watching the urboot integration into MiniCore from the sidelines. One really useful feature to me seems the OTA updatability with an external SPI flash. The documentation for this feature is relatively sparse, but if I'm not mistaken, indeed only SPI flash is supported, not SPI EEPROM.
Are there any plans to extend dual boot to SPI EEPROM? If not, what SPI flash ICs can you recommend (preferably in PDIP-8)?
Thanks,
Flössie
Interestingly I have a Arduino Nano clone with CH340 and Atmega328P (5V, 16MHz). It works well with 115200bps and even 1000000bps urboot hex file (tested with the variant (tested with ee_led+b5_fr_ce_ur_vbl) but not working with the autobaud firmware (no matter which baud rate I try). Kind of strange.
The autobaud FW works fine with my Uno Clone (ATmega328P, 5V, 16MHz) and Mega2560 Clone (ATmega2560, 5V, 16MHz).
Maybe this is not a real issue but rather board specific.
Caterina bootloader (USB AVR109) is popular for ATmega32U4 based boards (eg: Arduino Leonardo and Arduino Micro). However they are a bit troublesome to work with avrdude (1200bps touch).
Please refer to the following discussion in avrdude.
It may be a good idea to port urboot to ATmega32U4 (and similar) with USB to Serial support.
I think the current documentation is already pretty good. But it is still good to add more.
What is urboot -- README.md
urprotocol -- urprotocol.md
How to choose urboot bootloader options -- -- howtoselect.md
Compiling urboot -- more details to be added, some simple explanations about the usage of urboot-gcc and hexls would be nice.
How urboot works -- I am not so sure if something like the following is good to have or not.
https://github.com/Optiboot/optiboot/wiki/HowOptibootWorks
FAQ -- to be added (initially it may be empty but more can be added)
It would be great to provide urboot hex files for non-default serial port. I think this is one of the major missing feature from urboot.
As per the previous discussions in avrdude, it may not be so easy to do this automatically though.
Maybe @MCUdude has some ideas since he has done this in optiboot_flash.
This may be a personal taste but I feel that it will be better to seperate the big collection of hex files in the following directory into a seperate repo, say urboot_bin.
https://github.com/stefanrueger/urboot/tree/main/bootloaders
Hello, sorry for the question. I am testing the new firmware on my TransistorTester (MCU: atmega324pa), but when I want to add more features to said tester, I cannot upload it because it tells me that the space is exceeded (>100%). For this reason I thought that by putting this bootloader and it taking up less space than the default bootloader, I could add more functionality to the firmware, but avrdude throws me a message that it already exceeded the limit (100.3%) and does not allow me to upload it to said chip.
>make upload
AVR Memory Usage
----------------
Device: atmega324p
Program: 32878 bytes (100.3% Full)
(.text + .data + .bootloader)
Data: 264 bytes (12.9% Full)
(.data + .bss + .noinit)
EEPROM: 761 bytes (74.3% Full)
(.eeprom)
avrdude -c arduino -P /dev/ttyUSB0 -p m324pa -b 115200 \
-U flash:w:./ComponentTester.hex:a -U eeprom:w:./ComponentTester.eep:a
avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e9511 (probably m324pa)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude error: address 0x8010 out of range at line 2049 of ./ComponentTester.hex
avrdude error: read from file ./ComponentTester.hex failed
avrdude done. Thank you.
make: *** [Makefile:233: upload] Error 1
I would have to do something else, did you want to remap the memory? what am i missing?
It is clear that parts with flash above 128 kiBi need more than 16 bits for their PC. What isn't clear is whether lower-spec'd parts of the same architecture also have a 22-bit PC: for example, a m1280 might well be a m2560 reject with flash errors in the upper half where an undocumented fuse bit limits flash to 128 kiBi.
Why is this relevant? Urboot's SWIO routine can produce bit delays matching a given number of CPU cycles (within reason) but it needs to know whether the part has a 22-bit PC or a 16-bit PC as the respective timings of the rcall
and ret
opcodes differ.
Microchip's AVR instruction set manual does not say which parts have 22-bit PCs, but it asserts that only parts with 22-bit PC implement the eicall
that uses the EIND
register to extend the PC. Now, ATDF and avr-libc differ in their opinion whether a part has the EIND
register, see the table below. That's the closest allusion I found in the documentation as to which parts might have a 22-bit PC.
If you have one of the parts below, @mcuee @MCUdude @SpenceKonde @dl8dtl, please could you run the following function and edit the table below whether it returns 3 (ie, 22-bit PC) or 2 (ie, 16-bit PC).
uint8_t spwidth() {
uint8_t ret;
asm(
" rcall 1f\n"
" in %[ret], %[spl]\n"
" sub %[ret], r0\n"
" rjmp 2f\n"
"1: in r0, %[spl]\n"
" ret\n"
"2:\n"
: [ret] "=r"(ret): [spl] "I"(_SFR_IO_ADDR(SPL)) : "r0"
);
return ret;
}
Colums 2-4 show whether the part has an EIND
register. [Edited after discussion]
Part | ATDF | avr-libc | DS | Flash size | 22-bit PC | Comment |
---|---|---|---|---|---|---|
ATmega640 | 0x10000 | Error in ATDF, avr-libc and DS | ||||
ATmega1280 | 0x20000 | Error in ATDF, avr-libc and DS | ||||
ATmega1281 | 0x20000 | Error in avr-libc and DS | ||||
ATmega2560 | 0x40000 | Consistent, sane and good | ||||
ATmega2561 | 0x40000 | Consistent, sane and good | ||||
ATmega256RFR2 | 0x40000 | Consistent, sane and good | ||||
ATmega2564RFR2 | 0x40000 | Consistent, sane and good | ||||
ATmega8U2 | 0x02000 | Error in ATDF and avr-libc | ||||
ATmega16U2 | 0x04000 | Error in ATDF and avr-libc | ||||
ATmega16U4 | 0x04000 | Error in ATDF and avr-libc | ||||
ATmega32U2 | 0x08000 | Error in ATDF and avr-libc | ||||
ATmega32U4 | 0x08000 | Error in ATDF and ar-libc | ||||
AT90USB82 | 0x02000 | Error in ATDF | ||||
AT90USB162 | 0x04000 | Error in ATDF | ||||
AT90USB646 | 0x10000 | Error in ATDF | ||||
AT90USB647 | 0x10000 | Error in ATDF | ||||
AT90USB1286 | 0x20000 | Error in ATDF | ||||
AT90USB1287 | 0x20000 | Error in ATDF |
Unlike other AVRs, the internal oscillator in the ATtiny13/A runs at 9.6 MHz and is dividable down to 4.8 MHz, 1.2MHz, and 600kHz.
It would be great if these existed pre-compiled bootloaders for these clock speeds!
So, I have heard that urboot is smaller than optiboot, and does virtual boot erase correctly. If this is the case, I would rather like to adopt this in place of Optiboot as the serial bootloader supplied with ATTinyCore. I am impressed with the variety parts you have builds for (though - I'm rather baffled by the wacky file names. though that can be normalized with a python script - the goal would be to something more like this:
urboot_attiny441_8000000UL_uart1_(more feature flags if applicable).hex
(The only operation we can do is concatenation of strings within the context of the platform definition - we have no if/then, no math, just concatenation. And so, I build the hex file names by concatenating build.fcpu, the partnumber, and parameters for options like the LED pin and what port (on the dual usart ones) and such.)
Anyway - I was wondering about a few things. So the 841 and 1634 have 2 hardware serial ports. With optiboot, I provide 3 sets of 841 binaries. One with UART0, one with UART1, and a third with UART0, but the remap register set to move the UART0 to a different set of pins. How hard would support for multiple UARTs be? Is it just a matter of building with different options?
Also, how does Urboot handle the reset flags?
My approach has (since I recognized the fatal nature of allowing execution to proceed if there are not reset flags set - I think it causes the majority of hangs that need manual intervention to correct) been to read the reset flags. If they're not 0, copy their current value to GPIOR0, and clear them in the reset flag register (you can't count on the app to do this, the app won't do this, and you;ll think you had a clean reset when in fact it was a dirty reset, and you're trying to use UART at 14400 baud and 1 MHz, except the user code turned off the div8, so now your clock is running 8 times faster than you think, so small wonder the person can't upload even though there's an Optiboot blink. The chip is running the uart at 115200 baud and 8 MHz - things like that - can happen when you smash the return address (conveniently located right at the top of the stack!), or trigger an ISR that didn't exist. while the causes are all bad bugs in their own right, you're always better off bootlooping into a working bootloader than a non-working one. So since I clear the registers, I know that if I see something there, there must have been a reset, as there always must be, so all is well, and if I see nothing, I immediately trigger a reset because that's the only thing that's likely to be successful now. Though the problem is more acute on modern AVRs ( a missing ISR lands you in a state where not only are the settings not at their reset values, everything otherwise appears to work, except that interrupts can't trigger ISRs. (You overflow an array, and then when you return, execution resumes from the start of the program but with most of the current state retained, millis doesn't advance, but micros does, though it just keeps looping through 0-9999... can you imagine trying to debug that mess? On non-bootloader configurations, I have the app do the same thing in .init3).
But yeah, I am very interested in this...
I am not so sure how difficult it is to add the support of mega0 AVR and Tiny0/1/2 AVR, similar to optiboot_x.
Stretch goal will be to add the support of AVR DA/DB/DD part, similar to optiboot_dx.
Ref: optiboot_dx is too diffierent to be included in optiboot (optiboot_x is integrated into optiboot).
It will be good to add autoboot support as a potential enhancement.
It makes things simpler not just for users, but developers too.
Autobaud is also useful for older parts with RC oscillators that weren't well-tuned from the factory.
I am not so sure if this is really in scope for urboot or not.
The main problem I have is that many of my boards are not meant to be Arduino compatible -- they are simple breakout board and some of them have USB to TTL converter on board. Some of them have RESET button. But many of them do not have the DTR RC reset circuitry.
Ref: the typical minimum setup from MiniCore.
https://github.com/MCUdude/MiniCore#minimal-setup (10k ohm resistor and 100nF capacitor)
Yes I can use another USB to TTL converter and manually add the RC circuitry. But it can be a hassle.
The solution is to use an alternative entry method, typically used by many bootloaders -- using a GPIO pin and pull-up/pull-down to enter the bootloader, example is like AVR109 which detects Port Pin low status to enter bootloader.
https://ww1.microchip.com/downloads/en/Appnotes/doc1644.pdf
Same for AVR109 compatible xboot which has the option USE_ENTER_PIN. It has other options like USE_ENTER_DELAY and USE_ENTER_UART.
https://github.com/alexforencich/xboot#33-bootloader-entrance-options
There are quite some boards with urboot support out of the box in this repo. It is great to see that the popular Uno board and Pro Mini are supported. It is good to provide simple documentation of the other boards supported out of box.
Example:
https://github.com/stefanrueger/urboot/tree/main/bootloaders/board_uno (Arduino Uno or clones)
https://github.com/stefanrueger/urboot/tree/main/bootloaders/board_promini (Arduino Pro Mini and clones)
https://github.com/stefanrueger/urboot/tree/main/bootloaders/board_digispark-pro (ATtiny167 based)
https://github.com/stefanrueger/urboot/tree/main/bootloaders/board_digispark (ATtiny85 based)
https://github.com/stefanrueger/urboot/tree/main/bootloaders/board_mega-r3 (Is this Arduino Mega2560?)
I am not so sure if this is easy or not as we may need to understand more about optiboot.
Right now only limited attributes are printed.
C:\work\avr\urboot\src\all [main ≡ +22 ~1286 -448 !]> perl ..\hexls .\bigboot_328.hex
710 1024 o8.3 -.s-.-r-- .\bigboot_328.hex
C:\work\avr\urboot\src\all [main ≡ +22 ~1286 -448 !]> perl ..\hexls .\optiboot_atmega328.hex
474 512 o8.3 -.s-.-r-- .\optiboot_atmega328.hex
Stretch goal will be to add the support of AVR DA/DB/DD part, similar to optiboot_dx.
Ref: optiboot_dx is too diffierent to be included in optiboot (optiboot_x is integrated into optiboot).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.