06Dec 2014

First Steps with the ESP8266-03 Development Board

A fun afternoon project with two platforms...

fun with the esp8266s

As mentioned in my previous blog post I was very optimistic when designing my ESP8266-03 development board and didn't even prototype it before launching a batch in production. As I just received a few of these boards in the mail today and given that information about this module is scattered all over the internet, I'll detail here my first steps with it...

Configuring the FT230X

FT230X default configuration
The onboard USB to UART adapter has 4 CBUS pins that can be configured as GPIOs or status pins. Three of them (CBUS0/1/3) are connected to green LEDs so if you want to change the default settings, you can download the FTProg utility [here|http://www.ftdichip.com/Support/Utilities/FTProg_v3.0.56.245.zip|en|FT Prog utility], program your new settings, disconnect/reconnect the dev board.

Playing with the default firmware

This part is inspired by this awesome web page.
Connect the development board to your computer using a micro-usb cable, launch your favorite terminal program (in my case Realterm), set a 9600 baudrate, head to the "Send" tab, tick the +CR & +LF boxes, enter these different commands and click "Send ASCII".

Testing the communication

>AT
OK

Getting the firmware version:

>AT+GMR
0018000902-AI03

Setting Wifi mode as AP+STA and listing nearby Access Points (APs):

>AT+CWMODE=3
OK
>AT+CWLAP
+CWLAP:(3,"mysuperwifi",-76,"90:xx:xx:xx:xx:xx",1)
+CWLAP:(4,"zak-52122",-79,"a4:xx:xx:xx:xx:xx",3)
+CWLAP:(3,"ZyXEL_133A",-80,"cc:xx:xx:xx:xx:xx",2)
+CWLAP:(3,"somewifi",-81,"e0:xx:xx:xx:xx:xx",4)
+CWLAP:(0,"HP-Print-0C-Photosmart",-82,"6c:xx:xx:xx:xx:xx",4)
+CWLAP:(4,"anotherwifi",-83,"fc:xx:xx:xx:xx:xx",1)

As you can see you'll find the APs names together with their MAC addresses and RSSIs. The first digit is the encryption type (0:open, 1:wep, 2:wpapsk, 3:wpa2psk, 4:wpawpa2psk).
Connecting to your access point:

>AT+CWJAP="mysuperwifi","mypassword"
OK

Checking that you're actually connected:

>AT+CWJAP?
AT+CWJAP:"mysuperwifi"
OK

Download and run this TCP server/terminal made by tomeko: Bcbserver, send data to your main computer:

> AT+CIPMUX=0
OK
>AT+CIPSTART="TCP","your computer IP",7778
OK
Linked
+IPD,24:Connection established
OK

Here the TCP connection is established, you need to specify how many bytes you want to send (here 4)

>AT+CIPSEND=4
> (type your 4 bytes long text here)
SEND OK

You should see your text displayed in BCBcostam.
Finally, stop your TCP connection:

>AT+CIPCLOSE
OK
Unlink

You'll find a lot more AT commands here and here.

Building the Espressif toolchain

Until now we've used the ESP8266 as a peripheral, meaning that we need a computer/phone/microcontroller to operate it. However, since the ESP8266 manufacturer released the chip SDK we can reprogram it with our own code so it can work as a standalone device. To do so, we first need to build the Espressif toolchain.
This will unfortunately take quite a while... so only do it when you have some time to spend! I highly recommend following the great guide that can be found here. It is a tutorial for linux but you'll also find a Windows tutorial here.
Please note that in the Linux tutorial, at the time of writing I had to run "mv espiotsdkv0.9.3/* ESP8266SDK" and not "mv espiotsdkv0.9.3 ESP8266SDK".

Making our own program

Let's learn by example. In 4-5 hours I managed to make this fun setup:


The Doppler station

First, we need to setup one ESP8266 pin as input with its internal pull-up enabled so we can just connect our button between this IO and our platform ground:

PINFUNCSELECT(PERIPHSIOMUXMTCKU, FUNC_GPIO13); // Set GPIO13 function
gpiooutputset(0, 0, 0, BIT13); // Set GPIO13 as input
PINPULLDWNDIS(PERIPHSIOMUXMTCKU); // Disable pulldown
PINPULLUPEN(PERIPHSIOMUXMTCKU); // Enable pullup

Given that we don't have access to the ESP8266 english datasheet and want to use all its already included features, we are forced to use the SDK. Have a look for "ESP8266EX SDK Programming Guide" on your favorite search website.
As a given pin can be driven by several controllers inside the ESP8266, the first line specifies that we want to use the GPIO controller on GPIO13. The three others.... well read the comments ;-) . This is a simple and non energy-saving way to use a button as you'll need to poll its state rather than having an interrupt based readout:

ETSGPIOINTR_DISABLE(); // Disable gpio interrupts
ETSGPIOINTRATTACH(dopplerint_handler, 12); // GPIO12 interrupt handler
PINFUNCSELECT(PERIPHSIOMUXMTDIU, FUNC_GPIO12); // Set GPIO12 function
gpiooutputset(0, 0, 0, GPIOIDPIN(12)); // Set GPIO12 as input
GPIOREGWRITE(GPIOSTATUSW1TC_ADDRESS, BIT(12)); // Clear GPIO12 status
gpiopinintrstateset(GPIOIDPIN(12), 3); // Interrupt on any GPIO12 edge
ETSGPIOINTR_ENABLE(); // Enable gpio interrupts

The doppler sensor has a 5 volts frequency output (don't forget the voltage divider!) meaning that it'll toggle its pin several times per second at a frequency proportional to an object speed. In the simple firmware you can download below we're using a very simple strategy: everytime the HB-100 FOUT pin toggles, an interrupt is generated on the ESP8266 which will increment a counter. Every 0.5s we read this counter value and broadcast it to our computer and other ESP8266-03 module.
The interesting part above is the second line that registers dopplerinthandler as the GPIO12 interrupt function. Every time this function is called we increment our counter.

PINFUNCSELECT(PERIPHSIOMUXGPIO2U, FUNC_GPIO2); // Set GPIO2 function
gpiooutputset(0, BIT2, BIT2, 0); // Set GPIO2 low output

These two lines set GPIO2 as an output to drive the red LED. Given that the ESP8266-03 board already includes current limiting resistors you can directly connect your LED. As you can see in the video, this red LED blinks every 0.5sec:

ostimerdisarm(&led_timer); // Disarm led timer
ostimersetfn(&ledtimer, (ostimerfunct *)led_timerfunc, NULL); // Setup led timer
ostimerarm(&led_timer, 500, 1); // Arm led timer, 0.5sec, repeat

The ESP8266 'operating system' allows you to specify timers (functions) that will be fired at a pre-defined frequency. Here we specify that the led_timerfunc function should be called every 0.5sec indefinitely.

char ssid32 = "mywifissid"; // Wifi SSID
char password64 = "mywifipassord"; // Wifi Password
struct station_config stationConf; // Station conf struct
wifisetopmode(0x1); // Set station mode
os_memcpy(&stationConf.ssid, ssid, 32); // Set settings
os_memcpy(&stationConf.password, password, 64); // Set settings
wifistationset_config(&stationConf); // Set wifi conf
//wifistatusledinstall(13, PERIPHSIOMUXMTCKU, FUNCGPIO13); // Wifi LED status

Having your board connect to your home Wifi is so simple! The last line allows you to specify an LED dedicated to Wifi status indication. It will blink when trying to connect/having an error, it will switch off when everything is ok.

void ICACHEFLASHATTR networkcheckip(void)
{
struct ip_info ipconfig;

ostimerdisarm(&network_timer); // Disarm timer
wifigetipinfo(STATIONIF, &ipconfig); // Get Wifi info

if (wifistationgetconnectstatus() == STATIONGOTIP && ipconfig.ip.addr != 0)
{
network_start(); // Everything in order
}
else
{
os_printf("Waiting for IP...\n\r");
ostimersetfn(&networktimer, (ostimerfunct *)networkcheckip, NULL);
ostimerarm(&network_timer, 1000, 0);
}
}

This 1sec timer is called until the platform gets an IP from your home's DHCP server (usually your router). Once it has an IP address, you can start establishing connections to you computer and other devices.

globaltcpconnect.type=ESPCONN_TCP; // We want to make a TCP connection
globaltcpconnect.state=ESPCONN_NONE; // Set default state to none
globaltcpconnect.proto.tcp=&global_tcp; // Give a pointer to our TCP var
globaltcpconnect.proto.tcp->localport=espconnport(); // Ask a free local port to the API
globaltcpconnect.proto.tcp->remote_port=7778; // Set remote port (bcbcostam)
globaltcpconnect.proto.tcp->remote_ip0=ip1; // Your computer IP
globaltcpconnect.proto.tcp->remote_ip1=ip2; // Your computer IP
globaltcpconnect.proto.tcp->remote_ip2=ip3; // Your computer IP
globaltcpconnect.proto.tcp->remote_ip3=ip4; // Your computer IP
espconnregistconnectcb(&globaltcpconnect, tcpNetworkConnectedCb); // Register connect callback
espconnregistdisconcb(&globaltcpconnect, tcpNetworkDisconCb); // Register disconnect callback
espconnregistreconcb(&globaltcpconnect, tcpNetworkReconCb); // Register reconnection function
espconnconnect(&globaltcp_connect); // Start connection

Setting up a TCP connection is not so complex. You specify your destination IP/port together with functions to call if the connection is made, disconnected or reconnected.

globaludpconnect.type=ESPCONN_UDP; // We want to make a UDP connection
globaludpconnect.state=ESPCONN_NONE; // Set default state to none
globaludpconnect.proto.udp=&global_udp; // Give a pointer to our UDP var
globaludpconnect.proto.udp->local_port=2222; // Set local port
globaludpconnect.proto.udp->remote_port=2222; // Set remote port
globaludpconnect.proto.udp->remote_ip0=ip1; // The other ESP8266 IP
globaludpconnect.proto.udp->remote_ip1=ip2; // The other ESP8266 IP
globaludpconnect.proto.udp->remote_ip2=ip3; // The other ESP8266 IP
globaludpconnect.proto.udp->remote_ip3=ip4; // The other ESP8266 IP
if(espconncreate(&globaludp_connect) == 0) // Correctly setup
{
os_printf("UDP connection set\n\r");
udpconnok = TRUE;
}

UDP connection are much simpler given that there's strictly no added logic on the data sending part like with TCP. The ESP8266 is just sending bytes to a given IP address.

I think I covered most of the low level stuff. I'll summarize what the firmware does in case you want to have a look at the source code:
- setup the input/outputs
- register a 0.5sec timer in charge of toggling the red LED, reading the doppler frequency, sending it to your computer and other ESP8266
- register a 1sec timer that will check the ESP8266 connection status. Once it has an IP, start making a TCP connection to the computer and a UDP one to the ESP8266

The indicating platform

The code here is much simpler:
- Connect to your Wifi
- Set 3 pins as outputs for the green/orange/red LEDs
- Create a UDP connection
- Parse the incoming data to know which LEDs to turn on/off.

Want the files? Here they are: doppler sensor code esp8266 client code
If you want more examples have a look at this github repository and don't hesitate to come to #esp8266 on freenode!
Thanks zarya for the help and code!

5 comments

1. On Sunday, December 7 2014, 11:20 by José Xavier

Thank for the info :) during your research did you found if it is possible to put it on access mode? If yes it is possible to change client and access point mode on the fly?

2. On Saturday, March 14 2015, 18:57 by Dennis

I got it working at 9600 . . . seemed to need a fresh usb connection.

And I realized the button isn't reset!!

Great board!

3. On Sunday, March 15 2015, 18:43 by limpkin

@Dennis : Hey there! Glad it's working now for you!

4. On Sunday, March 22 2015, 01:28 by ben

I've been meaning to get one of these chips to play with! I'd like to do webserver (or ftp server) that can be used for updating the programming file of an arduino!

In general once you have the compiler/toolchain setup (or download a virtual machine image), can you flash a small tcp/ip stack (ex. uip or lwip) onto the chip for a totally custom internet solution?

Or is the idea that Espressif's library has a tcp/ip stack that can do it all, and so no tcp/ip programming is required.

Also, I've used an ARMs in the past, is the architecture of the 80Mhz Tensilica Xtensa 32bit processor remotely similar to an ARM? Either in the architecture ARM7,8 etc, or in the instruction set ARM7v6, v7-M?

5. On Sunday, March 29 2015, 20:32 by limpkin

@ben : Espressif indeed already has a TCP/IP stack included. Unfortunately I don't know about the esp8266 architecture.

This post's comments feed

Add a comment

Comments can be formatted using a simple wiki syntax.

They posted on the same topic

Trackback URL : https://www.limpkin.fr/index.php?trackback/199