#include #include #include #include #include // Use watchdog #define WATCHDOG // UART buffer size #define BUFFER_LEN 48 // LED pin info #define LED_PIN_DIR PORT_C.DDR.Pin3 #define LED_PIN_CR1 PORT_C.CR1.Pin3 #define LED_PIN_CR2 PORT_C.CR2.Pin3 #define LED_PIN_OUT PORT_C.ODR.Pin3 // UART RX pin info #define RX_PIN_DIR PORT_D.DDR.Pin6 #define RX_PIN_CR1 PORT_D.CR1.Pin6 #define RX_PIN_CR2 PORT_D.CR2.Pin6 #define RX_PIN_OUT PORT_D.ODR.Pin6 // UART TX pin info #define TX_PIN_DIR PORT_D.DDR.Pin5 #define TX_PIN_CR1 PORT_D.CR1.Pin5 #define TX_PIN_CR2 PORT_D.CR2.Pin5 #define TX_PIN_OUT PORT_D.ODR.Pin5 // Time defines #define SHORT_PRESS_MS 25 #define LONG_PRESS_MS 1000 #define LED_FADE_TIME 888 // Countdown timestamp (2^15 max, sign used to notify "unitialized") volatile i16 countdown_tick = 0; // Light timer volatile i16 timer = 0; // volatile u08 exec = 0; volatile u08 cmd[BUFFER_LEN]; volatile u08 cmdPos = 0; volatile u08 cmdLen = 0; volatile u08 state = 0; u08 led_state = 0; /** * Hang processor with big delay and hope for watchdog to kick-in or directly * start watchdog restart by setting counter to 0. */ void reboot(void) { #ifdef WATCHDOG IWATCHDOG.Key = IndependWatchdogReset; #else delay_tick(0xffff); #endif WWDG.Control.Activate = 1; WWDG.Control.Counter = 0; } /** * Start feeding cmd into UART (will process with interrupts) */ void start_cmd(u08 len) { cmdPos = 0; cmdLen = len; UART1.CR2 |= UART_CR2_TXE_IVT; UART1.Data = cmd[0]; } /** * Mark current time for further comparison */ inline void start_countdown(void) { countdown_tick = (TIM1.CounterH << 8) | TIM1.CounterL; } /** * Mark countdown as unitialized */ inline void stop_countdown(void) { countdown_tick = -1; } /** * Check if countdown is active */ inline bool is_countdown_active(void) { return countdown_tick >= 0; } /** * Get time elapsed from countdown start in ms */ i16 elapsed(void) { if (!is_countdown_active()) { return -1; } u16 next = (TIM1.CounterH << 8) | TIM1.CounterL; if (next < countdown_tick) { // Handle case if timer overflowed return (next + 2500) - countdown_tick; } else { return next - countdown_tick; } } void send_some_command(void) { cmd[0] = 'C'; cmd[1] = 'M'; cmd[2] = 'D'; start_cmd(3); } void initialize_state(void) { switch (state) { case 0: send_some_command(); // initialization step 0 break; case 1: send_some_command(); // initialization step 1 break; } state++; } /** * Fade in LED for ticks defined in LED_FADE_TIME * Note: if already turned on - do nothing */ void turn_on(void) { if (led_state == 1) { return; } led_state = 1; u16 delay = LED_FADE_TIME; while (delay > 1) { LED_PIN_OUT ^= 1; delay_tick(delay); delay--; } LED_PIN_OUT = 1; } /** * Fade out LED for ticks defined in LED_FADE_TIME * Note: if already turned of - do nothing */ void turn_off(void) { if (led_state == 0) { return; } led_state = 0; u16 delay = 1; while (delay < LED_FADE_TIME) { LED_PIN_OUT ^= 1; delay_tick(delay); delay++; } LED_PIN_OUT = 0; } /** * Tick event handler */ void tick_250ms(void) { // Go trough all initialization states if (state < 2) { initialize_state(); // and skip other tasks if not finished return; } // Decrease light timer if (timer > 0) { timer--; } // If we still have time // note: timer can be below zero to work without timer if (timer != 0) { // Keep light on (will do nothing if already enabled) turn_on(); } else { // Turn off otherwise turn_off(); } } interrupt(IRQ_UART1_RX_F, uart_recv) { u08 s = UART1.Status; u08 c = UART1.Data; // if (exec == 1) { // switch (c) { // case 0x2A: // timer = 1200; // break; // case 0x2B: // timer = -1; // break; // case 0x2C: // timer = 0; // break; // } // } // if (c == 0x24) { // exec = 1; // } else { // exec = 0; // } } interrupt(IRQ_UART1_TX_C, uart_sent) { cmdPos++; if (cmdPos < cmdLen) { UART1.Data = cmd[cmdPos]; } else { cmdPos = 0; cmdLen = 0; memset(cmd, '\0', BUFFER_LEN); UART1.CR2 &= ~UART_CR2_TXE_IVT; } } interrupt(IRQ_EXTI_C, touch) { if (PORT_C.IDR.Pin4) { // Mark touch start start_countdown(); } else if (is_countdown_active()) { // Get time on release i16 time = elapsed(); if (time > LONG_PRESS_MS) { // Make light continuously if pressed for long timer = -1; } else if (time > SHORT_PRESS_MS) { // If it was short touch set timer for enough time timer = 30 * 4; // 30 seconds * 4 (250ms tick) } } } interrupt(IRQ_TIM1_OVERFLOW, timer1_tick) { TIM1.Status1.UpdateInterruptFlag = 0; #ifdef WATCHDOG IWATCHDOG.Key = IndependWatchdogReset; #endif tick_250ms(); } void main(void) { // Setup clock (External, 16Mhz) CLK.External.HighSpeedExternalEnable = 1; while (CLK.External.HighSpeedExternalReady == 0) { nop(); } CLK.MasterSwitch = HighSpeedExternal; while (CLK.SwitchControl.SwitchInterruptFlag == 0) { nop(); } CLK.SwitchControl.SwitchStartStop = 1; CLK.Divider.Prescaler = 0x00; CLK.Divider.HighSpeedPrescaler = 0x00; // Disable unused peripherals CLK.Peripheral1.I2C= 0; CLK.Peripheral1.SPI = 0; CLK.Peripheral1.Timer2 = 0; CLK.Peripheral1.Timer4 = 0; CLK.Peripheral2.AnalogDigitalConvertor = 0; // Setup UART pins RX_PIN_DIR = 0; RX_PIN_CR1 = 0; RX_PIN_CR2 = 0; TX_PIN_DIR = 1; // Setup touch sensor pins PORT_C.DDR.Pin4 = 0; PORT_C.CR1.Pin4 = 0; PORT_C.CR2.Pin4 = 1; EXTI_CR1.PortC = EXTI_RISING_FALLING; // Setup UART (115200 8N1, with interupt) // 115200 | 9600 | 57600 UART1.CR3 &= ~(UART_CR3_STOP1 | UART_CR3_STOP2); // UART1.BRR2 = 0x0B; // 0x03; // 0x11; // UART1.BRR1 = 0x08; // 0x68; // 0x06; UART1.BRR2 = 0x03; UART1.BRR1 = 0x68; UART1.CR2 = UART_CR2_TEN | UART_CR2_REN | UART_CR2_RXNE_IVT | UART_CR2_SBK; CLK.Peripheral1.Serial1 = 1; // Setup LED pin LED_PIN_DIR = 1; LED_PIN_CR1 = 1; LED_PIN_CR2 = 0; LED_PIN_OUT = 1; // Setup timer 250ms tick CLK.Peripheral1.Timer1 = 1; const u16 div = 1599; const u16 cou = 2500; TIM1.PrescalerH = div >> 8; TIM1.PrescalerL = div & 0xFF; TIM1.AutoReloadH = cou >> 8; TIM1.AutoReloadL = cou & 0xFF; TIM1.Interrupt.UpdateInterrupt = 1; TIM1.Control1.CounterEnable = 1; #ifdef INVERSION LED_PIN_OUT = 1; #else LED_PIN_OUT = 0; #endif #ifdef WATCHDOG // Start watchdog IWATCHDOG.Key = IndependWatchdogOn; IWATCHDOG.Key = IndependWatchdogEdit; IWATCHDOG.Prescaler = WatchdogPrescaler_256; // Around 128kHz/256=500Hz=2ms IWATCHDOG.Reload = 0xFF; // 2ms*256=512ms IWATCHDOG.Key = IndependWatchdogReset; #endif // Start interrupts rim(); // Just for test CFG_GCR |= 0x02; // Set AL for disable main(); wfi(); // Infinite worker loop for (;;) { delay_tick(0xff); #ifdef WATCHDOG IWATCHDOG.Key = IndependWatchdogReset; #endif } }