Subversion Repositories group.electronics

Rev

Rev 139 | 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/interrupt.h>
#include <string.h>
#include <util/delay.h>
#include <stdlib.h>

#include "config.h"
#include "avrutil.h"
#include "hc595.h"
#include "twires.h"


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


void writeSegment(uint8_t digit, uint8_t value);
void pcInterrupt(void);
void receiveEvent(uint8_t bytes);

/* ------------------------------------------------------------------------- */


#ifndef TWI_RX_BUFFER_SIZE
#define TWI_RX_BUFFER_SIZE ( 16 )
#endif

volatile uint8_t user_debug = 0;
volatile uint8_t tmr0_ovf = 0;
volatile struct {
        uint8_t current;
        uint8_t last;
        uint8_t mask;
} pcInt;

volatile struct {
        int8_t outer;
        int8_t inner;
} input;

//volatile uint8_t doInt = 0;


//uint8_t disVal[] = {8,8,8,8,8,8,8,8,8,8};
volatile uint8_t disVal[] = {0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a};
volatile uint16_t disPt = 0x00;

int main(void) {


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


  /*
        PA0 -   Output          - HC595 DS
        PA1 -   Output          - HC595 ST
        PA2 -   Output          - HC595 SH
        PA3 -   Output          - 4511 blanking
        PA4 -   SCK
        PA5 -   Output          - Decimal Point
        PA6 -   SDA
        PA7 -   Input, Pullup   - Flip button
  */
  DDRA          = 0B00101111;
  PORTA         = 0B10001000;
  /*
        PB0     - Input, PCInt, Pullup  - Rot1a
        PB1     - Input, PCInt, Pullup  - Rot1b
        PB2     - Input, Pullup         - Swap button
        PB3     - N/A                   - Reset (Future - I2C address select)
  */
  DDRB          = 0B00000000;
  PORTB         = 0B00000111;

    systime = 0;
    sysclockInit();

    PCMSK1 |= (( 1 << ROT_1A_PIN ) | ( 1 << ROT_1B_PIN ));
    GIMSK |= (1 << PCIE1);

    pcInt.last = ROT_1_PIN;
    pcInt.current = pcInt.last;
    pcInt.mask = 0;

    twires_begin(I2C_SLAVE_ADDR);
    twires_onReceive(receiveEvent);

    wdt_enable(WDTO_1S);        // Watchdog for 1 sec
    sei();                      // Enable interrupts

    uint32_t refresh = systime;
    uint8_t disIdx = 0;

    // Init and clear the displays
    hc595_init();
    hc595_write(0x00);



    for(;;){
         wdt_reset();

        if (user_debug) {
                disVal[9] = rbi(SB_INPUT, SB_PIN);
                disVal[8] = rbi(FB_INPUT, FB_PIN);
                disVal[0] = input.outer & 0x0f;
                disVal[1] = input.outer >> 4;
        }

                if (pcInt.current != pcInt.last) {
                        cli();          // Dont process interrupts for a bit
                        pcInterrupt();
                        sei();
                }

                if (systime > refresh) {
                        writeSegment(disIdx, disVal[disIdx]);
                        refresh = systime + DISPLAY_REFRESH;
                        disIdx++;
                        if (disIdx > 10) disIdx = 0;
                }

                twires_stop_check();
    }
    return 0;
}

void receiveEvent(uint8_t bytes) {
        uint8_t cmd = twires_receive();
        bytes--;
        switch (cmd) {
                case (0x01): {
                        // Send 2 bytes with version details
                        twires_send(HW_VERSION);
                        twires_send(SW_VERSION);
                }
                        break;
                case (0x03): {
                        // Enable debugging mode
                        user_debug = twires_receive();
                }
                        break;
                case (0x05): {
                        // Receive n numbers of digits to DISPLAY_REFRESH
                        // High nibble = segment number
                        // Low nibble = digit to display
                        while (bytes--) {
                                uint8_t data = twires_receive();
                                disVal[(data >> 4)] = (data & 0x0f);
                        }
                }
                        break;
                case (0x08): {
                        // Recieve 2 bytes, for the decimal points
                        //  5 bits used in eac byte
                        disPt = (uint16_t)twires_receive() << 8;
                        disPt |= (uint16_t)twires_receive();
                }
                        break;
                case (0x09): {
                        // Reset the rotary
                        input.outer = 0;
                        input.inner = 0;
                }
                        break;
                case (0x0a): {
                        // Send the value of the rotary count
                        twires_send(input.outer);
                }
                        break;
                /* Not used in this version
                case (0x0b): {
                        twires_send(input.inner);
                }
                        break;
                */

                case (0x0c): {
                        // Send that status of the buttons
                        uint8_t out = (!rbi(SB_INPUT, SB_PIN)) << 1;
                        out |= (!rbi(FB_INPUT, FB_PIN));
                        twires_send(out);
                }
                /* Comined into 0x0c
                case (0x0d): {
                        twires_send(rbi(FB_INPUT, FB_PIN));
                }
                        break;
                */
                default: {
                        // Don't know what it is, empty buffer
                        while (twires_available())
                                twires_receive();
                }
                        break;
        }
}

void writeSegment(uint8_t digit, uint8_t value) {
        //uint8_t dp = 0;
        //if (digit <= 4 && rbi(disPt[0], digit)) dp = 1;
        //if (digit > 4 && rbi(disPt[1], digit-5)) dp = 1;

        cbi(BL_PORT, BL_PIN);                   // Blank the 4511
        cbi(DP_PORT, DP_PIN);                   // Drop the DP before changing digit

// Changed my mind and reversed order of digit display for release version
//   0-9 is left to right on release, right to left on prototype
//   This below hack for the prototype means i didn't have to change the ls145n
//       connections, but have been changed on the release version
#ifdef PROTOTYPE
        hc595_write((value << 4) | (9-(digit & 0x0f))); //Write the value and digit
#else
        hc595_write((value << 4) | (digit & 0x0f)); //Write the value and digit
#endif
        if (rbi(disPt, digit)) sbi(DP_PORT, DP_PIN);            // Add DP if required
        sbi(BL_PORT, BL_PIN);                   // Enable the 4511
}

void pcInterrupt() {
        pcInt.mask = pcInt.current ^ pcInt.last;
        pcInt.last = pcInt.current;

        if (!pcInt.mask)
                return;

        // Check which pin caused the interrupt. If they both
        //  equal 0 || 1, the pin that interrupted is the direction
        if (((rbi(pcInt.current, ROT_1A_PIN) == 1 &&
             rbi(pcInt.current, ROT_1B_PIN) == 1) ||
             (rbi(pcInt.current, ROT_1A_PIN) == 0 &&
              rbi(pcInt.current, ROT_1B_PIN) == 0))) {

                if (rbi(pcInt.mask, ROT_1A_PIN) ) {
                        input.outer += 1;
              } else if (rbi(pcInt.mask, ROT_1B_PIN) ) {
                input.outer -= 1;
            }

        }
        // Clear the mask so we know we've dealt with it
        // Shouldn't be required now that 'doInt' has been removed
        //pcInt.mask = 0;

}

ISR(PCINT1_vect) {
        pcInt.current = ROT_1_PIN;
}

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>=15) {
                        systime++;
                        tmr0_ovf = 0;
        }

}