Tuesday, December 10, 2019

Arduino code on the ATtiny13

Optimization and minimalism are things I appreciate in technology.  Since the standard Arduino AVR core takes 1-2kB of flash memory, one might think that porting to a MCU with 1kB of flash and 64 bytes of RAM would be a futile effort.  However Hans [MCUDude] has managed to support most of the Arduino core API with MicroCore, while only using a tiny amount of flash and RAM.

Although you can't use Serial.print, digitalRead, digitalWrite, analogRead, and analogWrite are all implemented.  When the millis timer is not needed, it can be disabled to save space.  When it is used, it takes about 60 bytes of flash thanks to my AVR assembler implementation.  MicroCore also includes my optimized versions of shiftIn and shiftOut that are faster and smaller than the standard Arduino versions.

One thing that is missing from the MicroCore documentation is details on how small it is.  An empty sketch takes just 46 bytes of flash and no RAM.  A blink example using sleep and millis takes 154 bytes of flash and 5 bytes of RAM.  The buttons example for my TM1638 library takes 266 bytes of flash and 0 bytes of RAM.

While has MicroCore has a software SPI implementation (TinySPI), it doesn't have I2C/Wire.  I've been working on a bit-bang I2C library that is optimized for size and speed.  On a 9.6Mhz ATtiny13 it runs at 660kHz.  The next step before I release it is to make it as compatible as reasonably possible with the Arduino Wire library.

In addition to expanding the functionality of MicroCore, I'm hoping to simplify the use of millis so it is not linked in when it is not used.  This would avoid having to modify core_settings.h, or clutter up the IDE menus with an option to enable/disable millis.  I keep an eye on the github issues list for MicroCore, and will implement requested improvements that I find interesting.

Wednesday, July 18, 2018

Reading extended signature bytes with AVRdude


AVR MCUs like the ATtiny85 and the ATtiny13 store their signature and RC oscillator data in a special page of flash.  Just like the flash for program storage, this special page of flash can be erased and reprogrammed.  If you are not careful with your ICSP connections, it's not hard to accidentally erase this special page of flash.  I have 2 ATtiny13 chips that had their signature erased when I forgot to connect the power wire from a USBasp.  The voltage on the MOSI and SCK lines was enough to power up the ATtiny13, but without a stable Vcc, the serial programming instructions were scrambled in such a way that the chips interpreted them as an undocumented command to erase the signature page.

Official documentation for the signature table is rather terse, but forum and blog posts about this special page of flash date back for more than a decade.  Here is an example of the official documentation from the ATtiny85 datasheet:

The last row in the table has an error, since the page size of the t85 is 64 bytes, the signature table addresses go up to 0x3F, not 0x2A.  For devices like the ATtiny25 and ATtiny13 with a 32-byte page size, the signature table addresses only go up to 0x1F.  Most AVRs have the ability to read the signature table in software using the SPM instruction and the RSIG bit in SPMCSR.  The ATtiny13 does not not support reading the signature in software, so the only way to read it is through the serial programming interfaces.  I even tried setting the reserved bits in SPMCSR on the t13 in case reading the signature through software is an undocumented feature, but that did not work.

For most users, the ability to read the extended signature bytes is likely academic.  Since each chip seems to have slightly different data in the reserved signature area, it could be used for a sort of serial number to keep track of different chips.  The practical use for reading the signature page is when you can also reprogram it.  Since the default OSCCAL value is stored in the signature table, it would be possible to tune the frequency to a different default value.  One of my goals for reprogramming the signature page is to have a UART-friendly clock rate for debugWire.  Having the default OSCCAL value correspond to a clock speed close to 7372.8Mhz means debugWire will run at a baud rate of 7372.8/128 = 57.6 kbps.  It would also be possible to store other calibration data such as a more precise measurement of the internal voltage reference than what is specified in the datasheet.

While my ultimate goal is to create an AVR programmer that will read and write the signature table, a simple first step is to have AVRdude read the signature.  Fortunately, the programming sequences used by AVRdude are not hard-coded in the source.  The avrdude.conf file contains information on the command sequences to use for different protocols such as standard serial and high-voltage programming.  To get AVRdude to read 32 bytes of signature data instead of just 3, make the following changes to the ATtiny85 section of the avrdude.conf file:

  memory "signature"
     size    = 32;
     read    = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
               "x  x  x a4  a3 a2 a1 a0   o  o  o  o   o  o  o  o";

To read the 32 bytes of calibration data (which is just the odd bytes of the signature page), make the equivalent change for memory "calibration".

The next step in my plan is to write a program that tests undocumented serial programming instructions in order to discover the correct command for writing the signature page.  Since there are likely other secret serial programming instructions that do unknown things to the AVR, I could end up bricking a chip or two in the process.  If anyone already knows the program signature page opcode, please let me know.

Saturday, July 7, 2018

Sonoff S26: OK hardware, bad app

After I read about the Sonoff S26, and that it is compatible with Google home, I decided to order a couple of them.  In addition to using them as a remote-controlled power switch, I'm interested in resuming my experimentation with the esp8266 that the devices use.

The physical construction is OK, though, as can be seen from the photo above, the logo is upside-down.  I know there is some debate over which way a Nema 5-15R outlet should be oriented, with the ground down being more common in residential, and ground up perhaps being more common in commercial.  The readability of the logo does not effect functionality, so that's not a big deal.  What does effect functionality is the size of the S26, which can partially block the ability to use both outlets.

Cnx-software has a teardown of the S26, so I won't bother repeating any of the details.  The unit I received was virtually indistinguishable from the one depicted in the teardown.  The one slight difference I noticed was the esp8266 module in my S26 has a hot air solder leveling finish (HASL) instead of electroless nickel immersion gold (ENIG).

The eWeLink app is my biggest gripe about the s26.  In order to install the app, it requires numerous permissions that have nothing to do with controlling the s26.  Things like access to device location and contacts are an invasion of privacy, and a liability for itead if someone hacks their database and gets access to all the personal information from eWeLink users.  The only permission the app should need is local wifi network access.

After holding my nose over the permission requirements, it didn't get much better once the app was installed.  It does not work in landscape mode, and once you create an account, it doesn't remember the email when it gets you to log in to the newly created account.  The menus and some of the fonts are rather small, especially on an older phone with a 4" screen.

I also tested out the firmware update function in the app.  My s26 came with v1.6 firmware, which I updated to v1.8.  The new firmware version is supposed to support direct device control over the LAN without an active internet connection.  After the upgrade the device info indicated it was running the new firmware, but direct LAN control did not work.  Without an active internet connection, when I tried turning the s26 on, I got an "operation failed" message.

My last gripe is about the cumbersome process of setting up devices to work with Google home devices.  Having to first setup an account for the Sonoff devices, then having to link that account with the google home account is cumbersome and error-prone.  The google home app should be able to scan for devices the same way it can scan the local network and find a Chromecast.  And for people that are using Sonoff devices without Google home or Amazon, the app should allow users to control devices locally without having to set up any account.

Friday, July 6, 2018

Testing the IBM Cloud


Although I have a Google Cloud free account, I recently decided to try out IBM's Cloud Lite account.  I wasn't just interested in learning, I was also wondering if it could be a viable backup to my Google cloud account.  I'm not concerned with reliability, rather I'm concerned with dependability, since free services could be discontinued or otherwise shutdown.

The Cloud lite description says it includes, "256 MB of instantaneous Cloud Foundry runtime memory, plus 2 GB with Kubernetes Clusters".  I hadn't heard of Kubernetes before, but from a quick review of their web site, it appears to be a platform for deploying scalable docker images. For comparison, the Google compute platform which provides a Linux (Ubuntu 16.04 in my case) VM with 512MB of RAM and 30GB of disk.  I prefer the simplicity and familiarity of a Linux VM with full root access, but I thought there still should be a way to run a LAMP image with Kubernetes.

The IBM Cloud dashboard allows you to choose from the available services based on your account options.  Choosing the IBM Cloud Kubernetes Service from the dashboard links to another page to create a cluster.  However clicking on the create cluster button brings up a new page with the message: "Kubernetes clusters are not available with your current account type."  I opened up a support ticket about it, but after 10 days there has been no action on the ticket.

Since the Kubernetes wasn't working, I decided to try Cloud Foundry Apps.  In order to use cloud foundry, it is necessary to download their commandline tools.  With the Google cloud you get access to a development shell separate from your compute instance VM, and that shell has all the google cloud tools pre-installed.  This is one way the Google cloud is easier and simpler to use.

Instead of setting up a bare cloud foundry app, I decided to use their boilerplate Flask application.  The setup process in the web dashboard lets you choose a subdomain of mybluemix.net, so I chose http://rd-flask.mybluemix.net/.  In order to modify the app, IBM's docs instruct you to download the sample code, make changes locally, then push the changes to the could using their CLI tools.  However, at least in the case of the Python Flask app, there was no download instructions, and no link to the sample code.  After going through the CLI docs, I found it is possible to ssh into the vm instance for your app using "bluemix cf ssh". Yet any changes I made to the code online were wiped whenever I restarted the service.

After some more research, I realized this problem is several months old. In the end, I was able to find an earlier version of the template code, fork it, and updated it to match the code running in the app container. The repo I forked specified "python-2.7.11" in runtime.txt, but the cloud foundry only supports 2.7.12 & 2.7.13 (along 3.x). At first I changed it to 2.7.12 in my fork, but then I removed the runtime.txt so it will use the default version of python. I also added some brief instructions on uploading it to the IBM cloud. You'll find the fork at https://github.com/nerdralph/Flask-Demo.

Saturday, June 23, 2018

Using shiftIn with a 74165 shift register


The Arduino shiftIn function is written to be used with a CD4021.  The 74165 shift register is another inexpensive and widely available parallel-input shift register that works slightly different than the 4021.  The logic diagram of the 74HC165 is depicted in the figure above, and shows Qh is connected directly to the output of the 8th flip-flop.  This means that the state of Qh needs to be sampled before the first clock pulse.  With the 4021, the serial output is sampled after the rising edge of the clock.  This can also be determined by looking at the source for shiftIn, which sets the clock pin high before reading the serial data pin:
  for (i = 0; i < 8; i++)  {
    if (bitOrder == LSBFIRST)
      digitalWrite(dataPin, !!(val & (1 << i)));
    else  
      digitalWrite(dataPin, !!(val & (1 << (7 - i))));
      
    digitalWrite(clockPin, HIGH);
    digitalWrite(clockPin, LOW);    
  }

By setting the clock pin high, setting the latch (shift/load) pin high, and then calling shiftIn, the first call to digitalWrite(clockPin, HIGH) will have no effect, since it is already high.  Here's the example code:
  // set CLK high before shiftIn so it works with 74165
  digitalWrite(CLK, HIGH);
  digitalWrite(LATCH, HIGH);
  uint8_t input = shiftIn(DATA, CLK, MSBFIRST);
  digitalWrite(LATCH, LOW);

Like much of the Arduino core, the shiftIn function was not well written.  For a functionally equivalent but faster and smaller version, have a look at MicroCore.

Thursday, June 21, 2018

A second look at the TM1638 LED & key controller

A few weeks ago I released a small TM1638 library.  My goal was to make the library small and efficient, so I had started with existing libraries which I refactored and optimized.  While looking at the TM1638 datasheet, I thought other libraries might not be following the spec, but since they seemed to work, I followed the same basic framework.  My concern had to do with the clock being inverted from the clock generated by the Arduino shiftOut function.

Figure 8.1 from the datasheet shows the timing for data clocked from the MCU to the TM1638, which the TM1638 samples on the rising edge.  The clock for SPI devices, which shiftOut is intended to control, is low when idle, whereas the TM1638 clock is pulled high when idle with a 10K pull-up. For data that is sent from the TM1638 to the MCU, data is supposed to be sampled after the falling edge of the clock.  After doing some testing at high speed (>16Mhz) that revealed problems reading the buttons pressed, I decided to rewrite the library using open-drain communication, and trying to adhere to the TM1638 specs.

With open-drain communications, the MCU pin is switched to output low (0V) to signal a zero, and switched to input to signal a 1.  When the pin is in input mode, the pull-up resistor on the line brings it high.  The Arduino code to do this is the pinMode function, using OUTPUT to signal low, and INPUT to signal high.  The datasheet specifies a maximum clock rate of 1Mhz, but that appears to be more related to the signal rise time with a 10K pullup than a limit of the speed of it's internal shift registers.  For example I measured a rise time from 0V to 3V of 500ns with my scope:


To account for possibly slower rise times when using longer and therefore higher capacitance wires, before attempting to bring the clock line low, I read it first to ensure it is high.  If is not, the code waits until the line reads high.  As an aside, you may notice from the scope shot, the lines are rather noisy.  I experimented with changing the decoupling capacitors on the board, but it had little effect on the noise.  I also noticed a lot of ringing due to undershoot when the clock, data, or strobe lines are brought low:

I found that adding a series resistor of between 100 and 150 Ohms eliminates the ringing with minimal impact on the fall time.

The updated TM1638 library can be found in my nerdralph github repo:
https://github.com/nerdralph/nerdralph/tree/master/TM1638NR

Friday, June 15, 2018

Hacking LCD bias networks


Those of you who follow my blog know that I like to tinker with character LCD displays.  Until recently, that tinkering was focused on the software side.  What started me down the road to hacking the hardware was an attempt to reduce the power consumption of the displays.  The photo above shows the modified resistor network used to provide the bias voltages used by the LCD controller.  One end of the resistor ladder is connected to Vcc, and the other is connected to the bias/constrast pin (#3).  My modules came with 5 resistors of 2.2K Ohms each for a total of 11K.  Powered from 5V, the bias network will use about 450uA even when the LCD display is off.  When I changed the middle resistor in the ladder to 15K, the display stopped working, so I started investigating how the voltages are used to drive the LCD.

I remembered coming across an AVR application note on driving LCD displays, which helped explain some of the basic theory.  I also read a Cypress application note on driving LCD displays.  What I lacked was a full description of how the HD44780 drives the LCD, as the manual only describes the waveform for the common lines and not the segment lines.  From the application notes, I knew that the difference between the segment and common lines would be around the LCD threshold voltage.  The first information I found indicated a threshold voltage of over 2V, but modifying the bias resistors for a 2V threshold voltage resulted in a blank display.  Further investigation revealed the threshold voltage to be much lower, close to 1V.  Therefore the segment waveform looks something like the green line in the following diagram:

With the stock 2.2K resistor ladder, my modules gave the best contrast with 0.3-0.4V on the contrast pin.  With Vcc at about 5.05V, that means the difference between each step in the bias ladder was 0.94V.  To confirm the theory, I calculated the resistance values needed to maintain 1.2V between V2 and V3, and ~0.95V between the rest, for a total of 5V.  This means the middle resistor in the ladder needs to be 1.2/0.95 = 1.26 x the resistance of the rest.  Using some 7.5K 0805 resistors I have on hand meant I needed something around 9.5K for the middle resistor.  The next size up I have in chip resistors is 15K, which was too much, but I could re-use one of the original 2.2K resistors in series with a 7.5K to get a close-enough 9.7K.  After the mod, I plugged it into a breadboard, and it worked:

With additional hacking to the bias network, it should even be possible to get the modules to work at 3.3V.  That would require flipping V2 and V3, so that V3 > V2, and V3-V4 = ~1V.  And that likely requires removing the resistor ladder, and adding an external ladder with taps going back to the PCB pads on the LCD module.  That's a project for another day.