Subversion Repositories group.electronics

Rev

Rev 139 | Rev 150 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>

#include "config.h"
#include "avrutil.h"
#include "usbdrv.h"
#include "i2cbb.h"


#ifndef NULL
#define NULL    ((void *)0)
#endif

void usbEventResetReady(void);
static void calibrateOscillator(void);
static void updateDisplay(uint8_t dis);
static void updateInput();

//static void requestData(uint8_t addr, uint8_t code, uint8_t* data, uint8_t len);

void print16(uint8_t dis, uint8_t dig, uint16_t val);

#define DISPLAY_ATTACHED 1
#define INPUT_REFRESH 5

struct display_type {
        uint8_t address;
        uint8_t value[10];
        uint16_t decpts;

        uint8_t rotary;         // State of the rotary encoder
        uint8_t buttons;        // State of the buttons
} display[2];



static uint8_t usbReplyBuf[8];
static uint8_t update = 255;


volatile uint8_t tmr0_ovf = 0;


int main(void) {
        // calibration value from last time
        uchar   calibrationValue;
        calibrationValue = eeprom_read_byte(0);
        if(calibrationValue != 0xff){
                OSCCAL = calibrationValue;
        }

        /*
                DDR : 1 = Output, 0 = Input
                PORT: 1 = Pullup for Input, otherwise set output
                PIN : Read input pin

                PB0     -
                PB1     -               - USB D- Low Speed
                PB2     -               - USB D+
                PB3     -               - SCL i2c bb
                PB4     -               - SDA i2c bb
                PB5     -
        */
        DDRB          = 0B00000001;
        PORTB         = 0B00000001;


    usbDeviceDisconnect();
    _delay_ms(500);
    usbDeviceConnect();

    systime = 0;
    uint32_t refresh = 0;
    sysclockInit();

    wdt_enable(WDTO_1S);
    usbInit();
    sei();


    // Set the displays to blank
    display[0].address = 0x26;
    display[0].decpts = 0x00;
    uint8_t i;
    for (i=0; i<DISPLAY_ATTACHED; i++) {
        uint8_t j;
        for (j=0; j<10; j++)
                display[i].value[j] = 0x0a;
        updateDisplay(i);
    }

    for(;;){
         wdt_reset();
         usbPoll();

        // Only update the display when a change
        //  comes in fron the usb port
        if (update != 255) {
                updateDisplay(update);
                update = 255;
        }

                if (systime > refresh) {
                        refresh = systime + 5;
                        updateInput();
                }
    }
    return 0;
}

static void updateInput() {
        /*
        uint8_t data[1];
        requestData(0x4c, 0x0a, data, 1);
        display[0].rotary = data[0];
        requestData(0x4c, 0x0c, data, 1);
        display[0].buttons = data[0];
        */


        i2cbb_Init();
        i2cbb_Start();
        i2cbb_Write( 0x4c );
        i2cbb_Write( 0x0a );
        i2cbb_Stop();

        i2cbb_Start();
        i2cbb_Write( 0x4d );
        display[0].rotary = i2cbb_Read(1);
        i2cbb_Stop();

        i2cbb_Init();
        i2cbb_Start();
        i2cbb_Write( 0x4c );
        i2cbb_Write( 0x0c );
        i2cbb_Stop();

        i2cbb_Start();
        i2cbb_Write( 0x4d );
        display[0].buttons = i2cbb_Read(1);
        i2cbb_Stop();

}

/*
static void requestData(uint8_t addr, uint8_t code, uint8_t* data, uint8_t len) {
        i2cbb_Init();
        i2cbb_Start();
        i2cbb_Write( addr );
        i2cbb_Write( code );
        i2cbb_Stop();

        uint8_t i;
        i2cbb_Write( addr + 1 );
        for (i=0; i<len; i++)
                data[i] = i2cbb_Read(1);
        i2cbb_Stop();
}
*/

static void updateDisplay(uint8_t dis) {
    cbi(PORTB, PB0);

    // Send the display buffer to display board
    i2cbb_Init();
    i2cbb_Start();
    i2cbb_Write(0x4c);
    i2cbb_Write(0x05);
    uint8_t n;
    for (n=0; n<10; n++) {
        uint8_t send = (n << 4) | display[0].value[n];
        i2cbb_Write( send );
    }
    i2cbb_Stop();

    /*
    // Send the decimal point
        i2cbb_Init();
        i2cbb_Start();
        i2cbb_Write( 0x4c );
        i2cbb_Write(0x08);
        i2cbb_Write((uint8_t)(display[dis].decpts>>8));
        i2cbb_Write((uint8_t)display[dis].decpts);
        i2cbb_Stop();
        */

    sbi(PORTB, PB0);
}

#define USB_SET_LATCH                   20
#define USB_SET_DISPLAY1                21
#define USB_SET_DISPLAY2                22

#define USB_GET_INPUT                   30

#define USB_SET_INT16                   50

usbMsgLen_t usbFunctionSetup(uchar data[8])
{
    usbRequest_t    *rq = (void *)data;

        switch (rq->bRequest ) {
                case USB_SET_LATCH: {
                        update = 0;
                        break;
                }
                case USB_SET_DISPLAY1: {
                        uint8_t dis = rq->wValue.bytes[1];
                        uint8_t dig = rq->wValue.bytes[0];
                        //uint8_t dp = rq->wIndex.bytes[1];
                        uint8_t val = rq->wIndex.bytes[0];
                        display[dis].value[dig] = val;
                        /*
                        if (dp)
                                sbi(display[dis].decpts, 1 << dig);
                        else
                                cbi(display[dis].decpts, 1 << dig);
                        //display[dis].decpts |= dp << dig;*/
                        break;
                }
                case USB_SET_INT16: {
                        uint8_t dis = rq->wValue.bytes[1];
                        uint8_t dig = rq->wValue.bytes[0];
                        uint16_t val = ((uint16_t)rq->wIndex.bytes[1]) << 8;
                        val |= (rq->wIndex.bytes[0] & 0x0f);
                        print16(dis, dig, val);
                        break;
                }
                case USB_GET_INPUT: {
                        usbReplyBuf[0] = display[0].buttons;
                        usbReplyBuf[1] = display[0].rotary;
                        usbMsgPtr = usbReplyBuf;
                        return sizeof(usbReplyBuf);
                }

        }
        return 0;
}

void print16(uint8_t dis, uint8_t dig, uint16_t val) {
        uint8_t buf[] = {0x0a, 0x0a, 0x0a, 0x0a, 0x0a};
        uint8_t len = itobcd16(val, buf);

        uint8_t i;
        for (i=0; i<5; i++) {
                if (i < len)
                        display[dis].value[dig+i] = buf[i];
        }
}

static void calibrateOscillator(void) {
    uchar step = 128;
    uchar trialValue = 0, optimumValue;
    int x, optimumDev;
    int targetValue = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5);

    /* do a binary search: */
    do {
        OSCCAL = trialValue + step;
        x = usbMeasureFrameLength();    /* proportional to current real frequency */
        if(x < targetValue)             /* frequency still too low */
            trialValue += step;
        step >>= 1;
    } while(step > 0);
    /* We have a precision of +/- 1 for optimum OSCCAL here */
    /* now do a neighborhood search for optimum value */
    optimumValue = trialValue;
    optimumDev = x; /* this is certainly far away from optimum */
    for(OSCCAL = trialValue - 1; OSCCAL <= trialValue + 1; OSCCAL++){
        x = usbMeasureFrameLength() - targetValue;
        if(x < 0)
            x = -x;
        if(x < optimumDev){
            optimumDev = x;
            optimumValue = OSCCAL;
        }
    }
    OSCCAL = optimumValue;
}


void usbEventResetReady(void) {
    cli();
    calibrateOscillator();
    sei();
    eeprom_write_byte(0, OSCCAL);   /* store the calibrated value in EEPROM */
}

ISR(TIM0_OVF_vect) {

        tmr0_ovf++;

        // Clk/1 TCCR0B = (1<< CS00);
        //20.0Mhz, 1ms = 78ovf
        //16.5Mhz, 1ms = 64ovf
        //16.0Mhz, 1ms = 62ovf
        //12.0Mhz, 1ms = 46ovf
        // 8.0Mhz, 1ms = 31ovf
        // 8.0Mhz, .5ms = 15ovf, 160r

        if (tmr0_ovf>=64) {
                        systime++;
                        tmr0_ovf = 0;
        }

}