340 lines
6.8 KiB
C
340 lines
6.8 KiB
C
#include <type.h>
|
|
#include <stm_base.h>
|
|
#include <stm8s103f3.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
// 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
|
|
}
|
|
}
|