Shallow Thoughts : : Nov
Akkana's Musings on Open Source Computing and Technology, Science, and Nature.
Wed, 29 Nov 2017
Having written a basic blink program in C for
my
ATtiny85 with a USBtinyISP (Part 1), I wanted to use it to control other
types of hardware. That meant I wanted to be able to use Arduino libraries.
The Arduino IDE
I normally use Makefiles, but the Arduino IDE is much better supported
so I tried that first. I followed the steps at
High-Low
Tech: Programming an ATtiny w/ Arduino 1.6 (or 1.0).
But the short summary is:
- Run the Arduino IDE
- File->Preferences
- In "Additional Boards Manager" near the bottom, paste this:
https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json
and click OK
- Tools->Boards->Board Manager...
- Find the ATTiny entry, click on it, and click Install
- Back in the main Arduino IDE, Tools->Boards should now havea
couple of Attiny entries. Choose the one that corresponds to your
ATTiny; then, under Processor, narrow it down further.
In
Tools->Programmer, choose the programmer you're using
(for example,
USBtinyISP).
Now you should be able to Verify and Upload a blink sketch
just like you would to a regular Arduino, subject to the pin limitations
of the ATTiny.
That worked for blink. But it didn't work when I started adding libraries.
Since the command-line was what I really cared about, I moved on rather
than worrying about libraries just yet.
ATtiny with Arduino-Makefile
For most of my Arduino development I use an excellent package called
Arduino-Makefile.
There's a Debian package called arduino-mk that works fine for normal
Arduinos, but for ATtiny, there have been changes, so use the version
from git.
A minimal blink Makefile looks like this:
BOARD_TAG = uno
include /usr/share/arduino/Arduino.mk
It assumes that if you're in a directory called blink, it
should compile a file called blink.ino. It will also build
any additional .cpp files it finds there. make upload
uploads the code to a normal Arduino.
With Attiny it gets quite a bit more complicated.
The key is that you have to specify an alternate core:
ALTERNATE_CORE = ATTinyCore
But there are lots of different ATtiny cores, they're all different,
and they each need a different set of specifiers like BOARD_TAG in
the Makefile. Arduino-Makefile comes with an example, but it isn't
very useful since it doesn't say where to get the cores that correspond
with the various samples. I ended up filing a documentation bug and
exchanging some back-and-forth with the maintainer of the package,
Simon John, and here's what I learned.
First: as I mentioned earlier, you should use the latest git version
of Arduino-Makefile. The version in Debian is a little older and some
things have changed; while the older version can be made to work with
ATtiny, the recipes will be different from the ones here.
Second, the recipes for each core will be different depending on which
version of the Arduino software you're using. Simon
says he sticks to version 1.0.5 when he uses ATtinys, because newer
versions don't work as well. That may be smart (certainly he has a lot
more experience than I do), but I'm always hesitant to rely on
software that old, so I wanted to get things working with the latest
Arduino, 1.8.5, if i could, so that's what the recipes here will
reflect.
Third, as mentioned in Part 1, clock rate should be 1MHz, not 8MHz
as you'll see in a lot of web examples, so:
F_CPU = 1000000L
Fourth, uploading sketches. As mentioned in the last article, I'm using
a USBtinyISP. For that, I use ISP_PROG = usbtiny
and
sketches are uploaded by typing make ispload
rather than
the usual make upload
. change that if you're usinga
different programmer.
With those preliminaries over:
I ended up getting two different cores working,
and there were two that didn't work.
Install the cores in subdirectories in
your ~/sketchbook/hardware directory. You can have multiple
cores installed at once if you want to test different cores.
Here are the recipes.
CodingBadly's arduino-tiny
This is the core that Simon says he prefers, so it's the one I'm going
to use as my default. It's at
https://github.com/Coding-Badly/arduino-tiny.git,
and also a version on Google Code. (Neither one has been updated since 2013.)
git clone
it into your sketchbook/hardware.
Then either cp 'Prospective Boards.txt' boards.txt
or create a new boards.txt and copy from 'Prospective Boards.txt'
all the boards you're interested in (for instance, all the attiny85
definitions if attiny85 is the only attiny board you have).
Then your Makefile should look something like this:
ARDUINO_DIR = /path/to/arduino-1.8.5
BOARD_TAG = attiny85at8
ALTERNATE_CORE = tiny
F_CPU = 1000000L
ISP_PROG = usbtiny
include /path/to/Arduino-Makefile/Arduino.mk
If your Arduino software is installed in /usr/share/arduino you can
omit the first line.
Now copy blink.ino -- of course, you'll have to change pin 13
to be something between 1 and 6 since that's how many pins an ATtiny
has -- and try make
and make ispload
.
SpenceKonde's ATTinyCore
This core is at https://github.com/SpenceKonde/ATTinyCore.git.
I didn't need to copy boards.txt or make any other changes,
just clone it under sketches/hardware and then use this Makefile:
ARDUINO_DIR = /path/to/arduino-1.8.5
ALTERNATE_CORE = ATTinyCore
BOARD_TAG = attinyx5
BOARD_SUB = 85
F_CPU = 1000000L
ISP_PROG = usbtiny
include /path/to/Arduino-Makefile/Arduino.mk
Non-working Cores
There are plenty of other ATtiny cores around. Here are two that
apparently worked once, but I couldn't get them working with the
current version of the tools. I'll omit links to them to try to
reduce the probability of search engines linking to them rather
than to the more up-to-date cores.
Damellis's attiny (you may see this referred to as HLT after the
domain name, "Highlowtech"), on GitHub as
damellis/attiny,
was the first core I got working with Debian's older version of
arduino-mk and Arduino 1.8.4. But when I upgraded to the latest
Arduino-Makefile and Arduino 1.8.5, it no longer worked. Ironic since
an older version of it was the one used in most of the tutorials I
found for using ATtiny with the Arduino IDE.
Simon says this core is buggy: in particular, there are problems with
software PWM.
I also tried rexxar-tc's arduino-tiny.core2 (also on GitHub).
I couldn't get it to work with any of the Makefile or Arduino
versions I tried, though it may have worked with Arduino 1.0.
With two working cores, I can get an LED to blink.
But libraries are the point of using the Arduino framework ...
and as I tried to move beyond blink.ino, I found that
not all Arduino libraries work with ATtiny.
In particular, Wire, used for protocols like I2C to talk to all
kinds of useful chips, doesn't work without substantial revisions.
But that's a whole separate topic. Stay tuned.
Tags: hardware, arduino, programming
[
19:06 Nov 29, 2017
More hardware |
permalink to this entry |
]
Sun, 26 Nov 2017
I wrote earlier about how to use an
IR
remote on Raspbian Jessie.
It turns out several things have changed under Raspbian Stretch.
Update, August 2019:
Apparently these updated instructions don't work any more either.
What apparently works now:
In /boot/config.txt, add:
dtoverlay=gpio-ir,gpio_pin=18
In /etc/lirc/lirc_options.conf, add:
driver=default
device = /dev/lirc0
/etc/modules and /etc/lirc/hardware.conf/
don't need to be changed. Thanks to Sublim21 on #raspberrypi for the tip.
Here's the older procedure and discussion.
Here's the abbreviated procedure for Stretch:
Install LIRC
$ sudo apt-get install lirc
Enable the LIRC Overlay
Eedit /boot/config.txt as root, look for
this line and uncomment it:
# Uncomment this to enable the lirc-rpi module
dtoverlay=lirc-rpi
Or if you prefer to use a pin other than 18,
change the pin assignment like this:
# Uncomment this to enable the lirc-rpi module
dtoverlay=lirc-rpi,gpio_in_pin=25,gpio_out_pin=17
See /boot/overlays/README for more information on overlays.
Fix the LIRC Options
Edit /etc/lirc/lirc_options.conf,
comment out the existing driver and device lines,
and add:
driver = default
device = /dev/lirc0
Reboot and stop the daemon
Reboot the Pi.
Now a bunch of LIRC daemons will be running. You don't want them
while you're configuring, and if you're eventually going to be
reading button presses from Python, you don't want them at all.
Disable them temporarily with
sudo systemctl stop lircd
which seems to be shorthand for
sudo systemctl stop lircd.socket
sudo systemctl stop lircd.service
Be sure to check with ps aux | grep lirc
to make sure you've
turned them off.
If you want to disable them permanently,
sudo systemctl disable lircd.socket lircd.service lircd-setup.service lircd-uinput.service lircmd.service
I got that list from:
systemctl list-unit-files | grep lirc
But you need them if you want to read from the
/var/run/lirc/lircd socket.
Use mode2 to verify it sees the buttons
With the daemons not running, a program called
mode2
can verify that your device's buttons are being seen at all.
I have no idea why it's named that, or what Mode 1 is.
mode2 -d /dev/lirc0
You should see lots of output. If you don't, double-check your wiring
and everything else you've done up to now.
Set up an lircd.conf
Here's where it gets difficult. On Jessie, you could run
irrecord -d /dev/lirc0 ~/lircd.conf
as described in my
earlier article.
However, that doesn't work on stretch. There's apparently a
bug in the
irrecord in stretch that makes it generate a file that doesn't work.
If you try it and it doesn't work, run
tail -f /var/log/messages | grep lirc
and you may see Info: Cannot configure the rc device for /dev/lirc0
and when you press buttons you'll see Notice: repeat code without
last_code received but you won't get any keys.
If you have a working lirc setup from a Jessie machine, try it first.
If it doesn't work, there's a script you can try that converts older
lirc conf files to a newer format. The safest way to try it is to
copy (with cp -a) the whole /etc/lirc directory to a local
directory and run:
/usr/share/lirc/lirc-old2new your-local-copy
Or if you feel brave, back up
/etc/lirc and run
sudo /usr/share/lirc/lirc-old2new with no arguments.
Either way, you should get an
lirc.conf that has a
chance of working with stretch.
If you don't have a working Jessie config, you're in trouble.
You might be able to edit the one from irrecord to make it work.
Here's the first part of my
working Jessie lircd.conf:
begin remote
name /home/pi/lircd.conf
bits 16
flags SPACE_ENC|CONST_LENGTH
eps 30
aeps 100
header 9117 4494
one 569 1703
zero 569 568
ptrail 575
repeat 9110 2225
pre_data_bits 16
pre_data 0xFD
gap 108337
toggle_bit_mask 0x0
begin codes
KEY_POWER 0x00FF
KEY_VOLUMEUP 0x807F
KEY_STOP 0x40BF
KEY_BACK 0x20DF
KEY_PLAYPAUSE 0xA05F
KEY_FORWARD 0x609F
KEY_DOWN 0x10EF
and here's the corresponding part of the nonworking one generated on Stretch:
begin remote
name DingMai
bits 32
flags SPACE_ENC|CONST_LENGTH
eps 30
aeps 100
header 9117 4494
one 569 1703
zero 569 568
ptrail 575
repeat 9110 2225
gap 108337
toggle_bit_mask 0x0
frequency 38000
begin codes
KEY_POWER 0x00FD00FF 0xBED8F1BC
KEY_VOLUMEUP 0x00FD807F 0xBED8F1BC
KEY_STOP 0x00FD40BF 0xBED8F1BC
KEY_BACK 0x00FD20DF 0xBED8F1BC
KEY_PLAYPAUSE 0x00FDA05F 0xBED8F1BC
KEY_FORWARD 0x00FD609F 0xBED8F1BC
KEY_DOWN 0x00FD10EF 0xBED8F1BC
It looks like setting bits to 16 and then using the second quartet
from each key might work. So try that if you're stuck.
Once you get irw working, you're home free. The Python modules
probably still won't do anything useful, but you can use my
pyirw.py
script as a model for a simple way to read keys from the lirc daemon.
In case you hit problems beyond what I saw, I found
this
discussion useful, which links to a complete
GitHub
gist of instructions for setting up lirc on Stretch.
Those instructions have a couple of extra steps involving module loading
that it turned out I didn't need, and on the other hand
it doesn't address the problems I saw with irrecord.
It looks like lirc configuration is a black art, not a science.
See what works for you. Good luck!
Tags: raspberry pi, linux, remote
[
12:00 Nov 26, 2017
More hardware |
permalink to this entry |
]
Thu, 02 Nov 2017
Arduinos are great for prototyping, but for a small, low-power,
cheap and simple design, an ATtiny chip seems like just the ticket.
For just a few dollars you can do most of what you could with an
Arduino and use a lot of the same code, as long as you can make do
with a little less memory and fewer pins.
I've been wanting to try them, and recently I ordered a few ATtiny85 chips.
There are quite a few ways to program them. You can buy programmers
specifically intended for an ATtiny, but I already had a USBtinyISP,
a chip used to program Arduino bootloaders, so that's what I'll
discuss here.
Wiring to the USBtinyISP
The best reference I found on wiring was
Using USBTinyISP to program ATTiny45 and ATTiny85.
That's pretty clear, but I made my own Fritzing diagram, with colors,
so it'll be easy to reconstruct it next time I need it.
The colors I used:
MISO
| yellow
| VCC | red
|
SCK
| white
| MOSI | green
|
RESET
| orange or red/black
| GND | black
|
Programming the ATtiny in C
I found a couple of blink examples at
electronut.in,
Getting Started with ATtiny AVR programming,
and in a Stack Exchange thread,
How
to program an AVR chip in Linux
Here's some basic blink code:
#include <avr/io.h>
#include <util/delay.h>
int main (void)
{
// Set Data Direction to output on port B, pins 2 and 3:
DDRB = 0b00001000;
while (1) {
// set PB3 high
PORTB = 0b00001000;
_delay_ms(500);
// set PB3 low
PORTB = 0b00000000;
_delay_ms(500);
}
return 1;
}
Then you need a Makefile. I started with the one linked from the electronut
page above. Modify it if you're using a programmer other than a USBtinyISP.
make
builds the program, and make install
loads it to the ATtiny. And, incredibly, my light started blinking,
the first time!
Encouraged, I added another LED to make sure I understood.
The ATtiny85 has six pins you can use (the other two are power and ground).
The pin numbers correspond to the bits in DDRB and PORTB:
my LED was on PB3. I added another LED on PB2 and made it alternate
with the first one:
DDRB = 0b00001100;
[ ... ]
// set PB3 high, PB2 low
PORTB = 0b00001000;
_delay_ms(500);
// set PB3 low, PB2 high
PORTB = 0b00000100;
_delay_ms(500);
Timing Woes
But wait -- not everything was rosy. I was calling _delay_ms(500)
,
but it was waiting a lot longer than half a second between flashes.
What was wrong?
For some reason, a lot of ATtiny sample code on the web assumes the
chip is running at 8MHz. The chip's internal oscillator is indeed 8MHz
(though you can also run it with an external crystal at various
speeds) -- but its default mode uses that oscillator in "divide by
eight" mode, meaning its actual clock rate is 1MHz. But Makefiles
you'll find on the web don't take that into account (maybe because
they're all copied from the same original source). So, for instance,
the Makefile I got from electronut has
CLOCK = 8000000
If I changed that to
CLOCK = 1000000
now my delays were proper milliseconds, as I'd specified.
Here's my working
attiny85
blink Makefile.
In case you're curious about clock rate, it's specified by what are
called fuses, which sound permanent but aren't: they hold their
values when the chip loses power, but you can set them over and over.
You can read the current fuse settings like this:
avrdude -c usbtiny -p attiny85 -U lfuse:r:-:i -v
which should print something like this:
avrdude: safemode: hfuse reads as DF
avrdude: safemode: efuse reads as FF
avrdude: safemode: Fuses OK (E:FF, H:DF, L:62)
To figure out what that means, go to the
Fuse calculator,
scroll down to Current settings and enter the three values
you got from avrdude (E, H and L correspond to Extended, High and Low).
Then scroll up to Feature configuration
to see what the fuse settings correspond to.
In my case it was
Int. RC Osc. 8 Mhz; Start-up time PWRDWN/RESET; 6CK/14CK+
64ms; [CKSEL=1011 SUT=10]; default value
and Divide clock by 8 internally; [CKDIV8=0]
was checked.
More on ports and pins
There's more info on ATtiny ports in
ATTiny
Port Manipulation (Part 1): PinMode() and DigitalWrite()
Nobody seems to have written much about AVR/ATTINY
programming in general. Symbols like PORTB and
functions like _delay_ms() come from files in
/usr/lib/avr/include/, at least on my Debian system.
There's not much there, so if you want library functions to handle
nontrivial hardware, you'll have to write them or find them somewhere else.
As for understanding pins, you're supposed to go to the datasheet and read it
through, all 234 pages. Hint: for understanding basics of reading from and
writing to ports, speed forward to section 10, I/O Ports.
A short excerpt from that section:
Three I/O memory address locations are allocated for each port, one
each for the Data Register - PORTx, Data Direction Register - DDRx,
and the Port Input Pins - PINx. The Port Input Pins I/O location is
read only, while the Data Register and the Data Direction Register are
read/write. However, writing a logic one to a bit in the PINx
Register, (comma sic) will result in a toggle in the
corresponding Data Register. In addition, the Pull-up Disable - PUD
bit in MCUCR disables the pull-up function for all pins in all ports
when set.
There's also some interesting information there about built-in pull-up
resistors and how to activate or deactivate them.
That's helpful, but here's the part I wish they'd said:
PORTB (along with DDRB and PINB) represents all six pins. (Why B? Is
there a PORTA? Not as far as I can tell; at least, no PORTA is
mentioned in the datasheet.) There are six output pins, corresponding
to the six pins on the chip that are not power or ground. Set the bits
in DDRB and PORTB to correspond to the pins you want to set. So if you
want to use pins 0 through 3 for output, do this:
DDRB = 0b00001111;
If you want to set logical pins 1 and 3 (corresponding to pins 6 and 2
on the chip) high, and the rest of the pins low, do this:
PORTB = 0b00001010;
To read from pins, use PINB.
In addition to basic functionality, all the pins have specialized
uses, like timers, SPI, ADC and even temperature measurement (see the
diagram above). The datasheet goes into more detail about how to get
into some of those specialized modes.
But a lot of those specialties are easier to deal with using
libraries. And there are a lot more libraries available for the Arduino
C++ environment than there are for a bare ATtiny using C.
So the next step is to program the ATtiny using Arduino ...
which deserves its own article.
Tags: hardware, arduino, programming
[
18:01 Nov 02, 2017
More hardware |
permalink to this entry |
]