|
|
#include <stdint.h> |
|
|
#include <stdlib.h> |
|
|
#include <chopstx.h> |
|
|
|
|
|
#include "board.h" |
|
|
|
|
|
static uint8_t main_finished; |
|
|
|
|
|
#define PERIPH_BASE 0x40000000 |
|
|
#define APB1PERIPH_BASE PERIPH_BASE |
|
|
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) |
|
|
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000) |
|
|
#define AHB2PERIPH_BASE (PERIPH_BASE + 0x08000000) |
|
|
|
|
|
struct GPIO { |
|
|
volatile uint32_t MODER; |
|
|
volatile uint16_t OTYPER; |
|
|
uint16_t dummy0; |
|
|
volatile uint32_t OSPEEDR; |
|
|
volatile uint32_t PUPDR; |
|
|
volatile uint16_t IDR; |
|
|
uint16_t dummy1; |
|
|
volatile uint16_t ODR; |
|
|
uint16_t dummy2; |
|
|
volatile uint16_t BSRR; |
|
|
uint16_t dummy3; |
|
|
volatile uint32_t LCKR; |
|
|
volatile uint32_t AFR[2]; |
|
|
volatile uint16_t BRR; |
|
|
uint16_t dummy4; |
|
|
}; |
|
|
#define GPIOA_BASE (AHB2PERIPH_BASE + 0x0000) |
|
|
#define GPIOA ((struct GPIO *) GPIOA_BASE) |
|
|
#define GPIOF_BASE (AHB2PERIPH_BASE + 0x1400) |
|
|
#define GPIOF ((struct GPIO *) GPIOF_BASE) |
|
|
|
|
|
static struct GPIO *const GPIO_LED = ((struct GPIO *)GPIO_LED_BASE); |
|
|
static struct GPIO *const GPIO_OTHER = ((struct GPIO *)GPIO_OTHER_BASE); |
|
|
|
|
|
static chopstx_mutex_t mtx; |
|
|
static chopstx_cond_t cnd0, cnd1; |
|
|
|
|
|
#define BUTTON_PUSHED 1 |
|
|
static uint8_t button_state; |
|
|
|
|
|
static uint8_t |
|
|
user_button (void) |
|
|
{ |
|
|
return button_state; |
|
|
} |
|
|
|
|
|
|
|
|
static uint8_t l_data[5]; |
|
|
#define LED_FULL ((0x1f << 20)|(0x1f << 15)|(0x1f << 10)|(0x1f << 5)|0x1f) |
|
|
|
|
|
static void |
|
|
set_led_display (uint32_t data) |
|
|
{ |
|
|
l_data[0] = (data >> 0) & 0x1f; |
|
|
l_data[1] = (data >> 5) & 0x1f; |
|
|
l_data[2] = (data >> 10) & 0x1f; |
|
|
l_data[3] = (data >> 15) & 0x1f; |
|
|
l_data[4] = (data >> 20) & 0x1f; |
|
|
} |
|
|
|
|
|
static void |
|
|
scroll_led_display (uint8_t row) |
|
|
{ |
|
|
l_data[0] = (l_data[0] << 1) | ((row >> 0) & 1); |
|
|
l_data[1] = (l_data[1] << 1) | ((row >> 1) & 1); |
|
|
l_data[2] = (l_data[2] << 1) | ((row >> 2) & 1); |
|
|
l_data[3] = (l_data[3] << 1) | ((row >> 3) & 1); |
|
|
l_data[4] = (l_data[4] << 1) | ((row >> 4) & 1); |
|
|
} |
|
|
|
|
|
|
|
|
static void |
|
|
wait_for (uint32_t usec) |
|
|
{ |
|
|
chopstx_usec_wait (usec); |
|
|
} |
|
|
|
|
|
static void |
|
|
led_prepare_row (uint8_t col) |
|
|
{ |
|
|
uint16_t data = 0x1f; |
|
|
|
|
|
data |= ((l_data[0] & (1 << col)) ? 1 : 0) << 5; |
|
|
data |= ((l_data[1] & (1 << col)) ? 1 : 0) << 6; |
|
|
data |= ((l_data[2] & (1 << col)) ? 1 : 0) << 7; |
|
|
data |= ((l_data[3] & (1 << col)) ? 1 : 0) << 9; |
|
|
data |= ((l_data[4] & (1 << col)) ? 1 : 0) << 10; |
|
|
GPIO_LED->ODR = data; |
|
|
} |
|
|
|
|
|
|
|
|
static void |
|
|
led_enable_column (uint8_t col) |
|
|
{ |
|
|
GPIO_LED->BRR = (1 << col); |
|
|
} |
|
|
|
|
|
static void * |
|
|
led (void *arg) |
|
|
{ |
|
|
(void)arg; |
|
|
|
|
|
chopstx_mutex_lock (&mtx); |
|
|
chopstx_cond_wait (&cnd0, &mtx); |
|
|
chopstx_mutex_unlock (&mtx); |
|
|
|
|
|
while (!main_finished) |
|
|
{ |
|
|
int i; |
|
|
|
|
|
for (i = 0; i < 5; i++) |
|
|
{ |
|
|
led_prepare_row (i); |
|
|
led_enable_column (i); |
|
|
wait_for (1000); |
|
|
} |
|
|
} |
|
|
|
|
|
GPIO_LED->ODR = 0x0000; /* Off all LEDs. */ |
|
|
GPIO_LED->OSPEEDR = 0; |
|
|
GPIO_LED->OTYPER = 0; |
|
|
GPIO_LED->MODER = 0; /* Input mode. */ |
|
|
GPIO_OTHER->PUPDR = 0x0000; /* No pull-up. */ |
|
|
|
|
|
return NULL; |
|
|
} |
|
|
|
|
|
|
|
|
static uint8_t get_button_sw (void) { return (GPIO_OTHER->IDR & 1) == 0; } |
|
|
|
|
|
static void * |
|
|
button (void *arg) |
|
|
{ |
|
|
uint8_t last_button = 0; |
|
|
|
|
|
(void)arg; |
|
|
|
|
|
chopstx_mutex_lock (&mtx); |
|
|
chopstx_cond_wait (&cnd1, &mtx); |
|
|
chopstx_mutex_unlock (&mtx); |
|
|
|
|
|
while (!main_finished) |
|
|
{ |
|
|
uint8_t button = get_button_sw (); |
|
|
|
|
|
if (last_button == button && button != button_state) |
|
|
{ |
|
|
wait_for (1000); |
|
|
button = get_button_sw (); |
|
|
if (last_button == button) |
|
|
button_state = button; |
|
|
} |
|
|
|
|
|
wait_for (2000); |
|
|
last_button = button; |
|
|
} |
|
|
|
|
|
return NULL; |
|
|
} |
|
|
|
|
|
#define PRIO_LED 3 |
|
|
#define PRIO_BUTTON 2 |
|
|
|
|
|
#define STACK_MAIN |
|
|
#define STACK_PROCESS_1 |
|
|
#define STACK_PROCESS_2 |
|
|
#include "stack-def.h" |
|
|
|
|
|
#define STACK_ADDR_LED ((uint32_t)process1_base) |
|
|
#define STACK_SIZE_LED (sizeof process1_base) |
|
|
|
|
|
#define STACK_ADDR_BUTTON ((uint32_t)process2_base) |
|
|
#define STACK_SIZE_BUTTON (sizeof process2_base) |
|
|
|
|
|
#define DATA55(x0,x1,x2,x3,x4) (x0<<20)|(x1<<15)|(x2<<10)|(x3<< 5)|(x4<< 0) |
|
|
#define SIZE55(img) (sizeof (img) / sizeof (uint32_t)) |
|
|
|
|
|
static uint32_t l55[] = { |
|
|
DATA55 (0x08, 0x04, 0x1c, 0x00, 0x00), |
|
|
DATA55 (0x00, 0x14, 0x0c, 0x08, 0x00), |
|
|
DATA55 (0x00, 0x04, 0x14, 0x0c, 0x00), |
|
|
DATA55 (0x00, 0x08, 0x06, 0x0c, 0x00), |
|
|
DATA55 (0x00, 0x04, 0x02, 0x0e, 0x00), |
|
|
DATA55 (0x00, 0x00, 0x0a, 0x06, 0x04), |
|
|
DATA55 (0x00, 0x00, 0x02, 0x0a, 0x06), |
|
|
DATA55 (0x00, 0x00, 0x04, 0x03, 0x06), |
|
|
DATA55 (0x00, 0x00, 0x02, 0x01, 0x07), |
|
|
DATA55 (0x02, 0x00, 0x00, 0x05, 0x03), |
|
|
DATA55 (0x03, 0x00, 0x00, 0x01, 0x05), |
|
|
DATA55 (0x03, 0x00, 0x00, 0x02, 0x11), |
|
|
DATA55 (0x13, 0x00, 0x00, 0x01, 0x10), |
|
|
DATA55 (0x11, 0x01, 0x00, 0x00, 0x12), |
|
|
DATA55 (0x12, 0x11, 0x00, 0x00, 0x10), |
|
|
DATA55 (0x18, 0x11, 0x00, 0x00, 0x01), |
|
|
DATA55 (0x08, 0x19, 0x00, 0x00, 0x10), |
|
|
DATA55 (0x09, 0x18, 0x10, 0x00, 0x00), |
|
|
DATA55 (0x08, 0x09, 0x18, 0x00, 0x00), |
|
|
DATA55 (0x10, 0x0c, 0x18, 0x00, 0x00), |
|
|
}; |
|
|
|
|
|
#define DATA55V(x0,x1,x2,x3,x4) (x0<<0)|(x1<<5)|(x2<<10)|(x3<< 15)|(x4<< 20) |
|
|
|
|
|
#define CHAR_SPC 0 |
|
|
#define CHAR_H 1 |
|
|
#define CHAR_A 2 |
|
|
#define CHAR_P 3 |
|
|
#define CHAR_Y 4 |
|
|
#define CHAR_C 5 |
|
|
#define CHAR_K 6 |
|
|
#define CHAR_I 7 |
|
|
#define CHAR_N 8 |
|
|
#define CHAR_G 9 |
|
|
#define CHAR_EXC 10 |
|
|
#define CHAR_W 11 |
|
|
#define CHAR_h 12 |
|
|
#define CHAR_t 13 |
|
|
#define CHAR_AP 14 |
|
|
#define CHAR_s 15 |
|
|
#define CHAR_U 16 |
|
|
#define CHAR_QT 17 |
|
|
#define CHAR_o 18 |
|
|
#define CHAR_X 19 |
|
|
|
|
|
static uint8_t hh[] = { |
|
|
CHAR_H, CHAR_A, CHAR_P, CHAR_P, CHAR_Y, |
|
|
CHAR_SPC, |
|
|
CHAR_H, CHAR_A, CHAR_C, CHAR_K, CHAR_I, CHAR_N, CHAR_G, |
|
|
CHAR_EXC, |
|
|
CHAR_SPC, CHAR_SPC, CHAR_SPC, |
|
|
}; |
|
|
|
|
|
static uint8_t gnu[] = { |
|
|
CHAR_W, CHAR_h, CHAR_A, CHAR_t, CHAR_AP, CHAR_s, CHAR_SPC, |
|
|
CHAR_G, CHAR_N, CHAR_U, CHAR_QT, |
|
|
CHAR_SPC, CHAR_SPC, |
|
|
CHAR_G, CHAR_N, CHAR_U, CHAR_AP, CHAR_s, CHAR_SPC, |
|
|
CHAR_N, CHAR_o, CHAR_t, CHAR_SPC, |
|
|
CHAR_U, CHAR_N, CHAR_I, CHAR_X, |
|
|
CHAR_EXC, |
|
|
CHAR_SPC, CHAR_SPC, |
|
|
}; |
|
|
|
|
|
struct { uint8_t width; uint32_t data; } chargen[] = { |
|
|
{ 3, 0 }, /* SPACE */ |
|
|
{ 4, DATA55V (0x1f, 0x04, 0x04, 0x1f, 0x00) }, /* H */ |
|
|
{ 3, DATA55V (0x17, 0x15, 0x0f, 0x00, 0x00) }, /* A */ |
|
|
{ 4, DATA55V (0x1f, 0x14, 0x14, 0x08, 0x00) }, /* P */ |
|
|
{ 4, DATA55V (0x19, 0x05, 0x05, 0x1e, 0x00) }, /* Y */ |
|
|
{ 4, DATA55V (0x0e, 0x11, 0x11, 0x0a, 0x00) }, /* C */ |
|
|
{ 4, DATA55V (0x1f, 0x04, 0x0c, 0x13, 0x00) }, /* K */ |
|
|
{ 3, DATA55V (0x11, 0x1f, 0x11, 0x00, 0x00) }, /* I */ |
|
|
{ 4, DATA55V (0x1f, 0x08, 0x06, 0x1f, 0x00) }, /* N */ |
|
|
{ 4, DATA55V (0x0e, 0x11, 0x15, 0x07, 0x00) }, /* G */ |
|
|
{ 2, DATA55V (0x1d, 0x1c, 0x00, 0x00, 0x00) }, /* ! */ |
|
|
{ 5, DATA55V (0x1e, 0x01, 0x0e, 0x01, 0x1e) }, /* W */ |
|
|
{ 3, DATA55V (0x1f, 0x04, 0x07, 0x00, 0x00) }, /* h */ |
|
|
{ 4, DATA55V (0x08, 0x1e, 0x09, 0x09, 0x00) }, /* t */ |
|
|
{ 3, DATA55V (0x04, 0x18, 0x18, 0x00, 0x00) }, /* ' */ |
|
|
{ 4, DATA55V (0x09, 0x15, 0x15, 0x12, 0x00) }, /* s */ |
|
|
{ 4, DATA55V (0x1e, 0x01, 0x01, 0x1e, 0x00) }, /* U */ |
|
|
{ 4, DATA55V (0x08, 0x10, 0x15, 0x08, 0x00) }, /* ? */ |
|
|
{ 4, DATA55V (0x06, 0x09, 0x09, 0x06, 0x00) }, /* o */ |
|
|
{ 5, DATA55V (0x11, 0x0a, 0x04, 0x0a, 0x11) }, /* X */ |
|
|
{ 4, DATA55V (0x1f, 0x11, 0x11, 0x0e, 0x00) }, /* D */ |
|
|
{ 4, DATA55V (0x0e, 0x15, 0x15, 0x0d, 0x00) }, /* e */ |
|
|
{ 4, DATA55V (0x1f, 0x05, 0x05, 0x06, 0x00) }, /* b */ |
|
|
{ 1, DATA55V (0x17, 0x00, 0x00, 0x00, 0x00) }, /* i */ |
|
|
{ 4, DATA55V (0x02, 0x15, 0x15, 0x0f, 0x00) }, /* a */ |
|
|
{ 4, DATA55V (0x0f, 0x08, 0x08, 0x0f, 0x00) }, /* n */ |
|
|
}; |
|
|
|
|
|
|
|
|
#define REPEAT_COUNT 10 |
|
|
|
|
|
static int |
|
|
life_display (void) |
|
|
{ |
|
|
unsigned int i; |
|
|
uint8_t count = 0; |
|
|
uint8_t state = 0; |
|
|
|
|
|
while (count++ < REPEAT_COUNT) |
|
|
for (i = 0; i < SIZE55 (l55); i++) |
|
|
{ |
|
|
if (user_button ()) |
|
|
{ |
|
|
set_led_display (LED_FULL); |
|
|
state = 1; |
|
|
} |
|
|
else if (state == 1) |
|
|
return 0; |
|
|
else |
|
|
set_led_display (l55[i]); |
|
|
wait_for (350*1000); |
|
|
} |
|
|
|
|
|
return 1; |
|
|
} |
|
|
|
|
|
|
|
|
static int |
|
|
text_display (uint8_t kind) |
|
|
{ |
|
|
unsigned int i, j; |
|
|
uint8_t *text; |
|
|
uint8_t len; |
|
|
uint8_t count = 0; |
|
|
uint8_t state = 0; |
|
|
|
|
|
if (kind) |
|
|
{ |
|
|
text = hh; |
|
|
len = sizeof (hh); |
|
|
} |
|
|
else |
|
|
{ |
|
|
text = gnu; |
|
|
len = sizeof (gnu); |
|
|
} |
|
|
|
|
|
set_led_display (0); |
|
|
while (count++ < REPEAT_COUNT) |
|
|
for (i = 0; i < len; i++) |
|
|
{ |
|
|
for (j = 0; j < chargen[text[i]].width; j++) |
|
|
{ |
|
|
if (user_button ()) |
|
|
{ |
|
|
set_led_display (LED_FULL); |
|
|
state = 1; |
|
|
} |
|
|
else if (state == 1) |
|
|
return 0; |
|
|
else |
|
|
scroll_led_display ((chargen[text[i]].data >> j * 5) & 0x1f); |
|
|
wait_for (120*1000); |
|
|
} |
|
|
|
|
|
if (user_button ()) |
|
|
{ |
|
|
set_led_display (LED_FULL); |
|
|
state = 1; |
|
|
} |
|
|
else if (state == 1) |
|
|
return 0; |
|
|
else |
|
|
scroll_led_display (0); |
|
|
wait_for (120*1000); |
|
|
} |
|
|
|
|
|
return 1; |
|
|
} |
|
|
|
|
|
|
|
|
int |
|
|
main (int argc, const char *argv[]) |
|
|
{ |
|
|
chopstx_t led_thd; |
|
|
chopstx_t button_thd; |
|
|
uint8_t happy = 1; |
|
|
(void)argc; |
|
|
(void)argv; |
|
|
|
|
|
chopstx_conf_idle (1); |
|
|
|
|
|
chopstx_mutex_init (&mtx); |
|
|
chopstx_cond_init (&cnd0); |
|
|
chopstx_cond_init (&cnd1); |
|
|
|
|
|
led_thd = chopstx_create (PRIO_LED, STACK_ADDR_LED, |
|
|
STACK_SIZE_LED, led, NULL); |
|
|
button_thd = chopstx_create (PRIO_BUTTON, STACK_ADDR_BUTTON, |
|
|
STACK_SIZE_BUTTON, button, NULL); |
|
|
|
|
|
chopstx_usec_wait (200*1000); |
|
|
|
|
|
chopstx_mutex_lock (&mtx); |
|
|
chopstx_cond_signal (&cnd0); |
|
|
chopstx_cond_signal (&cnd1); |
|
|
chopstx_mutex_unlock (&mtx); |
|
|
|
|
|
wait_for (100*1000); |
|
|
if (user_button ()) |
|
|
{ |
|
|
/* Wait button release. */ |
|
|
while (user_button ()) |
|
|
wait_for (100*1000); |
|
|
|
|
|
happy = 0; |
|
|
goto do_text; |
|
|
} |
|
|
|
|
|
while (1) |
|
|
{ |
|
|
if (life_display ()) |
|
|
break; |
|
|
do_text: |
|
|
if (text_display (happy)) |
|
|
break; |
|
|
} |
|
|
|
|
|
main_finished = 1; |
|
|
chopstx_join (button_thd, NULL); |
|
|
chopstx_join (led_thd, NULL); |
|
|
|
|
|
chopstx_conf_idle (4); |
|
|
return 0; |
|
|
}
|
|
|
|