/* * XIOHV5.12 power sequence * Copyright (C) 2012 Avencall * Authors: * Jean-Marc Ouvrard * Noe Rubinstein * Guillaume Knispel * * 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 3 of the License, or * (at your option) any later version. * * 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, see . */ /* Random notes: * * We have decided to remove the reset button and to keep the power button. * * We should make sure that the power button works more reliably especially * considering the ACPI specification and interactions with the EP80579 * standard ACPI subsystem. We should also debounce the On -> Off transition * of the power button. */ /* define WATCHDOG to get one :) */ #define WATCHDOG //#undef WATCHDOG /* define TRACE_SERIAL to get debugging traces capabilities on the * MSP430 serial port * WARNING: This might disable some functions too, check the code * to see exactly what that does in this particular version */ // #define TRACE_SERIAL #undef TRACE_SERIAL /* define LOOP_REBOOT if you want that the board reboot forever * define it to the number of ms to spend in the WAIT_STOP state. */ //#define LOOP_REBOOT 5000 #undef LOOP_REBOOT #ifdef TRACE_SERIAL #include #endif /* TRACE_SERIAL */ #include #include #include #include "def.h" #include "hardware.h" static void InitPorts(void); static void GlobalInit(void); volatile u16 TAVector; volatile u16 Timer1; volatile u16 Timer2; volatile u16 SW1State; volatile u16 SW2State; #ifdef CAN_WAIT_TENSION //has to be coded on real board volatile u8 bV1P0 = true; volatile u8 bV1P2 = true; volatile u8 bV1P8_DDR = true; volatile u8 bV2P5 = true; volatile u8 bVCC3 = true; #define TENSION_EXPIRED (Timer1 == 0) #define TENSION_WAIT(t) (t) #else #define TENSION_EXPIRED (0) #define TENSION_WAIT(t) (Timer1 == 0) #endif #define STOP 10 #define WAIT_START 20 #define WAIT_ATX_OK 30 #define WAIT_V1P0 40 #define WAIT_V1P2 50 #define WAIT_V1P8 60 #define WAIT_RSMRST 70 #define CK410_VTT_GD 80 #define STATE_SYS_PWR_OK 90 #define CPU_RUN 100 #define WAIT_STOP 110 #define RST_STATE 10 #define ON_STATE 20 #define RST_WAIT 30 #ifdef TRACE_SERIAL // For UCOS16 = 1 // BRCLK Baud Rate UCBRx UCBRSx UCBRFx Tx Error Rx Error // 12,000,000 115200 6 0 8 -1.8 0 -2.2 0.4 static void SerialInit(void) { UCA0CTL1_bit.UCSWRST = 1; UCA0CTL0 = 0; UCA0CTL1 = 0xC1; // UCSSEL=11b => SMCLK; (keep) UCSWRST = 1; UCA0BR0 = 6; UCA0BR1 = 0; UCA0MCTL = 0x81; // UCOS16 = 1; UCBRSx = 0; UCBRFx = 8; UCA0STAT = 0; // Configure port for UART access // Pin 25 as UCA0TXD // Pin 26 as UCA0RXD P3SEL |= MSP_BSL_TXD | MSP_BSL_RXD; UCA0CTL1_bit.UCSWRST = 0; } static void ll_putchar(unsigned char c) { while (!IFG2_bit.UCA0TXIFG); UCA0TXBUF = c; } /* __write, remove, __close, and __lseek need to be implemented by the * application for the full DLib to work. */ size_t __write(int handle, const unsigned char * buffer, size_t size) { size_t nChars = 0; if (buffer == 0) return 0; for (; size != 0; --size) { ll_putchar(*buffer++); ++nChars; } return nChars; } int remove(const char *name) { return -1; } int __close(int handle) { return 0; } long __lseek(int handle, long offset, int whence) { return -1; } // TB_SIZE must be a power of 2 #define TB_SIZE 64 static u8 trace_buffer[TB_SIZE]; static u8 tb_beg; static u8 tb_fill; static inline u8 TB_I(u8 raw_idx) { return raw_idx & (TB_SIZE - 1); } static void trace(u8 val) { if (tb_fill == TB_SIZE) { tb_beg = TB_I(tb_beg + 1); tb_fill--; } trace_buffer[TB_I(tb_beg + (tb_fill++))] = val; } static inline char hex_nibble(u8 n) { return n + ((n > 9) ? 'a' - 10 : '0'); } static inline void dump_byte(char b[3], u8 n) { b[0] = hex_nibble(n >> 4); b[1] = hex_nibble(n & 0xf); b[2] = ' '; } static void dump_trace(void) { static char buf[64]; int pos = 0; #define flush() do { buf[pos] = 0; fputs(buf, stdout); pos = 0; } while (0) int i; fputs("TRACE:\r\n", stdout); pos = 0; for (i = 0; i < tb_fill; i++) { dump_byte(buf + pos, trace_buffer[TB_I(tb_beg + i)]); pos += 3; if ((i & 15) == 15) { buf[pos++] = '\r'; buf[pos++] = '\n'; } else if ((i & 7) == 7) { buf[pos++] = ' '; } if (pos >= 56) flush(); } flush(); if (i & 15) puts("\r"); } #define TRACE(v) trace(v) #define change_state(ns) do { trace(ns); state = (ns); } while (0) #else /* !TRACE_SERIAL */ #define TRACE(v) /* noop */ #define change_state(ns) do { state = (ns); } while (0) #endif /* TRACE_SERIAL */ volatile u16 Timer_A_count; int main(void) { u16 state, resetState; #ifndef WATCHDOG WDTCTL = WDTPW | WDTHOLD; #endif /* WATCHDOG */ __disable_interrupt(); GlobalInit(); InitPorts(); #ifdef TRACE_SERIAL SerialInit(); #endif /* TRACE_SERIAL */ __enable_interrupt(); state = WAIT_START; resetState = ON_STATE; while (1) { P2OUT = (P2OUT & ~GP24) | ((Timer_A_count & 1) ? GP24 : 0); //////////////////////////////////////////////////////////////////// #ifdef TRACE_SERIAL // debug behavior switch (resetState) { case ON_STATE: if (SW2State > 100) { dump_trace(); resetState = RST_WAIT; } break; resetState = ON_STATE; case RST_WAIT: if (SW2State == 0) break; } #else // normal behavior switch (resetState) { case ON_STATE: if (SW2State > 300) { resetState = RST_STATE; } break; case RST_STATE: ClrBit(P2REN, SYS_RESET_N); SetBit(P2DIR, SYS_RESET_N); ClrBit(P2OUT, SYS_RESET_N); Timer2 = 150; resetState = RST_WAIT; break; case RST_WAIT: if (Timer2 == 0) { SetBit(P2OUT, SYS_RESET_N); if (SW2State == 0) resetState = ON_STATE; } break; } #endif /* TRACE_SERIAL */ //////////////////////////////////////////////////////////////////// switch (state) { case WAIT_START: #ifdef LOOP_REBOOT change_state(WAIT_START + 1); #endif if (SW1State > 30) change_state(WAIT_START + 1); break; case WAIT_START + 1: if (SW1State == 0) { SetBit(P4OUT, CMDPWR); // Start Atx Power Supply Timer1 = 2000; change_state(WAIT_ATX_OK); } break; case WAIT_ATX_OK: if (SW1State || TENSION_EXPIRED) { change_state(STOP); } if ((P4IN & ATX_PWROK) && TENSION_WAIT(bV2P5 && bVCC3)) { ClrBit(P1OUT, V1P2_CORE_EN_N); Timer1 = 30; change_state(WAIT_V1P2); } break; case WAIT_V1P2: if (SW1State || TENSION_EXPIRED) change_state(STOP); if (TENSION_WAIT(bV1P2)) { Timer1 = 30; SetBit(P4OUT, V1P8_CMD); change_state(WAIT_RSMRST); } break; case WAIT_RSMRST: if (SW1State) change_state(STOP); if (Timer1 < 19) { SetBit(P2OUT, IMCH_RSMRST_N); change_state(WAIT_V1P8); } break; case WAIT_V1P8: if (SW1State || TENSION_EXPIRED) change_state(STOP); if (TENSION_WAIT(bV1P8)) { ClrBit(P2OUT, CPU_VCCP_EN_N); Timer1 = 30; change_state(WAIT_V1P0); } break; case WAIT_V1P0: if (SW1State || TENSION_EXPIRED) change_state(STOP); if (TENSION_WAIT(bV1P0)) { SetBit(P3OUT, VRMPWRGD); ClrBit(P2OUT, GREEN_LED_N); Timer1 = 3; change_state(CK410_VTT_GD); } break; case CK410_VTT_GD: if (Timer1 == 0) { SetBit(P2DIR, CK410_PWR_GD_N); ClrBit(P2OUT, CK410_PWR_GD_N); Timer1 = 105; change_state(STATE_SYS_PWR_OK); } break; case STATE_SYS_PWR_OK: if (Timer1 == 0) { SetBit(P3OUT, SYS_PWR_OK); Timer1 = 10; change_state(CPU_RUN); } break; case CPU_RUN: if (SW1State) change_state(STOP); if (Timer1 == 0) { // Start Tolapai: emulate the power button from its point of view // we don't really know where is the best place to do that so // we will try it here at first. SetBit(P2DIR, IMCH_PWRBTN_N); Timer1 = 200; change_state(CPU_RUN + 1); } break; case CPU_RUN + 1: if (SW1State) change_state(STOP); if (Timer1 == 0) { ClrBit(P2DIR, IMCH_PWRBTN_N); #ifdef LOOP_REBOOT Timer1 = LOOP_REBOOT; #endif change_state(WAIT_STOP); } break; case WAIT_STOP: #ifdef LOOP_REBOOT if (Timer1 == 0) change_state(STOP); #endif if (SW1State >= 4000) // Sw1 button pressed for more than 4 seconds change_state(STOP); break; case STOP: InitPorts(); Timer1 = 3000; // Disable any other Power up for 3 s. ClrBit(P2OUT, RED_LED_N); // To show no restart is possible for now change_state(STOP + 1); break; case STOP + 1: if ((Timer1 == 0) && (SW1State == 0)) { SetBit(P2OUT, RED_LED_N); // To show restart is possible now change_state(WAIT_START); } break; } } } #pragma vector = TIMERA1_VECTOR __interrupt void Timer_A(void) { #ifdef WATCHDOG /* ACLK (VLO) /64 => T belongs to [0.016; 0.0032] s */ WDTCTL = WDTPW | WDTCNTCL | WDTSSEL | WDTIS1 | WDTIS0; P3OUT = P3IN ^ MSP_BSL_TXD; /* if (IFG2_bit.UCA0TXIFG) UCA0TXBUF = 'a'; */ #endif /* WATCHDOG */ Timer_A_count++; if (!(P1IN & START_SW1_N)) SW1State++; else SW1State = 0; if (!(P1IN & RST_SW2_N)) SW2State++; else SW2State = 0; if (Timer1) Timer1--; if (Timer2) Timer2--; TAVector = TAIV; } static void InitPorts(void) { /* DIR: direction: 0 input 1 output * SEL: function: 0 gpio * REN: resistor enabled * OUT: output when REN=0 and DIR=1 * 0 pull-down 1 pull-up if REN=1 * IES: Interrupt Edge Select * IE: Interrupt Enable */ P1DIR = P1DIR_INIT; P1SEL = P1SEL_INIT; P1REN = P1REN_INIT; P1OUT = P1OUT_INIT; P1IES = P1IES_INIT; P1IE = P1IE_INIT; P2OUT = P2OUT_INIT; P2SEL = P2SEL_INIT; P2REN = P2REN_INIT; P2DIR = P2DIR_INIT; P2IES = P2IES_INIT; P2IE = P2IE_INIT; P3OUT = P3OUT_INIT; P3SEL = P3SEL_INIT; P3DIR = P3DIR_INIT; P4OUT = P4OUT_INIT; P4SEL = P4SEL_INIT; P4DIR = P4DIR_INIT; P4REN = P4REN_INIT; } static void GlobalInit(void) { /******** MCLK SMCLK ACLK Configuration ********/ /* freq selection procedure compliant with errata BCL12 * (potentially switching from RSEL < 12 to > 13) */ DCOCTL = 0; /* LFXT1 low freq (to allow for VLO), ACLK will be /1 */ BCSCTL1 = CALBC1_12MHZ & ~(XTS | DIVA0 | DIVA1); DCOCTL = CALDCO_12MHZ; BCSCTL3 = LFXT1S_2 /* VLO */; /* Status here: * MCLK and SMCLK from DCO, 12MHz nominal. * ACLK from VLOCLK, 4 -> 20kHz. */ #ifdef WATCHDOG /******** Watchdog early configuration ********/ /* ACLK /8192 */ WDTCTL = WDTPW + WDTCNTCL + WDTSSEL + WDTIS0; /* This initial WDT will expire in 0.4 to 2.1 s * Note that it will be reconfigured to expire with shorter intervals * starting from the next clearing. */ #endif /* WATCHDOG */ /******** Timer A configuration ********/ TACTL = TASSEL_2 | ID_3 | TACLR | TAIE | MC_1; // SMCLK | div by 8 | reset | // enable interrupt | UP // Calibrated DCO Frequencies - Tolerance Over Temperature 0C to 85C // // Min Typ Max // BCSCTL1 = CALBC1_12MHZ, 2.2 V 11.7 12 12.3 // fCAL(12MHz) DCOCTL = CALDCO_12MHZ, 3 V 11.7 12 12.3 MHz // Gating time: 5 ms 3.6 V 11.7 12 12.3 // Timer_A called every: // // >>> 1539 / 1500000. * .975 // 0.00100035 1.000 ms min // >>> 1539 / 1500000. // 0.001026 1.026 ms nom // >>> 1539 / 1500000. * 1.025 // 0.00105165 1.052 ms max TACCR0 = 1539 + 1; /* TA16 errata => + 1 => so T belongs to [1.000 ; 1.053] */ }