253 lines
4.9 KiB
C
253 lines
4.9 KiB
C
#include "o3.h"
|
|
#include "gpio.h"
|
|
#include "systick.h"
|
|
|
|
/**************************************************************************/ /**
|
|
* @brief Konverterer nummer til string
|
|
* Konverterer et nummer mellom 0 og 99 til string
|
|
*****************************************************************************/
|
|
void int_to_string(char *timestamp, unsigned int offset, int i)
|
|
{
|
|
if (i > 99)
|
|
{
|
|
timestamp[offset] = '9';
|
|
timestamp[offset + 1] = '9';
|
|
return;
|
|
}
|
|
|
|
while (i > 0)
|
|
{
|
|
if (i >= 10)
|
|
{
|
|
i -= 10;
|
|
timestamp[offset]++;
|
|
}
|
|
else
|
|
{
|
|
timestamp[offset + 1] = '0' + i;
|
|
i = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**************************************************************************/ /**
|
|
* @brief Konverterer 3 tall til en timestamp-string
|
|
* timestamp-argumentet må være et array med plass til (minst) 7 elementer.
|
|
* Det kan deklareres i funksjonen som kaller som "char timestamp[7];"
|
|
* Kallet blir dermed:
|
|
* char timestamp[7];
|
|
* time_to_string(timestamp, h, m, s);
|
|
*****************************************************************************/
|
|
void time_to_string(char *timestamp, int h, int m, int s)
|
|
{
|
|
timestamp[0] = '0';
|
|
timestamp[1] = '0';
|
|
timestamp[2] = '0';
|
|
timestamp[3] = '0';
|
|
timestamp[4] = '0';
|
|
timestamp[5] = '0';
|
|
timestamp[6] = '\0';
|
|
|
|
int_to_string(timestamp, 0, h);
|
|
int_to_string(timestamp, 2, m);
|
|
int_to_string(timestamp, 4, s);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
typedef struct {
|
|
word CTRL;
|
|
word MODEL;
|
|
word MODEH;
|
|
word DOUT;
|
|
word DOUTSET;
|
|
word DOUTCLR;
|
|
word DOUTTGL;
|
|
word DIN;
|
|
word PINLOCKN;
|
|
} gpio_port_map_t;
|
|
|
|
typedef volatile struct {
|
|
gpio_port_map_t ports[6];
|
|
word unused_space[10];
|
|
word EXTIPSELL;
|
|
word EXTIPSELH;
|
|
word EXTIRISE;
|
|
word EXTIFALL;
|
|
word IEN;
|
|
word IF;
|
|
word IFS;
|
|
word IFC;
|
|
word ROUTE;
|
|
word INSENSE;
|
|
word LOCK;
|
|
word CTRL;
|
|
word CMD;
|
|
word EM4WUEN;
|
|
word EM4WUPOL;
|
|
word EM4WUCAUSE;
|
|
} gpio_t;
|
|
|
|
typedef volatile struct {
|
|
word CTRL;
|
|
word LOAD;
|
|
word VAL;
|
|
word CALIB;
|
|
} systick_t;
|
|
|
|
static volatile gpio_t* const gpio = (gpio_t*) GPIO_BASE;
|
|
static volatile systick_t* const systick = (systick_t*) SYSTICK_BASE;
|
|
|
|
#define GPIO_LED GPIO_PORT_E
|
|
#define GPIO_PB GPIO_PORT_B
|
|
#define LED_PIN 2
|
|
#define PB0_PIN 9
|
|
#define PB1_PIN 10
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
enum PROGRAM_STATE {
|
|
ADD_SECS,
|
|
ADD_MINS,
|
|
ADD_HOURS,
|
|
COUNTDOWN,
|
|
ALARM,
|
|
PROGRAM_STATE_SIZE,
|
|
};
|
|
|
|
static struct {
|
|
char display[7];
|
|
unsigned char hours;
|
|
unsigned char minutes;
|
|
unsigned char seconds;
|
|
unsigned char programState;
|
|
} state;
|
|
|
|
void initializeState() {
|
|
state.hours = 0;
|
|
state.minutes = 0;
|
|
state.seconds = 0;
|
|
state.programState = ADD_SECS;
|
|
}
|
|
|
|
void initializeInterruptHandlers()
|
|
{
|
|
// Setup SYSTICK
|
|
systick->CTRL = 0b111;
|
|
systick->LOAD = FREQUENCY;
|
|
systick->VAL = 1;
|
|
|
|
// Setup LED
|
|
volatile word* setting;
|
|
setting = &gpio->ports[GPIO_LED].MODEL;
|
|
*setting &= ~(0xF << (4 * LED_PIN));
|
|
*setting += GPIO_MODE_OUTPUT << (4 * LED_PIN);
|
|
|
|
// Setup buttons
|
|
for (char i=0; i<2; i++) {
|
|
setting = i ? &gpio->ports[GPIO_PB].MODEH : &gpio->EXTIPSELH;
|
|
*setting &= ~(0xFF << 4);
|
|
*setting += 0x110;
|
|
|
|
word button = i ? PB0_PIN : PB1_PIN;
|
|
gpio->EXTIFALL |= (1 << button);
|
|
gpio->IEN |= (1 << button);
|
|
}
|
|
}
|
|
|
|
void activateAlarm()
|
|
{
|
|
state.programState = ALARM;
|
|
gpio->ports[GPIO_LED].DOUTSET = 1 << LED_PIN;
|
|
}
|
|
|
|
void deactivateAlarm()
|
|
{
|
|
gpio->ports[GPIO_LED].DOUTCLR = 1 << LED_PIN;
|
|
}
|
|
|
|
void turnToNextState()
|
|
{
|
|
if (state.programState == COUNTDOWN) return;
|
|
if (state.programState == ALARM)
|
|
deactivateAlarm();
|
|
|
|
state.programState++;
|
|
state.programState %= PROGRAM_STATE_SIZE;
|
|
}
|
|
|
|
void updateScreen()
|
|
{
|
|
time_to_string(state.display, state.hours, state.minutes, state.seconds);
|
|
lcd_write(state.display);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void SysTick_Handler()
|
|
{
|
|
gpio->ports[GPIO_LED].DOUTTGL = 1;
|
|
if (state.programState != COUNTDOWN) return;
|
|
|
|
if (!state.seconds) {
|
|
if (!state.minutes) {
|
|
if (!state.hours) {
|
|
activateAlarm();
|
|
return;
|
|
}
|
|
state.hours--;
|
|
state.minutes = 60;
|
|
return;
|
|
}
|
|
state.minutes--;
|
|
state.seconds = 60;
|
|
return;
|
|
}
|
|
state.seconds--;
|
|
}
|
|
|
|
// PB0
|
|
void GPIO_ODD_IRQHandler()
|
|
{
|
|
switch (state.programState)
|
|
{
|
|
case ADD_SECS:
|
|
state.seconds++;
|
|
state.seconds %= 60;
|
|
break;
|
|
|
|
case ADD_MINS:
|
|
state.minutes++;
|
|
state.minutes %= 60;
|
|
break;
|
|
|
|
case ADD_HOURS:
|
|
state.hours++;
|
|
break;
|
|
}
|
|
gpio->IFC = 1 << PB0_PIN;
|
|
}
|
|
|
|
// PB1
|
|
void GPIO_EVEN_IRQHandler()
|
|
{
|
|
turnToNextState();
|
|
gpio->IFC = 1 << PB1_PIN;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int main(void)
|
|
{
|
|
init();
|
|
initializeInterruptHandlers();
|
|
initializeState();
|
|
|
|
for (;;) {
|
|
updateScreen();
|
|
__asm__("WFI");
|
|
}
|
|
|
|
return 0;
|
|
}
|