Monday, August 19, 2013

madparts release 1.2

It's been a few months, but finally the new madparts 1.2 release is available!

Madparts is a functional electronics footprint editor with support for the Kicad and Eagle electronics Cad programs.

screenshot of madparts 1.2 running on linux/xmonad

Highlights


 KiCad support


Finally full support for importing and exporting footprints from/to KiCad is now available. madparts supports both the old .mod file format and the newer .pretty/.kicad_mod file format.

More shapes


1.2 adds support for arcs, partial circles, polygons and holes.

QtScriptEngine


Alex Schultz contributed javascript handling with QtScriptEngine instead of PyV8. This means there is one less dependency for the program making it easier to install, package and maintain. It is also faster! Thanks again Alex!

More documentation


Documentation is still sparse, but there is some more description of the supported features and code structures. Be sure to also have a look at my own private github repo of madparts footprints for more code examples.

Conclusion

If you want to give it a try, head to the website at http://madparts.org/ for more information and downloads. If you find issues or have questions, don't hesitate to email me.

The future

For madparts 1.3 a few changes are planned:
  • switch to SVG based graphics rendering to get rid of the dependency on modern openGL 2.1, making the program also usable on older computers
  • more documentation
  • better error handling

Tuesday, August 13, 2013

Experiments with Bluetooth Low Energy (4.0) under Linux

With iPhônes liberated from the apple authentication chip by it, and Android also having added support in the latest Android 4.3, Bluetooth Low Energy (4.0) is starting to look more interesting.

In this blog post I'm going to use a bluegiga BT111 based USB bluetooth dongle on Linux as a client and a TI CC2541 SensorTag as server.

USB dongle in computer
The SensorTag is a nice little bluetooth 4 example device provided by Texas Instruments.

Device

First step is put the device in the computer. As my laptop already has an existing bluetooth device build-in, the new one will enumerate as "hci1". This can be found out also by using hcitool.


$ hcitool dev
Devices:
        hci1    00:07:80:60:CE:4D
        hci0    EC:55:F9:F4:A0:xx

In this case the bluetooth mac address of the BT111 is 00:07:80:60:CE:4D.

Scanning for a device

Normal bluetooth scanning is done with hcitool scan. Low Energy scanning is done with hcitool lescan.
Make sure to press the button on the side of the SensorTag first to make it discoverable. Scanning is continuous to stop it with Ctrl-C. Low Energy devices require root access hence the sudo. I would expect being in the bluetooth group to be enough but for some reason it isn't.


$ sudo hcitool -i hci1 lescan
LE Scan ...
BC:6A:29:AC:2E:B4 (unknown)
BC:6A:29:AC:2E:B4 SensorTag
BC:6A:29:AC:2E:B4 (unknown)
BC:6A:29:AC:2E:B4 SensorTag
BC:6A:29:AC:2E:B4 (unknown)
^C

Using gatttool to access the device

Now we know the address of the SensorTag: BC:6A:29:AC:2E:B4. In contrast with regular Bluetooth where there are a whole range of protocols, with Bluetooth Low Energy there is only one protocol at the top and it is GATT (Generic Attribute).

The actual functionality of a device is implemented by means of attributes which can be read, written to or notification/indication enabled for, depending on the attribute.

gatttool is a simple Linux tool that can be used to manipulate these attributes with a Bluetooth Low Energy device. It can be used as a simple command line tool but I find it easier to use it in it's interactive mode.

Let's enter the interactive mode.




$ sudo gatttool -i hci1 -b BC:6A:29:AC:2E:B4 -I
[   ][BC:6A:29:AC:2E:B4][LE]>

It returns us a prompt. Let's connect to the device.


[   ][BC:6A:29:AC:2E:B4][LE]> connect
[CON][BC:6A:29:AC:2E:B4][LE]>

The CON indication tells us that the connection is established.
Now the primary command can be used to find the primary services of the device.

[CON][BC:6A:29:AC:2E:B4][LE]> primary
[CON][BC:6A:29:AC:2E:B4][LE]> 
attr handle: 0x0001, end grp handle: 0x000b uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x000c, end grp handle: 0x000f uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x0010, end grp handle: 0x0022 uuid: 0000180a-0000-1000-8000-00805f9b34fb
attr handle: 0x0023, end grp handle: 0x002a uuid: f000aa00-0451-4000-b000-000000000000
attr handle: 0x002b, end grp handle: 0x0035 uuid: f000aa10-0451-4000-b000-000000000000
attr handle: 0x0036, end grp handle: 0x003d uuid: f000aa20-0451-4000-b000-000000000000
attr handle: 0x003e, end grp handle: 0x0048 uuid: f000aa30-0451-4000-b000-000000000000
attr handle: 0x0049, end grp handle: 0x0054 uuid: f000aa40-0451-4000-b000-000000000000
attr handle: 0x0055, end grp handle: 0x005c uuid: f000aa50-0451-4000-b000-000000000000
attr handle: 0x005d, end grp handle: 0x0061 uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
attr handle: 0x0062, end grp handle: 0x0068 uuid: f000aa60-0451-4000-b000-000000000000
attr handle: 0x0069, end grp handle: 0xffff uuid: f000ffc0-0451-4000-b000-000000000000

Attributes in GATT have uuids and handles. UUIDs (unique identifiers) define a certain type of entry, handles can be used to access a value. To make things more complicated there is also nesting involved. Certain UUIDs are defined in the standard and always have to be provided. Others can just be vendor specific and provide the actual data for the service. It's beyond the scope of this blog post to further look into how all that fits together.

SensorTag attributes

Luckily for us, the meaning of the sensortag attributes are defined on the user guide at http://processors.wiki.ti.com/index.php/SensorTag_User_Guide.

For this blog I'm looking at the humidity sensor as it is the easiest and the values shown in the document are actually correct :) http://processors.wiki.ti.com/index.php/SensorTag_User_Guide#Humidity_Sensor_2

As you can see on that page, there are 3 important handles for the humidity sensor, Data (0x38), DataNotification (0x39) and Config (0x3C).

Let's try reading from the Data handle:

[CON][BC:6A:29:AC:2E:B4][LE]> char-read-hnd 38
[CON][BC:6A:29:AC:2E:B4][LE]> 
Characteristic value/descriptor: 00 00 00 00

So far so good, but no useful data. We first need to enable the sensor. This is done by writing 1 in the Config handle.

[CON][BC:6A:29:AC:2E:B4][LE]> char-write-req 3c 01
[CON][BC:6A:29:AC:2E:B4][LE]> Characteristic value was written successfully

Let's retry reading the value now.

[CON][BC:6A:29:AC:2E:B4][LE]> char-read-hnd 38
[CON][BC:6A:29:AC:2E:B4][LE]> 
Characteristic value/descriptor: 68 68 4e 72

That's more like it. Using the math provided on the website and a python script, this gives the temperature and the humidity.

>>> -46.85 + 175.72/65536 * 0x6868
24.8151025390625
>>> -6.0 + 125.0/65536 * (0x72e4 & ~3)
50.09893798828125

So 25 Celsius and 50% humidity. That agrees with my local weather sensor. Nice :)

Instead of reading values it is also possible to use notifications.


[CON][BC:6A:29:AC:2E:B4][LE]> char-write-req 39 0100
[CON][BC:6A:29:AC:2E:B4][LE]> Characteristic value was written successfully

Notification handle = 0x0038 value: 68 68 f6 71 
[CON][BC:6A:29:AC:2E:B4][LE]>
...
This will provide the temperature and the humidity every second automatically. Let's disable it again it is spamming me :)

[CON][BC:6A:29:AC:2E:B4][LE]> char-write-req 39 0000
[CON][BC:6A:29:AC:2E:B4][LE]> Characteristic value was written successfully

Finally let's disable the sensor and disconnect.

[CON][BC:6A:29:AC:2E:B4][LE]> char-write-req 3c 00
[CON][BC:6A:29:AC:2E:B4][LE]> Characteristic value was written successfully
[CON][BC:6A:29:AC:2E:B4][LE]> disconnect 
[   ][BC:6A:29:AC:2E:B4][LE]>

Conclusion

Bluetooth Low Energy might look a bit different/strange at first but it is really quite nice! I'm certainly going to explore it further!

Shameless plug!

Don't forget to check out the very nice BT111 based USB dongle available for sale at my tindie store!



Saturday, August 10, 2013

using the atxmega32e5 under linux

The Atmel AVR atxmega*e5 is an interesting chip. However it is still rather new so getting it to work on my linux environment took some tinkering.


compiler


Compiling requires a compiler that knows the CPU. In the previous post I just cheated and used a mostly compatible CPU.

My Debian comes default with gcc 4.7.3 which does not support the new atxmega*e5 CPU's yet. Luckily someone already packaged the gcc 4.8.1 compiler source, so it was just a matter of recompiling Debian's gcc-avr package against the gcc 4.8.1 source package. If you don't feel like that using the atxmega*D4 as cpu type during compilation is doable.

avr-libc


Besides the compiler, avr-libc also needs to be adapted. It is avr-libc that provides the io description headers for the CPU's. There is no avr-libc for linux yet that does this. Luckily Atmel's AVR Studio product also uses gcc internally, and they already support the atxmega*e5 CPU's.

I took the files iox8e5.h, iox16e5.h and iox32e5.h from avr studio and copied these to /usr/lib/avr/include/avr/ .

Also /usr/lib/avr/include/avr/io.h needs to be updated to add the new CPU's:

--- io.h.old 2013-08-10 09:51:40.963241968 +0200
+++ io.h 2013-08-10 13:29:12.682545107 +0200
@@ -382,12 +382,6 @@
 #  include <avr/iox32a4.h>
 #elif defined (__AVR_ATxmega32D4__)
 #  include <avr/iox32d4.h>
+#elif defined (__AVR_ATxmega8E5__)
+#  include <avr/iox8e5.h>
+#elif defined (__AVR_ATxmega16E5__)
+#  include <avr/iox16e5.h>
+#elif defined (__AVR_ATxmega32E5__)
+#  include <pavr/iox32e5.h>
 #elif defined (__AVR_ATxmega64A1__)
 #  include <avr/iox64a1.h>
 #elif defined (__AVR_ATxmega64A1U__)

Besides that, some other files are needed. I took the files crtx8e5.o, crtx16e5.o and crtx32e5.o from avr studio and copied these to /usr/lib/avr/lib/avrxmega2/

With those two in place, compilation works :)

Example


Here is an example that demonstrates the following:

  • switch to the internal 32Mhz oscillator
  • configure an USART on ports D6 and D7 at 9600 baud and run a simple echo follower
  • blink a LED on port A0


// (c) 2013 Joost Yervante Damad <joost@damad.be>
// License: GPL3
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

static void usart_write(uint8_t data)
{
    USARTD0.DATA = data;
    if(!(USARTD0.STATUS & USART_DREIF_bm)) {
        while(!(USARTD0.STATUS & USART_TXCIF_bm)); // wait for TX complete
    }
    USARTD0.STATUS |= USART_TXCIF_bm;  // clear TX interrupt flag
}


static inline void init_oscillator() {
  // enable 32Mhz internal oscillator
  OSC.CTRL |= OSC_RC32MEN_bm;
  // wait for it to be stable
  while (!(OSC.STATUS & OSC_RC32MRDY_bm)); 
  // tell the processor we want to change a protected register
  CCP=CCP_IOREG_gc;
  // and start using the 32Mhz oscillator
  CLK.CTRL=CLK_SCLKSEL_RC32M_gc; 
  // disable the default 2Mhz oscillator
  OSC.CTRL&=(~OSC_RC2MEN_bm);
  // enable 32kHz calibrated internal oscillator
  OSC.CTRL|= OSC_RC32KEN_bm;
  while (!(OSC.STATUS & OSC_RC32KRDY_bm)); 
  // set bit to 0 to indicate we use the internal 32kHz
  // callibrated oscillator as auto-calibration source
  // for our 32Mhz oscillator
  OSC.DFLLCTRL = OSC_RC32MCREF_RC32K_gc;
  // enable auto-calibration for the 32Mhz oscillator
  DFLLRC32M.CTRL |= DFLL_ENABLE_bm; 
}

static inline void init_usart() {
  // enable clock out on port PC7
  PORTCFG.CLKOUT = (PORTCFG.CLKOUT & ~PORTCFG_CLKOUTSEL_gm) | PORTCFG_CLKOUT_PC7_gc;
  // set PC7 as output
  PORTC.DIRSET = PIN7_bm;

  // set PD7 as output for TX0
  PORTD.DIRSET = PIN7_bm;
  PORTD.OUTSET = PIN7_bm;
  // remap USARTD0 to PD[7-4]
  PORTD.REMAP |= PORT_USART0_bm;
  // set baud rate 9600: BSEL=12, BSCALE=4
  // as found in table in 
  // Atmel-42005-8-and-16-bit-AVR-Microcontrollers-XMEGA-E_Manual.pdf
  USARTD0.BAUDCTRLA = 12; // BSEL
  USARTD0.BAUDCTRLB = 4 << USART_BSCALE_gp; // BSCALE
  // disable 2X
  USARTD0.CTRLB = USARTD0.CTRLB & ~USART_CLK2X_bm;
  // enable RX and TX
  USARTD0.CTRLB = USARTD0.CTRLB | USART_RXEN_bm | USART_TXEN_bm;
  // enable async UART 8N1
  USARTD0.CTRLC = USART_CMODE_ASYNCHRONOUS_gc | USART_PMODE_DISABLED_gc | USART_CHSIZE_8BIT_gc;
  USARTD0.CTRLC &= ~USART_SBMODE_bm;
  USARTD0.CTRLD = 0; // No LUT

  // set interrupt level for RX
  USARTD0.CTRLA = (USARTD0.CTRLA & ~USART_RXCINTLVL_gm) | USART_RXCINTLVL_LO_gc;
}

static inline void init_interrupts() {
  // Enable PMIC interrupt level low
  PMIC.CTRL |= PMIC_LOLVLEX_bm;
  // enable interrupts
  sei();
}

static volatile uint8_t echo_char = 42;

int main( void )
{
  init_oscillator();

  // enable clock out on port PC7
  PORTCFG.CLKOUT = (PORTCFG.CLKOUT & ~PORTCFG_CLKOUTSEL_gm) | PORTCFG_CLKOUT_PC7_gc;
  // set PC7 as output
  PORTC.DIRSET = PIN7_bm;

  init_usart();

  init_interrupts();

  // set PA0 as output
  PORTA.DIRSET = PIN0_bm;
  // blink LED on PA0 with 1 second on, 1 second off
  // write echo_char on USART on D7; defaults to 42(*)
  while (1) {
    usart_write(echo_char);
    PORTA.OUTSET = PIN0_bm;
    _delay_ms( 1000 );
    usart_write(echo_char);
    PORTA.OUTCLR = PIN0_bm;
    _delay_ms( 1000 );
  }
}

// USART RX receive interrupt handler
ISR(USARTD0_RXC_vect) {
  echo_char = USARTD0.DATA;
}

Code


The code can be found on github, together with the files mentioned here for convenience.

Hardware


I have some extra atxmega32e5 breakout boards available. You can find them in my tindie store.

breakout on a breadboard with USB-serial adapter

In addition, the eagle schematic and board files are available on github as well.

More fun


I'm still exploring this nice little microcontroller. Be sure to check back later on my blog for new adventures!



Wednesday, August 7, 2013

atxmega enable internal 32Mhz oscillator (part 2)

The atxmega also supports using the calibrated internal 32kHz clock as auto-calibration reference for the 32Mhz internal oscillator, improving the accuracy.

This code should do the trick. I'm not sure how I could actually verify it. Perhaps I can get the clock signal external and get it on a scope.



#include <avr/io.h>
#include <util/delay.h>

int main( void )
{
  // enable 32Mhz internal oscillator
  OSC.CTRL|=OSC_RC32MEN_bm;
  // wait for it to be stable
  while (!(OSC.STATUS & OSC_RC32MRDY_bm)); 
  // tell the processor we want to change a protected register
  CCP=CCP_IOREG_gc;
  // and start using the 32Mhz oscillator
  CLK.CTRL=CLK_SCLKSEL_RC32M_gc; 
  // disable the default 2Mhz oscillator
  OSC.CTRL&=(~OSC_RC2MEN_bm);
  // enable 32kHz calibrated internal oscillator
  OSC.CTRL|= OSC_RC32KEN_bm;
  while (!(OSC.STATUS & OSC_RC32KRDY_bm)); 
  // set bit to 0 to indicate we use the internal 32kHz
  // callibrated oscillator as auto-calibration source
  // for our 32Mhz oscillator
  OSC.DFLLCTRL &= ~OSC_RC32MCREF_bm;
  // enable auto-calibration for the 32Mhz oscillator
  DFLLRC32M.CTRL |= DFLL_ENABLE_bm;

  // set PA0 as output
  PORTA.DIRSET = 0b00000001;
  
  // blink LED on PA0 with 1 second on, 1 second off
  while (1) {
    PORTA.OUTSET = 0b00000001 ;
    _delay_ms( 1000 );
    PORTA.OUTCLR = 0b00000001 ;
    _delay_ms( 1000 );
  }
}

Tuesday, August 6, 2013

atxmega enable 32Mhz internal oscillator

The atxmega (I'm playing with an atxmega16e5) has multiple internal oscillators. By default it starts on the 2Mhz clock, which is actually an 8Mhz internal oscillator divided by 4. The following code switches to the 32Mhz internal oscillator.

register definitions can be found in iox16e5.h. As I'm using an older avr-gcc I've looked in iox16d4.h instead, assuming that the base registers like for the clock are the same.

#include <avr io.h>
#include <util delay.h>

int main( void )
{
  // enable 32Mhz internal oscillator
  OSC.CTRL|=OSC_RC32MEN_bm;
  // wait for the oscillator to stabilize
  while (!(OSC.STATUS & OSC_RC32MRDY_bm)); 
  // tell the processor we want to change a protected register
  CCP=CCP_IOREG_gc;
  // and start using the 32Mhz oscillator
  CLK.CTRL=CLK_SCLKSEL_RC32M_gc; 
  // finally disable the default 2Mhz oscillator (optional)
  OSC.CTRL&=(~OSC_RC2MEN_bm);

  // set PA0 as output
  PORTA.DIRSET = 0b00000001;
  
  // blink LED on PA0 with 1 second on, 1 second off
  while (1) {
    PORTA.OUTSET = 0b00000001 ;
    _delay_ms( 1000 )
    PORTA.OUTCLR = 0b00000001 ;
    _delay_ms( 1000 )
  }
}