sebastians site
Adventures in Open Source Hard and Software

RingLock for AVR - 18.10.2011

How it started

After reading about PIClock4 a inter-microcontroller mutex on dangerousprototypes.com, I got curious about the actual implementation. It uses shift registers to pass a token in form of just a single bit around. Once the token arrives at a mcu that needs access to the resource, the mcu can stop the shifting. After having done whatever it needs the resource for, it can start the shifting again. Unfortunately the schematic files were down, so I had to ask for them. The marker of piclock told me that his project was just for fun and never intended for actual usage. Because of the huge amount of logic chips needed he suggested rather using a arduino/atmega328 to emulate the hardware in software. That's what got me thinking initially. Using a 32k flash mcu to emulate 9 logic ics, sounded terribly wasteful to me.

First idea: I could use a Attiny instead.

Advantages: I would not waste that much flash space.

Disadvantage: Attinys have only few IO-pins and therefore the amount of mcus that can be attached to the lock is limited.

So I was looking for a solution that allows a huge number of mcus, while needing no/not much additional hardware. At some point I got reminded of token ring networks, something I've never seen myself, because it's a rather old technique and at least for computer networks totally replaced by Ethernet. It's basic ideas is that the hosts pass a token from one to the next in a ring like topology. Once a host gets a token he is allowed to attach data to it while passing it on. This is very similar to the bit that gets shifted around in the piclock system, but it does not require a central piece of hardware controlling the whole process. That sounded just like the thing I wanted.

After googling for a while I found a few implementations for token passing on microcontrollers, but the majority of them were integrated in other projects and designed for a single usage scenario. At that point I started experimenting with an own implementation. It had easily configurable for different AVR mcus and applicable to various scenarios where multiple mcus access the same resource.

It's important to notice that I don't claim this to be a full featured library. Let's be honest, there not even enough lines of code to call this a program. I rather wanted to present the idea behind it, as well as providing a little reference implementation. So just think of this as a request for comments.

How it works

The basic idea is to implement a decentralized token passing mechanism, allowing multiple mcus to share access to a resource like external memory, a sensor or a communication interface of some kind. Each mcu has one of its IO Pins connected to the external interrupt pin e.g. INT0 of the next mcu. The last mcu in this chain has one of its IOs connected to the interrupt pin of the first one. This results in a ring topology as shown below.

Rough idea for the ringlock system

When everything is powered up somebody has to have the token and the access initially. I called this special mcu master. It does whatever it needs to do with the resource and then pulls his IO-pin (called PYX in the drawing) high for 1us. Slave 1 will get interrupted because of the rising signal at his INT0. In his ISR he will check whether the rest of his program has requested access to the resource. This is done by simply checking a flag. If the flag is not set it will pass the token to slave 2 immediately in his ISR. Otherwise it will set a flag, signalling the program that it can now access the resource and leave the ISR. It's now up to the program to work with the shared resource for a while and to pass on the token. The next mcus will do exactly the same thing and the token will circulate in the ring infinitely.

At least theory. In praxis you'll sooner or later lose the token, simply because of murphys law. Imagine a mcu crashes, there is a power failure or a bad connection. Having lost the token, the system will get stuck since no one is allowed to access the shared resource. Every mcu waits for the token, that will never arrive. That's the point where a timeout might come handy. Using a timer of the master mcu it's easy to implement one. The timer gets reset every time the master gets the token back from the last mcu in the ring. If the token doesn't arrive in time, the master assumes that it was lost and pretends to have the token. The new token will be passed on and everything is hopefully working again. Still there is one pitfall in this approach, the timeout has to be chosen carefully. If the master sends a new token while another is still on the ring, to mcu will try to work with the resource, which is in fact the situation we are trying to avoid using lock. The best idea is to use a timeout that is at least 1,5 times as long, as the longest time a token need back to the master.

How to use it

There are two ways of getting the source code :

  1. Get the tarball here
  2. Clone the git repository: git clone https://github.com/LongHairedHacker/avr-ringlock

Once you got the source, you'll want to adjust the configuration in include/ringlock.h. The config is documented there and changing it should be pretty straight forward.

Using the makefile is a bit more complex then the usual make all. There are some variables that need to be set :

So if you want to build a slave for an Atmega8 with 8MHz call make ROLE=slave AVRMCU=atmega8 F_CPU=8000000 all. Currently the source only supports Atmega32 as master or slave and Atmega8 as slave. This can be changed by extending the configs in include/ringlock.h. Once you have added a new mcu, it would be nice to send me patch so I can add it to the source.

Using the ringlock in your source code is simple, it boils down to 4 functions :

Example

Since this was a solution to which I didn't have a Problem I made one up: One ATmega32 (Master) and one Atmega8 (Slave) share the TXD line of a RS232 connection. I used the OpenBench LogicSniffer to measure the signals.

Schematic of the test setup for the ringlock system

The and gate was in a HCF4081. If you set the TXD of the passive mcu to high-Z you won't need it, but I wanted the unmixed signals as well. The program used in this test is bundled with the sourcecode as main.c.

Here are all the signals in the jawis OLS client:

Signal traces in the OLS client

and a photo of my setup :

Actual hardware test-setup

So that's all so far.

Have fun with this stuff and please don't waste an entire Atmega32 on locks.

Published: 18.10.2011 20:36

AVR library for lc7981 - 12.04.2010

The information on this page is only for the DataVision DG-16080-11 lcd. It may apply to your lcd as well, but this also may not be the case. Be sure your read this page completely. It contains information about setting up the hardware which are not covered in the sourcecode documentation.

Idea

After discovering a quite cheap touchscreen lcd on the Roboternetz website I decided that such a display might be a useful addition to some of my projects. Therefore I bought some of them and started to write a C-library to use them with an ATmega32.

All the other librarys available missed some of the features I needed or they had some inefficient code.

Result

it has touch

it really has touch

The result was a small and quite flexible library for the lc7981-chip which is used by this display.

Features

I can hear you say now : 'That's just like any other library out there. So where's the point in using yours ?'

The lc7981 has to ways of setting Pixels. The first is using it's set pixel command. The advantage of plotting a bitmap with this command is that you get a simple short sourcecode, and it is easy to place a bitmap anywhere you like on the screen. A big disadvantage of doing it this way is that you'll need to transfer 2byte per pixel. Plotting a 10x10px bitmap will result in 200 bytes of data being send. The other approach is to transfer a byte directly into the display memory. One byte represents 8 pixel of a display row. Using this approach, transferring the 10x10 bitmap will require 4 bytes per row, which results in 40 bytes in total. The major disadvantage is that it is difficult to place a bitmap on an X-coordinate that isn't a multiple of 8. My library uses the second approach in combination with some tricky bit shift operations to be able to plot a bitmap fast and at every X-ccordinate. It needs some more computing time, but I thinks it's a good trade-off.

Wiring stuff up

My primary aim was the use the DataVision DG-16080-11 lcd, therefore I'll provide some info how I wired it up here. Using a plain lc7981 with some other lcd would be beyond the scope of this document. See the datasheet here for the display pinout. Connect each one of RS, RW and EN to a free pin of your controller. You'll have to specify the pins used in the lc7981.h. RES (Reset) has to be high and CS has to be low, so they have to be connected to Vcc and Gnd. The DB0-DB7 pins must be connect to one port of the AVR. Like for example PortB. Connect DB0 to PB0, DB1 to PB1 and so on. The Display supply voltage (pin 3) has to be connected to pin 17 and Gnd using a potentiometer. The potentiometer will be used to adjust the contrast.

License

The Versions below 0.6 beta were released under GPL. All newer versions including 0.6 and above are/will be realeased under MPL. I won't support the old GPLed versions anymore.

You may ask yourself why I changed my license. The answer is rather simple: I used GPL since it wanted my library to profit from bugs that get fixed and features that get written by other people who use it.

What I did not think about was the following scenario : Somebody uses my lib in an automated garden irrigation for his carrots. He does not change anything or adds any feature. He just uses my work, but he has to publish his source under GPL. I don't see any advantages in that. (Not that I don't like gardening or carrots, but I can't see a relation to my work here.) So I cause additional work for this poor guy and take away his freedom to chose an own license without any advantages for me, my work or him and his work. This is simply not what I intended to do in the first place

Okay, you might complain that I could have used LGPL instead of MPL. But it's terms are rather unclear to me and the rule of thumb with dynamic and static linking stuff is ridiculous when you use a mircocontroller where you have to use static linking. Therefore I use MPL so I still can profit from changes made to my code, but other can use it how they want as long as they don't change it.

Downloads

All the files can be obtained here : https://github.com/LongHairedHacker/avr-lc7981/

If you need the (not supported and not maintained) GPL Version or the latest development version use git to clone the repo and go back. I would not recommend using the GPL version, it has some ugly bugs.

If you have any questions feel free to ask using my mail adress, that can be found in the source code.

Have fun with your display!

Comments

Edmundo: (29.8.2011 9:44:48)

Thanks, I´m professor in the "INSTITUO POLITECNICO > NACIONAL" at MEXICO, just all the info my students needs to start. Very grateful.

Good information , very complete. Thanks again

Jesus Palomo: (11.9.2011 2:15:54)

Hi, I am student in the "Instituto Tecnologico de Toluca" at Mexico, you program and library very well, I compile in AVR Studio and worked well, Thanks for you info and post...Greetings from México

Published: 12.04.2010 16:47