Subversion Repositories group.NITPanels

Rev

Rev 2 | 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;

uint8_t i2c_address = I2C_SLAVE_ADDR;
uint8_t disIdx = 0;
volatile uint8_t disVal[] = {0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a};
volatile uint16_t disPt = 0x00;



int main(void) {


#if HW_VERSION==0x01
          /*
          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;
#else
          /*
          DDR : 1 = Output, 0 = Input
          PORT: 1 = Pullup for Input, otherwise set output
          PIN : Read input pin
          */

          /*
                PA0 -   Input, Pullup                   - i2c addr select 0 (Dip 1)
                PA1 -   Input, Pullup                   - i2c addr select 1 (Dip 2)
                PA2 -   Reset
          */
          DDRA          = 0B00000000;
          PORTA         = 0B00000011;
          /*
                PB0     - Input, PCInt0, Pullup - Rot1a
                PB1     - Input, PCInt1, Pullup - Rot1b
                PB2     - Input, PCInt2, Pullup - Rot2a
                PB3     - Input, PCInt3, Pullup - Rot2b
                PB4     - Input, Pullup                 - Rot button
                PB5     - SDA
                PB6     - Input, Pullup                 - Swap button
                PB7     - SCL
          */
          DDRB          = 0B00000000;
          PORTB         = 0B01011111;
          /*
                PD0     - Output                                - Decimal point
                PD1     - Output                                - 4511 Blanking
                PD2     - Output                                - '95 DS   Ser
                PD3     - Output                                - '95 SHCP Sck
                PD4     - Output                                - '95 STCP Rsk
                PD5     - Input, Pullup                 - Config (Dip 3)
                PD6     - Input, Pullup                 - Config (Dip 4)
          */
          DDRD          = 0B00011111;
          PORTD         = 0B01100010;
#endif

    systime = 0;
    sysclockInit();

#if HW_VERSION==0x01
    // hwver1 only has a single rotary shaft
    PCMSK1 |= (( 1 << ROT_1A_PIN ) | ( 1 << ROT_1B_PIN ));
    GIMSK |= (1 << PCIE1);
#else
    // hwver2 only has a selectable single/dual rotary shaft
    PCMSK |= (( 1 << ROT_1A_PIN ) | ( 1 << ROT_1B_PIN ) | ( 1 << ROT_2A_PIN ) | ( 1 << ROT_2B_PIN ));
    GIMSK |= (1 << PCIE);
#endif

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

#if HW_VERSION==0x02
    // hw vers 2 has selectable i2c address. Add the value of
    //  the selections to the default i2c address
    uint8_t i2c_add = ((!rbi(I2CADDR_PIN, I2CADDR_0)) << 1);
    i2c_add |= (!rbi(I2CADDR_PIN, I2CADDR_1));
    i2c_address += i2c_add;
#endif

    twires_begin(i2c_address);
    twires_onReceive(receiveEvent);

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

    uint32_t refresh = systime;


    // 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 (0x06): {
                        // Recive a digit to retrieve to value of
                        uint8_t digit = twires_receive();
                        uint8_t out = (digit << 4) | (disVal[digit] & 0x0f);
                        twires_send(out);
                }
                        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): {
                        twires_send(input.outer);
                }
                        break;
#if HW_VERSION==0x02
                case (0x0b): {
                        twires_send(input.inner);
                }
                        break;
#endif
                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);
                }
                        break;
#if HW_VERSION==0x02
                case (0x0d): {
                        // Send all the config switch data
                        uint8_t out = ((!rbi(I2CADDR_PIN, I2CADDR_0)) << 3);
                        out |= ((!rbi(I2CADDR_PIN, I2CADDR_1)) << 2);
                        out |= ((!rbi(CONFSW_PIN, CONFSW_1)) << 1);
                        out |= (!rbi(CONFSW_PIN, CONFSW_0));
                        twires_send(out);
                }
                break;
#endif
                default: {
                        // Don't know what it is, empty buffer
                        while (twires_available())
                                twires_receive();
                }
                        break;
        }
}

void writeSegment(uint8_t digit, uint8_t value) {
        cbi(BL_PORT, BL_PIN);                   // Blank the 4511
        cbi(DP_PORT, DP_PIN);                   // Drop the DP before changing digit

        hc595_write((value << 4) | (9-(digit & 0x0f))); //Write the value and digit
        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;
                }
        }

#if HW_VERSION==0x02
        if (((rbi(pcInt.current, ROT_2A_PIN) == 1 &&
                                rbi(pcInt.current, ROT_2B_PIN) == 1) ||
                 (rbi(pcInt.current, ROT_2A_PIN) == 0 &&
                                rbi(pcInt.current, ROT_2B_PIN) == 0))) {

                if (rbi(pcInt.mask, ROT_2A_PIN) ) {
                        input.inner -= 1;
                  } else if (rbi(pcInt.mask, ROT_2B_PIN) ) {
                        input.inner += 1;
                }
        }
#endif
        // Clear the mask so we know we've dealt with it
        // Shouldn't be required now that 'doInt' has been removed
        //pcInt.mask = 0;

}
#if HW_VERSION==0x01
ISR(PCINT1_vect) {
#else
ISR(PCINT_B_vect) {
#endif
        pcInt.current = ROT_PIN;
}



#if HW_VERSION==0x01
ISR(TIM0_OVF_vect) {
#else
ISR(TIMER0_OVF_vect) {
#endif
    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;
        }

}