Tuesday, December 24, 2013

using madparts for making electronics footprints: an eleborate example

In this blog post I'm discussing a more complex footprint I've made and how I made it with madparts based on the vendor's specification. More specifically I'm making a footprint for the Bluegiga BLE113 Bluetooth Low Energy module.

Lets start by collecting all the needed data.

The physical dimensions of the module are found in the spec page 16:

This will be used to define the physical boundaries of the package.

Next is the landing pattern. It can be found on page 17 of the specification:

 This is used to define the pads for the module.

The order of the pins can be found on page 7:

Finally the specification also gives a clearance for the antenna on page 20:

This means we'll have to add a restrict area to the part for this clearance area.

let's write code!

Define the size of the module as found in the physical dimensions:

  module_dx = 9.15
  module_dy = 15.74

Define the size of the pad as found in the recommended landing pattern:

  pad_dx = 2
  pad_dy = 0.5

The horizontal pads need an adjustment from the center of the module. The landing pattern defines 5.35mm between the two columns of pads, and we orient from the center of the pad so in total this gives and adjustment value of:

  pad_hadj = (5.35+pad_dx)/2

The landing pattern tells us the distance between pads:

  pad_between = 0.8

The pinout description gives the number of pins:

  n_left = 18
  n_down = 6
  n_right = 12

The physical dimension tells us the distance from the bottom of the module to the center of the bottom left and right pad. This works because the pad centers are the same for the physical diagram and the landing pattern.

  lr_pad_from_bottom = 1.45

Now this gets a bit tricky. We need to calculate the vertical adjustment needed for the column of pads, but this is relative to the center of the module. The trick is to take pad 18, move it to the 0 point, then to the bottom of the module, and then use the lr_pad_to_bottom adjust value specified in the spec.

  pad_vadj = ((n_left-1)/2)*pad_between  # move pad 18 to 0
  pad_vadj -= module_dy/2                # move pad 18 down to bottom
  pad_vadj += lr_pad_from_bottom         # and back up by 1.45

Let's draw a rectangle to document the module shape, and draw a silk around it to make it easily visible on the board later.

  r1 = make_rect module_dx, module_dy, 0.1, 'docu'
  r2 = make_rect module_dx+0.2, module_dy+0.2, 0.1, 'silk'

Let's define the pad shape with the earlier defined constant. we want 100% round corners.

  pad = new Smd 
  pad.dx = pad_dx
  pad.dy = pad_dy
  pad.ro = 100

Now lets make the left row of pads. First make them, then adjust the x and y by the values we calculated earlier.

  l1 = single pad, n_left, pad_between
  l1 = adjust_x l1, -pad_hadj
  l1 = adjust_y l1 , pad_vadj

Next the bottom row. clone and rotate the pad, and create a horizontal row of pads. Adjust the y as specified in the landing pattern figure. Finally renumber starting with the number after the last number we used for the first column of pads.

  l2 = rot_single (rotate90pad clone pad), n_down, pad_between
  l2 = adjust_y l2, -module_dy/2+lr_pad_from_bottom-0.55
  l2 = generate_names l2, n_left

Finally the right row. Again a single row of pads. Reverse the order. Renumber starting after the last number used for the down pads.

  l3 = single pad, n_right, pad_between
  l3 = reverse l3
  l3 = generate_names l3, n_left+n_down
  l3 = adjust_x l3, pad_hadj
  l3 = adjust_y l3, pad_vadj+(n_right-n_left)/2*pad_between

Let's add a name somewhere inside the module, a bit below the top:

  name = new Name (module_dy/2-1)

Let's add a rectangular for the restrict area. This is a but messy but it boils down to placing it right above pas 36 and 3.5mm on the right of the left side of the module.

  k = new Rect
  k.type = 'restrict'
  k.dx = module_dx
  k.dy = module_dy/2-l3[n_right-1].y
  k.x = -module_dx/2+3.5+k.dx/2
  k.y = l3[n_right-1].y+pad_dy/2+k.dy/2

Finally combine it all in a list and we're done.

  combine [name, r1,r2, l1, l2,l3, k]

The latest version of the full file can be found at https://github.com/andete/madparts-parts/blob/master/3ca17b8bc41648d2b968c33ae8f35092.coffee

This is a screenshot:


And this is the part in eagle cad:


And in kicad:


Saturday, December 21, 2013

a look inside the shielding can of the BLE112 Bluetooth Low Energy module

Given that I accidentally damaged this Bluetooth Low Energy anyway, I thought it interesting to take a look what is inside the shielding can with a macro lens.

Here you see the bluegiga BLE112 module on a board with the shield still in place:



And here I removed the metal shielding can:


As you can see no real surprises here:

The central unit is a Texas Instruments CC2540 SoC Bluetooth Low Energy module.
On the lower right of it sits a 32 Mhz crystal for the main clock.
Above it is what I assume the 32.768 kHz low speed clock crystal.

The antenna was already visible with the can in place, but what's interesting is the second companion chip inside the can. I assume it is some kind of filter for the antenna.

Besides that just a few passives and that is it!

Sunday, December 15, 2013

madparts release 1.2.1

This is mostly a bug-fix release, mainly fixing bugs to do with rotation of certain parts, especially in combination with KiCAD export.

Builds are available for Debian Jessie and Wheezy, Ubuntu Saucy, MacOSX and Win32.

Go download one of them at http://madparts.org/footprint.html#download !






Saturday, December 14, 2013

stm32f105 cortex-m3 getting to blink

This is not going to be a detailed post. All the code can be found in github at https://github.com/andete/blog-stuff/tree/master/STM32F105 .

In my quest for more experience with different microcontrollers I made a little breakout for the ST STM32F105 ARM Cortex-M3 micro-controller.

The breakout provides a 8Mhz external clock, which is multiplied by 9 by the internal PLL to give a nice 72Mhz clock.


The MCU is programmed with the STLINK V2 programmer via SWD. It should also be possible to program it via DFU but I have not tried that yet.

I cobbled some code together from all over the internet to make a simple blink file.


#include "stm32f10x.h"

// loosely based on
// http://www.overtracks.com/stm32/baby-steps.htm
// http://dics.voicecontrol.ro/dicsEE-IP/chapter/Setting%20GPIO%20manually
// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/BGBEEJHC.html
// https://forum.sparkfun.com/viewtopic.php?f=11&t=21107
// http://en.radzio.dxp.pl/stm32vldiscovery/

// LED is connected to PC0, so first bit on GPIOC
#define LED_BITMASK          1 << 0 // bit 0

#define USE_SYSTICK

#ifdef USE_SYSTICK
void SysTick_Handler(void) {
  GPIOC->ODR ^= LED_BITMASK; // toggle LED state
}
#else
void TIM3_IRQHandler(void) {
  // why the check for UIF ?
  if (TIM3->SR & TIM_SR_UIF) // if UIF flag is set
  {
    TIM3->SR &= ~TIM_SR_UIF; // clear UIF flag
    GPIOC->ODR ^= LED_BITMASK; // toggle LED state
  }
}
#endif

int main() {

  // enable GPIOC
  RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
  // configure GPIOC port 0 as output; 4 bits per pin
  // 4+0 -> (0) input mode, (4) floating (reset state)
  // 0+2 -> (2) output mode, (0) generic push-pull
  GPIOC->CRL = 0x44444442;

#ifdef USE_SYSTICK
  // 1 second = 72000000 / 8000000 = 9000000
  SysTick->LOAD = 9000000;
  // start counting from zero
  SysTick->VAL = 0;
  // enable and enable interrupt
  SysTick->CTRL |= (SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk);
#else
  // enable clock for timer3
  RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
  // Set prescaler to 24 000 (PSC + 1) // why?
  TIM3->PSC = 23999;
  // // Auto reload value 1000
  TIM3->ARR = 1000;
  // Enable update interrupt (timer level)
  TIM3->DIER = TIM_DIER_UIE; // Enable update interrupt (timer level)
  TIM3->CR1 = TIM_CR1_CEN;   // Enable timer

  NVIC_EnableIRQ(TIM3_IRQn);
#endif

  // sleep till the end of time
  while (1) { __WFI(); }
  return 0;
}
It does blinking via the SysTick interrupt or alternatively via the TIM3 timer interrupt. It is also possible to do this without interrupts at all, just using the timers, but this is not shown here.

Friday, November 29, 2013

using efm32 simplicitystudio under Linux

Intro


So I went to a workshop yesterday mostly about the Silabs/Energy Micro micro-controllers. The workshop was rather interesting, but the workshop was done with the tools in Windows 7. As I'm working almost exclusively under Linux since 1998, this was quite a painful experience for me. Especially USB device handling is so much smoother in Linux. But enough about my windows pain. The EFM32 micro-controllers are based around ARM Cortex and seem to be genuinely nice ICs with a bunch of special low-power features. I'm not going to list all those as this is not a marketing post, you can find enough information about that on the internet already.

I came back home with two very nice dev-boards, which is pretty cool in itself!

EFM32 ZERO GECKO running a nice Space Invaders clone demo
EFM32 WONDER GECKO running a light sense demo


Linux

When I arrived back home I started reading up a bit more about the ICs and one of the first things I found  in a vid on youtube is that the simplicity studio is also available for Linux and OSX.

Going to the silabs download website only gave a download for windows, but a quick google brought me to the Energy Micro forum where there is a beta download or simplicity studio for Linux and OSX available. After a few tricks it works smoothly in Linux, if only I had known that a day sooner ;)

Installation

What I did to get a working installation on on my x86-64 Debian Jessy laptop:
  • download the simplicity studio beta
  • unzip the zipfile somewhere
  • enter the studiow/ map
  • start the start-studio.sh shell script: ./start-studio.sh
This will provide you with an installer for the simplicity studio software. This installer will install all the needed software. When the software is installed you can start simplicity studio itself also with ./start-studio.sh.

In the simplicity studio main tool page press the add-remove button and use it to install everything. This will download all the examples, demos and app-notes.

Now while the main tool works, I quickly found out that most sub-tools didn't. It turned out that because simplicity studio is a 32-bit application and my system is 64-bit, I was missing some 32-bit libraries it needs, although I could imagine some people also missing some libraries on their 32-bit system.

A quick apt-get to the rescue:

sudo apt-get install libusb-0.1-4:i386 libqt4-svg:i386 

Depending on your system you may need to install some more missing libraries. This is rather easy to see as if you started simplicity studio from the command-line it will print out a missing library when you access a tool that is needing it.


Demos

The easiest way to play with the dev-kits is run some of the demos. Connect the board with the mini usb cable and press the Demos button in simplicity studio. Select a demo and press start. It will upload the demo and start the energyAware profiler program allowing you to real-time monitor the current consumption for that particular demo.


Compilers & Uploading

Demos are fun, but compiling your own code requires some more setup.

  • download and install the arm-gcc compiler from https://launchpad.net/gcc-arm-embedded
  • in simplicity studio press examples, select the dev-board you're using (EFM32WG_STK3800 for the wonder gecko, EFM32ZG_STK3200 for the zero gecko)
  • choose the blink example (or another one)
  • press open folder, this will open some gui explorer for your desktop environment
  • go to that directory in the shell, in my case it is /some/path/kits/EFM32WG_STK3800/examples/blink
  • enter the armgcc directory
  • there is a makefile there called Makefile.blink
  • open the file with an editor and a definition for your toolchain location to it, in my case I added
 LINUXCS := /some/path/gcc-arm-embedded/gcc-arm-none-eabi-4_7-2013q3

  • alternatively you could just export that LINUXCS to the environment
  • now do:
make -f Makefile.blink
  • it will now have made a file blink.bin in the exe/ subdirectory
  • you can upload this bin file with the tool called "energyAware commander", this should be easy
  • alternatively you can use energyAware commander to upload from the commandline:
./start-eACommander.sh --flash /some/path /kits/EFM32WG_STK3800/examples/blink/armgcc/exe/blink.bin

The same principle works for other examples and app-notes.

Some more pics

a closeup of the 128x128 sharp memory LCD display on the ZERO GECKO

ZERO GECKO running an analog clock demo


Cortex-M0+ closeup
Cortex-M4 closeup


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 )
  }
}

Tuesday, July 30, 2013

adding a new device to avrdude

So I made a little breakout for the new Atmel AtXmega E5 series. More specifically I'm testing it with the atxmega16e5.

This is a new chip that is not yet supported by the latest avrdude.

Making it work turned out to be reasonably straightforward.

First let's open avrdude.conf, the config file of avrdude.
Let's find a section of a chip that is reasonably similar, I've selected the atxmega16d4:

#------------------------------------------------------------
# ATxmega16D4
#------------------------------------------------------------

part parent ".xmegasmall"
    id  = "x16d4";
    desc = "ATxmega16D4";
    signature = 0x1e 0x94 0x42;
    has_jtag = no;

    memory "eeprom"
        size  = 0x0400;
        offset  = 0x08c0000;
        page_size = 0x20;
        readsize = 0x100;
    ;

    memory "application"
        size  = 0x00004000;
        offset  = 0x0800000;
        page_size = 0x100;
        readsize = 0x100;
    ;

    memory "apptable"
        size  = 0x00001000;
        offset  = 0x00803000;
        page_size = 0x100;
        readsize = 0x100;
    ;

    memory "boot"
        size  = 0x00001000;
        offset  = 0x00804000;
        page_size = 0x100;
        readsize = 0x100;
    ;

    memory "flash"
        size  = 0x00005000;
        offset  = 0x0800000;
        page_size = 0x100;
        readsize = 0x100;
    ;
;

copy this to a new section and change the id to x16e5 and the desc to ATxmega16E5.
Find the signature like by hooking up the PDI to your x16e5 board and doing:

avrdude -P usb -c avrispmkII -p x16d4

It will now say that it is the wrong signature and will print you the signature it actually found:

 0x1e 0x94 0x45

Use that in the config section.

Now find the XML files distributed as part of Atmel AVR Studio that contain the device descriptions of the two devices: ATxmega16D4.xml and ATxmega16E5.xml

Now look at the differences and make the necc. changes. The only changes I made are the eeprom size,  the page_size and readsize settings. The x16e5 uses 128 byte pages and the x16d4 256 byte pages.

This gives as a result:


#------------------------------------------------------------
# ATxmega16E5
#------------------------------------------------------------

part parent ".xmegasmall"
    id  = "x16e5";
    desc = "ATxmega16E5";
    signature = 0x1e 0x94 0x45;
    has_jtag = no;

    memory "eeprom"
        size  = 0x0200; # J
        offset  = 0x08c0000;
        page_size = 0x20;
        readsize = 0x80; # J was 0x100
    ;

    memory "application"
        size  = 0x00004000;
        offset  = 0x0800000;
        page_size = 0x80;
        readsize = 0x80;
    ;

    memory "apptable"
        size  = 0x00001000;
        offset  = 0x00803000;
        page_size = 0x80;
        readsize = 0x80;
    ;

    memory "boot"
        size  = 0x00001000;
        offset  = 0x00804000;
        page_size = 0x80;
        readsize = 0x80;
    ;

    memory "flash"
        size  = 0x00005000;
        offset  = 0x0800000;
        page_size = 0x80;
        readsize = 0x80;
    ;
;

This seems to work fine for programming. I'm pretty sure some things are still missing concerning fuses and such though.

In order to get code compiled with gcc I use another atxmega target as chip as the x16e5 is not yet part of
the avr-gcc I'm using either.

./avrdude -C ./avrdude.conf -e -P usb -c avrispmkII -p x16e5 -U flash:w:blink.hex

And it blinks :)

Tuesday, July 23, 2013

high power LED retrofit (part 5)

So it's been a while since I showed progress on my LED retrofit project. I've been mostly busy preparing the madparts 1.2 release, which should happen "real soon now".

PCBs

As discussed in the previous post, while I had everything working for one lamp, it was a total mess of cables and really not acceptable to be a permanent part of the home. Also I wanted to decouple the functionality in two parts:
  1. LED PWM, relay control and Lux sensing
  2. fan PWM and temperature measurement
Main reason being that fan PWM and temperature measurement need to be done relatively close to the actual lamp, while the others should be done close to the LED driver.

To avoid having to run cables between the two boards, and because I'm using RF already anyway, I decided to let both boards talk directly over wireless.

Schematics & board design


I'm hoping to switch to KiCAD soon, but these boards were still designed with Eagle CAD.

LED PWM, relay control and Lux sensing

Overal schematic:



Let's look at the different sections in detail:


12V is taken in with a standard power connector. Diode D3 is used to protect against reverse polarity. F1 is a re-settable polyfuse, which combined with the TVS diode D4 provides further overloading protection.


The 12V rail is converted to a 5V and 3.3V rail by means of MCP1703 voltage regulators.


Headers are provided for Debug TX/RX serial interface, I2C bus for the Lux sensor and the standard 6-pin ISP programming header.

The I2C bus is actually connected to 5V, but the Lux sensor I'm using runs on 3.3V only. (It dies on 5V :( ) This means I had to do some bodge wiring to get 3.3V instead of 5V on that connector.

The Lux sensor is only connected to one of the two boards I've created because they'll be together anyway.


The main workhorse is an Atnel AVR atmega328p microcontroller clocked at 16Mhz. A conservative choice but it allowed me to spent minimal time making the firmware as it is fully Arduino compatible. I also broke out the other pins just to be sure but I did not end up using those.

 The wireless connection is provided by a cheap RFM12B module. It is connected to the SPI bus of the main processor. This module runs on 3.3V hence the simple voltage divider action for MOSI, SCK and SS signals that go from the processor to the RFM12B. The other way around nothing is needed as 3.3V is still above the high-threshold for the processor.


The relay used is a neat little latching relay to avoid constantly powering the relay when the lamp is on. The relay is driven from the micro-controller via the NPN transistors T1 and T2 and flyback protection diodes D1 and D2 are provided around the relay coils to absorb possible inductive kicks.



Finally an adjustable voltage regulator together with a trim pot is used to set the peak voltage of the PWM signal towards the LED driver. This can be used to limit the maximum current provided by the LED driver. This works because internally the LED driver just converts the PWM signal to a voltage anyway with a low-pass filter. This adds another safety mechanism to limit the LED current if your setup is not capable of dissipating all the heat the LED die produces when it is running at it's maximum current rating.

The PWM signal provided by the micro-controller is then first inverted an then brought up to almost the voltage level provided by the voltage regulator. In practice a small drop is still seen causing a 10V maximum output signal when the voltage regulator is set to 10.5V.

R12 ensures that the LED drops to 10% dimming instead of going full on if for some reason the board dies and the lamp is still on as the LED driver also supports programming the current with a resistor.

Finally this gives rise to the following board layout:


The code has also been rewritten. I will not further explain the code.
You can find code and eagle schematic and board files at https://github.com/andete/blog-stuff/tree/master/HPLEDRF2/relay_pwm .

Note that I mirrored the power connector. Luckily I could just cut off the side pin and it still works fine.

Fan PWM and temperature sensing


Overal schematic:


Many parts are the same as the other board and I will not go in them again. These are different:

The fan PWM is just directly driven from the micro-controller as the FAN has 5V PWM compatible. The fan also provides a pulse signal which is connected to the INT1 interrupt pin of hte micro-controller.




Temperature sensing is provided by the AD8495 k-type thermocouple amplifier. I did not write my own driver for it, I just used code already made available by http://adafruit.com/ .

This is the board layout:


For this board, the code and files can be found at https://github.com/andete/blog-stuff/tree/master/HPLEDRF2/temp_fan .

Boards

I ordered boards from http://seeedstudio.com. They took slightly longer then 2 weeks to arrive counting from first order date which is very reasonable given that they have to come from China. Pricing is also extremely competitive.

.
The boards look reasonably well. The silk screen is a bit poor at places. I did not find any electrical errors (besides my own :p ). Copper does tends to peel of when you do rework, so don't use to much heat.

In the meanwhile I have also other boards in progress from http://oshpark.com/. I'm quite curious how long they'll take to get in Europe and make a comparison of the quality.

Assembly


Here is a picture of a fan-temperature board hand assembled. It went pretty well.


Here I'm testing temperature measurement with a k-type thermocouple.



Here you can see the relay PWM board sitting on top of the LED driver for testing. the Lux sensor is mounted on the lid of the case sensing through a hole.


Here I'm testing the entire setup with LED driver and LED PWM board below and temperature-fan board sitting on top of the stairs.

It's all starting to work!



As I want two of these lamps in my living, I started on assembly of the second lamp. I've slight changed the mounting. in the first lamp I used screws and aluminium to put the LED die in place. Here I've used termo-conductive glue to place the die on the plate. This has a big advantage that there are no screws in the way and the heat sink sits snugly on the other side of the plate. Also I've opted to mount the fan directly on the heat sink for simplicity.

On the top picture you can nicely see the thermocouple mounted on the LED die. Insulated with kapton tape.



With both lamps working fine, it's time to clean up the assembly for their final wiring. Wiring is always such a mess...


Here is the final wiring for the LED PWM boards and the LED drivers. Wires will of course be flattened when they're at their final location, and the cases will be closed. At this point I finished up the firmware as once the lamps are in place it will be next to impossible to reach the boards.

So all that is left is mounting them on a piece of wood and hanging the lamps on their final spot!

Friday, May 31, 2013

BufferSerial: let Arduino Stream writes go in a buffer

When you have existing code that uses an Arduino Stream like "Serial" or "SoftwareSerial" data is written part by part on the serial device. Sometimes you want to collect different parts first, maybe adding something like a checksum and only then send everything on one go. By using the BufferSerial construct you can just keep the existing code, pass it the BufferSerial instead of your normal Serial and afterward use the content of the buffer, and send it as one big blob.

 A simple example:
uint8_t mybuffer[32];
BufferSerial bs(mybuffer, 32);
bs.print((int)42);
bs.write(' ');
bs.print(127, HEX);
bs.print("hello");

Serial.println(bs);

The code for BufferSerial is really simple and can be found at: https://github.com/andete/blog-stuff/tree/master/BUFSER1 .

Tuesday, May 28, 2013

NullSerial, a /dev/null Serial Stream for Arduino

Sometimes I use a (Software) Serial device for debugging in some AVR/Arduino code.

An easy way to disable this debugging without going through the entire code or using macros is using this simple dummy serial device instead of the real thing.

Usage example:

#ifdef WANT_DEBUG
#include <softwareserial.h>
SoftwareSerial Debug(4, 5); // RX. TX
#else
#include "NullSerial.h"
NullSerial Debug;
#endif
NullSerial itself is this:
class NullSerial : public Stream
{
private:

public:
  // public methods
  NullSerial() {}
  ~NullSerial() {}
  void begin(long speed) {}
  bool listen() { return true; }
  void end() {}
  bool isListening() { return true; }
  bool overflow() { return false; }
  int peek() { return -1; }

  virtual size_t write(uint8_t byte) { return 0; }
  virtual int read() { return -1; }
  virtual int available() { return 0; }
  virtual void flush() {}
  
  size_t write(const char *str) { return 0; }
  size_t write(const uint8_t *buffer, size_t size) { return 0; }
    
  size_t print(const __FlashStringHelper *) { return 0; }
  size_t print(const String &) { return 0; }
  size_t print(const char[]) { return 0; }
  size_t print(char) { return 0; }
  size_t print(unsigned char, int = DEC) { return 0; }
  size_t print(int, int = DEC) { return 0; }
  size_t print(unsigned int, int = DEC) { return 0; }
  size_t print(long, int = DEC) { return 0; }
  size_t print(unsigned long, int = DEC) { return 0; }
  size_t print(double, int = 2) { return 0; }
  size_t print(const Printable&) { return 0; }

  size_t println(const __FlashStringHelper *) { return 0; }
  size_t println(const String &s) { return 0; }
  size_t println(const char[]) { return 0; }
  size_t println(char) { return 0; }
  size_t println(unsigned char, int = DEC) { return 0; }
  size_t println(int, int = DEC) { return 0; }
  size_t println(unsigned int, int = DEC) { return 0; }
  size_t println(long, int = DEC) { return 0; }
  size_t println(unsigned long, int = DEC) { return 0; }
  size_t println(double, int = 2) { return 0; }
  size_t println(const Printable&) { return 0; }
  size_t println(void) { return 0; }

  // public only for easy access by interrupt handlers
  static inline void handle_interrupt();
};
All this assumes you're not using the return values of the print/println methods.
The full code can be downloaded at github.

Friday, May 24, 2013

madparts release 1.1

A new release of the madparts functional electronics footprint editor is available.

Important changes are:

  • py2exe simple Windows installation: just unzip the zip file and execute madparts.exe
  • linux packages for madparts and pyv8 for Debian and Ubuntu i386 and x86_64
  • a ton of bug-fixes
  • various internal code cleanups
  • simple built-in command line interface for listing of libraries and import and export of footprints
For downloads, and more details head over to the madparts.org website. As always, don't hesitate to contact me with questions or feedback at joost@madparts.org or use the github bugtracker.

The next release will normally contain support for KiCad, but I first I need to learn working with it :)

madparts running on macosx

Tuesday, May 14, 2013

high power LED retrofit (part 4)

So the lamp is working fine. Here it is suspended to the stairs for duration testing.


So dimming works, remote control works and temperature measurement all works. For some reason Lux measurement is not working, I think I may have fried that sensor by accident.

Cabling is still somewhat of a mess, but I was thinking of sorting that out when the lamp is moved to it's final place.

Then a day passed, and I got some time to think :)

Right now there are two locations where active circuitry is located: near the lamp for temperature measurement and fan control, and near the power supply for on/off (relay), wireless, dimming and lux measurement.

These two locations are connected via a whole bunch of cables. And I'm already doing cheap wireless at one point.  That is just silly!

So the next step will be creating a separate board with wireless for each of those two locations. The only wiring remaining between the two locations will be a 12V/GND cable, and of course the LED current cable.

To be continued, but somewhat further in the future as I'm working on some other things at the moment, and I want to design some proper PCBs for the next step that fit in a nice casing and such.

Sunday, May 5, 2013

high power LED retrofit (part 3)

Murphy always strikes multiple times...

fan speed control (PWM) fried

So Friday I accidentally hooked up the fan the wrong way and (as I found out afterwards) killed the fan PWM circuitry.

micro-controller fried

Turned out the fan speed control died "short". This also caused a power surge towards the micro-controller which also died. Strangely it still somewhat worked but when I tried to re-program that always failed. So I replaced the micro-controller for the second time, installed the boot-loader and firmware, and back to business.

Not so fast though, I first need to install a new fan.
So I open the lamp only to find out...

LED broken

I guess my crude mounting with the aluminium brackets put to much strain on the LED die and that combined with heat caused it to crack. Luckily I had a spare lying around.

It's not all bad though, while having the lamp open, I decided to improve some things.

Better LED mounting


 

With the help of some thick aluminium foil cut to the right size and bolted down, I get a much nicer mounting of the LED. While at it I also improved the location of the thermo-couple. It now sits all the way on top of the LED, right at the official temperature measurement point!

Speaking about temperature...

LED PWM

In my early testing with the LED, I found that when driving the LED at near or full blast (800mA-1000mA) the LED got warm really fast, easily reaching 60-70 degrees Celsius.

With my testing with the whole setup, temperature stayed nice and low, peaking at about 42 degrees Celsius. What is happening there?

First thing I did was measure with the thermo-couple of my multi-meter. Exactly the same temperature. Then I measured the current provided to the LED.
Turns out exactly 330mA is provided when PWM is fully on. And I'm using 3.3V PWM... That can't be a coincidence. 

The LED driver officially works on 10V PWM, but I assumed as it was dimming fine with 3.3V PWM that it also supports that. My guess is now they're just using an analog filter to convert the PWM signal to a voltage., and then interpret the Voltage on a scale from 0 to 10V.

Easily fixed though, I created a simple amplifier circuit like this:



Brief testing showed this works just fine! Brief testing also immediately showed the temperature rising again rapidly!

Other heatsink

While inside the lamp anyway, I decided to install another heat-sink:



Some more testing showed that even though the heat-sink does the job, some active (fan) cooling is still highly appropriate.

New fan


Here the new fan is spinning nicely during a test.

Cable mess

While working on the inside anyway, I got annoyed by all the cables easily blocking the fan, etc.. so I re-arranged and fixed them.

That's where the lamp is at now!

To be continued!

Click here for Part 4.