Saturday, April 9, 2011

uC/OS-II on the AVR XMEGA

Although the files have been quietly available to download from my site for a couple of weeks now [here], I'd just like to give a little bit more exposure to using uC/OS-II as a real-time operating system on the AVR XMEGA series of microcontrollers.

A port of uC/OS-II for the XMEGA was released quite some time ago by Micrium, however, this port was designed specifically to run on the STK600 - a relatively expensive development board produced by Atmel. It was therefore my goal to modify this original port and create a more universal port which could be used on both Atmel's low cost XMEGA evaluation boards (AVR XMEGA-A1 Xplain & the newer Xplained) as well any custom XMEGA-based board (after some simple modifications).

As a result, I have made available to download two full AVR Studio 4 projects [see link at bottom of page]:
  • uC/OS-II v2.91 for the AVR XMEGA-A1 Xplain
  • uC/OS-II v2.91 for the AVR XMEGA-A1 Xplained

Terminal application connected to the AVR XMEGA-A1 Xplain running uC/OS-II v2.92.01

On an unrelated note, my qt-opencv-multithreaded project hosted over at Google Code has reached over 130 total downloads in two months - I never expected it to be this popular! For all those interested in creating OpenCV-based computer vision applications, please do check it out - as always, I appreciate any feedback and suggestions. Stay tuned for the next version of the application where I hope to incorporate the option of using OpenGL to display the frames and also utilize the new OpenCV C++ interface.

Links:

Wednesday, March 2, 2011

HOW TO: Peter Fleury's I2C Driver and the AVR XMEGA

Even though the AVR XMEGA microcontroller features multiple hardware Two-Wire Interfaces (i.e. I2C interfaces), there may be times when it is simply not possible to use them because the pins to these interfaces are already in use (as I have experienced). Fortunately, the I2C interface can be emulated in software using regular I/O pins by "bit-banging".

This post will explain how to modify Peter Fleury's I2c Master Interface library to work with the XMEGA. Modifications are necessary due to the fact that unlike other AVRs, XMEGA I/O port registers have addresses outside the I/O space and thus must be mapped to "virtual ports" (which have registers in the I/O space) for this library to function.

1. Download the I2C Master Interface library from Peter Fleury's website (here) or here and unzip.

2. The only file which needs to modified is i2cmaster.S:

Original (Lines 41-56):

;***** Adapt these SCA and SCL port and pin definition to your target !!
;
#define SDA4                     // SDA Port D, Pin 4
#define SCL5                     // SCL Port D, Pin 5
#define SDA_PORT PORTD           // SDA Port D
#define SCL_PORT PORTD           // SCL Port D

;******

;-- map the IO register back into the IO address space
#define SDA_DDR        (_SFR_IO_ADDR(SDA_PORT) - 1)
#define SCL_DDR        (_SFR_IO_ADDR(SCL_PORT) - 1)
#define SDA_OUT         _SFR_IO_ADDR(SDA_PORT)
#define SCL_OUT         _SFR_IO_ADDR(SCL_PORT)
#define SDA_IN         (_SFR_IO_ADDR(SDA_PORT) - 2)
#define SCL_IN         (_SFR_IO_ADDR(SCL_PORT) - 2)

 

With Modifications (Lines 41-56):

;***** Adapt these SCA and SCL port and pin definition to your target !!
;
#define SDA            0
#define SCL            1
#define SDA_PORT       VPORT0_OUT
#define SCL_PORT       VPORT0_OUT     

;******

;-- map the IO register back into the IO address space
#define SDA_DDR        (_SFR_IO_ADDR(SDA_PORT) - 1)
#define SCL_DDR        (_SFR_IO_ADDR(SCL_PORT) - 1)
#define SDA_OUT         _SFR_IO_ADDR(SDA_PORT)
#define SCL_OUT         _SFR_IO_ADDR(SCL_PORT)
#define SDA_IN         (_SFR_IO_ADDR(SDA_PORT) + 1)
#define SCL_IN         (_SFR_IO_ADDR(SCL_PORT) + 1)

3. The next step is to map the appropriate port (the one containing the pins which you will use as the I2C interface) to the virtual port as defined in the modified code above (Virtual Port 0 has been chosen).

For example, the following will make PORTA PIN0 SDA and PORTA PIN1 SCL:
PORTCFG.VPCTRLA = PORTCFG_VP0MAP_PORTA_gc;
(This line of configuration code must be placed in your C source file and should be executed before initializing and using the I2C interface).

Of course, the port and pin mappings can be changed to suit your particular needs.

Note: It is possible to have SDA and SCL on different ports by using two virtual ports. Also note that register VPCTRLA configures Virtual Port 0 and 1 whereas VPCTRLB configures Virtual Port 2 and 3.

4. Next we must modify the i2c_delay_T2 assembly function (also in i2cmaster.S) to give the appropriate delay:

 

Original (Lines 66-83):

;*************************************************************************
; delay half period
; For I2C in normal mode (100kHz), use T/2 > 5us
; For I2C in fast mode (400kHz),   use T/2 > 1.3us
;*************************************************************************
        .stabs    "",100,0,0,i2c_delay_T2
        .stabs    "i2cmaster.S",100,0,0,i2c_delay_T2
        .func i2c_delay_T2    ; delay 5.0 microsec with 4 Mhz crystal
    i2c_delay_T2:    ; 4 cycles
rjmp 1f              ; 2   "
1: rjmp 2f           ; 2   "
2: rjmp 3f           ; 2   "
3: rjmp 4f           ; 2   "
4: rjmp 5f           ; 2   "
5: rjmp 6f           ; 2   "
6: nop               ; 1   "
    ret              ; 3   "
        .endfunc     ; total 20 cyles = 5.0 microsec with 4 Mhz crystal

With Modifications (Lines 66-85):

The following modification assumes a 2MHz clock and that the I2C interface is operating in Normal Mode. Use R17 (thanks Joerg!).

Note: Use the AVR Delay Loop Generator program to generate appropriate ASM delay functions for other combinations of clock frequency and I2C modes.

;*************************************************************************
; delay half period
; For I2C in normal mode (100kHz), use T/2 > 5us
; For I2C in fast mode (400kHz),   use T/2 > 1.3us
;*************************************************************************
        .stabs    "",100,0,0,i2c_delay_T2
        .stabs    "i2cmaster.S",100,0,0,i2c_delay_T2
        .func i2c_delay_T2    ; delay 5.0 microsec with 2 Mhz crystal
    i2c_delay_T2:             ; 4 cycles
; =============================
;    delay loop generator
;     3 cycles:
; -----------------------------
; delaying 3 cycles:
          ldi  R17, 01
WGLOOP0:  dec  R17
          brne WGLOOP0
; =============================
    ret              ; 3 cycles
        .endfunc     ; total 10 cyles = 5.0 microsec with 2 Mhz clock

5. Finally, follow the documentation provided by Peter Fleury (here or in the archive downloaded in Step 1) to correctly initialize and use the I2C interface.

 

Update (5th March 2011): 

This library doesn't seem to work correctly when using the XMEGA internal 32MHz clock (even after modifying the delay routine appropriately). I'll post another update when this issue has been resolved.

 

Update (13th March 2011):

After modifying the delay routine (i2c_delay_T2) to reduce the I2C clock down to 20kHz (or 10kHz), I was able to successfully communicate with my slave device with the XMEGA clock set at 32MHz. Admittedly though however, the slave device (Texas Instruments bq20z65-R1) I used to to test this driver actually uses the SMBus protocol and it therefore must be noted that the SMBus and the I2C bus are usually compatible with each other - with complete compatibility only ensured at clock speeds below 100kHz.

 

Links:

Thursday, February 24, 2011

qt-opencv-multithreaded: v1.12 Released

A custom ROI set with canny edge detection on.

This multithreaded Qt-based OpenCV application was first released mid-January this year on Google Code (here) and since then a few minor changes (mostly coding style and GUI-related) to the original application have been made.

This program was originally written to serve as basic "framework" application for my undergraduate project which required the tracking of multiple moving objects (using OpenCV). The initial implementation of the tracking program simply used a large "while" loop which first captured a frame from the camera and then performed image processing on it - a sequential process. It soon became apparent that as the image processing became quite intensive, not only did the responsiveness of the Qt-based GUI suffer, but the frame processing rate also decreased drastically (resulting in "dropped" frames).

As a result of this, I decided to re-write the entire tracking program from scratch using separate threads for the capturing of frames from the camera and the image processing. This was a logical decision considering the increasing popularity (and low cost!) of multi-core processors in both laptops and desktops nowadays.

I have intentionally kept this program quite simple so it can be easily modified to suit the needs of any Qt GUI-based computer vision project using OpenCV. Several in-built (and user-settable) OpenCV image processing functions have also been included so that multithreading performance can be assessed (see full list of features here).

In short, this application takes advantage of multithreading to allow frames to be captured from the camera while at the same time performing image processing. In other words, once a frame has been captured from the camera, the application does not have to wait until image processing is performed on that frame before it starts capturing a new frame - instead a new frame is captured, added to a FIFO queue and is processed a short time later.

Please go to the project page at Google Code to download and for more details (including installation and usage instructions). Any feedback/suggestions/questions concerning this "framework" application would be greatly appreciated. I hope it serves as a basis for many interesting computer vision projects in the future!


Processing Settings dialog used to customize the in-built OpenCV functions.

Links: