Học liệu

ĐIỀU KHIỂN RGB LED CUBE 8x8x8 BẰNG PHƯƠNG PHÁP BAM 4 BIT VỚI 74HC595

  • 13/01/2018
  • Học liệu

ĐIỀU KHIỂN RGB LED CUBE 8x8x8 BẰNG PHƯƠNG PHÁP BAM 4 BIT VỚI 74HC595

I. GIỚI THIỆU

Với khối RGB CUBE 8x8x8, chúng ta có 512 LED RED, 512 LED GREEN và 512 LED BLUE, tổng cộng là: 512x3 = 1,536 LED. Để điều khiển chúng riêng biệt với màu sắc mong muốn, chúng ta dùng 24 con 74HC595 và 8 con TIP42C và áp dụng phương pháp BAM – 4bit (Bit Angle Modulation). Về BAM, các bạn có thể tham khảo tại:

Bằng phương pháp 4 bit BAM, chúng ta có thể tạo ra 4,096 màu riêng biệt (16^3) cho từng RGB LED.

II. BOM CHO RGB CUBE 8x8x8

No. Items Specification Q'ty Remarks
1 Arduino Mega 2560 R3   1  
2 74HC595   24  
3 ULN2803   24  
4 TIP42C   8  
5 2N2222A   8  
6 Đế IC 16P DIP16 24 Dùng cho 74HC595
7 Đế IC 18P DIP18 24 Dùng cho ULN2803
8 RGB Led 5mm 512  
9 Resistors R100   250  
10 Resistors R1K   10  
11 Resistors R10K   20  
12 Capacitor 0.1uF   30  
13 Bus 8   30  
14 Bus 4   8  
15 Hàng rào đực đơn thẳng dài (40pin) Chân dài 7 Dùng cho cube base
16 Hàng rào đực đơn thẳng ngắn (40pin) Chân ngắn 10  
17 Jack nguồn DC đực 5V 5.5x2.1mm 1 Cấp nguồn cho Arduino
18 Board đồng 2 lớp Khổ A4 1 Dùng cho cube base
19 Board đồng 1 lớp Khổ A4 2  
20 Mica trong khổ A3   1 Làm hộpchứa đèn
21 Mica đục khổ A3   1 Làm hộp chứa board
22 Công tắc gạt ON/OFF 1  
23 Quạt nhỏ   1 Làm quạt hút cho hộp chứa board
24 Dây kẽm/ dây đồng Cuộn 1  
25 Pin 9V   1 Dùng để test led.
26 Hộp đế pin 9V   1  
27 Dung dịch rửa mạch in   1  
28 Nhựa thông   1  
29 Xăng thơm   1  
30 Mũi khoan mạch các loại   1  
31 Keo 502 Hộp lớn 1 Dán hộp mica
32 Dao cắt mạch   1 Cắt mạch và mica

III. PHẦN CỨNG

1. CUBE TEMPLATE

Các bạn dùng mũi khoan 5mm (RGB LED 5mm) để tạo ra 64 lỗ trên tấm gỗ với khoảng cách giữa các LED là 20mm.

2. HÀN KHỐI CUBE

Dựa vào TEMPLATE trên, các bạn sẽ tạo ra được một PLANE của LED CUBE. Mỗi PLANE có 64 RGB LED. Đây là công đoạn mất nhiều thời gian nhất và dễ sai sót nhất. Do vậy, trước và sau khi hàn LED các bạn phải kiểm tra lại, nếu không sẽ rất khó sửa sau khi làm thành khối CUBE.

3. SHIFT REGISTER BOARD & LAYER BOARD

Các bạn có thể tham khảo tại: 

Lưu ý: Chúng ta cần 3 board mạch in SHIFT REGISTER BOARD, mỗi mạch in đều khiển một màu cho 64 RGB LED. Các mạch in này mắc nối tiếp với nhau để mỗi lần chốt ta có 24 byte data được shift out theo thứ tự:

4. CUBE BASE

Hộp chứa nguồn, các board, arduino và bên ngoài có thêm các công tắc, switch, hay nút nhấn. Các bạn có thể tham khảo trên internet cách làm một cube.

III. CHƯƠNG TRÌNH

Chương trình bên dưới tham khảo tại trang: http://www.kevindarrah.com/?cat=99... của Kevin Darrah.

  1. #include<SPI.h>// Dùng thư viện SPI
  2. #define latch_pin 4// Chân LATCH
  3. #define blank_pin 5// Chân OE
  4. #define data_pin 51// Chân DATA (MOSI, pin 51 on MEGA2560)
  5. #define clock_pin 52// Chân CLOCK (SCK, pin 52 on MEGA2560)
  6. /* *Khai báo các layer* */
  7. #define layer1 26// bottom layer
  8. #define layer2 27
  9. #define layer3 28
  10. #define layer4 29
  11. #define layer5 30
  12. #define layer6 31
  13. #define layer7 32
  14. #define layer8 33// top layer
  15. int layerArray[8]={ layer1, layer2, layer3, layer4, layer5, layer6, layer7, layer8 };
  16. int lastAnode;
  17. //This is how the brightness for every LED is stored,
  18. //Each LED only needs a 'bit' to know if it should be ON or OFF, so 64 Bytes gives you 512 bits= 512 LEDs
  19. //Since we are modulating the LEDs, using 4 bit resolution, each color has 4 arrays containing 64 bits each
  20. byte red[4][64];
  21. byte blue[4][64];
  22. byte green[4][64];
  23. //*********** Defining the Cube *************
  24. #define BAM_RESOLUTION 4// EG 4 bit colour = 15 variation of R, G & B (4,096 colours)
  25. constbyteSize_X=8;//Number of LEDs X axis
  26. constbyteSize_Y=8;//Number of Layers Y axis
  27. constbyteSize_Z=8;//Number of LEDs Z axis
  28. int level =0;//keeps track of which level we are shifting data to
  29. int anodeLevel =0;//this increments through the anode levels
  30. int BAM_Bit, BAM_Counter =0;// Bit Angle Modulation variables to keep track of things
  31. //****setup****setup****setup****setup****setup****setup****setup****setup****setup****setup****setup****setup****setup
  32. void setup()
  33. {
  34. SPI.setBitOrder(MSBFIRST);//Most Significant Bit First
  35. SPI.setDataMode(SPI_MODE0);// Mode 0 Rising edge of data, keep clock low
  36. // SPI.setClockDivider(SPI_CLOCK_DIV2);//Run the data in at 16MHz/2 - 8MHz
  37. SPI.setClockDivider(SPI_CLOCK_DIV2);//Run the data in at 16MHz/2 - 8MHz
  38. //Serial.begin(115200);// if you need it?
  39. noInterrupts();// kill interrupts until everybody is set up
  40. //We use Timer 1 to refresh the cube
  41. TCCR1A = B00000000;//Register A all 0's since we're not toggling any pins
  42. TCCR1B = B00001011;//bit 3 set to place in CTC mode, will call an interrupt on a counter match
  43. //bits 0 and 1 are set to divide the clock by 64, so 16MHz/64=250kHz
  44. TIMSK1 = B00000010;//bit 1 set to call the interrupt on an OCR1A match
  45. OCR1A =30;// you can play with this, but I set it to 30, which means:
  46. //our clock runs at 250kHz, which is 1/250kHz = 4us
  47. //with OCR1A set to 30, this means the interrupt will be called every (30+1)x4us=124us,
  48. // which gives a multiplex frequency of about 8kHz
  49. //finally set up the Outputs
  50. // pinMode(latch_pin, OUTPUT);//Latch
  51. pinMode(2, OUTPUT);// turn off PWM and set PortD bit 4 as output
  52. pinMode(3, OUTPUT);// turn off PWM and set PortD bit 5 as output
  53. pinMode(data_pin, OUTPUT);//MOSI DATA
  54. pinMode(clock_pin, OUTPUT);//SPI Clock
  55. //pinMode(blank_pin, OUTPUT);//Output Enable important to do this last, so LEDs do not flash on boot up
  56. //*** Here layer pins are set as outputs
  57. pinMode(layer1, OUTPUT);
  58. pinMode(layer2, OUTPUT);
  59. pinMode(layer3, OUTPUT);
  60. pinMode(layer4, OUTPUT);
  61. pinMode(layer5, OUTPUT);
  62. pinMode(layer6, OUTPUT);
  63. pinMode(layer7, OUTPUT);
  64. pinMode(layer8, OUTPUT);
  65. SPI.begin();//start up the SPI library
  66. interrupts();//let the show begin, this lets the multiplexing start
  67. }//***end setup***end setup***end setup***end setup***end setup***end setup***end setup***end setup***end setup***end setup
  68. void loop()
  69. {//***start loop***start loop***start loop***start loop***start loop***start loop***start loop***start loop***start loop
  70. clearfast();
  71. LED(4,5,6,3,6,13);
  72. delay(5000);
  73. clearfast();
  74. LED(0,0,0,15,0,0);
  75. delay(5000);
  76. LED(7,0,0,0,15,0);
  77. delay(5000);
  78. LED(7,7,0,0,0,15);
  79. delay(5000);
  80. LED(0,7,0,15,15,0);
  81. delay(5000);
  82. LED(0,7,7,15,0,15);
  83. delay(5000);
  84. LED(7,0,7,0,15,15);
  85. delay(5000);
  86. LED(0,0,7,15,15,15);
  87. delay(5000);
  88. LED(7,7,7,15,9,0);
  89. delay(5000);
  90. }
  91. void LED(int Z,int Y,int X,int R,int G,int B)
  92. {//****LED Routine****LED Routine****LED Routine****LED Routine
  93. // First, check and make sure nothing went beyond the limits, Limits are either 0 or Size of the Y,X,Z axis -1 for locations, and 0 or Bam_Resolution - 1 for brightness/colour
  94. X = constrain(X,0,Size_X-1);//Cube X axis
  95. Y = constrain(Y,0,Size_Y-1);//Cube Y axis
  96. Z = constrain(Z,0,Size_Z-1);//Cube Z axis
  97. R = constrain(R,0,(1<< BAM_RESOLUTION)-1);//Cube Red
  98. G = constrain(G,0,(1<< BAM_RESOLUTION)-1);//Cube Green
  99. B = constrain(B,0,(1<< BAM_RESOLUTION)-1);//Cube Blue
  100. //There are Y * X * Z LEDs (Size_Cube) in the cube, so when if we write to level (Y) 2, panel (X) 5, row 4 (Z), that needs to be translated into a number from 0 to Size_Cube then devided by the number of bits per byte
  101. // Since we use an integer we are left with the byte number, the remainder is dropped off. EG (2*64 + 5*8 + 4)/8 = 21.5, the int of this is WhichByte number 21.(Assuming a cube 8*8*8 LEDs)
  102. intWhichByte=int(((Z <<6)+(Y <<3)+ X)>>3);
  103. // This next variable is the same thing as before except we don't devide by 8, so we get the LED number 0 to Size_Cube.
  104. //Then we find which bit of the byte is required. EG (From Above) (2*64 + 5*8 + 4) = LED# 172 - (8 * WhichByte) = 4
  105. intWhichBit=((Z <<6)+(Y <<3)+ X)-(WhichByte<<3);
  106. // So WhichByte 21 WhichBit 4 is the location we will write too for LED 172.
  107. //Now we write to our Cube array if Red, Green and Blue are on or off, using Bit angular modulation.
  108. for(byte I =0; I < BAM_RESOLUTION; I++){
  109. //*** RED ***
  110. bitWrite(red[I][WhichByte],WhichBit, bitRead(R, I));
  111. //*** GREEN ***
  112. bitWrite(green[I][WhichByte],WhichBit, bitRead(G, I));
  113. //*** BLUE ***
  114. bitWrite(blue[I][WhichByte],WhichBit, bitRead(B, I));
  115. }
  116. }//****LED ROUTINE END****
  117. ISR(TIMER1_COMPA_vect)
  118. {//***MultiPlex BAM***MultiPlex BAM***MultiPlex BAM***MultiPlex BAM***MultiPlex BAM***MultiPlex BAM***MultiPlex BAM
  119. //This routine is called in the background automatically at frequency set by OCR1A
  120. //In this code, I set OCR1A to 30, so this is called every 124us, giving each level in the cube 124us of ON time
  121. //There are 8 levels, so we have a maximum brightness of 1/8, since the level must turn off before the next level is turned on
  122. //The frequency of the multiplexing is then 124us*8=992us, or 1/992us= about 1kHz
  123. PORTE |=1<< blank_pin;//The first thing we do is turn all of the LEDs OFF, by writing a 1 to the blank pin
  124. //Note, in my bread-boarded version, I was able to move this way down in the cube, meaning that the OFF time was minimized
  125. //due to signal integrity and parasitic capcitance, my rise/fall times, required all of the LEDs to first turn off, before updating
  126. //otherwise you get a ghosting effect on the previous level
  127. //This is 4 bit 'Bit angle Modulation' or BAM, There are 8 levels, so when a '1' is written to the color brightness,
  128. //each level will have a chance to light up for 1 cycle, the BAM bit keeps track of which bit we are modulating out of the 4 bits
  129. //Bam counter is the cycle count, meaning as we light up each level, we increment the BAM_Counter
  130. if(BAM_Counter ==8)
  131. BAM_Bit++;
  132. elseif(BAM_Counter ==24)
  133. BAM_Bit++;
  134. elseif(BAM_Counter ==56)
  135. BAM_Bit++;
  136.  
  137. BAM_Counter++;//Here is where we increment the BAM counter
  138. switch(BAM_Bit){//The BAM bit will be a value from 0-3, and only shift out the arrays corresponding to that bit, 0-3
  139. //Here's how this works, each case is the bit in the Bit angle modulation from 0-4,
  140. //Next, it depends on which level we're on, so the byte in the array to be written depends on which level, but since each level contains 64 LED,
  141. //we only shift out 8 bytes for each color
  142. case0:
  143. //Red
  144. mySPI(red[0][level]);
  145. mySPI(red[0][level +1]);
  146. mySPI(red[0][level +2]);
  147. mySPI(red[0][level +3]);
  148. mySPI(red[0][level +4]);
  149. mySPI(red[0][level +5]);
  150. mySPI(red[0][level +6]);
  151. mySPI(red[0][level +7]);
  152.  
  153. //Green
  154. mySPI(green[0][level]);
  155. mySPI(green[0][level +1]);
  156. mySPI(green[0][level +2]);
  157. mySPI(green[0][level +3]);
  158. mySPI(green[0][level +4]);
  159. mySPI(green[0][level +5]);
  160. mySPI(green[0][level +6]);
  161. mySPI(green[0][level +7]);
  162. //Blue
  163. mySPI(blue[0][level]);
  164. mySPI(blue[0][level +1]);
  165. mySPI(blue[0][level +2]);
  166. mySPI(blue[0][level +3]);
  167. mySPI(blue[0][level +4]);
  168. mySPI(blue[0][level +5]);
  169. mySPI(blue[0][level +6]);
  170. mySPI(blue[0][level +7]);
  171. break;
  172. case1:
  173. //Red
  174. mySPI(red[1][level]);
  175. mySPI(red[1][level +1]);
  176. mySPI(red[1][level +2]);
  177. mySPI(red[1][level +3]);
  178. mySPI(red[1][level +4]);
  179. mySPI(red[1][level +5]);
  180. mySPI(red[1][level +6]);
  181. mySPI(red[1][level +7]);
  182. //Green
  183. mySPI(green[1][level]);
  184. mySPI(green[1][level +1]);
  185. mySPI(green[1][level +2]);
  186. mySPI(green[1][level +3]);
  187. mySPI(green[1][level +4]);
  188. mySPI(green[1][level +5]);
  189. mySPI(green[1][level +6]);
  190. mySPI(green[1][level +7]);
  191. //Blue
  192. mySPI(blue[1][level]);
  193. mySPI(blue[1][level +1]);
  194. mySPI(blue[1][level +2]);
  195. mySPI(blue[1][level +3]);
  196. mySPI(blue[1][level +4]);
  197. mySPI(blue[1][level +5]);
  198. mySPI(blue[1][level +6]);
  199. mySPI(blue[1][level +7]);
  200. break;
  201. case2:
  202. //Red
  203. mySPI(red[2][level]);
  204. mySPI(red[2][level +1]);
  205. mySPI(red[2][level +2]);
  206. mySPI(red[2][level +3]);
  207. mySPI(red[2][level +4]);
  208. mySPI(red[2][level +5]);
  209. mySPI(red[2][level +6]);
  210. mySPI(red[2][level +7]);
  211. //Green
  212. mySPI(green[2][level]);
  213. mySPI(green[2][level +1]);
  214. mySPI(green[2][level +2]);
  215. mySPI(green[2][level +3]);
  216. mySPI(green[2][level +4]);
  217. mySPI(green[2][level +5]);
  218. mySPI(green[2][level +6]);
  219. mySPI(green[2][level +7]);
  220. //Blue
  221. mySPI(blue[2][level]);
  222. mySPI(blue[2][level +1]);
  223. mySPI(blue[2][level +2]);
  224. mySPI(blue[2][level +3]);
  225. mySPI(blue[2][level +4]);
  226. mySPI(blue[2][level +5]);
  227. mySPI(blue[2][level +6]);
  228. mySPI(blue[2][level +7]);
  229. break;
  230. case3:
  231. //Red
  232. mySPI(red[3][level]);
  233. mySPI(red[3][level +1]);
  234. mySPI(red[3][level +2]);
  235. mySPI(red[3][level +3]);
  236. mySPI(red[3][level +4]);
  237. mySPI(red[3][level +5]);
  238. mySPI(red[3][level +6]);
  239. mySPI(red[3][level +7]);
  240. //Green
  241. mySPI(green[3][level]);
  242. mySPI(green[3][level +1]);
  243. mySPI(green[3][level +2]);
  244. mySPI(green[3][level +3]);
  245. mySPI(green[3][level +4]);
  246. mySPI(green[3][level +5]);
  247. mySPI(green[3][level +6]);
  248. mySPI(green[3][level +7]);
  249. //Blue
  250. mySPI(blue[3][level]);
  251. mySPI(blue[3][level +1]);
  252. mySPI(blue[3][level +2]);
  253. mySPI(blue[3][level +3]);
  254. mySPI(blue[3][level +4]);
  255. mySPI(blue[3][level +5]);
  256. mySPI(blue[3][level +6]);
  257. mySPI(blue[3][level +7]);
  258. //Here is where the BAM_Counter is reset back to 0, it's only 4 bit, but since each cycle takes 8 counts,
  259. //, it goes 0 8 16 32, and when BAM_counter hits 64 we reset the BAM
  260. if(BAM_Counter ==120){
  261. BAM_Counter =0;
  262. BAM_Bit =0;
  263. }
  264. break;
  265. }//switch_case
  266. // ** This routine selects layer without shift register.
  267. lastAnode =(anodeLevel -1);
  268. if(anodeLevel ==0){
  269. lastAnode =7;
  270. }// if we are at the bottom, the last layer was the top
  271. digitalWrite(layerArray[lastAnode], LOW);// turn off the previous layer
  272. digitalWrite(layerArray[anodeLevel], HIGH);// turn on the current layer
  273. PORTE |=1<< latch_pin;//Latch pin HIGH
  274. PORTE &=~(1<< latch_pin);//Latch pin LOW
  275. delayMicroseconds(3);//???;
  276. PORTE &=~(1<< blank_pin);//Blank pin LOW to turn on the LEDs with the new data
  277. //delayMicroseconds(3); //???;
  278. // Blank is the same as the OE or ENABLE pin
  279. anodeLevel++;//inrement the anode level
  280. level = level +8;//increment the level variable by 8, which is used to shift out data, since the next level woudl be the next 8 bytes in the arrays
  281. if(anodeLevel ==8)//go back to 0 if max is reached
  282. anodeLevel =0;
  283. if(level ==64)//if you hit 64 on level, this means you just sent out all 63 bytes, so go back
  284. level =0;
  285. pinMode(blank_pin, OUTPUT);//moved down here so outputs are all off until the first call of this function
  286. }
  287. void clearfast()
  288. {
  289. for(unsignedchar j =0; j <64; j++){
  290. red[0][j]=0;
  291. red[1][j]=0;
  292. red[2][j]=0;
  293. red[3][j]=0;
  294. green[0][j]=0;
  295. green[1][j]=0;
  296. green[2][j]=0;
  297. green[3][j]=0;
  298. blue[0][j]=0;
  299. blue[1][j]=0;
  300. blue[2][j]=0;
  301. blue[3][j]=0;
  302. }
  303. }
  304. inlinestaticuint8_t mySPI(uint8_t mydata)
  305. {
  306. SPDR = mydata;
  307. asmvolatile("nop");
  308. asmvolatile("nop");
  309. }

IV. GIẢI THÍCH CHƯƠNG TRÌNH

1. INPUT & OUTPUT ARDUINO MEGA 2560

Sơ đồ đấu nối như hình vẽ và RGB LED được dùng là loại Common Anode, điện trở hạn dòng được dùng là R100.

       

2. SƠ LƯỢC VỀ CHƯƠNG TRÌNH

Vậy để điều khiển một đèn, ta cần có 2 thông số: tọa độ và màu, ex: LED (z, y, x, redgreenblue).

2.1. XÁC ĐỊNH TỌA ĐỘ (z, y, x)

WhichByte = int (((z << 6) + (y << 3) + x) >> 3) --> Xác định được byte cần set  --> 74HC595 cần set.

WhichBit = ((z << 6) + (y << 3) + x) - (WhichByte << 3) --> Xác định được bit cần set --> Chân cần set của 74HC595 tương ứng ở trên.

Lấy ví dụ ta cần set led lại tọa độ (z=4, y=5, x=6). Như tính toán trong chương trình, vị trí cần set là byte thứ 37, bit thứ 6 của tọa độ không gian LED CUBE.

WhichByte = int ((4*2^6 + 5*2^3 + 6)/2^3) = 37

WhichBit = (4*2^6 + 5*2^3 + 6) - (37 * 2^3) = 6

Hình trên biểu thị 512 RGB LED với mối liên hệ theo tọa độ không gian, byte và bit. Phần tô xanh, chữ đỏ là vị trí cần set cho RGB LED:

Layer (Z) = 4, Y = 5, X =6 --> LED thứ 302 --> Byte thứ 37, bit thứ 6.

2.2. XÁC ĐỊNH MÀU (redgreenblue)

Lấy ví dụ ta cần set led lại tọa độ (z=4, y=5, x=6) màu (red=3, green=6, blue=13), khi đó chương sẽ biên dịch như sau:

Như phân tích ở trên, ta thấy tại vị trí byte 37, bit thứ 6 (tại mỗi vị trí có 3 led bên trong đèn RGB), các đèn sẽ được phối màu như hình sau:

CÁC LƯU Ý

  • Trục tọa độ X trên hình vẽ biểu thị thời gian LED sáng/ tắt với Time_Base = 125us. Khoảng thời gian của Bam_Bit[0] = 8 x Time_Base = 1,000us (1kHz), của Bam_Bit[1]=16 x Time_Base = 2,000us, của Bam_Bit[2]=32 x Time_Base = 4,000us, của Bam_Bit[3]=64 x Time_Base = 8,000us.
  • Lưu ý các con số BAM_Counter = 8, 24, 56 và 120 và BAM_Bit++. Cứ mỗi lần TIMER1 interupt (sau mỗi 125us), thì BAM_Counter sẽ tăng giá trị lên 1, đến giá trị 120 thì reset về 0. Mối liên hệ giữa BAM_Counter và BAM_Bit như sau:
    • BAM_Bit = 0, khi BAM_Counter nằm trong dãy: 0 ~ 7.
    • BAM_Bit = 1, khi BAM_Counter nằm trong dãy: 8 ~ 23.
    • BAM_Bit = 2, khi BAM_Counter nằm trong dãy: 24 ~ 55.
    • BAM_Bit = 3, khi BAM_Counter nằm trong dãy: 56 ~ 119.
  • Ở đây, mình không dùng hàm có sẵn trong thư viện SPI: SPI.transfer(mydata) mà tạo ra hàm mySPI(mydata)Lý do là để cải thiện tốc độ hiển thị LED. Sau này, mình dùng một số hiệu ứng phức tạp, nếu dùng hàm trong thư viện sẽ bị flicker (nhấp nháy) và rất chậm, nhìn không mượt mà.

2.3. HÌNH ẢNH THỰC TẾ LED (4, 5, 6, 3613)

2.4. MỘT SỐ VIDEO VÀ HÌNH ẢNH CỦA DỰ ÁN

Các hiệu ứng trong Video bên dưới đa số mình dùng ColorWheel. Nếu có thời gian, mình rất vui khi cùng chia sẻ với các bạn ở các phần tiếp theo.

THANKS.heartheartheart.

Youtube: 
[RGB LED CUBE 8x8x8] - PART1- FIRST TEST
[RGB LED CUBE 8x8x8] - PART2- UPDATE #1 ANIMATIONS
[RGB LED CUBE 8x8x8] - PART3 - UPDATE #2 ANIMATIONS

Các tin khác