Subversion Repositories Projects

Rev

Blame | Last modification | View Log | RSS feed

/*****************************************************************************
 *   Copyright (C) 2009 Peter "woggle" Mack, mac@denich.net                  *
 *                                                                           *
 *   This program is free software; you can redistribute it and/or modify    *
 *   it under the terms of the GNU General Public License as published by    *
 *   the Free Software Foundation; either version 2 of the License.          *
 *                                                                           *
 *   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 General Public License for more details.                            *
 *                                                                           *
 *   You should have received a copy of the GNU General Public License       *
 *   along with this program; if not, write to the                           *
 *   Free Software Foundation, Inc.,                                         *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.               *
 *                                                                           *
 *****************************************************************************/


#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <string.h>
#include <util/twi.h>

#include "main.h"
#include "motortest.h"
#include "lcd.h"
#include "usart.h"
#include "timer.h"


uint8_t m;


#define SCL_FREQ  200000L

#define I2C_STATE_TX_ADDRESS    0
#define I2C_STATE_TX_DATA                       1
#define I2C_STATE_TX_STOP                       2
#define I2C_STATE_RX_ADDRESS    3
#define I2C_STATE_RX_1BYTE              4
#define I2C_STATE_RX_2BYTE              5

volatile uint8_t i2c_state;
volatile uint8_t motor_addr = 0;

//*****************************************************************************
//
void I2C_Init(void)
{
        uint8_t sreg = SREG;
        cli();
       
        DDRC  &= ~(1<<DDC1);    // SDA is input
        DDRC |= (1<<DDC0);              // SCL is output
        PORTC |= (1<<PORTC0)|(1<<PORTC1);       // pull up SDA and SCL
       
        // prescaler 1 (TWPS1 = 0, TWPS0 = 0)
        TWSR &= ~((1<<TWPS1)|(1<<TWPS0));

        TWBR = ((F_CPU/SCL_FREQ)-16)/2;
       
        i2c_state = I2C_STATE_TX_ADDRESS;

        SREG = sreg;
}

//*****************************************************************************
//
void I2C_Start(uint8_t start_state)
{
        i2c_state = start_state;

        // generate start condition and enable interrupts
        TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN) | (1<<TWIE);
}

//*****************************************************************************
//
void I2C_Stop(uint8_t start_state)
{
        i2c_state = start_state;

        // generate stop condition and disable interrupt
        TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);
}

//*****************************************************************************
//
void I2C_WriteByte(int8_t b)
{
        TWDR = b;
        // clear interrupt flag (TWINT = 1)
        // enable i2c bus (TWEN = 1)
        // enable interrupt (TWIE = 1)
        TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWIE);
}

//*****************************************************************************
//
void I2C_ReceiveByte(void)
{
        TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWIE) | (1<<TWEA);
}

//*****************************************************************************
//
void I2C_ReceiveLastByte(void)
{
        TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWIE);
}


//*****************************************************************************
//
ISR (TWI_vect)
{
        int8_t mrCurrent;
        int8_t mrMaxpwm;
       
        switch (i2c_state++)
        {
                // TWI Master Transmit
                case I2C_STATE_TX_ADDRESS:
                        I2C_WriteByte(0x52 + (motor_addr * 2) ); // select slave adress in tx mode
                        break;

                case I2C_STATE_TX_DATA:
                        I2C_WriteByte(m);
                        break;

                case I2C_STATE_TX_STOP:
                        if(TWSR == TW_MT_DATA_NACK) // Data transmitted, NACK received
                        {
                                // error occured
                        }
                        I2C_Stop(I2C_STATE_TX_ADDRESS);
                        I2C_Start(I2C_STATE_RX_ADDRESS); // Repeated start -> switch slave or switch Master Transmit -> Master Receive
                        break;

                        // Master Receive Data
                case I2C_STATE_RX_ADDRESS:
                        I2C_WriteByte(0x53 + (motor_addr * 2) ); // select slave adress in rx mode
                        if(TWSR != TW_MR_SLA_ACK) //  SLA+R transmitted, if not ACK received
                        {       // no response from the addressed slave received
                                I2C_Stop(I2C_STATE_TX_ADDRESS);
                        }
                        else
                        {
                                I2C_ReceiveByte(); //Transmit 1st byte
                        }
                        break;

                case I2C_STATE_RX_1BYTE: //Read 1st byte and transmit 2nd Byte
                        mrCurrent = TWDR;
                        I2C_ReceiveLastByte(); // nack
                        break;

                case I2C_STATE_RX_2BYTE:
                        //Read 2nd byte
                        mrMaxpwm = TWDR;;
                        I2C_Stop(I2C_STATE_TX_ADDRESS);
                        break;
                       
                default:
                        I2C_Stop(I2C_STATE_TX_ADDRESS);
                        break;
        }
}

//*****************************************************************************
//
void motor_i2c (void)
{
        uint8_t blc = 0;
       
        lcd_cls ();
        m = 0;
       
        lcd_printp (PSTR("I2C Motor Test"), 0);
        lcd_printpns_at (0, 7, PSTR("dec  inc    Exit Off"), 0);
       
        lcd_printp (PSTR("BLC #"), 0);
       
        do
        {
                if ((get_key_press (1 << KEY_PLUS) || get_key_rpt (1 << KEY_PLUS)) && (m < 254))
                {
                        m++;
                }
                if ((get_key_press (1 << KEY_MINUS) || get_key_rpt (1 << KEY_MINUS)) && (m > 0))
                {
                        lcd_frect (GX, GY, (m * 108) / 255, 10, 0);
                        m--;
                }
                if (get_key_press (1 << KEY_ENTER))
                {
                        lcd_frect (GX, GY, (m * 108) / 255, 10, 0);
                        m = 0;
                }
        }
        while (!get_key_press (1 << KEY_ESC));
       
        // switch all engines off at exit !
}


//*****************************************************************************
//
void motor (uint8_t m)
{
        memset (buffer, m, 16);
#if 0
        buffer[0] = m;  // 0
        buffer[1] = m;  // 1
        buffer[2] = m;  // 2
        buffer[3] = m;  // 3
        buffer[4] = m;  // 4
        buffer[5] = m;  // 5
        buffer[6] = m;  // 6
        buffer[7] = m;  // 7
        buffer[8] = m;  // 8
        buffer[9] = m;  // 9
        buffer[10] = m; // 10
        buffer[11] = m; // 11
        buffer[12] = m; // 12
        buffer[13] = m; // 13
        buffer[14] = m; // 14
        buffer[15] = m; // 15
#endif
        SendOutData('t', ADDRESS_FC, 1, buffer, 16);
       
        // hier könnte man noch eine I2C-Ausgabe einbauen...
       
        lcd_frect (GX, GY, (m * 108) / 255, 10, 1);
        write_ndigit_number_u (MX, MY, m, 3, 0);
}

//*****************************************************************************
//
void motor_test (void)
{
        //uint8_t m;

        lcd_cls ();
        m = 0;

        lcd_printp (PSTR("Motor Test"), 0);
        lcd_printpns_at (0, 7, PSTR("dec  inc    Exit Off"), 0);

        if (hardware == NC && current_hardware == NC)
        {
                SwitchToFC();
        }
       
        motor (m);

        do
        {
                if ((get_key_press (1 << KEY_PLUS) || get_key_rpt (1 << KEY_PLUS)) && (m < 254))
                {
                        m++;
                }
                if ((get_key_press (1 << KEY_MINUS) || get_key_rpt (1 << KEY_MINUS)) && (m > 0))
                {
                        lcd_frect (GX, GY, (m * 108) / 255, 10, 0);
                        m--;
                }
                if (get_key_press (1 << KEY_ENTER))
                {
                        lcd_frect (GX, GY, (m * 108) / 255, 10, 0);
                        m = 0;
                }
                motor (m);
        }
        while (!get_key_press (1 << KEY_ESC));

        // switch all engines off at exit !
        motor (0);
}