Mar 252017
 
STM32F4 Discovery and Espruino

Some time ago I installed Espruino on the STM32F4 Discovery board.

Here my notes:

sudo aptitude install cmake libusb-1.0-0-dev
git clone https://github.com/texane/stlink.git
cd stlink
cmake .
make
# install into /usr/local/
sudo make install
sudo ldconfig -v

How you should be able to see the STM32F4 Discovery board:

$ sudo st-info --probe 
Found 1 stlink programmers 
 serial: 563f6b06493f51521236213f 
openocd: "\x56\x3f\x6b\x06\x49\x3f\x51\x52\x12\x36\x21\x3f" 
  flash: 1048576 (pagesize: 16384) 
   sram: 196608 
 chipid: 0x0413 
  descr: F4 device

and now flash:

 
$ sudo st-flash write espruino_1v91_stm32f4discovery.bin 0x08000000                                
st-flash 1.3.1-11-g78ced6a 
2017-03-25T20:41:03 INFO src/common.c: Loading device parameters.... 
2017-03-25T20:41:03 INFO src/common.c: Device connected is: F4 device, id 0x10016413 
2017-03-25T20:41:03 INFO src/common.c: SRAM size: 0x30000 bytes (192 KiB), Flash: 0x100000 bytes (1024 KiB) in pages of 16
384 bytes 
2017-03-25T20:41:03 INFO src/common.c: Attempting to write 298872 (0x48f78) bytes to stm32 address: 134217728 (0x8000000) 
Flash page at addr: 0x08040000 erasedEraseFlash - Sector:0x6 Size:0x20000  
2017-03-25T20:41:09 INFO src/common.c: Finished erasing 7 pages of 131072 (0x20000) bytes 
2017-03-25T20:41:09 INFO src/common.c: Starting Flash write for F2/F4/L4 
2017-03-25T20:41:09 INFO src/flash_loader.c: Successfully loaded flash loader in sram 
enabling 32-bit flash writes 
size: 32768 
size: 32768 
size: 32768 
size: 32768 
size: 32768 
size: 32768 
size: 32768 
size: 32768 
size: 32768 
size: 3960 
2017-03-25T20:41:13 INFO src/common.c: Starting verification of write complete 
2017-03-25T20:41:16 INFO src/common.c: Flash written and verified! jolly good!

How you should be able to see the STM32F4 Discovery board:

And here a small program which reads out the accelerometer LIS302DL and the most upper LED will be lit up. Be aware that on newer F4 Discovery boards this model has changed to LIS3DSH, which is not compatibel.

function onInit() {
 SPI1.setup({sck: A5, miso:A6, mosi:A7});
 SPI1.send([0x20,0b01000111], E3);
}

var avrx=0.0, avry=0.0;
function getAcc() {
  var accx = SPI1.send([0xA9,0], E3)[1];
  var accy = SPI1.send([0xAB,0], E3)[1];
  if (accx>127) accx-=256;
  if (accy>127) accy-=256;
  avrx = 0.1*accx + 0.9*avrx;
  avry = 0.1*accy + 0.9*avry;
  digitalWrite(LED1, avrx > 32);
  digitalWrite(LED4, avrx < -32);
  digitalWrite(LED2, avry > 32);
  digitalWrite(LED3, avry < -32);
}
onInit();setInterval(getAcc, 10);

Mar 052017
 
Espruino, ESP8266 and the I2C OLED

Small Sunday afternoon project: Make the ESP8266 with Espruino work with the OLED display I have. NodeMCU has no issues. Time to try Espruino+JavaScript instead of NodeMCU+Lua.

Ingredients:

~/.local/bin/esptool.py --port /dev/ttyUSB0 --baud 115200 write_flash 
--flash_freq 80m --flash_mode qio --flash_size 32m \
 0x0000 "boot_v1.6.bin" \
0x1000 espruino_esp8266_user1.bin \
0x3FC000 esp_init_data_default.bin \
0x37E000 blank.bin
  • and then this little program will use it (if you have configured everything correctly and I2C works as it should):
I2C1.setup({sda: NodeMCU.D2, scl: NodeMCU.D1});

function start(){
 // write some text
 g.drawString("Hello World!",2,2);
 // write to the screen
 g.flip(); 
}

var g = require("SSD1306").connect(I2C1, start, {height:64});

 

Took me some tries to get it working and very helpful was the ability to scan the I2C bus:

function isDeviceOnBus(i2c,id) {
  try {
    return i2c.readFrom(id,1);
  }
  catch(err) {
    return -1;
  }
}

function detect(i2c,first, last) {
  first = first | 0;
  last = last | 0x77;
  var idsOnBus = Array();
  for (var id = first; id <= last; id++) {
    if ( isDeviceOnBus(i2c,id) != -1) {
      idsOnBus.push("0x"+id.toString(16));
    }
  }
  return idsOnBus;
}

I2C1.setup({sda: NodeMCU.D2, scl: NodeMCU.D1});
console.log('I2C detect as array:',detect(I2C1));

Note that I could not make the Wemos OLED work as its size (64×48) seems not supported. The 128×64 display I have worked out of the box. 128×32 is supposed to work too (see here).

 

Nov 062016
 

During today’s Dev Japan Meetup I finally had the time to do something I always wanted to do but never had time to implement: Create a fast link from an end-device (AKA browser or phone application) to my LED display. That display is a simple 10×10 WS2812 LEDs strip originally connected to an Arduino with a Bluetooth receiver, but replaced by a Wemos D1 mini flashed with Espruino since that has WiFi and more RAM.

Here the important (but incomplete) part of the Espruino program:

var host = "the_ws_server.co.jp";
var WebSocket = require("ws");
var ws = new WebSocket(host,{
  path: '/',
  port: 8080, // default is 80
  protocol : "echo-protocol", // websocket protocol name (default is none)
  protocolVersion: 13, // websocket protocol version, default is 13
  origin: 'Espruino',
  keepAlive: 60
});

ws.on('open', function() {
  console.log("Connected to server");
});

ws.on('message', function(msg) {
  console.log("MSG: " + msg);
  if (msg == "R") {
    colorize(40, 10, 10);
  } else if (msg == "G") {
    colorize(10, 40, 10);
  } else if (msg == "B") {
    colorize(10, 10, 40);
  }
  esp8266.neopixelWrite(NodeMCU.D4, leds);
});

The logic is as simple as it looks: connect to a WS server and wait for incoming messages. If it’s “R”, or “G”, or “B”, then colorize the LED array.

Here a section of the browser part:

var ws = new WebSocket("ws://the_ws_server.co.jp:8080/");

ws.onopen = function(evt) {
  var conn_status = document.getElementById('conn_text');
  ws.send(JSON.stringify({"join":"led"}));
};

ws.onmessage = function(evt) {
  var newMessage = document.createElement('p');
  newMessage.textContent = "Server: " + evt.data;
  document.getElementById('messages_txt').appendChild(newMessage);
};

ws.onclose = function(evt) {
  alert ("Connection closed");
};

$(".color").click(function(evt) {
  console.log($(this).attr("val"));
  ws.send(JSON.stringify({"room":"led","msg":$(this).attr("val")}));
});

and the buttons look like

<button type="submit" class="color" val="R">Red</button>
<button type="submit" class="color" val="G">Green</button>
<button type="submit" class="color" val="B">Blue</button>

The one missing part is the websocket server in the middle which relays messages, which I took quite literally from here from the Espruino Websocket docs.

This is anything but clean code, and not yet a complete and instructive example application, but it’s the first step and a good proof-of-concept.

Next step is a web page to have a 10×10 grid of buttons which can be turned on/off by touching, and the corresponding commands are sent to the LED display.

Oct 302016
 

Previously I made LEDs on/off via Lua. The pin-order was 4, 3, 2, 1, 5, 0, 6, 7, 8 in NodeMCU: 6 red LEDs, and a RGB LED.

Using Espruino (specifically version 1.87), the order turns out to be: D2, D0, D4, D5, D14, D16?, D12, D13, D15. D1 seems to turn the WiFi LED on/off, which is a bit odd.

 

Update:

Espruino has a nice feature to convert NodeMCU pins into Espruino pins:

for (var i=1; i<11; ++i) { console.log(NodeMCU["D"+i])}
D5
D4
D0
D2
D14
D12
D13
D15
D3
D1

Or easier, just use NodeMCU.D1 for what was D1 in NodeMCU. It also helps to know that the Espruino numbers are simply the GPIO numbers of the ESP8266 (Espruino D5 = ESP8266 GPIO 14 = NodeMCU D1)

Oct 302016
 

Lua is neat, but learning Lua and JavaScript and NodeJS. Although Lua and especially NodeMCU is similar (not only in name) to NodeJS, it would be nicer to use only one language.

Here the recipe:

  1. Download espruino_1v87.tve_master_b3dc05b_esp8266.tgz
  2. Write flash (note: might use 80m and qio, but my old one does dio):
    ./esptool.py --port /dev/ttyUSB0 --baud 115200 write_flash --flash_freq 40m --flash_mode dio --flash_size 32m \
    0x0000 ~/Downloads/espruino_1v87.tve_master_b3dc05b_esp8266/boot_v1.6.bin \
    0x1000 ~/Downloads/espruino_1v87.tve_master_b3dc05b_esp8266/espruino_esp8266_user1.bin \
    0x3FC000 ~/Downloads/espruino_1v87.tve_master_b3dc05b_esp8266/esp_init_data_default.bin \
    0x37E000 ~/Downloads/espruino_1v87.tve_master_b3dc05b_esp8266/blank.bin
  3. Verify it:
    ./esptool.py --port /dev/ttyUSB0 --baud 115200 verify_flash \
    0x1000 ~/Downloads/espruino_1v87.tve_master_b3dc05b_esp8266/espruino_esp8266_user1.bin \
    0x3FC000 ~/Downloads/espruino_1v87.tve_master_b3dc05b_esp8266/esp_init_data_default.bin \
    0x37E000 ~/Downloads/espruino_1v87.tve_master_b3dc05b_esp8266/blank.bin
  4. Connect at 115200bps.
  5. Connect to your AP:
    var wifi = require("Wifi");
    wifi.connect("your_sid", {password:"your_password"}, function(err){
     console.log("connected? err=", err, "info=", wifi.getIP());
    });
    wifi.stopAP();
    wifi.save();
  6. In the Espruino IDE add the IP address
  7. When you reconnect via Espruino IDE, you should now have 2 choices: serial or TCP/IP via WLAN

 

Oct 162016
 
Node-RED: Functions

My light sensor (actually just a LDR connected to the single ADC pin on the ESP8266) tends to be a bit jumpy and the graphs looked anything but smooth. Quick fix: averaging samples. Node-RED has functions for this. And here is one to average 4 samples:

// jshint esversion: 6

const oldDataMax=4;
let lastData;
let count = context.get('count')||0;
let oldData = context.get('oldData')||[];

// Need to shift all numbers one left if array full
// Circular buffer would be nice, but overly complex for such small buffers

if (count==oldDataMax) {
 for (let i=1; i<oldDataMax; ++i) {
 oldData[i-1]=oldData[i];
 }
 lastData=oldDataMax-1;
} else {
 lastData=count++; 
}
oldData[lastData]=parseInt(msg.payload);

// Calculate the average

let avg=0;
for (let i=0; i<=lastData; ++i) {
 avg+=oldData[i];
 }
avg=avg/(lastData+1);

context.set('count', count);
context.set('oldData', oldData);

let avgMsg = { payload: ""+avg };

return [ msg, avgMsg ];

Much less jumpy graphs now!

 

Aug 142016
 

When you have a microcontroller which can connect to the network and it has a RGB LED, the logical step is to make this LED controllable via a web browser.

The list of issues faced is numerous:

  • NodeMCU does not handle websockets natively
  • Thus a bridge between normal TCP sockets used by NodeMCU and WebSockets used by the web browser is needed: ws-tcp-bridge does that
  • ws-tcp-bridge defaults to binary blobs which the browser cannot handle. Switching the websocket’s binaryType to arraybuffer fixes this
  • Sending data too fast to a just created websocket which has its binaryType not yet changed to arraybuffer breaks ws-tcp-bridge with a fatal error:
    TypeError: “list” argument must be an Array of Buffers
  • NodeMCU uses Lua, the browser JavaScript. The langages are quite similar! See below for an example.

Code is at https://github.com/haraldkubota/rgbled-websocket

Interesting is the comparison of Lua and JavaScript variable names are the same):

JavaScript Lua
for (c of s.split('')) {

  if (c>='0' && c<='9') {
    if (state==1)
      value=10*value+c.charCodeAt()-48;

    } else {
      if (state==1) {
        setOneColor(color, value);
        state=0;
      }
      if (c=='R' || c=='G' || c=='B') {
        color=c;
        value=0;
        state=1;
      }
   }
}
for n=1,s:len(),1 do
   c=s:sub(n, n)
   if c>='0' and c<='9' then
     if state==1 then
       value=value*10+c:byte(1)-48
     end
   else
     if state==1 then
       setOneColor(color, value)
       state=0
     end
     if c=='R' or c=='G' or c=='B' then
       color=c
       value=0
       state=1
     end
   end
 end