Blame | Last modification | View Log | Download
/** Copyright (C) 2004 Darren Hutchinson (dbh@gbdt.com.au)** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU Library General Public License as published by* the Free Software Foundation; either version 2 of the License, or (at your* option) any later version.** This program is distributed in the hope that it will be useful, but* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public* License for more details.** You should have received a copy of the GNU Library General Public License* along with this software; see the file COPYING. If not, write to* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,* MA 02111-1307, USA.** $Id: driver.c,v 1.4 2004/04/04 06:54:05 dbh Exp $*//* This file contains the code that takes the excitation values for each* coil (determined by the stepper module) and performs a crude PWM* and generates the output values for the stepper drivers.** This module has it's own timer at a high frequency timer, so efficiency* is an important issue.*/#include <avr/io.h>#include <avr/interrupt.h>#include <inttypes.h>#include "eq6.h"#include "stepper.h"#include "driver.h"/* Like the stepper.h module this one is heavily table-driven. Basically* each excitation value corresponds to 4, 8 bit lists of values are used* for 8 clock cycles. This gives a crude PWM system.** The hardware is orginized such that both "ends" of a coil are in* adjacent bits, so each pair of 8 bits is interleaved into a single* 16 bit word where the bits are used two at a time.** Note: The high side and low side tables here were different - basically if* a high side was driven for one coil, the low side should be driven for the* other.** However the low side bits are reversed because of the bit numbers running* in the opposite direction for Port A (low side) vs Port C (high side), so* it turns out that the same table can be used for both!** Of course the bits for the coils are composed in the opposite direction* too, but that happens below*/uint8_t driveTbl[] ={[EX_M_1] = 0xaa,[EX_M_0_67] = 0x2a,[EX_M_0_4] = 0x22,[EX_M_0_2] = 0x02,[EX_0] = 0x00,[EX_P_0_2] = 0x01,[EX_P_0_4] = 0x11,[EX_P_0_67] = 0x15,[EX_P_1] = 0x55};#define PWM_RATE 48000 /* PWM update speed */#define PWM_STEPS 4 /* Steps per PWM cycle *//* driverInit() initializes the port used by the stepper motors and the timer* used to update the stepper driver state** Passed:* Nothing** Returns:* Nothing**/voiddriverInit(void){/* Set up port A and C as outputs and set them to a safe default state* i.e. no outputs driven*/PORTA = 0x00; // Disable high-side driversDDRA = 0xff; // Set as outputsPORTC = 0xff; // Disable low-side driversDDRC = 0xff; // Set as outputs/* Setup the "magic" relay bit as an output */MAGIC_PORT &= ~_BV(MAGIC_BIT);MAGIC_DDR |= _BV(MAGIC_BIT);/* Setup timer 0 to generate interrupts for PWM */OCR0 = (CLK_RATE / PWM_RATE / 8);TCCR0 = _BV(WGM01) | _BV(CS01); // Divied by 8, CTC mode/* Enable interrupt generation from timer 0 */TIMSK |= _BV(OCIE0);}/* driverInt() is called whenever a timer 0 overflow interrupt occurs** Passed:* Nothing** Returns:* Nothing*/SIGNAL(SIG_OUTPUT_COMPARE0){static uint8_t raCoil1States;static uint8_t raCoil2States;static uint8_t decCoil1States;static uint8_t decCoil2States;static uint8_t ctr = PWM_STEPS - 1;uint8_t highSidePort;uint8_t lowSidePort;// PORTA = ~excitation.ra;// PORTC = ~excitation.dec;/* Increment the step count. Reinitialize the states entries* if the counter wraps around*/if (++ctr == PWM_STEPS){uint8_t tmp;ctr = 0;/* Update states */tmp = _GET_C1(raExcitation.excitation);raCoil1States = driveTbl[tmp];tmp = _GET_C2(raExcitation.excitation);raCoil2States = driveTbl[tmp];tmp = _GET_C1(decExcitation.excitation);decCoil1States = driveTbl[tmp];tmp = _GET_C2(decExcitation.excitation);decCoil2States = driveTbl[tmp];/* Update magic relay state */if (raExcitation.useRelay)MAGIC_PORT &= ~_BV(MAGIC_BIT);elseMAGIC_PORT |= _BV(MAGIC_BIT);}/* Build the high_side driver output value */highSidePort = decCoil2States & 0x3;highSidePort <<= 2;highSidePort |= decCoil1States & 0x3;highSidePort <<= 2;highSidePort |= raCoil2States & 0x3;highSidePort <<= 2;highSidePort |= raCoil1States & 0x3;/* Build the low-side driver states. Note that, due to the* reverse pin pordering for Port A vs Port C that these are built in* the opposite direction*/lowSidePort = raCoil1States & 0x3;lowSidePort <<= 2;raCoil1States >>= 2;lowSidePort |= raCoil2States & 0x3;lowSidePort <<= 2;raCoil2States >>= 2;lowSidePort |= decCoil1States & 0x3;lowSidePort <<= 2;decCoil1States >>= 2;lowSidePort |= decCoil2States & 0x3;decCoil2States >>= 2;/* Potential safety check: rev (PortA) & PortC == 0 *//* Write the values to the output ports */PORTC = highSidePort;PORTA = ~lowSidePort;}