MD Lab: Assembly Language 101 #1 - Program a PIC16F882 to blink an LED & Binary Counter

แชร์
ฝัง
  • เผยแพร่เมื่อ 6 พ.ย. 2024

ความคิดเห็น • 63

  • @David13241
    @David13241 12 ปีที่แล้ว

    Had to walk away from it for a bit, but think I finally converted your tutorial to a pic 16f648a because that's what I have to work with. Tomorrow I will try it out on the breadboard. Pulled my hair out on the stack under run error. Then on the PC memory wrap. Your videos on LED matrix's and 7 segment displays will also be very helpful when the time comes. Thanks again

  • @David13241
    @David13241 12 ปีที่แล้ว

    Awesome!!!! FINALLY I find someone who speaks my language. I have been wracking my brains trying to figure code compiling out. Thank You so much for explaining what the commands are doing as you do them. MPLAB and the PIC datasheets are pretty technical. Im off to check out more of your videos. Thanks again

  • @mrcotech
    @mrcotech 11 ปีที่แล้ว

    I am working with a pic 18f46k22 using assembly. I would love to see a video working with indirect addressing. And not just using the example that the datasheet shows clearing a set of registers. I would like to to see it from start to finish with an application please. I hope you can do this for us, I have really enjoyed your videos and found them really helpful.

  • @robertanthony4342
    @robertanthony4342 11 ปีที่แล้ว

    this is by far the best pic tutorial on the web!

  • @magidavid
    @magidavid  12 ปีที่แล้ว

    Stack over and under runs can drive one crazy, and finding the problem can be an adventure in itself, especially when you have thousands of lines of code.... A good habit to get into is to always use the "banksel f" instruction before referencing a register, especially if you are letting the compiler decide where the program's variables will be located in RAM.

  • @magidavid
    @magidavid  11 ปีที่แล้ว

    That depends on what language you're using and what microcontroller. Some of the commands you have there aren't available in Microchip's assembly and are leaning more towards C. But in theory, you're code looks sound.

  • @magidavid
    @magidavid  11 ปีที่แล้ว

    If you don't already know a programming language, trying to learn off the web can be a very challenging experience. You are also facing the fact that different platforms have programming differences. The best advice I can give you is to purchase a programming book for beginners on the programming language you want to learn.

  • @maziarghorbani
    @maziarghorbani 11 ปีที่แล้ว

    I would be grateful if you could explain the very basic of writing a program to turn a LED on while the switch is pressed.

  • @magidavid
    @magidavid  12 ปีที่แล้ว

    @David13241 You're welcome, and I'm glad you found the video useful.

  • @magidavid
    @magidavid  11 ปีที่แล้ว

    Make sure the code is DECFSZ LED_LOOP,F
    If the F isn't there then compiler will assume you mean the working register (w) and store the resulting math there instead of back in F, thereby causing an endless loop.

  • @johndouglas6806
    @johndouglas6806 12 ปีที่แล้ว

    Trying to make my first led blink. But I'm using a 16F84A, Pic Basic Pro Demo version and the K150 programmer. I used code on p 126 of book, Picbasic Projects by Dogan Ibrahim. The code compiled successfully, and I programmed the 16F84A. Transferred the chip to the breadboard and powered on. Nothing happened. I rechecked programming, wiring and fuses, and disabled the WDT. Still nothing. There is 1.57 V on the pin driving the led, not 5V. Any suggestions? I can provide info on circuit.

  • @Inquire98
    @Inquire98 9 ปีที่แล้ว +1

    "Thank You", thank you very much. I look forward to your tutoring...

    • @magidavid
      @magidavid  9 ปีที่แล้ว

      +Inquire98 You're most welcome, and thank you. :)

  • @magidavid
    @magidavid  11 ปีที่แล้ว

    I can certainly add this to my to do list, though if you have a specific question regarding using the FSR and INDF registers just let me know, I'll do my best to answer your question.

  • @chingano
    @chingano 11 ปีที่แล้ว

    nice thats detailed but what about this one, wrote it yesterday and dont know if its good because my program is not working atm:
    variable equ 0x20
    do
    ; decrementing portc and incrementing variable
    decf PORTC
    decf PORTC
    incf variable
    ; putting 0x16 to w-reg to compare with variable to see if variable is greater than w-reg
    movlw 0x16
    cpfsgt variable
    goto do
    goto out
    is this ok or do i have something wrong?

  • @macguionbajo
    @macguionbajo 11 ปีที่แล้ว

    First of all, thanks so much for these tutorials. This is perfect, and although I have a PIC12F675, the datasheet shows the different register names and there's no problem there.
    Second: I didn't get the external power supply part... I assume then that the PIC is not able to draw enough current to feed all the 8 LED's then? How did you wire them? I'm new to PIC's and I definitely dont want to burn anything. I'm more of an Arduino guy... yet. Thanks again, David.

    • @magidavid
      @magidavid  11 ปีที่แล้ว

      Thank you,
      Actually, it's the programmer that can't supply enough current to drive a whole lot. Adding in external power to the breadboard relieves that demand on the programmer.
      Every PIC is different in what it can and can't do. Most can supply 100ma on a port, so driving 8 LEDs is very possible as long as you keep the current under that 100ma. However, it's always best to check the datasheet of the PIC you're using to be sure what it's electrical limits are.

  • @AndrewSouthworth
    @AndrewSouthworth 7 ปีที่แล้ว

    Originally I was trying to decfsz PORTC directly, and after messing with the code for about an hour, countless google searches, I came across this video where you break that same command into several commands (INCF, MOVF, and then MOWF PORTA). Doing it this way fixed my probem.
    Why doesn't decfsz PORTC seem to work? I've seen code examples that have incf PORTx, but my experience suggests that they are mistaken. I've tried googling this but its kind of a hard situation to look up.

    • @magidavid
      @magidavid  7 ปีที่แล้ว

      Hello Andrew,
      It really depends on the MCU you're using, not all of them support all the assembly commands, hence why I used INCF, MOVF, and MOVWF. Look at the datasheet and make sure the command is supported and also that it will do what you want it to do.
      Also, don't write to PORTC directly, write to LATC. If the MCU is running fast enough, it's possible to read a port before the previously written data has fully registered. So you can write a 1 and if you read back the port right after, it's possible to read the previous data that was there, such as a 0. Two things prevent this, using a NOP to give voltages time to settle or writing to LATx (which is why it's there).
      Hope this helps.

  • @chingano
    @chingano 11 ปีที่แล้ว

    can someone tell me how i can write a do while program like, decrease portc with 2 and increase x by 1 while x < 16.

  • @larrypoorman2300
    @larrypoorman2300 9 ปีที่แล้ว

    David,
    An excellent tutorial and very well presented!
    I have one comment and one question: I downloaded the source code and assembled it successfully.
    1. at the start of the program the statement: #include is commented out but at the end of the program it appears again and is not commented out.
    2. in the .err file, for the statements CRLF ANSEL and MOVWF TRISTA
    I get the message: "Register in operand not in Bank0". Nonetheless it assembles successfully.
    Is the appearance of these messages normal or is there something one can do to eliminate them as well?
    thanks,
    larry

    • @magidavid
      @magidavid  9 ปีที่แล้ว

      Hello Larry,
      First, I've been coding in C for the past year and half and it's has been a long time since I've coded anything in assembly, so my memory is bit fuzzy on some details.
      1) There might be a more pressing reason, but I think it's just control placement of the code during the compile.
      2) It's not really an error, more of a warning that's there to remind you to make sure you've selected the correct bank that the register appears in. I do believe there is a compiler directive you can add to your code that will suppress that particular warning. However, I prefer to see the warning as it is intended as useful information.

  • @magidavid
    @magidavid  11 ปีที่แล้ว

    There's not much to something like this. You just need to check the IO bit the switch is tied to and then turn on / off the LED. The code would look something like this:
    BTFSS PORTA,0 ;is switch pressed?
    BSF PORTA,1 ;yes - so turn on LED.
    BTFSC PORTA,0 ;is switched released?
    BCF PORTA,1 ;yes - so turn off LED.
    Use a pull-up resistor to set PORTA,0 high with switch tied to PORTA,0 and ground. When switch is pressed, it will pull that input low and turn off the LED.

  • @mega2034
    @mega2034 4 ปีที่แล้ว

    Hello Dave,
    I have a project board with 6 seven segments display designed for a pic16f877.
    I tried to find any a program to multiplex the 6 or lesser 7 seg-displays, but nothing will work. The reason that no programs will work is because the 7 seg-segment are common anode. Can you please do a video or give me an idea on how to multiplex common anode the 7seg-displays? The 6 transistors to turn On the 6 ; 7seg_ displays (turn them High to 5 volts ) are connected to port A, and the 7seg_Display LED’s are connected to port D. Thanks in advance.

    • @magidavid
      @magidavid  4 ปีที่แล้ว +1

      C or Assembly?
      Sounds like you're circuit is setup correctly with the transistors driving the Anode of the display to +5V. To turn on a segment you just need to bring the bit on PORT D low (effectively making it ground).
      steps:
      1) Turn off all transistors (make sure display is off)
      2) Update data on PORTD to reflect new digit to display.
      3) Turn on first transistor
      4) Wait long enough for the human eye to register the data. (refresh rate).
      5) Turn of first transistor
      repeat steps 2 - 5 for each digit.
      Also, make sure the port on that MCU can handle the current you're trying to sink into it. Otherwise the port will shut down to protect the MCU. You can adjust the current draw by adjusting the resistor values you are using on the display.

    • @mega2034
      @mega2034 4 ปีที่แล้ว

      Assembly language. About the Board, you are correct; that is the way the board is set up. Today, thanks to your suggestion I was able to turn On the 7seg_Displays. However I can not make the 7seg_Display show different characters or number. ( multiplexing) Even with a delay all 6 -7seg-Display segments are all On. Thank you for the quick response.

    • @magidavid
      @magidavid  4 ปีที่แล้ว

      ​@@mega2034 How do you have your memory setup to keep track of each digits' current value?
      For example: use a SRAM memory location to keep track of what digit 1 displays, another memory location for digit 2, ect...
      Setup some labels to point to SRAM in the PIC memory. For example (hex values are example only, you'll have to assign them to un-allocated SRAM addresses.):
      #define display_1 0x00
      #define display_2 0x01
      #define display_3 0x02
      #define display_4 0x03
      #define display_5 0x04
      ect...
      As you move from digit to digit you can reference the stored data to display the correct value using the method listed in my previous message.
      To change displayed data you just need change the value in the memory location referenced by display_x.

  • @alhawsawi84
    @alhawsawi84 12 ปีที่แล้ว

    هلا و الله ..............
    جزاك الله خير .......
    Finally......... I got the idea, I hope to improve my project very well

  • @ene_lym8906
    @ene_lym8906 10 ปีที่แล้ว

    do you know how to control or block usb ports using emulator 8086?can i have the copy of the code? or do you have any code of emu8086 that implementing pc interfacing

    • @magidavid
      @magidavid  10 ปีที่แล้ว

      Sorry, I'm not familiar with emu8086.

  • @magidavid
    @magidavid  12 ปีที่แล้ว

    Hello John,
    If you can forward a copy of the circuit and the program to me, I'm sure I can help you. Without that information, I'll just be guessing at what the problem is.
    David

  • @mrhappy3761
    @mrhappy3761 9 ปีที่แล้ว

    tanks for all ; plz how to control time of blinking ; if i want 1 second or half or maybe 1 min ????

    • @magidavid
      @magidavid  9 ปีที่แล้ว +1

      +garcia pedro I recommend using a timer in the MCU. Configure the timer to increment every 10ms, then all you have to do is change the LED when the timer reaches a certain value. Don't forget to reset the timer after you change the LED.

    • @mrhappy3761
      @mrhappy3761 9 ปีที่แล้ว

      I wish you makes another video to explain that

  • @zuowang5185
    @zuowang5185 7 ปีที่แล้ว

    why do you need 2 loops for pause, why isn't 1 loop DECFSZ working?

    • @zuowang5185
      @zuowang5185 7 ปีที่แล้ว

      because 1 loop is not enough pause time (blink too fast)?

    • @magidavid
      @magidavid  7 ปีที่แล้ว

      Exactly, the second loop is allowing more time.

  • @parkerhampton7755
    @parkerhampton7755 10 ปีที่แล้ว

    What is the original path to the templates?

    • @magidavid
      @magidavid  10 ปีที่แล้ว

      You can find the link for the code in the description of the video, you'll need to click the "show more" button to see the links.

  • @LIN30Sec
    @LIN30Sec 6 ปีที่แล้ว

    Sir which software use to programing

    • @magidavid
      @magidavid  6 ปีที่แล้ว

      MPLAB X which is free from Microchip.com

  • @magidavid
    @magidavid  11 ปีที่แล้ว

    How nice, all my CRs were removed, which makes reading that code hard.

  • @chingano
    @chingano 11 ปีที่แล้ว

    im learning asm for a pic18f458

  • @maziarghorbani
    @maziarghorbani 11 ปีที่แล้ว

    Thank you very much for the video.

  • @magidavid
    @magidavid  11 ปีที่แล้ว

    you're welcome and thank you.

  • @magidavid
    @magidavid  11 ปีที่แล้ว

    Thanks!

  • @magidavid
    @magidavid  11 ปีที่แล้ว

    In assembly, something like this: Off the top of my head, so could be buggy.
    BANKSEL COUNT ;NOT NEEDED IF COUNT IS GLOBAL.
    CLRF COUNT
    BANKSEL PORTC
    CLRF PORTC
    PORTC_INCREMENT
    BANKSEL PORTC
    INCF PORTC,F ; Increment PORTC by 1.
    INCF PORTC,F ; Increment PORTC by 1.
    BANKSEL COUNT ; Select bank COUNT register is in.
    INCF COUNT,F ; Increment COUNT by 1.
    MOVLW 0X10
    SUBWF COUNT,W
    BTFSS STATUS,C ; Count = 16?
    GOTO PORTC_INCREMENT ; No, loop around and do it again.
    ...

  • @kerdiangmiabok9704
    @kerdiangmiabok9704 9 ปีที่แล้ว

    FIRST THANKS FOR THE TUTORIAL. SECOND WHERE IS PART 2 SIR?

    • @magidavid
      @magidavid  9 ปีที่แล้ว

      Hello,
      They aren't exactly labeled as part 1, part 2, ect... But there are a lot of videos on Assembly programming in my channel.

    • @kerdiangmiabok9704
      @kerdiangmiabok9704 9 ปีที่แล้ว

      Hi David, You're a legend sir. In the video, I heard you mentioning that you would do a tutorial where you would 'add the code to define ASCII Characters' in another video. It'd nice if you could post that video, sir. Thank you again.

    • @magidavid
      @magidavid  9 ปีที่แล้ว

      Kerdiang Miabok
      Lots of good info on in the Keyboard videos and the "Real Time Clock Calander", both of these use ASCII code to send data to the computer for display. As for doing that in the Dot Matrix project, I never have gotten back to the project. Though, I'm thining about designing up a PC board for a DOT matrix display so everyone could follow along easily.

    • @kerdiangmiabok9704
      @kerdiangmiabok9704 9 ปีที่แล้ว

      David, that would be awesome. You make em assembly look very simple in your videos. Do more of em please. Regards, Kerdiang.

  • @j.c.serranosanchez3190
    @j.c.serranosanchez3190 8 ปีที่แล้ว

    Dear David
    Thank you very much for your tutoring. I am an absolute beginer
    I have tried to compile yor file Lab.001.asm for my PIc16f876a without success.
    Here is the code
    LIST p=16F876a ; list directive to define processor
    #INCLUDE ; processor specific variable definitions
    ; TODO INSERT CONFIG CODE HERE USING CONFIG BITS GENERATOR
    ; CONFIG
    ; __config 0xFFFB
    __CONFIG _FOSC_EXTRC & _WDTE_OFF & _PWRTE_OFF & _BOREN_ON & _LVP_ON & _CPD_OFF & _WRT_OFF & _CP_OFF
    ; '__CONFIG' directive is used to embed configuration word within .asm file.
    ; The lables following the directive are located in the respective .inc file.
    ; See data sheet for additional information on configuration word settings.
    ; Note that the _DEBUG_ON is changed by selecting a debugger or programmer.
    ; There isn't much advantage to setting it in the code.
    ; UDATA declares a section of uninitialized data
    VARIABLES UDATA ; VARIABLES is the name of the section of memory
    myvar1 RES 1 ; uninitialized data, placed by linker in GPR's.
    myvar2 RES 1
    LED_VAR UDATA_SHR
    LED_LOOP RES 1
    LED_LOOP2 RES 1
    LED_COUNT RES 1
    FX_TEMP RES 1
    GLOBAL FX_TEMP
    ;#INCLUDE
    ;------------------------------------------------------------------------------
    ; EEPROM INITIALIZATION
    ;
    ; The 16F882 has 128 bytes of non-volatile EEPROM, starting at address 0x2100
    ;
    ;------------------------------------------------------------------------------
    ORG 0x2100
    DE 0x00, 0x01, 0x02, 0x03
    ;------------------------------------------------------------------------------
    ; RESET VECTOR
    ;------------------------------------------------------------------------------
    RES_VECT CODE 0x0000 ; processor reset vector
    GOTO START ; go to beginning of program
    ;------------------------------------------------------------------------------
    ; TODO ADD INTERRUPTS HERE IF USED
    ;------------------------------------------------------------------------------
    ; CONFIGURATION CODE
    ;------------------------------------------------------------------------------
    ;START ORG 0X05
    MAIN_PROG CODE ; let linker place main program
    START
    BANKSEL PORTA
    CLRF PORTA
    BANKSEL ANSEL
    CLRF ANSEL
    BANKSEL TRISA
    MOVLW 0X00
    MOVWF TRISA
    MOVLW 0X01
    MOVWF LED_COUNT
    BANKSEL STATUS
    BCF STATUS,C
    ;------------------------------------------------------------------------------
    ; MAIN CODE
    ;------------------------------------------------------------------------------
    MAIN
    BANKSEL PORTA
    RRF LED_COUNT,F
    MOVF LED_COUNT,W
    MOVWF PORTA
    CALL LED_PAUSE
    GOTO MAIN
    LED_PAUSE
    MOVLW 0XFF
    MOVWF LED_LOOP2
    LED_PAUSE2
    CLRF LED_LOOP
    DECFSZ LED_LOOP,F
    GOTO $-1
    DECFSZ LED_LOOP2,F
    GOTO LED_PAUSE2
    RETURN
    ;#include
    GOTO $ ; loop forever
    END
    and here the errors
    Warning[205] C:\USERS\JCASE\MPLABXPROJECTS\MAGIDAVID_AL_101.X\MAGIDAVID_LAB_001.ASM 50 : Found directive in column 1. (GLOBAL)
    Error[113] C:\USERS\JCASE\MPLABXPROJECTS\MAGIDAVID_AL_101.X\MAGIDAVID_LAB_001.ASM 85 : Symbol not previously defined (ANSEL)
    Error[113] C:\USERS\JCASE\MPLABXPROJECTS\MAGIDAVID_AL_101.X\MAGIDAVID_LAB_001.ASM 86 : Symbol not previously defined (ANSEL)
    My E mail is jcaser1948@yahoo.es

    • @magidavid
      @magidavid  8 ปีที่แล้ว

      Not sure about the first error, but maybe this line? ";START ORG 0X05", should the ";" be there?
      Try ANSELA in place of the ANSEL. Different MCUs handle the ANSEL registers differently, you can look in the datasheet to find out what label names to use for each register, Microchip is pretty good about using the same name in the datasheet in the compiler.

    • @j.c.serranosanchez3190
      @j.c.serranosanchez3190 8 ปีที่แล้ว

      I have tried another approach.
      First I took your Surcecode and tried to compile it "as it is"It failed because file was not there. I commented t5his file out. Still did not compile with the error
      Warning[205] C:\USERS\JCASE\MPLABXPROJECTS\MAGIDAVID_AL_101.X\MAGIDAVID_LAB_001.ASM 26 : Found directive in column 1. (__CONFIG).
      I commented the configutations bits out, and then your source code compiled. with no errors.
      I substituted the processor for the PIC16F876a (Nothing else changed) and I get the following errors
      Warning[205] C:\USERS\JCASE\MPLABXPROJECTS\MAGIDAVID_AL_101.X\MAGIDAVID_LAB_001.ASM 47 : Found directive in column 1. (GLOBAL)
      Error[113] C:\USERS\JCASE\MPLABXPROJECTS\MAGIDAVID_AL_101.X\MAGIDAVID_LAB_001.ASM 77 : Symbol not previously defined (ANSEL)
      Error[113] C:\USERS\JCASE\MPLABXPROJECTS\MAGIDAVID_AL_101.X\MAGIDAVID_LAB_001.ASM 78 : Symbol not previously defined (ANSEL).
      So I am now more confused as bevor.Does it mean I have to change every programm to fit every single of the Microchip chips?.Could your recommend me a book where a systematic approach to the assebler language is implemented?
      Thanks

    • @magidavid
      @magidavid  8 ปีที่แล้ว

      There's a template directory with MPLABX C:\Program Files (x86)\Microchip\MPLABX\v3.26\mpasmx\templates which has a template file for all the MCUs that Microchip makes. Find the one for the PIC16F876 and start with that file, it will contain the correct __config directives.
      Next, fine the proper include file for the PIC16F876 and copy it over to your project folder. The INC file has the proper labels for the resources inside the PIC16F876, so you'll want to include this in your project file.
      If your MCU doesn't have analog capability then it won't use the ANSEL register. In this case, you can remove the ANSEL command from the code. If the PIC16F876 does have analog control then look up the analog section in the datasheet and see if PORTA is analog capable, if it is then you'll need to configure the ANSELA register for digital.

    • @j.c.serranosanchez3190
      @j.c.serranosanchez3190 8 ปีที่แล้ว

      Thanks for your tip.
      I have builded a sort of "frankenstein" between your code and the template. Now it compiles.
      I post it here in case some bloody beguinner leik me can use it.
      list p=16f876A ; list directive to define processor
      #include ; processor specific variable definitions
      __CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _RC_OSC & _WRT_OFF & _LVP_ON & _CPD_OFF
      ; '__CONFIG' directive is used to embed configuration data within .asm file.
      ; The lables following the directive are located in the respective .inc file.
      ; See respective data sheet for additional information on configuration word.
      ;***** VARIABLE DEFINITIONS
      w_temp EQU 0x7D ; variable used for context saving
      status_temp EQU 0x7E ; variable used for context saving
      pclath_temp EQU 0x7F ; variable used for context saving
      ; UDATA declares a section of uninitialized data
      VARIABLES UDATA ; VARIABLES is the name of the section of memory
      myvar1 RES 1 ; uninitialized data, placed by linker in GPR's.
      myvar2 RES 1
      LED_VAR UDATA_SHR
      LED_LOOP RES 1
      LED_LOOP2 RES 1
      LED_COUNT RES 1
      FX_TEMP RES 1
      GLOBAL FX_TEMP
      ;**********************************************************************
      ORG 0x000 ; processor reset vector
      nop ; nop required for icd
      goto MAIN ; go to beginning of program
      ORG 0x004 ; interrupt vector location
      movwf w_temp ; save off current W register contents
      movf STATUS,w ; move status register into W register
      movwf status_temp ; save off contents of STATUS register
      movf PCLATH,w ; move pclath register into w register
      movwf pclath_temp ; save off contents of PCLATH register
      movf pclath_temp,w ; retrieve copy of PCLATH register
      movwf PCLATH ; restore pre-isr PCLATH register contents
      movf status_temp,w ; retrieve copy of STATUS register
      movwf STATUS ; restore pre-isr STATUS register contents
      swapf w_temp,f
      swapf w_temp,w ; restore pre-isr W register contents
      retfie ; return from interrupt
      MAIN
      BANKSEL PORTA
      RRF LED_COUNT,F
      MOVF LED_COUNT,W
      MOVWF PORTA
      CALL LED_PAUSE
      GOTO MAIN
      LED_PAUSE
      MOVLW 0XFF
      MOVWF LED_LOOP2
      LED_PAUSE2
      CLRF LED_LOOP
      DECFSZ LED_LOOP,F
      GOTO $-1
      DECFSZ LED_LOOP2,F
      GOTO LED_PAUSE2
      RETURN
      END ; directive 'end of program'

  • @sorinpetrila
    @sorinpetrila 7 ปีที่แล้ว

    Hello David and thank you for your wonderful work. You said that we can ask questions and that's what I'm going to do. Based on your video from above I tried to program an 16f690 and I encounter the following problem (th-cam.com/video/G-qzoRoL-9I/w-d-xo.html) .Thank you for your time.

  • @levert.gomellewis.8306
    @levert.gomellewis.8306 8 ปีที่แล้ว

    goen

  • @Mrdjwhoknows
    @Mrdjwhoknows 9 ปีที่แล้ว +1

    did you have to to play music? I find your video very informative but the music is just unbearable