Example Source Code:
ME-110 Unicoder Generic C Interface

Description

This example consists of general purpose routines to interface with the unique control interface in the AS5040 sensor chip contained in the Nubotics ME-110. This interface is somewhat similar to SPI. More information can be found on the Austria Microsystems website.

To make this code run on a given microcontroller, you will need to provide your own implementations of delay_us(), set_bit(), clear_bit(), change_bit_to_output(), and change_bit_to_input().


 

Download

as5040.c - C source
as5040.h - header file

 

Source Code


as5040.c


//---------------------------------------------------
// Unicoder C Demo
//
// Copyright 2009, Noetic Design, Inc.
//
// This set of generic C code shows how to access
// the registers of the Unicoder ME-110 encoder.
//---------------------------------------------------

// AS5040 support routines

#include "stdint.h" // or whatever header defines support routines and data types...

BOOL good_checksum;
WORD read_back;
WORD prog_reg;
WORD factory;


// implementation-dependent functions
// to be supplied by user

void delay_us(int8 microseconds)
{
    // delay the requested number of microseconds...
    // TBD
}

void control_cs(BOOL set, BOOL long_time)
{
    if (set)
        set_bit(AS_CS);     // replace set_bit() with platform-specific method to set an output pin to 1
    else
        clear_bit(AS_CS);   // replace clear_bit() with platform-specific method to clear an output pin to 0
    delay_us(long_time ? 6 : 1);
}

void control_clk(BOOL set, BOOL long_time)
{
    if (set)
        set_bit(AS_CLK);
    else
        clear_bit(AS_CLK);
    delay_us(long_time ? 6 : 1);
}

void control_prog(BOOL set, BOOL long_time)
{
    if (set)
        set_bit(AS_PROG);
    else
        clear_bit(AS_PROG);
    delay_us(long_time ? 6 : 1);
}

// ******************************
// generic AS5040 access routines
// ******************************


// initialize chip for access

void init_as5040(void)
{
    int i;

    good_checksum = FALSE;

// set I/O up
    change_bit_to_output(AS_CS);                            // replace with platform-specific routines
    change_bit_to_output(AS_CLK);
    change_bit_to_output(AS_PROG);
    change_bit_to_input(AS_DO);

// shift out factory settings
    control_cs(TRUE, FALSE);                                // AS_CS = 1;
    control_clk(FALSE, TRUE);                               // AS_CLK = 0;
    control_prog(TRUE, TRUE);                               // AS_PROG = 1;
    for (i = 0; i < 16; i++)
    {
        control_clk(TRUE, TRUE);                            // AS_CLK = 1;
        control_clk(FALSE, TRUE);                           // AS_CLK = 0;
    }
    control_clk(TRUE, TRUE);                                // AS_CLK = 1;
    control_prog(FALSE, TRUE);                              // AS_PROG = 0;
    control_clk(FALSE, TRUE);                               // AS_CLK = 0;
    control_clk(TRUE, TRUE);                                // AS_CLK = 1;

    get_factory_register();                                 // read factory settings; must be retained
}


// get the current angle and status BOOLs

int16 get_orientation(void)
{
    int i;
    int chksum = 0;
    int16 orientation = 0;

    control_clk(TRUE, FALSE);                               // AS_CLK = 1;  // from smact
    control_cs(TRUE, FALSE);                                // AS_CS = 1;
    control_cs(FALSE, FALSE);                               // AS_CS = 0;
    for (i = 0; i < 16; i++)
    {
        control_clk(FALSE, FALSE);                          // AS_CLK = 0;
        control_clk(TRUE, FALSE);                           // AS_CLK = 1;
        orientation <<= 1;
        orientation |= get_bit(AS_DO);                      // replace get_bit() with platform-specific method to read an input pin
        if (i < 13)
            chksum ^= get_bit(AS_DO);
    }

    if (chksum == (orientation & 0x01))
        good_checksum = 1;
    else
        good_checksum = 0;
    orientation >>= 1;                                       // remove parity BOOL
    delay_us(1);
    return orientation;
}




void set_prog_register(WORD value)
{
    int i;
    WORD mask = 0x8000;
    WORD output;

// base line state
    control_prog(FALSE, FALSE);                             // AS_PROG = 0; // from smact
    control_clk(TRUE, FALSE);                               // AS_CLK = 1;
    control_cs(TRUE, FALSE);                                // AS_CS = 1;

    control_cs(FALSE, TRUE);                                // AS_CS = 0; // from smact
    control_clk(FALSE, TRUE);                               // AS_CLK = 0;
    control_prog(TRUE, TRUE);                               // AS_PROG = 1;
    control_cs(TRUE, TRUE);                                 // AS_CS = 1;
    prog_reg = value;
    output = factory;
    
    for (i = 0; i < 32; i++)
    {
        control_prog(((output & mask) != 0), TRUE);  // output most significant BOOL first
        if (i == 15)
            output = value;
        mask >>= 1;
        if (!mask)
            mask = 0x8000;
        control_clk(TRUE, TRUE);                             // AS_CLK = 1;
        control_clk(FALSE, TRUE);                            // AS_CLK = 0;
    }
    control_prog(FALSE, TRUE);                               // AS_PROG = 0;
    control_cs(FALSE, TRUE);                                 // AS_CS = 0;
    control_cs(TRUE, TRUE);                                  // by observation of demo, pulse cs low, then raise clock and leave high
    control_clk(TRUE, TRUE);                                 // AS_CLK = 1;
}

void get_factory_register(void)
{
    int i;
    WORD mask = 0x8000;
    WORD output;

// base line state
    control_prog(FALSE, FALSE);                             // AS_PROG = 0; // from smact
    control_clk(TRUE, FALSE);                               // AS_CLK = 1;
    control_cs(TRUE, FALSE);                                // AS_CS = 1;

    control_cs(FALSE, TRUE);                                // AS_CS = 0; // from smact
    control_clk(FALSE, TRUE);                               // AS_CLK = 0;
    control_prog(TRUE, TRUE);                               // AS_PROG = 1;
    control_cs(TRUE, TRUE);                                 // AS_CS = 1;
    read_back = 0;
    control_cs(FALSE, TRUE);                                // AS_CS = 0;
    control_clk(TRUE, TRUE);                                // AS_CLK = 1;
    control_clk(FALSE, TRUE);                               // AS_CLK = 0; per app note AN 5040-20

    set_bit(AS_CS);                                         // AS_CS = 1;
    change_bit_to_input(AS_PROG);                           // make Prog read only; first BOOL is now available
                                                            // replace with platform-specific routine to make a pin an input
    delay_us(6);
    for (i = 0; i < 32; i++)
    {
        if (get_bit(AS_PROG))
            read_back |= mask;
        if (i == 15)
        {
            factory = read_back;
            read_back = 0;
        }
        mask >>= 1;
        if (!mask)
            mask = 0x8000;
        control_clk(TRUE, TRUE);                             // AS_CLK = 1;
        control_clk(FALSE, TRUE);                            // AS_CLK = 0;
    }
    set_bit(AS_CLK);                                         // AS_CLK = 1;
    change_bit_to_output(AS_PROG);                           // make Prog push/pull again; replace with platform-specific routine to make a pin an output
    delay_us(6);
    control_cs(FALSE, TRUE);                                 // AS_CS = 0;
    control_prog(FALSE, TRUE);                               // AS_PROG = 0;
    control_clk(FALSE, TRUE);                                // AS_CLK = 0;
    
    control_cs(TRUE, TRUE);                                  // by observation of demo, pulse cs low, then raise clock and leave high
    control_clk(TRUE, TRUE);                                 // AS_CLK = 1;
}


void enter_alignment_mode(void)
{
    control_prog(FALSE, TRUE);                              // start with this low
    control_cs(FALSE, TRUE);                                // and this low too
    control_cs(TRUE, TRUE);                                 // this goes high
    control_prog(TRUE, TRUE);                               // then this
    control_cs(FALSE, TRUE);                                // now this goes low -- now in alignment mode
    control_prog(FALSE, TRUE);                              // and then this can go low
}

as5040.h


// AS5040 support routines

#ifndef _AS5040_H_
#define _AS5040_H_

// change to match your micro's connections to these pins on the Unicoder ME-110:
#define AS_CS   0x01
#define AS_CLK  0x02
#define AS_DO   0x04
#define AS_PROG 0x08
#define AS_SDA  0x10
#define AS_SCL  0x20
#define AS_CHA  0x40
#define AS_CHB  0x80

typedef struct _as5040 {
   int16 par : 1;
   int16 mag_dec : 1;
   int16 mag_inc : 1;
   int16 lin : 1;
   int16 cof : 1;
   int16 ocf : 1;
   int16 angle : 10;
} AS5040;


typedef struct _as5040_prog {
   int16 mode : 2;
   int16 div : 2;
   int16 index : 1;
   int16 z : 10;
   int16 ccw : 1;
} AS5040PROG;

#define AP_QUAD_512 0x0001 // 0000 0000 0000 0001
#define AP_QUAD_256 0x0005 // 0000 0000 0000 0101
#define AP_QUAD_128 0x0009 // 0000 0000 0000 1001
#define AP_QUAD_64  0x000D // 0000 0000 0000 1101
#define AP_SNMG_512 0x0002 // 0000 0000 0000 0010
#define AP_SNMG_256 0x0006 // 0000 0000 0000 0110
#define AP_SNMG_128 0x000A // 0000 0000 0000 1010
#define AP_SNMG_64  0x000E // 0000 0000 0000 1110

#define APM_MODE  0x0002
#define APR_MODE  0
#define APM_DIV   0x0002
#define APR_DIV   2
#define APM_INDEX 0x0001
#define APR_INDEX 4
#define APM_Z     0x03ff
#define APR_Z     5
#define APM_CCW   0x0001
#define APR_CCW   15

extern WORD factory;
extern bit good_checksum;
extern void delay(void);
extern void long_delay(void);
extern int16 get_orientation(void);
extern void set_prog_register(WORD value, bit read_fact);
extern void init_as5040(void);
extern void enter_alignment_mode(void);

extern void control_cs(bit set, bit long_time);
extern void control_clk(bit set, bit long_time);
extern void control_prog(bit set, bit long_time);

#endif


 

 © 2004-2011 Noetic Design, Inc. All Rights Reserved. Nubotics and WheelWatcher are trademarks of Noetic Design, Inc.