Using Blynk to Control an RGB LED Strip with an ESP-8266

I am installing recessed RGB LED strip lighting under our kitchen cabinets and wanted to control them via Wifi and Amazon Alexa. I found and purchased an inexpensive ESP-8266 based Wifi controller on Amazon (see photo below). After a quick disassembly, I was easily able to reverse-engineer the device, and reprogram it for my purpose. This device came with an IR detector for use with an
IR remote control, however, I didn’t use this and therefore removed the detector. I’ve subsequently noticed version are available on Amazon without the IR remote option.

Wifi RGB LED Strip Controller

The pinouts on the device were labelled R, G, B, with an additional common cathode pin and an un-populated pin labelled W (a fourth MOSFET is installed for this pin). The R-G-B pins are controlled by MOSFETs and connected to the following ESP-8266 GPIOs:

  • G – Q1 – Pin #14 GPIO05
  • R – Q2 – Pin #05 GPIO14
  • B – Q3 – Pin #06 GPIO12
  • IR – Pin #13 GPIO04
  • I didn’t trace the un-populated pin and MOSFET (labelled Q4).

    As suspected, the test points on the reverse side of the PCB are for programming the onboard ESP-8266. Two of the test points were labelled RX and TX. I traced the other two points to GROUND and GPIO0, which are used to place the ESP-8266 into flash mode. Perfect!

    For testing, I reprogrammed the device to respond to a simple Blynk IoT program with 3 slider widgets, one each for the R, G, B pins:

     * Title: Simple ESP-8266 Wifi RGB LED Strip Light Controller
     * File: esp8266_rgb_led_controller.ino
     * Author: James Eli
     * Date: 1/14/2018
     * Blynk slider #1 (r) GPIO14
     * Blynk slider #2 (g) GPIO05
     * Blynk slider #3 (b) GPIO12
     * This program controls an RGB LED strip light. 
     * Notes:
     *  (1) Requires the following arduino libraries:
     *      ESP8266
     *  (2) Compiled with arduino ide 1.8.3
     *  (4) To place an ESP8266 into program mode, GPIO0 must be LOW during power up. 
     *  (5) Test Pads on PCB back:
     *        #1 – GND
     *        #2 – Pin #12 IO00
     *        TX – Pin #16 TX
     *        RX – Pin #15 RX
    #include <ESP8266WiFi.h>
    #include <BlynkSimpleEsp8266.h>
    // Blynk App authentication token, wifi ssid and password.
    char auth[] = "***";
    char ssid[] = "***";
    char pass[] = "***";
    // Esp8266 pins.
    const int RED_PIN   = 14;
    const int GREEN_PIN = 5;
    const int BLUE_PIN  = 12;
    void setup() {
      pinMode( RED_PIN, OUTPUT );
      pinMode( GREEN_PIN, OUTPUT );
      pinMode( BLUE_PIN, OUTPUT );
      Blynk.begin( auth, ssid, pass );
    void loop() {;
    Posted in iot | Tagged , , | Leave a comment

    Re-programming a Lyasi ESP-8285 WiFi Wall Switch

    I purchased a couple of Lyasi wall switches from for $24.99 USD. There are several versions (GresaTek, Jesiya, NewRice, etc) available through amazon, ebay and various other web outlets, however they appear to be very similar with only minor differences. After disassembly and a cursory inspection, I determined a few specifics about how they operate.

    To disassemble the switch, remove the 4 screws holding the face plate to the body. On several of my devices, these screws were extremely tight and required careful use of an appropriately matched/sized screwdriver to prevent damaging the screw heads. This will expose the underlying PCB. The PCB is held in place by 3 additional screws. The switch plate is also connected via a 2-wire JST style connector which can be wiggled apart. Be careful, the connector-to-board solder joint on my device was weak and could have easily been damaged.

    The device incorporate an Espressif Systems ESP-8285 Wifi SOC chip (datasheet), which is great news because this chip is virtually the same as the well-liked ESP-8266 used in the highly popular Sonoff line of products. The primary differences being the 8285 has 1 Meg of built-in memory. This is more than enough for programming simple IoT projects. However, if you need more memory, consider the un-populated chip outline (U2) on the PCB appears to have the appropriate traces running to add an auxiliary SD memory chip.

    My PCB was labelled “DLX Control Solutions” along with a “KS-602” part number which corresponded to the cardboard packaging part number. However, a web search turned up nothing under the text of “DLX Control Solutions”.

    The backside of the board incorporates an SGL-8022 proximity sensing chip which operates the touch sense face-plate. The PCB has componentry for producing the necessary ESP-8285 (3.3V) power and also includes a blue status LED and SRA05 20A relay for AC power switching. There are a few poorly-accomplished routered slots between the high voltage PCB traces for circuit isolation and arc-over protection, but BEWARE, my device didn’t have any indications of being UL approved.

    Regardless, the good news is that the ESP-8285 GROUND, VCC, RXD and TXD pins are brought out to an un-populated four-hole connector, labelled J1 on my board. I highlighted this J1 connector in red on the picture below. However, on some of my boards these were already filled with solder. So, I fired up my trusty de-solder station and was able to remove the solder from 3 of the holes, but the boxed ground hole was filled with something more akin to cement than solder. I was never able to extract whatever that was, so instead, I simply soldered a 4-pin male 90-degree header in place, neglecting to use the holes. That worked well.

    On my device the pins were connected in this order, left to right on the “J1” label side of the PCB: VCC, TXD, RXD and GROUND (individual box label). Remember to connect the TX output from your FTDI programmer to the J1 RXD pin.

    The final hurdle to re-programming would be grounding the ESP-8285 GPIO0 pin on power-up, in order to get the chip into flash mode. Since the GPIO0 pin is NOT brought out to the J1 connector, an alternate method is required. I read online where someone was able to jump the opposite edges of the R6 resister and C15 capacitor together using small tweezers and get the chip into boot mode. The R6 resistor is directly connected to the ESP-8285 GPIO0 pin. I tried this method several times, but was unable to get it to work. My method was to solder a length of wire to the chip side R5 resistor (see the picture), and ground this wire on power-up. This worked first time like a charm.

    I used the Arduino IDE for programming, setting the board to “generic ESP8285 module”, and selected “1M (64K SPIFFS)”. My Sparkfun 3.3V FTDI VCC out was sufficient to power the device for re-programming. I used virtually the same program from this post to allow my switch to respond to a Blynk application and amazon Echo/Alexa voice commands.

    Just like the Sonoff Wifi power switches, this device uses the same ESP-8285 connections. The blue status LED is controlled by GPIO13. This LED is on when the GPIO is low. The relay is controlled by GPIO12 and makes contact when the GPIO is high. The proximity (touch sensing) switch is connected to GPIO0 and the GPIO goes low when sensed. A majority of the other ESP-8285 GPIOs are not used.

    I have since noticed that some of the manufactured PCB boards have two front-side test-points labelled, RES and SW. I wonder if these connections are for placing the ESP-8285 into programming mode? Some of my boards did not have these test-points.

    [UPDATE: 11/15/2017]

    It’s just as I thought. Further investigation has shown that the lower test point on the above picture, the one I labeled ‘A’ is connected to GPIO0. The upper test point, the one labeled ‘B’ is connected to the ESP-8285 pin 33 and ground. Connecting these points together should place the chip into boot mode for programming.

    Posted in arduino, iot | Tagged , , , , | 2 Comments

    Modify Arduino Optimization Levels on the Fly


    Do you know and understand how compiler optimization is altering your code? Higher optimization levels can reveal problems in some programs that are not apparent at lower optimization levels.


    One method to prevent optimization issues with variables is to declare them as volatile. The declaration of a variable as volatile tells the compiler that the variable can be modified at any time externally to the implementation, for example, by the operating system, by an interrupt handler, or by hardware. Because the value of a volatile-qualified variable can change at any time, the actual variable in memory must always be accessed whenever its referenced in code. This means the compiler cannot perform optimizations on the variable.

    Arduino defines the volatile keyword on this webpage using the following example. However, this code neglects to access the 2-byte variable, state atomically. This code probably will survive because the variable, being a 2-byte integer, only uses the lower byte. See the first example on this page for further information.

    Arduino Example:

    // toggles LED when interrupt pin changes state
    int pin = 13;
    volatile int state = LOW;

    void setup() {
    pinMode(pin, OUTPUT);
    attachInterrupt(0, blink, CHANGE);

    void loop() {
    digitalWrite(pin, state);

    void blink() {
    state = !state;


    Another method is to compare versions of your code with different levels of optimization. You may not realize that changing the optimization level of your code is actually very easy once you know how. Here are two techniques to change the optimization level on the fly.

    Pragma-tic Programming

    To change optimization for large areas of code, I recommend using the optimize pragma. Surrounding the code with the push and pop option pragma is also a good practice. Here is an example:

    #pragma GCC optimize ("-O0")
    #pragma GCC push_options

    void setup() { }
    void loop() { }

    #pragma GCC pop_options

    Know Your Attributes

    If you want to effect the optimization of just a single function, use the optimize attribute like so:

    void loop() __attribute__((optimize("-O0")));
    void loop() { }


    More information on GCC optimization can be found here.
    More information on GCC function attributes can be found here.
    More information on GCC pragmas can be found here.

    Posted in arduino, avr | Tagged , , , | Leave a comment

    Controlling an IoT Yunshan ESP8266 WIFI Network Relay via an Amazon Echo/Alexa

    shoulders of giants

    Easy-Peasy, if you’re standing on the shoulders of giants! Here’s the demo code:

     * Title: Simple ESP-8266 Amazon Echo/yunshan wifi relay control demo
     * File: esp8266_yunshan_echo_demo.ino
     * Author: James Eli
     * Date: 1/15/2017
     * This program controls a Yunshan wifi relay module communicating through 
     * an amazon echo to the onboard esp-8266-12e module. 
     * Notes:
     *  (1) Requires the following arduino libraries:
     *      ESP8266
     *      ESPAsyncTCP
     *      FauxMoESP
     *  (2) Compiled with arduino ide 1.8.1
     *  (3) As of 11/27/16 the ESP8266 release core v2.3.0 did not have the right lwip 
     *      code. If you get a complaint about udp_set_multicast_ttl not being defined, 
     *      you'll need to uninstall the ESP8266 board support, then manually install 
     *      the most recent core from Essentialy 
     *      you'll need to git clone into your 
     *      Arduino sketchbook folder under hardware/esp8266com/esp8266 and then in a 
     *      terminal shell in hardware/esp8266com/esp8266/tools run python
     * Change Log:
     *   1/15/2017: Initial release. JME
    #include "fauxmoESP.h"
    // Esp8266 pins.
    #define ESP8266_GPIO2    2 // Blue LED.
    #define ESP8266_GPIO4    4 // Relay control.
    #define ESP8266_GPIO5    5 // Optocoupler input.
    #define LED_PIN          ESP8266_GPIO2
    #define WIFI_SSID       "…"
    #define WIFI_PASS       "…"
    #define SERIAL_BAUDRATE 9600
    fauxmoESP fauxmo;
    // Wifi setup
    void wifiSetup() {
      // Set WIFI module to STA mode
      WiFi.mode( WIFI_STA );
      // Connect
      Serial.printf( "[WIFI] Connecting to %s ", WIFI_SSID );
      WiFi.begin( WIFI_SSID, WIFI_PASS );
      // Wait
      while ( WiFi.status() != WL_CONNECTED ) {
        Serial.print( "." );
        delay( 100 );
      // Connected!
      Serial.printf( "[WIFI] STATION Mode, SSID: %s, IP address: %s\n", WiFi.SSID().c_str(), WiFi.localIP().toString().c_str() );
    void callback( uint8_t device_id, const char * device_name, bool state ) {
      Serial.print( "Device " ); 
      Serial.print( device_name ); 
      Serial.print( " state: " );
      if ( state ) {
        digitalWrite( ESP8266_GPIO4, 1 ); // Relay control pin on.
        Serial.println( "ON" );
      } else  {
        digitalWrite( ESP8266_GPIO4, 0 ); // Relay control pin off.
        Serial.println( "OFF" );
    void setup() {
      // Init serial port and clean garbage
      Serial.begin( SERIAL_BAUDRATE );
      Serial.println( "FauxMo demo sketch" );
      Serial.println( "After connection, ask Alexa/Echo to 'turn  on' or 'off'" );
      pinMode( ESP8266_GPIO4, OUTPUT );       // Relay control pin.
      pinMode( ESP8266_GPIO5, INPUT_PULLUP ); // Input pin.
      pinMode( LED_PIN, OUTPUT );             // ESP8266 module blue LED.
      digitalWrite( LED_PIN, LOW );           // Turn on LED.
      // Wifi
      digitalWrite( LED_PIN, HIGH );          // Turn off LED.
      // Fauxmo
      fauxmo.addDevice( "relay" );
      fauxmo.onMessage( callback );
    void loop() {


    The following libraries are required:
    1. ESPAsyncTCP library
    2. FauxMoESP library (to download, select download repository)


    Emulate a WeMo device with ESP8266
    Easy Alexa (or Echo) Control of your ESP8266 Huzzah

    Posted in iot | Tagged , , | 1 Comment

    Blynking an IoT Yunshan ESP8266 250V 10A AC/DC WIFI Network Relay Module


    I purchased a few of these Yunshan Wifi Relays through ebay for approximately $7.50US. The device should be perfect for use in simple IOT projects which require controlling household AC power. The onboard JQC-3FF relay is rated to 250VAC or 30VDC at up to 12A. There are routered slots between the high voltage PCB traces for circuit isolation and arc-over protection. Transient voltage suppression is incorporated on both the board power supply and the photocoupler (see description below) input line.

    The device requires a power supply between 7 and 30V DC. I unsuccessfully attempted to run it with an inexpensive 5V, 2A wall-wort, even though the onboard MP2303 buck converter is rated down to 4.8V. I did get it to operate successfully using a 9VDC wall-wort.

    The device contains an integrated ESP8266-12E, but appears to only use the GPIO4 and GPIO5 pins. That was a disheartening discovery because it discards a significant amount of functionality inside the ESP8266 WIFI module. Hence the ESP8266 low power, wake from sleep provisions (where GPIO16 and RESET need to be linked together) would require some skillful soldering of the module’s exposed pins.

    The good news is, programming the module is very easy, as I discuss later. I also found the overall build quality of my device to be above the typical level found on ebay-sourced Chinese electronics.

    The ebay listing contained a link to a zip file, entitled U4648-datasheet, which contained example programs, schematics, and a Chinese manual. Through the Google translation service I managed to translate the manual, but there’s no reason to do that, as there isn’t much there. More information can be learned from a quick study of the schematic and the board itself.

    Module Description
    The Chinese manual presents the following limited module description:


    1 – The power input terminals.
    2 – The relay output terminals.
    3 – IO input terminal.
    4 – Enter the status indicator, IO input high when lit, blue light.
    5 – The relay output status indicator, the relay is turned on, the red light.
    6 – TTL serial output.
    7 – Boot mode selection jumper.

    Board Connectors

    Here are the connections on my board:


    A: 7-30V+ DC power supply
    B: Power supply ground
    C: Normally closed (NC) relay contact
    D: Common (COM) relay contact
    E: Normally open (NO) relay contact
    F: 5V+ out
    G: ESP8266 GPIO5 Optocoupler Input
    H: Ground (isolated optocoupler input)

    AP MODE Webpage

    I was easily able to connect a 9V power supply to the A-B connector (see above picture and connector description) and control the device via WIFI. To do this, simply connect your computer or phone to the yunshan_wifi_xx_xx_xx network (where it appears the xx are hexadecimal numbers pulled from the ESP8266 MAC address). My device responded to the supplied password of yunshan123456789. Once a connection was established, I simply entered the IP address of into my browser. Once there, I was greeted by a Chinese web page, the translation of which appears below. From this webpage, I was able to open and close the relay. The status of the GPIO5 optocoupler input is also displayed on this webpage.


    Since I have big IOT home automation plans for these devices, my next task was to attempt a re-program of the onboard ESP8266 module. For a quick test, I uploaded the traditional Arduino IDE ESP8266 blink program, and was rewarded with a 1Hz blinking blue LED on the ESP8266 module.

    Program Upload

    On the lower left portion of the PCB is a section that grants access to the ESP8266 pins for programming (see the above photo). These same pins are also useful for TTL serial output purposes (debugging, etc.). Separate 2 and 3-pin headers will need to be soldered into these connector holes (labeled P5 and P6). The ESP8266 GPIO4 controls the relay through a 2N3904 transistor. Setting GPIO4 high, causes the relay to close the NO contact with Common and the NC contact to open. Additionally, taking connector “G” high causes GPIO5 to also go low isolated via a PC817 photocoupler. On my board the blue LED is connected to GPIO2, and can be illuminated by pulling the pin low.

    To program the ESP8266 module, I connected the TX, RX and ground pins of connector P6 to a SparkFun USB FTDI programmer, and jumped the two pins of connector P5 together when I was ready to upload. Connector P5 grounds GPIO0 and GPIO15, sending the device into bootloader mode. If you have trouble programming the ESP8266 like I did on the first attempt, ensure you also ground your FTDI device through the P6 connector.

    A very good introduction to the ESP8266 module can be found here. Excellent programming information for the individual ESP8266 modules is also widely available (two examples: ESP8266-01 and ESP8266-12e).

    Board Schematic


    Blynk Relay Control Application

     * Title: Simple ESP-8266 blynk/yunshan wifi relay control
     * File: esp8266_yunshan_relay.ino
     * Author: James Eli
     * Date: 12/25/2016
     * This program controls a Yunshan wifi relay module communicating through 
     * the onboard esp-8266-12e module. The module is controlled from the
     * internet via the Blynk cloud app. 
     * Notes:
     *  (1) Requires the following arduino libraries:
     *      ESP8266
     *      Blynk
     *  (2) Compiled with arduino ide 1.6.12
     *  (3) Uses three Blynk app widgets:
     *       V0: button configured as a switch.
     *       V1: led.
     *       V2: led.
     * Change Log:
     *   12/25/2016: Initial release. JME
     *   12/31/2016: Added input pin status. JME
     *   01/15/2017: Added volatile. JME
    #include <ESP8266WiFi.h>
    #include <BlynkSimpleEsp8266.h>
    // Esp8266 pins.
    #define ESP8266_GPIO2    2 // Blue LED.
    #define ESP8266_GPIO4    4 // Relay control.
    #define ESP8266_GPIO5    5 // Optocoupler input.
    #define LED_PIN          ESP8266_GPIO2
    // Blynk app authentication code.
    char auth[] = "***";
    // Wifi SSID.
    const char ssid[] = "***";
    // Wifi password.
    const char password[] = "***";    
    // Flag for sync on re-connection.
    bool isFirstConnect = true; 
    volatile int relayState = LOW;    // Blynk app pushbutton status.
    volatile int inputState = LOW;    // Input pin state.
    void setup() {
      pinMode( ESP8266_GPIO4, OUTPUT );       // Relay control pin.
      pinMode( ESP8266_GPIO5, INPUT_PULLUP ); // Input pin.
      pinMode( LED_PIN, OUTPUT );             // ESP8266 module blue LED.
      digitalWrite( LED_PIN, LOW );           // Turn on LED.
      Blynk.begin( auth, ssid, password );    // Initiate Blynk conection.
      digitalWrite( LED_PIN, HIGH );          // Turn off LED.
    // This function runs every time Blynk connection is established.
      if ( isFirstConnect ) {
        isFirstConnect = false;
    // Sync input LED.
    BLYNK_READ( V2 ) {
    // Blynk app relay command.
    BLYNK_WRITE( V0 ) {
      if ( param.asInt() != relayState ) {
        relayState = !relayState;                  // Toggle state.
        digitalWrite( ESP8266_GPIO4, relayState ); // Relay control pin.
        Blynk.virtualWrite( V1, relayState*255 );  // Set Blynk app LED.
    // Debounce input pin.
    int DebouncePin( void ) {
      // Read input pin.
      if ( digitalRead( ESP8266_GPIO5 ) == HIGH ) {
        // Debounce input.
        delay( 25 );
        if ( digitalRead( ESP8266_GPIO5 ) == HIGH )
          return HIGH;
      return LOW;
    // Set LED based upon state of input pin.
    void CheckInput( void ) {
      if ( DebouncePin() != inputState ) {
        Blynk.virtualWrite( V2, inputState*255 );
        inputState = !inputState;
    // Main program loop.
    void loop() {;
      //yield(); //Updated: 3/8/2017

    TCP Client Demo

    Here is a basic server which responds to TCP client HTTP GET commands (added 1/8/17):

    #include <ESP8266WiFi.h>
    // Esp8266 pinouts
    #define ESP8266_GPIO2    2  // Blue LED.
    #define ESP8266_GPIO4    4  // Relay control. 
    #define ESP8266_GPIO5    5  // Optocoupler input.
    #define LED_PIN          ESP8266_GPIO2
    // WiFi Definitions.
    const char ssid[] = "***";
    const char pswd[] = "***";
    WiFiServer server( 80 );
    volatile int relayState = 0;      // Relay state.
    void setup() {
    void GetClient( WiFiClient client ) {
      // Read the first line of the request.
      String req = client.readStringUntil( '\r' );
      Serial.println( req );
      String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\n";
      if ( req.indexOf( "OPTIONS" ) != -1 ) {
        s += "Allows: GET, OPTIONS";
      } else if ( req.indexOf( "GET" ) != -1 ) {
        if ( req.indexOf( "open" ) != -1 ) {
          // relay on!
          s += "relay on!";
          relayState = 1;
          digitalWrite( ESP8266_GPIO4, 1 ); // Relay control pin.
        } else if ( req.indexOf( "close" ) != -1 ) {
          // relay off!
          s += "relay off!";
          relayState = 0;
          digitalWrite( ESP8266_GPIO4, 0 ); // Relay control pin.
        } else if ( req.indexOf( "relay" ) != -1 ) {
          if ( relayState == 0 )
            // relay off!
            s += "relay off!";
            // relay on!
            s += "relay on!";
        } else if ( req.indexOf( "io" ) != -1 ) {
          if ( digitalRead( ESP8266_GPIO5 ) == 0 )
            s += "input io is:0!";
            s += "input io is:1!";
        } else if ( req.indexOf( "MAC" ) != -1 ) {
          uint8_t mac[WL_MAC_ADDR_LENGTH];
          WiFi.softAPmacAddress( mac );
          String macID = String( mac[WL_MAC_ADDR_LENGTH - 5], HEX) + String( mac[WL_MAC_ADDR_LENGTH - 4], HEX) +
                         String( mac[WL_MAC_ADDR_LENGTH - 3], HEX) + String( mac[WL_MAC_ADDR_LENGTH - 2], HEX) +
                         String( mac[WL_MAC_ADDR_LENGTH - 1], HEX) + String( mac[WL_MAC_ADDR_LENGTH], HEX);
          s += "MAC address: " + macID;
        } else
          s += "Invalid Request.<br> Try: open/close/relay/io/MAC";
      } else 
        s = "HTTP/1.1 501 Not Implemented\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\n";
      s += "</html>\n";
      // Send the response to the client.
      client.print( s );
      delay( 1 );
      Serial.println( "Client response sent." );
    void loop() {
      // Check if a client has connected.
      WiFiClient client = server.available();
      if ( client ) 
        GetClient( client );
    void connectWiFi() {
      byte ledStatus = LOW;
      Serial.println( "Connecting to: " + String( ssid ) );
      // Set WiFi mode to station (as opposed to AP or AP_STA).
      WiFi.mode( WIFI_STA );
      // WiFI.begin([ssid], [passkey]) initiates a WiFI connection.
      // to the stated [ssid], using the [passkey] as a WPA, WPA2, or WEP passphrase.
      WiFi.begin( ssid, pswd );
      while ( WiFi.status() != WL_CONNECTED ) {
        // Blink the LED.
        digitalWrite( LED_PIN, ledStatus ); // Write LED high/low.
        ledStatus = ( ledStatus == HIGH ) ? LOW : HIGH;
        delay( 100 );
      Serial.println( "WiFi connected" );  
      Serial.println( "IP address: " );
      Serial.println( WiFi.localIP() );
    void initHardware() {
      Serial.begin( 9600 );
      pinMode( ESP8266_GPIO4, OUTPUT );       // Relay control pin.
      pinMode( ESP8266_GPIO5, INPUT_PULLUP ); // Input pin.
      pinMode( LED_PIN, OUTPUT );             // ESP8266 module blue LED.
      digitalWrite( ESP8266_GPIO4, 0 );       // Set relay control pin low.
    Posted in iot | Tagged , | 82 Comments

    ATMEL Studio 7 Does Blink in Assembly Language


    See the previous post (here) for detailed information on AS7 installation and simulating of an Arduino program execution. As an exercise to gain familiarity with AS7, lets make an assembly language project using the below Blink code:

    • Select “File>New>Project”.

    • Assembler.

    • AVR Assembler Project.

    • Give it a unique name.

    • Select the proper device.

    Remember to select the Simulator in order to run the program inside the AS7 IDE. See the previous post on how to do this. Here is a screen shot of the assembly code running in AS7:


    Here is the code for a very basic assembly language blink program:

    .include ""
    .org 0x0000
       rjmp start
        ldi r16, 0           ; reset system status
        out SREG, r16        ; init stack pointer
        ldi r16, low(RAMEND)
        out SPL, r16
        ldi r16, high(RAMEND)
        out SPH, r16
        sbi DDRB, DDB5       ;pinMode(13, OUTPUT);
        sbi PORTB, PORTB5    ;turn LED on
        rcall _delay
        cbi PORTB, PORTB5    ;turn LED off
        rcall _delay
        rjmp _loop
        ldi r24, 0x00        ;one second delay iteration
        ldi r23, 0xd4 
        ldi r22, 0x30 
    _d1:                     ;delay ~1 second
        subi r24, 1   
        sbci r23, 0   
        sbci r22, 0
        brcc _d1

    Now, start learning inline assembly language:

    Also available as a book, with greatly expanded coverage!

    [click on the image]

    Posted in arduino, assembly language | Tagged , , , , , , , | Leave a comment

    Using ATMEL Studio 7 for Arduino Development


    While installing ATMEL Studio 7 (AS7) is not required in order to learn inline assembly language programming, it has worthwhile advantages. The ability to compile code for the Arduino, run it inside the included Simulator and immediately debug it will greatly speed your learning process. This seamless and iterative process would take several long minutes to complete if using the Arduino IDE. In fact, the Arduino IDE alone cannot perform the disassembly and debug functions.

    AS7 now features seamless, one-click importation of projects created in the Arduino development environment. Your sketch, including any libraries it references, can be imported into AS7 as a C++ project. Once imported, you can leverage many additional capabilities of AS7 to fine-tune and debug your design. For most Arduino boards, shield-adapters that expose debug connectors are available, or one could use an ATMEL-ICE debug wire interface with a standard Arduino (slight modification of the Arduino is required).

    More information on DebugWire with the Arduino can be found here:
    Debugging Arduino using debugWire
    Debugging with the new ATMEL-ICE
    Modify an Arduino for DebugWire

    Best of all, AS7 is free of charge. It is also important to note, that most of the functionality of AS7 is also available in the older Atmel Studio 6 IDE (AS6).

    Install ATMEL Studio 7

    I’m not going to go through the whole installation process (get the book), just navigate to the ATMEL Studio 7 website download page, and click the DOWNLOAD NOW link:

    Direct link to the download page:

    Select the web installer unless you have a specific requirement to install off-line.

    ATMEL Studio 7 Blinks

    Congratulations if you have completed the installation. Let’s run the Studio for the first time.

    On initial start, AS7 will ask you to select a user interface profile. I suggest the “Advanced” version, however either option is satisfactory. If desired, the profile can always be changed later.


    Be patient, it will seem like a long period of time for the program to load, but eventually you will be greeted with the IDE and the startup page populated with an ATMEL announcement internet feed. It is possible to disable this if it is unwanted (checkbox on the bottom left).


    From the file menu select NEW->Project.


    The New Project dialog will open and make the following selections:

    • Insure “Installed” and “C/C++” is highlighted on the far left.
    • Highlight “Create project from Arduino sketch”.
    • Give the project an appropriate name like, “AS7_Blink” (note, spaces are not allowed in the project name).
    • The default location should fill automatically.
    • The solution name defaults to the project name, and this is acceptable for now.


    The next dialog will ask for the existing Arduino sketch location. Click on the button containing the ellipsis to the right of the Sketch File. Navigate to the Arduino Blink example sketch, which should be located inside your Arduino installation folder (similar location to mine on Windows):

    C:\Program Files (x86)\Arduino\examples\01.Basics\Blink\Blink.ino

    Continuing along:

    • Insure your Arduino IDE path is properly filled in.
    • Make the appropriate selections for your board (Arduino/Genuino Uno) and device (atmega328p).
    • Click “Ok”.

    AS7 will take some time creating the folder(s) for the project and pulling in the Blink sketch with all of its dependencies (all core and variant include files, Arduino core source files and libraries). It will eventually finish by creating and opening an editable “sketch.cpp” file inside the IDE.


    The sketch.cpp file is primarily the code from the example Arduino blink program including some additional automatically generated code by the ATMEL studio. Your solution should look like this:


    Ready, Set, Simulate!

    We can now run the Blink program without an actual Arduino board using the simulator included with AS7. But first we need to inform AS7 to use the Simulator. Under the Project menu, select “Blink Properties…”.


    On the properties screen that appears, on the far left, select the “Tool” item, and under the heading of “Selected debugger/programmer”, select “Simulator” from the drop down list.


    Now, in order to run the program in the simulator, simply press “Alt+F5” or select “Debug->Start Debugging and Break” using the menu. AS7 will build the Blink project, execute the C-runtime startup code and then halt at the first line of the Arduino program. If you examine your screen, you’ll notice the debugger (on the far left) is pointing to and highlighting the line of code it has paused on:



    At this point, you might think to yourself, this code wasn’t in the Blink program. What gives?

    All of this is actually code that comes from the core Arduino wiring files which silently gets inserted into every Arduino sketch as needed. If you look further down the screen you will eventually see the call to the Blink Setup() function.

    Hitting the “F10” key (Step Over) twice should bring the simulator to the function call to Setup. At this time, pressing the “F11” key (Step Into) will cause the simulator to jump into the Blink program and pause it’s execution on the first line inside the Setup function:

    pinMode(led, OUTPUT);

    Now things should start to look familiar. The last feature I want to demonstrate is the ability to drill down into the underlying assembly language that was created by the compiler. We do this by selecting an option from the Debug menu, “Debug>Windows>Disassembly”.


    You should now see a mixture of C and assembly code which makes up the executable Blink program. The simulator should be paused on the following line:

    0000007B LDI R22,0x01 Load immediate


    I can not overstate the importance of this feature. The ability to examine the assembly code, compare it to the source, and to step through it line-by-line is an enormous asset to the inline assembly programmer. You can, among other features:

    • Set breakpoints
    • Watch variables
    • Alter register values
    • Time sections of code.

    You will want to remember how to do this.

    ATMEL has uploaded several informative videos on demonstrating the use of the Studio, how to debug and how to use the simulator. A good example is located here:

    Also available as a book, with greatly expanded coverage!

    [click on the image]

    Here’s a partial look at the disassembly listing (mixed C and assembly) produced by AS7:

    void setup() {                
      // initialize the digital pin as an output.
      pinMode(led, OUTPUT);     
    0000007B  LDI R22,0x01		Load immediate 
    0000007C  LDS R24,0x0100		Load direct from data space 
    0000007E  JMP 0x000001A5		Jump 
      pinMode(led, OUTPUT);     
    // the loop routine runs over and over again forever:
    void loop() {
    00000080  PUSH R28		Push register on stack 
    00000081  PUSH R29		Push register on stack 
      digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
    00000082  LDI R28,0x00		Load immediate 
    00000083  LDI R29,0x01		Load immediate 
    00000084  LDI R22,0x01		Load immediate 
    00000085  LDD R24,Y+0		Load indirect with displacement 
    00000086  CALL 0x000001E1		Call subroutine 
      delay(5000);               // wait for a second
    00000088  LDI R22,0x88		Load immediate 
    00000089  LDI R23,0x13		Load immediate 
    0000008A  LDI R24,0x00		Load immediate 
    0000008B  LDI R25,0x00		Load immediate 
    0000008C  CALL 0x00000119		Call subroutine 
      digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
    0000008E  LDI R22,0x00		Load immediate 
    0000008F  LDD R24,Y+0		Load indirect with displacement 
    00000090  CALL 0x000001E1		Call subroutine 
      delay(1000);               // wait for a second
    00000092  LDI R22,0xE8		Load immediate 
    00000093  LDI R23,0x03		Load immediate 
    00000094  LDI R24,0x00		Load immediate 
    00000095  LDI R25,0x00		Load immediate 
    00000096  POP R29		Pop register from stack 
    00000097  POP R28		Pop register from stack 
      delay(1000);               // wait for a second
    00000098  JMP 0x00000119		Jump 
    Posted in arduino, avr | Tagged , , , , , , , | Leave a comment