Архив на категория: Хардуер

Принтер/скенер/копир Dell 1815dn и Линукс

Наскоро се сдобих с въпросното устройство – принтер, скенер и копир Dell 1815dn. Добра машинка, намираща се на прилична цена от доставчиците на употребявана техника.

За да заработи под Линукс принтера (в моя случай Убунту 12.04), сваляте архив с драйвери от тук. Единственият файл, който ви интересува в този архив, е cdroot/Linux/noarch/at_opt/share/ppd/mfp1815ps.ppd. Трябва да го посочите при добавянето на нов принтер, след като автоматичното търсене на драйвер се окаже неуспешно.

За сканиране по мрежата, решението е тук. Работи без никакви проблеми.

linux boards

Linux GPIO programmer for AVRDUDE

Hello!

Here you’ll find a tutorial and example of how to connect an AVR microcontroller to the GPIO pins of an embedded Linux system and use avrdude with the linuxgpio programmer type to program it.

Embedded Linux systems are small computers running Linux. Usually they will have quite a bit of available GPIO (General purpose input output) pins which you can toggle between 1/0 using /sys/class/gpio interface provided by the Linux kernel. Although small Linux computers are very capable, frequently they work in cooperation with even smaller computers like the 8 bit AVR microcontrollers. That can be quite handy if you need to handle some hard realtime task for example.

Traditionally to upload new firmware to these little helpers you would use a bootloader and connect them to a spare UART for example. This presents a chicken and egg problem of programming the bootloader in the first place. Also you may want to use every bit of flash available on the micro and not spare any for a bootloader, or not have a spare UART and so on. That’s where the linuxgpio programmer described here come into play. You can connect the AVR ISP programming interface to any four spare GPIO pins (usually there are plenty) of your Linux board and program it using avrdude. This can also be of interest to you if you already have an embedded Linux board (like the popular RaspberryPi, OlinuXino and the like) and want to get started programming AVRs, but don’t have a dedicated ISP programmer.

This solution have existed as a patch for avrdude 5.10 for more than two years. Luckily embedded Linux systems got much more popular now and Richard Nauber ported the patches to the current SVN version (a task I’ve been meaning to do for quite a while). This prompted me to bring the patch up to standard and with the help and feedback of the awesome people on the avrdude-dev mailing list it’s included in the official avrdude SVN. No more patches, yay! Until a new version of avrdude is released and finds its way into distributions here’s a quick description how to build and use it yourself. I’m assuming you’re doing this on a Linux system with a complete C development environment – gcc, autotools, etc. If you get some errors try to figure out which package is missing and install it using your distributions package manager.

First, checkout a fresh copy of avrdude SVN trunk:

$svn co svn://svn.savannah.nongnu.org/avrdude/trunk

Bootstrap autotools:

$cd trunk/avrdude
$ ./bootstrap

The linuxgpio programmer is not enabled by default, because it’s usually only useful for embedded Linux systems. You have to pass an additional option to configure to enable it:

$./configure --enable-linuxgpio=yes

If you’re doing a cross-compile as opposed to a native build you may want to pass some additional options like:

$./configure --host=arm-angstrom-linux-gnueabi --enable-linuxgpio=yes

Finally:

$make

If all went well you should have the avrdude executable and avrdude.conf files in the current directory. If you want to do things the proper way you can try to prepare a package for your favourite distribution (in which case you may find it easier to sart from an available source package). I won’t bother with this for now and just copy the two files mentioned above to my board using scp.

Now, time for some hard(ware) work! You need to connect your Linux system’s GPIO pins to the AVR and also supply power to it. It’s recommended that you take some measures to keep the magic smoke in. Make sure both systems use the same or compatible voltage levels i.e. 3.3V vs 5V. It’s also a good idea to put some resistors in series to limit the maximum current. A more robust approach would be to put a 3-state buffer in between, you can find a description of such a setup here.

For my tests I made a simple straight trough cable connecting the 4 GPIO pins, 3.3V power and GND from a RaspberryPi to the ISP connector of a Freeduino board, equipped with an Atmega168. Note that this make the Atmega168 work a bit out of spec, because at 3.3V its max frequency is 12MHz and not 16MHz but it worked fine for me. Also note the Freeduino is not connected or powered by anything else, as it normally runs on 5V, only 3.3V is being supplied through the ISP connector. It happened so that I used the pins for the hardware SPI interface of the RPi, but this need not be so, they were just the most convenient to wire with 3.3v and GND on the sides.

The picture in the beginning shows my test setup with the Freeduino connected to the RaspberryPi. Next to it, showing some other Linux boards which can be used instead – OlinuXino maxi and a Bifferboard (where it all started).

Jump to your Linux board, wherever you copied avrdude and avrdude.conf and open the latter with a text editor. By default the entry of the linuxgpio programmer is commented out, because there is no way to know how you wired things up in your setup. Uncomment it and replace the question marks with the GPIO pins to match your wiring scheme. Note that in the first version of this patch the GPIO numbers were off by one (i.e. you had to put 13 in the config file if you meant GPIO 12). This has been fixed, so now you need to put the correct number. In my case:

programmer
id = "linuxgpio";
desc = "Use the Linux sysfs interface to bitbang GPIO lines";
type = "linuxgpio";
reset = 22;
sck = 10;
mosi = 11;
miso = 9;
;

The moment of truth:

root@raspberrypi:/tmp# ./avrdude -C avrdude.conf -c linuxgpio -p m168 -U flash:w:blink.hex

If you’re lucky you should see something like this:

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e9406
avrdude: NOTE: „flash“ memory has been specified, an erase cycle will be performed
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file „blink.hex“
avrdude: input file blink.hex auto detected as Intel Hex
avrdude: writing flash (3526 bytes):

Writing | ################################################## | 100% 1.77s

avrdude: 3526 bytes of flash written
avrdude: verifying flash memory against blink.hex:
avrdude: load data flash data from input file blink.hex:
avrdude: input file blink.hex auto detected as Intel Hex
avrdude: input file blink.hex contains 3526 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 1.97s

avrdude: verifying …
avrdude: 3526 bytes of flash verified

avrdude: safemode: Fuses OK

avrdude done. Thank you.

root@raspberrypi:/tmp#

Enjoy!

Прекомпилиране на Ардуино bootloader

В тази статия се описва как да се заобиколи проблем при прекомпилиране на bootloader-а на Ардуино при използване на gcc версии 4.х. Също така има кратко описание какво е bootloader и защо бихте искали да го промените и компилирате наново. Ако желаете превод на български, моля оставете коментар.

Some time ago I needed to recompile the Arduino bootloader for the ATmega8 MCU. Unfortunately I run into one problem – the generated executable code was too big. I write this to share the workaround I’ve found. If you don’t know what I’m talking about, but are curious to learn scroll down for a quick explanation.

Basically when trying to compile the bootloader it doesn’t fit in the 1KB designated space. The error spewed out is something like:

address 0x203e of ATmegaBOOT.elf section .text is not within region text.

The problem turns out to be a bug in more recent versions of avr-gcc. The binary in the Arduino distribution was compiled using the 3.x branch which isn’t affected and I was using a newer 4.x version. One way to handle this would be to install the complete 3.x toolchain but that doesn’t look like much fun.

Reading the bug description more closely showed that the problem is inlining functions more that once even though the -Os option is passed to the compiler to optimize for minimum size. Curiously for some other architectures even inlining a function twice can be smaller that not inlining, but for the AVR this is not the case. So until the gcc gurus figure out how to get this problem solved properly I have found a temporary workaround. At least with the Arduino bootloader adding -finline-limit=1 to the gcc parameters seems to do the trick. The code is again less that 1KB and happily fits in the bootloader section.

So, what the hell is a bootloader and why would I want to recompile it? I’m glad you asked :)!

The ATmega8 is a small computer – everything needed on a single chip. To make it useful, as with any computer, we need to put some program in it. More precisely on the internal flash memory. One way to do this would be using a special cable or adapter called a programmer. If we don’t have such cable or we want the user of the device to be able to change the software in the field there is another way. We can use any of the built-in peripherals to get the program, the most popular choice being the USART module aka ‘the serial port’. But there’s one catch – in order to do this we need to write a very small program that reads the data from our peripheral of choice and writes it to the flash memory. This small program is called a bootloader. When I say small in the case above this meant less than 1KB of the total 8KB of flash in the ATmega8.

If you have acquired an Arduino or Arduino like board it most probably already has the bootloader programmed into the chip. Thanks to its help you can just plug in the USB cable in your PC, and have your sketch uploaded to the board. The USB cable actually connects to a USB/UART converter chip, or more precisely the FT232RL, so from the viewpoint of the ATmega we are talking through a serial connection. One of the very important parameters of a serial link is its speed usually measured in bits/second. When we configure the serial link speed in the AtMega MCU we use the frequency of the CPU, or the CPU clock as a base, Usually this clock signal is run through a divider, so the „UART clock“ (i.e. the UART speed) is set as a fraction of the CPU clock. So if we change the CPU clock, but want to keep the same speed, we need to change the divider used. Since this divider is specified in the bootloader source code a recompile of the bootloader is needed.

By default the Arduino has a 16MHz external crystal (the shiny metal box that has written 16.000 on top) and that’s the frequency it runs at. In my case I wanted to run it at 4MHz or even at 1MHz instead. Why would anyone want to do this? Why run a CPU that is perfectly capable of running at 16MHz at only 1? The reason is power consumption. The lower the frequency the lower the voltage supply that is required. And the lower the voltage – the lower the power. For example certain parts of the ATMega family that have a V suffix, like the ATmega88V can work from as low as 1.8V if the CPU frequency is kept under 4MHz.

When a device is going to be battery powered it is important to make the batteries last as long as possible. One thing that helps to accomplish this goal is to run the CPU at the lowest frequency that satisfies the application’s need for computing power. Taken to the extreme this means 0Hz, or completely stopping the CPU. And this is exactly what should be done if the CPU isn’t needed for the moment – put in in power-down mode.

I got a little carried away here, but ways to minimize the power consumption is such an interesting topic. Do you have any power saving tips to share?

В борбата за сериен порт

Историята по-долу се разви преди доста време, но скоро ми се наложи да си я припомня. Реших, да си запиша нещата тук, пък може и на някой друг да свърши работа.

Напоследък серийните портове взеха напълно да изчезват от компютрите – осбено от преносимите. Дори и моят, който не е първа младост няма такъв (сигурно и защото е евтин модел).

RS232 интерфейсът може да е бавен, с обемист конектор и да работи на малки разстояния, но той има и едно предимство – изклютително прост е. Ако се занимавате с разни малки контролери ще знаете, че той е в порядъци по-удобен, достъпен, евтин и прост за реализация от USB или ETHERNET например.

И така, за да се сдобия с тази незаменима екстра се запътих към близкия магазин за конвертор от USB към сериен порт. Взех си и компютъра, защото за мен е важно чудото да работи под Линукс, а обикновено по опаковките това не го рекламират много. Преди да го купя включих USB конверторът и ядрото веднага го разпозна и се появи нов сериен порт. Купих го.

За съжаление радостта ми беше кратка, защото след като се прибрах установих, че въпросният конвертор не може да си комуникира с никакво серийно устройство – макар, че се разпознава. Може да е бил дефектен моя, но по-сокоро предположението ми е, че има проблеми с драйвера – cypres_m8. След това съм пробвал с други конвертори с чипове на FTDI и Prolific 2303 и при тях нямаше такъв проблем със серийната комуникация. Въпреки това при ситуации в които използвате серийния порт не съвсем по предназначение, а примерно превключвате контролните линии много бързо (bit banging) за да говорите някакъв друг протокол тези конвертори може и да не работят.

В крайна сметка реших да си взема „истински“ RS232 под формата на PCMCIA карта. След търсене с Гугъл попаднах на блога на Данчо, където той беше обявил за продажба точно такава карта поради несъвместимост с неговия компютър. Видяхме се. Пъхнах картата в моя компютър – ядрото я разпозна веднага – взех я.

Прибрах се. Първата ми работа беше да тествам новата придобивка – отново нищо! Никаква комуникация, нито с мобилния ми телефон, нито със стар външен модем, който успях да изровя.

Самата платка получих в картонена кутия, на която имаше йероглифи и единствено се разбираше, че пристига от Хонг Конг. Имаше и диск с драйвери – само за Унидоус. Всички отличителни белези по картата се свеждаха до надпис „BBL PCMCIA RS-232 CARD“. Търсенето за информация по тези ключови думи не даде полезен резултат.

Решен да не се предавам толкова лесно направих следния експеримент. Стартирах minicom и настроих порта на скорост 9600 бита в секунда. Пуснах да се изпраща файл съдържащ единствено буквата „а“. След това закачих изходящата линия (TX) към осцилоскоп и видях следното:

oscilloscope screen

Ура! Картата все пак работи и дори предава данни. Единствената малка подробност е, че ги предава доста по-бързо от колкото се очаква. На картинката по-горе осцилоскопът е настроен на 50 микросекуни за деление по оста Х. Грубо в едно деление се предават 3 бита, значи скоростта е над 62500 бита/секунда – доста над очакваните 9600.

След още малко търсене, проблемът напълно се изясни. Основният компомент осигуряващ серийната връзка e чип от вида UART (Universal Asynchronous Receiver-Transmitter). По-конкретно в моята платка има 16c950. Ядрото го разпознава правилно и драйверът успешно си говори с него. Скоростта обаче се определя чрез делене на тактовата честота получена от външен кварцов резонатор. Оказва се, че няма начин драйверът да разбере каква е честотата на този резонатор. До преди време най-масово се е използвал резонатор с честота 1.8432 MHz, която разделена на 16 дава базова скорост от 115200 бита/сек. Това е записано и в кода на драйвера като стойност по подразбиране.

В момента често се използват резонатори с по-високи честоти за да се постигнат по-големи скорости. Имайки предвид, че при мен получената скорост е около 7-8 пъти по-голяма от очакваната и стандартните стойности дадени в спецификацията на чипа установих, че в моята платка резонаторър най-вероятно е с честота 14.7456MHz, което разделено на 16 дава базова скорост от 921600 бита/сек. За щастие има лесен начин тази скорост да бъде указана с помощта на програмата setserial:


setserial /dev/ttyS0 baud_base 921600

Повтарям теста с осцилоскопа и този път резултатът е доста обнадеждаващ:

oscilloscope screen

Предаването на един бит отнема малко над 2 деления или 100 микросекунди. При зададена скорост от 9600 това е точно колкото се очаква – 1/9600=0,000104167 сек или около 104 микросекунди.

Комуникацията с мобилния телефон, стария външен модем и всичко друго което закача вече работи!

Остана само да добявя едно udev правило, за да не пиша горната команда всеки път когато пъхам картата. Аз си създадох нов файл – /etc/udev/rules.d/10-serial.rules и в него добавих само един ред:

KERNEL=="ttyS0", RUN+="/bin/setserial /dev/ttyS0 baud_base 921600"

Вече всички инструменти са на лице и мога да се заема с работата по проекта за монтаж на вентилатор в банята :).