From 2ed32581bde08fce4431b82ade32ff9a7b70b4d9 Mon Sep 17 00:00:00 2001 From: b Date: Wed, 25 Mar 2015 19:42:12 +0100 Subject: [PATCH 1/1] First version. --- .gitignore | 2 + definitions.h | 68 +++++ main.c | 736 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 806 insertions(+) create mode 100644 .gitignore create mode 100644 definitions.h create mode 100644 main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f039d96 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.a43 + diff --git a/definitions.h b/definitions.h new file mode 100644 index 0000000..bc5b5b4 --- /dev/null +++ b/definitions.h @@ -0,0 +1,68 @@ +//RTC commands: +#define RTC_EEREAD 0x03 +#define RTC_EEWRITE 0x02 +#define RTC_EEWRDI 0x04 +#define RTC_EEWREN 0x06 +#define RTC_SRREAD 0x05 +#define RTC_SRWRITE 0x01 +#define RTC_READ 0x13 +#define RTC_WRITE 0x12 +#define RTC_UNLOCK 0x14 +#define RTC_IDWRITE 0x32 +#define RTC_IDREAD 0x33 +#define RTC_CLRRAM 0x54 + +//SPI function flags: +#define ADDRFLAG 0x01 +#define WRITEFLAG 0x02 +#define READFLAG 0x04 + +//7 segment display + +#define SEG_A 0xdf +#define SEG_B 0xef // aaaa +#define SEG_C 0xbf // f b +#define SEG_D 0x7f // f b +#define SEG_E 0xfd //hh gggg +#define SEG_F 0xfb // e c +#define SEG_G 0xf7 // e c +#define SEG_H 0xfe // dddd + +#define SYMB_0 (SEG_A & SEG_B & SEG_C & SEG_D & SEG_E & SEG_F ) +#define SYMB_1 ( SEG_B & SEG_C ) +#define SYMB_2 (SEG_A & SEG_B & SEG_D & SEG_E & SEG_G) +#define SYMB_3 (SEG_A & SEG_B & SEG_C & SEG_D & SEG_G) +#define SYMB_4 ( SEG_B & SEG_C & SEG_F & SEG_G) +#define SYMB_5 (SEG_A & SEG_C & SEG_D & SEG_F & SEG_G) +#define SYMB_6 (SEG_A & SEG_C & SEG_D & SEG_E & SEG_F & SEG_G) +#define SYMB_7 (SEG_A & SEG_B & SEG_C ) +#define SYMB_8 (SEG_A & SEG_B & SEG_C & SEG_D & SEG_E & SEG_F & SEG_G) +#define SYMB_9 (SEG_A & SEG_B & SEG_C & SEG_F & SEG_G) +#define SYMB_A (SEG_A & SEG_B & SEG_C & SEG_E & SEG_F & SEG_G) +#define SYMB_B ( SEG_C & SEG_D & SEG_E & SEG_F & SEG_G) +#define SYMB_C ( SEG_D & SEG_E & SEG_G) +#define SYMB_D ( SEG_B & SEG_C & SEG_D & SEG_E & SEG_G) +#define SYMB_E (SEG_A & SEG_D & SEG_E & SEG_F & SEG_G) +#define SYMB_F (SEG_A & SEG_E & SEG_F & SEG_G) +#define SYMB_NUL (0xFF) +#define SYMB_o (SEG_A & SEG_B & SEG_F & SEG_G) +#define SYMB_n (SEG_A & SEG_B & SEG_F ) +#define SYMB_g (SEG_A & SEG_B & SEG_C & SEG_D & SEG_F & SEG_G) +#define SYMB_MIN ( SEG_G) +#define SYMB_DOT (SEG_H) + +//operation modes +#define MODE_INIT 0 +#define MODE_TIME 1 +#define MODE_SETTIME 2 +#define MODE_SETALARM 3 +#define MODE_ALARM 4 +#define MODE_DATE 5 +#define MODE_SETDATE 6 +#define MODE_SETYEAR 7 +#define MODE_COUNTUP 8 +#define MODE_SETCOUNTDOWN 9 +#define MODE_COUNTDOWN 10 +#define MODE_CALIBRATE 11 + +#define ALARMVALUE 0xa5 \ No newline at end of file diff --git a/main.c b/main.c new file mode 100644 index 0000000..a15d25c --- /dev/null +++ b/main.c @@ -0,0 +1,736 @@ +#include "msp430.h" +#include "definitions.h" + +unsigned char inbuf[8]; +unsigned char outbuf[8]; +unsigned char dispvalue[4]; +unsigned char time[8]; +unsigned char leap; +unsigned char settime[3]; +unsigned char mode; +unsigned char alarm[3]; +unsigned char digit; +unsigned char changed; +unsigned char run; +unsigned char symbol[16] ={ + SYMB_0, + SYMB_1, + SYMB_2, + SYMB_3, + SYMB_4, + SYMB_5, + SYMB_6, + SYMB_7, + SYMB_8, + SYMB_9, + SYMB_A, + SYMB_B, + SYMB_C, + SYMB_D, + SYMB_E, + SYMB_F}; + +__interrupt void P2_ISR(); +void display( + unsigned char *data); +void spi( + unsigned char command, + unsigned char addr, + unsigned char *inbuf, + unsigned char *outbuf, + unsigned short n); +int main( void ); + +void display(unsigned char *data) +{ + //lsd + P1OUT =data[0]; + P3OUT |=0x80; //74hc373 latch enable + P3OUT &=0x0f; + + P1OUT =data[1]; + P3OUT |=0x40; + P3OUT &=0x0f; + + P1OUT =data[2]; + P3OUT |=0x20; + P3OUT &=0x0f; + + //msd + P1OUT =data[3]; + P3OUT |=0x10; + P3OUT &=0x0f; +} + +void spi( + unsigned char command, + unsigned char addr, + unsigned char *inbuf, + unsigned char *outbuf, + unsigned short n) +{ + unsigned short i; + unsigned char nul; + unsigned char flags; + + switch (command) + { + case RTC_EEREAD: + case RTC_IDREAD: + case RTC_READ: + flags= ADDRFLAG|READFLAG; + break; + + case RTC_EEWRITE: + case RTC_IDWRITE: + n=(n>8)?8:n; + case RTC_WRITE: + flags= ADDRFLAG|WRITEFLAG; + break; + + case RTC_EEWREN: + case RTC_EEWRDI: + flags=0; + break; + + case RTC_SRREAD: + n=(n>1)?1:n; + flags=READFLAG; + break; + + case RTC_SRWRITE: //1 + case RTC_CLRRAM: //data ignored but has to be + case RTC_UNLOCK: //1 + n=(n>1)?1:n; + flags=WRITEFLAG; + break; + default: + return; + } + + P3OUT&=0xfe; //chip select down + + while((IFG2&UTXIFG0)==0); // wait until can be sent + U0TXBUF=command; // send command + while((IFG2&UTXIFG0)==0); // wait until received + nul=U0RXBUF; //pretend to read "data" + + if(flags&ADDRFLAG) + { + while((IFG2&UTXIFG0)==0); // wait until can be sent + U0TXBUF=addr; // send address + while((IFG2&UTXIFG0)==0); // wait until received + nul=U0RXBUF; //pretend to read "data" + } + if(flags&(READFLAG|WRITEFLAG)) + { + for(i=0;i0x23) + settime[2]&=0xf0; + --digit; + } + else + { + if(changed) + { + outbuf[0]=0x00; + outbuf[1]=0x00; + outbuf[2]=settime[1]&0x7f; + outbuf[3]=settime[2]&0x3f; + + spi(RTC_WRITE,0x01,inbuf,outbuf,1);//stop osc. + spi(RTC_READ,0x03,inbuf,outbuf,1); + outbuf[3]|=(inbuf[0]&0x80);//keep the calsgn bit. + + spi(RTC_WRITE,0x00,inbuf,outbuf,4);//write new time + + outbuf[0]=0x80; + spi(RTC_WRITE,0x01,inbuf,outbuf,1);//start osc; + + time[1]=0; + time[2]=settime[1]; + time[3]=settime[2]; + } + mode=MODE_TIME; + } + break; + case MODE_SETYEAR: + if(digit) + --digit; + else + { + if(changed) + { + time[7]=settime[0]; + spi(RTC_WRITE,0x07,inbuf,settime,1); + } + mode=MODE_DATE; + } + break; + case MODE_SETDATE: + if(digit) + { + --digit; + if(settime[0]>((settime[1]==0x02)?(leap?0x29:0x28):(((settime[1]&0x18) && !(settime[1]&0x01) || !(settime[1]&0x18) && (settime[1]&0x01))?0x31:0x30))) + settime[0]&=(digit?0x00:0xf0); + } + else + { + if (changed) + { + time[5]=settime[0]; + time[6]=settime[1]; + settime[2]=time[7]; + spi(RTC_WRITE,0x05,inbuf,settime,3); + } + mode=MODE_DATE; + } + + break; + case MODE_SETALARM: + if(digit) + { + if(digit==3&&settime[2]>0x23) + settime[2]&=0xf0; + --digit; + } + else + { + if(changed|| !alarm[0]) + { + alarm[0]=ALARMVALUE; + alarm[1]=settime[1]; + alarm[2]=settime[2]; + + spi(RTC_WRITE,0x20,inbuf,alarm,3); + } + else + { + alarm[0]=0; + spi(RTC_WRITE,0x20,inbuf,outbuf,1); + } + mode=MODE_TIME; + } + break; + case MODE_ALARM: + alarm[0]=0; + spi(RTC_WRITE,0x20,inbuf,outbuf,1); + mode=MODE_TIME; + break; + default: + break; + } + } + else if(P2IFG&0x20) // button C + { + P2IFG &= ~0x20; + + switch(mode) + { + case MODE_COUNTUP: + settime[1]=0x00; + settime[2]=0x00; + break; + case MODE_COUNTDOWN: + mode=MODE_SETCOUNTDOWN; + digit=3; + break; + case MODE_CALIBRATE: + if(digit==2) + settime[1]^=0x80; + else if(digit<2) + settime[0]+=(digit==1?0x10:(((settime[0]&0x0f)==0x0f)?0xf1:0x01)); + break; + case MODE_SETTIME: + case MODE_SETALARM: + changed=1; + case MODE_SETCOUNTDOWN: + //these 4 lines replaced a larger switch structure + if((settime[digit&0x02?2:1]&((digit&0x01)?0xf0:0x0f))<(digit==1?0x50:(digit==3?((mode==MODE_SETCOUNTDOWN)?0x90:0x20):((mode!=MODE_SETCOUNTDOWN&&digit==2&&settime[2]>0x19)?0x03:0x09)))) + settime[digit&0x02?2:1]+=((digit&0x01)?0x10:0x01); + else + settime[digit&0x02?2:1]&=((digit&0x01)?0x0f:0xf0); + break; + case MODE_SETYEAR: + changed=1; + if(digit) + { + if(settime[0]<0x90) + settime[0]+=0x10; + else + settime[0]&=0x0f; + } + else + { + if((settime[0]&0x0f)<0x09) + ++settime[0]; + else + settime[0]&=0xf0; + } + break; + case MODE_SETDATE: + changed=1; + switch (digit) + { + case 2: + if(settime[1]<0x12) + settime[1]=__bcd_add_short(settime[1],0x01); + else + settime[1]=0x01; + break; + case 1: + if((settime[0]&0xf0)<((settime[1]==0x02)?0x20:0x30)) + settime[0]+=0x10; + else + settime[0]&=0x0f; + break; + + case 0: + if((settime[0]<((settime[1]==0x02)?(leap?0x29:0x28):(((settime[1]&0x18) && !(settime[1]&0x01) || !(settime[1]&0x18) && (settime[1]&0x01))?0x31:0x30))) && (settime[0]&0x0f)<0x09) + ++settime[0]; + else + settime[0]&=0xf0; + break; + } + break; + case MODE_DATE: + mode=MODE_SETYEAR; + digit=1; + changed=0; + + settime[0]=time[7]; + break; + case MODE_TIME: + mode=MODE_SETALARM; + digit=3; + changed=0; + + settime[0]=0; + settime[1]=alarm[1]; //get last alarm time + if(settime[1]>0x59 || (settime[1]&0x0f)>0x09) + settime[1]=0x00; + settime[2]=alarm[2]; + if(settime[2]>0x23 || (settime[2]&0x0f)>0x09) + settime[2]=0x00; + break; + case MODE_ALARM: + alarm[0]=0; + spi(RTC_WRITE,0x20,inbuf,outbuf,1); + mode=MODE_TIME; + break; + default: + break; + } + } + else + P2IFG=0; + + switch(mode) + { + case MODE_SETTIME: + case MODE_SETALARM: + case MODE_SETCOUNTDOWN: + dispvalue[0]=(symbol[settime[1]&0x0f]|((digit!=0 && (time[1]&0x01))?SYMB_NUL:SYMB_8))&(((((time[1]+0x01)&0x02)^((time[1]&0x10)>>3))&&mode==MODE_SETCOUNTDOWN)?SYMB_NUL:SYMB_DOT); + dispvalue[1]=(symbol[(settime[1]&0xf0)>>4]|((digit!=1 && (time[1]&0x01))?SYMB_NUL:SYMB_8))&((((time[1]&0x02)^((time[1]&0x10)>>3))&&mode==MODE_SETCOUNTDOWN)?SYMB_NUL:SYMB_DOT); + dispvalue[2]=(symbol[settime[2]&0x0f]|((digit!=2 && (time[1]&0x01))?SYMB_NUL:SYMB_8)); + dispvalue[3]=(symbol[(settime[2]&0xf0)>>4]|((digit!=3 && (time[1]&0x01))?SYMB_NUL:SYMB_8))&((mode!=MODE_SETALARM && alarm[0] || mode==MODE_SETALARM && !(time[1]&0x01))?SYMB_DOT:SYMB_NUL); + break; + case MODE_SETYEAR: + dispvalue[0]=(symbol[settime[0]&0x0f]|((digit!=0 && (time[1]&0x01))?SYMB_NUL:SYMB_8)); + dispvalue[1]=(symbol[(settime[0]&0xf0)>>4]|((digit!=1 && (time[1]&0x01))?SYMB_NUL:SYMB_8)); + dispvalue[2]=(SYMB_0|((time[1]&0x01)?SYMB_NUL:SYMB_8)); + dispvalue[3]=(SYMB_2|((time[1]&0x01)?SYMB_NUL:SYMB_8))&(alarm[0]?SYMB_DOT:SYMB_NUL); + break; + case MODE_SETDATE: + dispvalue[0]=(symbol[settime[1]&0x0f]|((digit!=2 && (time[1]&0x01))?SYMB_NUL:SYMB_8)); + dispvalue[1]=(symbol[(settime[1]&0xf0)>>4]|((digit!=2 && (time[1]&0x01))?SYMB_NUL:SYMB_8))&SYMB_DOT; + dispvalue[2]=(symbol[settime[0]&0x0f]|((digit!=0 && (time[1]&0x01))?SYMB_NUL:SYMB_8)); + dispvalue[3]=(symbol[(settime[0]&0xf0)>>4]|((digit!=1 && (time[1]&0x01))?SYMB_NUL:SYMB_8))&(alarm[0]?SYMB_DOT:SYMB_NUL); + break; + case MODE_CALIBRATE: + dispvalue[0]=symbol[settime[0]&0x0f]|((digit!=0 && digit!=3 && (time[1]&0x01))?SYMB_NUL:SYMB_8); + dispvalue[1]=symbol[(settime[0]&0xf0)>>4]|((digit!=1 && digit!=3 && (time[1]&0x01))?SYMB_NUL:SYMB_8); + dispvalue[2]=(settime[1]?SYMB_MIN:SYMB_NUL)|((digit!=2 && digit!=3 && (time[1]&0x01))?SYMB_NUL:SYMB_8); + dispvalue[3]=alarm[0]?SYMB_DOT:SYMB_NUL; + break; + case MODE_DATE: + if((time[1]&0x03)==((time[1]&0x10)?0x01:0x03)) + { + dispvalue[0]=symbol[time[7]&0x0f]; + dispvalue[1]=symbol[(time[7]&0xf0)>>4]; + dispvalue[2]=SYMB_0; + dispvalue[3]=SYMB_2&(alarm[0]?SYMB_DOT:SYMB_NUL); + } + else + { + dispvalue[0]=symbol[time[6]&0x0f]; + dispvalue[1]=symbol[(time[6]&0xf0)>>4]&SYMB_DOT; + dispvalue[2]=symbol[time[5]&0x0f]; + dispvalue[3]=((time[5]&0xf0)?symbol[(time[5]&0xf0)>>4]:SYMB_NUL)&(alarm[0]?SYMB_DOT:SYMB_NUL); + } + break; + case MODE_COUNTDOWN: + if(!(settime[1]|settime[2])) + { + if(!run) + { + dispvalue[0]=SYMB_g&SYMB_DOT; + dispvalue[1]=SYMB_n&SYMB_DOT; + dispvalue[2]=SYMB_o; + dispvalue[3]=alarm[0]?SYMB_DOT:SYMB_NUL; + break; + } + run=0; + } + case MODE_COUNTUP: + dispvalue[0]=symbol[settime[1]&0x0f]&SYMB_DOT; + dispvalue[1]=symbol[(settime[1]&0xf0)>>4]&SYMB_DOT; + dispvalue[2]=symbol[settime[2]&0x0f]; + dispvalue[3]=((settime[2]&0xf0)?symbol[(settime[2]&0xf0)>>4]:SYMB_NUL)&(alarm[0]?SYMB_DOT:SYMB_NUL); + break; + case MODE_ALARM: + if(time[1]&0x01) + { + dispvalue[0]=SYMB_g; + dispvalue[1]=SYMB_n; + dispvalue[2]=SYMB_o; + dispvalue[3]=SYMB_DOT; + break; + } + case MODE_TIME: + default: + dispvalue[0]=symbol[time[2]&0x0f]&((time[1]&0x01)?SYMB_NUL:SYMB_DOT); + dispvalue[1]=symbol[(time[2]&0xf0)>>4]&((time[1]&0x01)?SYMB_NUL:SYMB_DOT); + dispvalue[2]=symbol[time[3]&0x0f]; + dispvalue[3]=((time[3]&0xf0)?symbol[(time[3]&0xf0)>>4]:SYMB_NUL)&((alarm[0] || mode==MODE_ALARM)?SYMB_DOT:SYMB_NUL); + break; + } + + display(dispvalue); + + + return; +} + +int main( void ) +{ + unsigned char delay; + + //watchdog: + WDTCTL = WDTPW + WDTHOLD; + + mode=MODE_INIT; + + //init 7 segment display + + P1OUT =0xff; //display data on p1 + P1DIR =0xff; + + P3OUT &=0x0f; //display control on p3.4-7 + P3DIR |=0xf0; + + dispvalue[0]=SYMB_NUL; + dispvalue[1]=SYMB_o; + dispvalue[2]=SYMB_o; + dispvalue[3]=SYMB_NUL; + + display(dispvalue); + + //clocking: + + BCSCTL2 |= DIVM_3; //errata sheet recommends this here + + DCOCTL =0x00; + BCSCTL1 = + RSEL2| //in the + XTS| //hi freq + DIVA_1; //ACLK = 6/2 MHz + + do + { + IFG1 &= ~OFIFG; + for (delay = 0xFF; delay > 0; --delay); + } + while ((IFG1 & OFIFG)); + + BCSCTL2 = + SELM_2| //MCLK from XT2 + DIVM_1| //MCLK = 6/2 MHz + SELS| //SMCLK from XT2 + DIVS_0; //SMCLK = 6/1 MHz + + //init SPI + + P3SEL =0x0e; // SPI on p3.1, 3.2, 3.3 + P3OUT |=0x01; + P3DIR |=0x01; //RTC CS on p3.0 + + U0CTL = + SWRST| //reset + MM| //master + SYNC| //SPI mode + CHAR; //8 bit data + U0TCTL= + CKPH| //polarity and phase + SSEL0|SSEL1| //SMCLK + STC; //3 pin mode + U0BR1=0x00; + U0BR0=0x02; //baudrate = SMCLK/2 = 3MHz + U0MCTL=0x00; + ME2|=USPIE0; + U0CTL &= ~SWRST; + + //init RTC + + //set 24 hour mode + spi(RTC_READ,0x03,inbuf,outbuf,1); + if(inbuf[0]&0x40) + { + outbuf[0]=inbuf[0]&(~0x40); + spi(RTC_WRITE,0x03,inbuf,outbuf,1); + } + + //enable battery + spi(RTC_READ,0x04,inbuf,outbuf,1); + if(!(inbuf[0]&0x08)) + { + outbuf[0]=inbuf[0]|0x08; //enable battery + spi(RTC_WRITE,0x04,inbuf,outbuf,1); + } + + //set control register + //spi(RTC_READ,0x08,inbuf,outbuf,1); + outbuf[0]= + 0x40| //squarewave enable + 0x04; //1Hz + //no hardware alarms :( + spi(RTC_WRITE,0x08,inbuf,outbuf,1); + + //get (soft) alarm from RTC SRAM + spi(RTC_READ,0x20,inbuf,outbuf,3); + + alarm[0]=(inbuf[0]==ALARMVALUE)?ALARMVALUE:0; + alarm[1]=inbuf[1]; + alarm[2]=inbuf[2]; + + //start oscillator + spi(RTC_READ,0x01,inbuf,outbuf,1); + if(!(inbuf[0]&0x80)) + { + outbuf[0]=inbuf[0]|0x80; + spi(RTC_WRITE,0x01,inbuf,outbuf,1); + } + + //init timer: + TACCR0 = 375-1; //3MHz/375/2=4kHz + TACCTL0= //also, compare, not capture + OUTMOD_4; //toggle + TACTL= + TASSEL_1| //ACLK, 3MHz + ID_0| //3MHz/1 + //MC_1| //up mode + TACLR; //reset + P2SEL|=0x04; //P2.2 timer output. + P2DIR|=0x04; + + // Init interrupts + P2IE= + 0x08| //p2.3 - int. from RTC + 0x02| //p2.1 - int. from button A + 0x01| //p2.0 - int. from button B + 0x20; //p2.5 - int. from button C + P2IES|=0x01|0x02|0x20; //button int. on falling edge + P2IES&= ~0x08; //RTC int. on rising edge + P2IFG=0x00; + + if(P2IN&0x02) //button A pressed at start? + mode=MODE_TIME; + else + { + mode=MODE_CALIBRATE; + spi(RTC_READ,0x03,inbuf,outbuf,1); + settime[1]=inbuf[0]&0x80; + spi(RTC_READ,0x09,inbuf,outbuf,1); + settime[0]=inbuf[0]; + digit=3; + } + + __enable_interrupt(); + + + while(1) + { + __low_power_mode_3(); + } +} -- 2.30.2