• Minimalist Frame

    Muth08/27/2016 at 15:37 0 comments

    I'm still thinking about the different ways to make a clean and nice looking enclosure for the 4.4" display. Meanwhile I made a very simple aluminium frame, which is not so bad in my opinion.

    I have put some unconnected plated holes on the PCB is order to fix it to a future mount, then some small copper plates do the job fairly well:

    The frame is just an aluminium plate, it probably needs a bit more of polishing :

    With these 3 AAA batteries and a 2 minutes refresh period, it lasts around a week. Some code tweaking is probably still possible on the ESP8266 side, and I'm sure I can adjust the refresh rate according to the time of the day. (do I need a 2 minutes refresh rate at 03:00 am ?)

  • PCB soldering

    Muth08/19/2016 at 09:54 1 comment

    First of all, a big thank you to @oshpark. I heard plenty of good things about them, and for a first experience, I'm really satisfied ! The boards took exactly 20 day from the kicad file upload to my french mail box, and the quality is spotless. Very nice, keep this good work really !

    After ordering the board, I was a bit worried about a via a bit close to a track:

    But it went very well !

    I populated one board and stick it behind the LCD screen as I planned. That's why I put the components only in one side, even if as a counter part the board is larger.

    Next step is to make a nice frame/case and make two new instance !

  • Prototype to PCB

    Muth08/02/2016 at 23:23 0 comments

    The project prototype works reasonably well. The ESP wakes up every 5 mins to refresh the screen. It connects to the wifi hotspot, open a socket with the pilogger, refresh the screen and go to deep sleep. The hotspot connection process lasts around 5 seconds, event with fix IP. I should investigate to shorter that. However it stayed up for more than a week with a big 3200 mAh battery.

    The prototype schematics looks like :

    and the ugly wiring :

    I ordered a more compact board on OSHPark:

    https://oshpark.com/shared_projects/acNL1VCz

  • Simplify

    Muth08/02/2016 at 22:58 0 comments

    By looking at the tests I made, I have to make something simpler (indeed). Java uploading an image using FTP which is translated to hex by a PHP script, to be received on the ESP8266 and interpreted in LUA to be sent to the SPI screen...

    Sockets

    Why use the web server ? I should focus, I digress. It could be nice to have a LCD screen showing whatever an image from internet, but it's another project.

    From what I have, I could simplify by open a socket server on the Pilogger Java program and connect to it with the ESP to retrieve the image data.

    On java side I not used sockets often, but it is not so complicated.

    serverServer = new ServerSocket(9999);
    clientSocket = serverServer.accept();
    inputStream = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    outputStream = new PrintStream(clientSocket.getOutputStream());
    
    while (true) {
    	line = inputStream.readLine();
    	if (line.contains("LCD")) {
    		outputStream.write(capture());
    		break;
    	}
    }
    
    clientSocket.close();
    On port 9999, if I receive the string "LCD", I send the raw data for the LCD. it is even nicer as I could directly send the bytes needed by the LCD, in the correct format. All the processing is done in Java on the raspberry pi. What still to be done on the ESP is the socket connection, and the CS line logic. The LUA script is as short as :
    -- GPIO 2 is the CS line of the LCD SPI connection
    gpio.mode(2, gpio.OUTPUT)
    gpio.write(2, gpio.LOW)
    spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 50, spi.HALFDUPLEX)
    
    srv = net.createConnection(net.TCP, 0)
    
    srv:on("receive", function(sck, c) 
        spi.send(1, c)
    end)
    
    srv:on("connection", function(sck, c)
        print("socket connected")
        sck:send("LCD\n")
        gpio.write(2, gpio.HIGH)
    end)
    
    srv:on("disconnection", function(sck, c)
        gpio.write(2, gpio.LOW)
        print("socket disconnected")
        wifi.sta.disconnect()
    end)
    
    srv:connect(9999, "192.168.xxx.xxx")
    And it works really well, the screen is refreshed in about 100ms !

  • SPI and Sharp Memory LCD

    Muth08/02/2016 at 22:34 0 comments

    Memory LCD

    The 'memory' LCD from sharp are somehow fascinating. Their main advantage is the low power consumption, but they are one of the rare passive reflective monochrome LCD. They are nearly as readable on sun light as the eink displays. I first had this module http://www.ebay.com/itm/201596712057, where the board had to be fixed (the ground does not cross from one side to the other... Cheap products... ) I finally opt for the larger 4.4" 320x240 version (http://www.digikey.com/product-detail/en/sharp-microelectronics/LS044Q7DH01/425-2910-ND/5054070) .

    NodeMCU speaks SPI

    LUA SPI module is nice, it is possible to use the hardware SPI at high speed. But I did not found a way to invert the CS line logic neither to send little endian bytes as the screen require. I had to use a GPIO for the ChipSelect line and do some trick to invert the byte reading:

    gpio.mode(2, gpio.OUTPUT)
    gpio.write(2, gpio.LOW)
    spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 400, spi.HALFDUPLEX)
    
    function printLine(line_nb)
      gpio.write(2, gpio.HIGH)
      spi.send(1, 128)
      spi.send(1, bit_invert(line_nb+1))
      for i=0,39 do 
        spi.send(1, array[i])
      end
      spi.send(1, 0)
      spi.send(1, 0)
      gpio.write(2, gpio.LOW)
    end
    
    function clear()
      gpio.write(2, gpio.HIGH)
      spi.send(1, 32)
      spi.send(1, 0)
      gpio.write(2, gpio.LOW)
    end
    
    function bit_invert(byte)
      inv = 0
      if (bit.isset(byte, 0)) then inv = bit.set(inv, 7) end
      if (bit.isset(byte, 1)) then inv = bit.set(inv, 6) end
      if (bit.isset(byte, 2)) then inv = bit.set(inv, 5) end
      if (bit.isset(byte, 3)) then inv = bit.set(inv, 4) end
      if (bit.isset(byte, 4)) then inv = bit.set(inv, 3) end
      if (bit.isset(byte, 5)) then inv = bit.set(inv, 2) end
      if (bit.isset(byte, 6)) then inv = bit.set(inv, 1) end
      if (bit.isset(byte, 7)) then inv = bit.set(inv, 0) end
      return inv
    end
    Performances

    Putting things all together, it works. But it is slow. Very slow. But it is not surprising. I used several heavy functions such as string operation string.gmatch(c, "%S+") and array[index] = encoder.fromHex(i).

    Refreshing the entier screen takes approximately 30 seconds... Not really conceivable for a battery application. We have to simplify that!

  • Starting with the ESP8266

    Muth08/02/2016 at 21:54 0 comments

    This is a big question, where to start with the ESP8266. There is the official SDK path, for the brave. There is the Arduino, Espruino... Well, I tried NodeMCU. Starting with this page https://nodemcu.readthedocs.io/en/master/, there is a lot explained to start from scratch.

    First dialog

    Adafruit gave a nice schematic to wire the ESP8266 (https://learn.adafruit.com/assets/24745).

    You can build online a NodeMCU image : http://nodemcu-build.com/ . Everything is very detailed on the documentation page : https://nodemcu.readthedocs.io/en/master/en/build/

    Once the port com is connected, flashing with NodeMCU flasher is done in two clicks.

    And here we are, the ESPlorer IDE let you yet start your first LUA scripts.

    Wifi connection

    I was very impressed how easy it is to configure the ESP as wifi station and connect it to my home network.

    wifi.setmode(wifi.STATION)
    wifi.sta.config("my_ssid", "the_password", 0)
    Transfer an image

    The raspberry pi regularly send datasets to an online web server using FTP, a solution could be so send an image as well and retrieve it on the ESP from internet. But it is rather difficult to interpret an image file directly on the ESP. So a PHP script could convert an image file to raw data. I realize the online serve does not like sending real raw bytes, so I had to convert bytes in their hex ascii form.

    <?php
    $info = getimagesize("pilogger320x240.png");
    $im = imagecreatefrompng("pilogger320x240.png");
    $width = $info[0];
    $height = $info[1];
    
    echo " <br>data:<br> ";
    
    for ($h = 0; $h < $height; $h++){
    	$byte = 0;
    	for ($w = 0; $w < $width; $w++){
    		if (($w%8) == 0) $byte = 0;
    		$bit = 0;
    		if (imagecolorat($im, $w, $h) < 40) $bit = 1; 
    		$byte += ( pow(2, ( 7-($w%8) ) )*  $bit);
    		$s = str_pad(dechex($byte), 2, '0', STR_PAD_LEFT);
    		if (($w%8) == 7) echo $s . " ";
    	}
    	//echo "<br>";
    }
    ?>
    
    And this should output something such as :

    data:
    00 00 00 00 0f ff ff ff ff f7 bf ff ff ff 7f ff ff c3 ff ff ff ff ff ff ff 87 ff ff ff ff ff ff ff ff ff ff ff ff 01 ff ff ff ff ff ff ff ff ff ff eb bf ff ff ff 7f ff ff dd ff ff ff ff ff ff ff bb ff ff ff ff ff ff ff ff ff ff ff fe 01 ff ff ff ff ff ff ff ff ff ff eb 08 47 18 43 0e 31 63 dd 8c 61 0b a3 1f ff ff bb 8f ff ff ff ff ff ff ff ff ff ff fc 00 00 ff ff ff ff ff ff ff ff ff dd bb ba eb dd [...]
    Interpret the image data

    Now it is time to get these data on the ESP. In LUA there is a high level HTTP client to directly do GET over http. The problem is it is limited to 1400 bytes. At this point I was a bit frustrated, my image is monochrome 320x240 pixels, 9600 bytes.

    Fortunately, NodeMCU expose direct socket TCP connection utilities. We can then get our data directly TCP, port 80, GET : (see nodemcu documentation example https://nodemcu.readthedocs.io/en/master/en/modules/net/#netsocketon )

    srv = net.createConnection(net.TCP, 0)
    
    srv:on("receive", function(sck, c) 
        print(c)
    end)
    
    srv:on("connection", function(sck, c)
      -- Wait for connection before sending.
      sck:send("GET /pilogger/getPNG.php HTTP/1.1\r\nHost: muth.inc.free.fr\r\nConnection: keep-alive\r\nAccept: */*\r\n\r\n")
    end)
    
    srv:connect(80,"muth.inc.free.fr")

    At this point the ESP receive all the data by blocks of ~1400 bytes ! We can reconstruct the bytes array from the hex chars with the 'encoder' LUA module :

    for i in string.gmatch(c, "%S+") do
            array[index] = encoder.fromHex(i)
            print(array[index])
            index = index +1
    end    
    Now let's connect a LCD screen to see these data.