first commit

This commit is contained in:
valeh
2020-12-22 14:30:09 +02:00
commit 26b0ba5954
1832 changed files with 17777948 additions and 0 deletions

View File

@@ -0,0 +1,149 @@
#
# Generic and Simple GNU ARM Makefile
#
# Desinged for the gnu-arm-none-eabi tool chain
#
# Features
# - create hex file
# - create assembler listing (.dis)
#
# Limitations
# - only C-files supported
# - no automatic dependency checking (call 'make clean' if any .h files are changed)
#
# Targets:
# make
# create hex file, no upload
# make upload
# create and upload hex file
# make clean
# delete all generated files
#
# Note:
# Display list make database: make -p -f/dev/null | less
#
#================================================
# External tools
# The base directory of gcc-arm-none-eabi
# Can be empty on Ubuntu and installed gcc-arm-none-eabi
# If set, GCCBINPATH must contain a "/" at the end.
GCCBINPATH:=/usr/bin/
#================================================
# Project Information
# The name for the project
TARGETNAME:=clock
# The source files of the project
CSRC:=$(wildcard *.c) ../../../sdl/clock/datecalc.c ../../../sdl/clock/guifn.c ../../../sdl/clock/guimenu.c ../../../sdl/clock/menu.c
SSRC:=$(wildcard ../stm32l0xx/src/*.s)
# The CPU architecture (will be used for -mcpu)
# for the LPC824, can we use "cortex-m0plus"?
MCPU:=cortex-m0plus
# Include directory for the system include files
SYSINC:=../stm32l0xx/inc
SYSSRC:=$(wildcard ../stm32l0xx/src/*.c)
# Include directory for the u8g2 include files
U8G2INC:=../../../../csrc/
U8G2SRC:=$(wildcard ../../../../csrc/*.c)
# directory for FatFS
#FFINC:=../fatfs
#FFSRC:=$(wildcard ../fatfs/*.c)
# Directory for the linker script
LDSCRIPTDIR:=.
# Name of the linker script (must be the "keep" script, because the other script is not always working)
LDSCRIPT:=stm32l031x6.ld
#================================================
# Main part of the Makefile starts here. Usually no changes are needed.
# Internal Variable Names
LIBNAME:=$(TARGETNAME).a
ELFNAME:=$(TARGETNAME).elf
HEXNAME:=$(TARGETNAME).hex
DISNAME:=$(TARGETNAME).dis
MAPNAME:=$(TARGETNAME).map
OBJ:=$(CSRC:.c=.o) $(SSRC:.s=.o) $(SYSSRC:.c=.o) $(U8G2SRC:.c=.o)
# $(SYSSRC:.c=.o) $(FFSRC:.c=.o)
# Replace standard build tools by arm tools
AS:=$(GCCBINPATH)arm-none-eabi-as
CC:=$(GCCBINPATH)arm-none-eabi-gcc
AR:=$(GCCBINPATH)arm-none-eabi-ar
OBJCOPY:=$(GCCBINPATH)arm-none-eabi-objcopy
OBJDUMP:=$(GCCBINPATH)arm-none-eabi-objdump
SIZE:=$(GCCBINPATH)arm-none-eabi-size
# Common flags
COMMON_FLAGS = -mthumb -mcpu=$(MCPU)
COMMON_FLAGS += -DSTM32L031xx
COMMON_FLAGS += -Wall
# define stack size (defaults to 0x0100)
# COMMON_FLAGS += -D__STACK_SIZE=0x0100
# COMMON_FLAGS += -Os -flto
COMMON_FLAGS += -Os
# COMMON_FLAGS += -fstack-protector
# COMMON_FLAGS += -finstrument-functions
# Do not use stand libs startup code. Uncomment this for gcclib procedures
# memcpy still works, but might be required for __aeabi_uidiv
# COMMON_FLAGS += -nostdlib
# remove unused data and function
#COMMON_FLAGS += -ffunction-sections -fdata-sections -fshort-wchar
COMMON_FLAGS += -ffunction-sections -fdata-sections
# C flags
CFLAGS:=$(COMMON_FLAGS) -std=gnu99 -I. -I$(SYSINC) -I$(U8G2INC) -I../../../sdl/clock/
# LD flags
# remove unreferenced procedures and variables, but __isr_vector
GC:=-Wl,--gc-sections -Wl,--undefined=__isr_vector
MAP:=-Wl,-Map=$(MAPNAME)
LFLAGS:=$(COMMON_FLAGS) $(GC) $(MAP)
#LDLIBS:=--specs=nosys.specs -lc -lc -lnosys -L$(LDSCRIPTDIR) -T $(LDSCRIPT)
LDLIBS:=--specs=nosys.specs -L$(LDSCRIPTDIR) -T $(LDSCRIPT)
# Additional Suffixes
.SUFFIXES: .elf .hex .bin .dis
# Targets
.PHONY: all
all: $(DISNAME) $(HEXNAME)
$(SIZE) $(ELFNAME)
.PHONY: upload
upload: $(DISNAME) $(HEXNAME) $(ELFNAME)
#stm32flash -b 115200 -e 255 -g 0 -w $(HEXNAME) -v /dev/ttyUSB0
stm32flash -b 230400 -e 255 -g 0 -w $(HEXNAME) -v /dev/ttyUSB0
$(SIZE) $(ELFNAME)
.PHONY: clean
clean:
$(RM) $(OBJ) $(HEXNAME) $(ELFNAME) $(LIBNAME) $(DISNAME) $(MAPNAME) libssp.a libssp_nonshared.a
# implicit rules
.elf.hex:
$(OBJCOPY) -O ihex $< $@
# explicit rules
$(ELFNAME): $(LIBNAME)($(OBJ)) libssp.a libssp_nonshared.a
$(LINK.o) $(LFLAGS) $(LIBNAME) $(LDLIBS) -o $@
$(DISNAME): $(ELFNAME)
$(OBJDUMP) -D -S $< > $@
# create empty ssp libs for -fstack-protector-all -fstack-protector
libssp.a:
$(AR) rcs $@
libssp_nonshared.a:
$(AR) rcs $@

View File

@@ -0,0 +1,129 @@
/*
delay.c
The delay function delay_micro_seconds() will use the global variable
SystemCoreClock. A call to SystemCoreClockUpdate() is required before
using delay_micro_seconds().
STM32L031 Project (U8g2 Library)
Copyright (c) 2017, olikraus@gmail.com
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "stm32l031xx.h"
/* Generic ARM delay procedure, based on the system timer (SysTick) */
/*
Delay by the provided number of system ticks.
The delay must be smaller than the RELOAD value.
This delay has an imprecision of about +/- 20 system ticks.
*/
static void _delay_system_ticks_sub(uint32_t sys_ticks)
{
uint32_t start_val, end_val, curr_val;
uint32_t load;
start_val = SysTick->VAL;
start_val &= 0x0ffffffUL;
end_val = start_val;
if ( end_val < sys_ticks )
{
/* check, if the operation after this if clause would lead to a negative result */
/* if this would be the case, then add the reload value first */
load = SysTick->LOAD;
load &= 0x0ffffffUL;
end_val += load;
}
/* counter goes towards zero, so end_val is below start value */
end_val -= sys_ticks;
/* wait until interval is left */
if ( start_val >= end_val )
{
for(;;)
{
curr_val = SysTick->VAL;
curr_val &= 0x0ffffffUL;
if ( curr_val <= end_val )
break;
if ( curr_val > start_val )
break;
}
}
else
{
for(;;)
{
curr_val = SysTick->VAL;
curr_val &= 0x0ffffffUL;
if ( curr_val <= end_val && curr_val > start_val )
break;
}
}
}
/*
Delay by the provided number of system ticks.
Any values between 0 and 0x0ffffffff are allowed.
*/
void delay_system_ticks(uint32_t sys_ticks)
{
uint32_t load4;
load4 = SysTick->LOAD;
load4 &= 0x0ffffffUL;
load4 >>= 2;
while ( sys_ticks > load4 )
{
sys_ticks -= load4;
_delay_system_ticks_sub(load4);
}
_delay_system_ticks_sub(sys_ticks);
}
/*
Delay by the provided number of micro seconds.
Limitation: "us" * System-Freq in MHz must not overflow in 32 bit.
Values between 0 and 1.000.000 (1 second) are ok.
Important: Call SystemCoreClockUpdate() before calling this function.
*/
void delay_micro_seconds(uint32_t us)
{
uint32_t sys_ticks;
sys_ticks = SystemCoreClock;
sys_ticks /=1000000UL;
sys_ticks *= us;
delay_system_ticks(sys_ticks);
}

View File

@@ -0,0 +1,55 @@
/*
delay.h
LPC11U3x GPS Logger (https://github.com/olikraus/lpc11u3x-gps-logger)
Copyright (c) 2016, olikraus@gmail.com
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _DELAY_H
#define _DELAY_H
#include <stdint.h>
/*
Delay by the provided number of system ticks.
Any values between 0 and 0x0ffffffff are allowed.
*/
void delay_system_ticks(uint32_t sys_ticks);
/*
Delay by the provided number of micro seconds.
Limitation: "us" * System-Freq in MHz must now overflow in 32 bit.
Values between 0 and 1.000.000 (1 second) are ok.
Important: Call SystemCoreClockUpdate() before calling this function.
*/
void delay_micro_seconds(uint32_t us);
#endif /* _DELAY_H */

View File

@@ -0,0 +1,251 @@
/*
guihal.c
*/
#include "stm32l031xx.h"
#include "gui.h"
/*============================================*/
/* reset */
void do_reset(void)
{
/* clear the display first, to provide some visual feedback to the user */
u8g2_ClearDisplay(gui_menu.u8g2);
__disable_irq();
/* Deactivate tamper so that the uC can be programmed via UART */
/* This is required, because RX pin is shared with Tamp2 */
RTC->WPR = 0x0ca; /* disable RTC write protection */
RTC->WPR = 0x053;
EXTI->IMR &= ~EXTI_IMR_IM19; /* disable tamper irq */
RTC->TAMPCR = 0; /* clear tamper detection */
RTC->WPR = 0; /* disable RTC write protection */
RTC->WPR = 0;
/* execute reset */
NVIC_SystemReset();
}
/*============================================*/
/* load & store from/to permanent memory */
/* 5x 32bit */
void store_gui_data(uint32_t *data)
{
RTC->BKP0R = data[0];
RTC->BKP1R = data[1];
RTC->BKP2R = data[2];
RTC->BKP3R = data[3];
RTC->BKP4R = data[4];
}
void load_gui_data(uint32_t *data)
{
int i;
for( i = 0; i < GUI_ALARM_CNT; i++ )
data[i] = 0;
data[0] = RTC->BKP0R;
data[1] = RTC->BKP1R;
data[2] = RTC->BKP2R;
data[3] = RTC->BKP3R;
data[4] = RTC->BKP4R;
}
/*============================================*/
/* input */
int is_por_reset(void)
{
return 1;
}
int is_button_reset(void)
{
return 0;
}
uint32_t get_boot_status_register(void)
{
/* POR: 00001100 (POR=1, PIN=1), reset pin has RC network connected */
/* Boot via NVIC: 00011100, compared to POR, the SW Reset flag is also set */
return RCC->CSR >> 24;
}
extern volatile unsigned long PWR_CSR_Backup;
uint32_t get_pwr_status_register(void)
{
/*
Bit 1 SBF: Standby flag
This bit is set by hardware and cleared only by a POR/PDR (power-on reset/power-down
reset) or by setting the CSBF bit in the PWR power control register (PWR_CR)
0: Device has not been in Standby mode
1: Device has been in Standby mode
Bit 0 WUF: Wakeup flag
This bit is set by hardware and cleared by a system reset or by setting the CWUF bit in the
PWR power control register (PWR_CR)
0: No wakeup event occurred
1: A wakeup event was received from the WKUP pin or from the RTC
POR (voltage off-on): 00
Reset Button: 00
WUF Reset: 11
*/
return PWR_CSR_Backup & 255;
}
extern volatile unsigned long ResetReason;
uint32_t get_reset_reason(void)
{
return ResetReason;
}
extern volatile unsigned long RTCWUCount;
uint32_t get_wakeup_count(void)
{
return RTCWUCount;
}
int is_dst_by_date(uint8_t region);
uint32_t get_dst_by_date(void)
{
return is_dst_by_date(1);
}
uint32_t get_dst_by_RTC(void)
{
uint32_t dst_state = 0;
if ( RTC->CR & RTC_CR_BCK ) /* BKP flag in the CR register */
dst_state = 1;
return dst_state;
}
/*============================================*/
/* output */
void SetAlarmSequence(const uint8_t *alarm_sequence);
extern const uint8_t ASeqTrippleBeep[];
void enable_alarm(void)
{
SetAlarmSequence(ASeqTrippleBeep);
}
void disable_alarm(void)
{
SetAlarmSequence(NULL);
}
void set_time(uint8_t ht, uint8_t ho, uint8_t mt, uint8_t mo, uint8_t st, uint8_t so)
{
uint32_t v;
v = ht;
v <<= 4,
v |= ho;
v <<= 4;
v |= mt;
v <<= 4;
v |= mo;
v <<= 4;
v |= st;
v <<= 4;
v |= so;
__disable_irq();
RTC->WPR = 0x0ca; /* disable RTC write protection */
RTC->WPR = 0x053;
RTC->ISR = RTC_ISR_INIT; /* request RTC stop */
while((RTC->ISR & RTC_ISR_INITF)!=RTC_ISR_INITF) /* wait for stop */
;
RTC->PRER = 0x07f00ff; /* 1 Hz clock */
RTC->TR = v;
RTC->ISR =~ RTC_ISR_INIT; /* start RTC */
RTC->WPR = 0; /* enable RTC write protection */
RTC->WPR = 0;
__enable_irq();
}
/*
weekday: 0 = monday
*/
void set_date(uint8_t yt, uint8_t yo, uint8_t mt, uint8_t mo, uint8_t dayt, uint8_t dayo, uint8_t weekday)
{
uint32_t v;
v = yt;
v <<= 4,
v |= yo;
v <<= 3;
v |= weekday+1; /* monday starts with 1 on the STM32L0 */
v <<= 1;
v |= mt;
v <<= 4;
v |= mo;
v <<= 4;
v |= dayt;
v <<= 4;
v |= dayo;
__disable_irq();
RTC->WPR = 0x0ca; /* disable RTC write protection */
RTC->WPR = 0x053;
RTC->ISR = RTC_ISR_INIT; /* request RTC stop */
while((RTC->ISR & RTC_ISR_INITF)!=RTC_ISR_INITF) /* wait for stop */
;
RTC->PRER = 0x07f00ff; /* 1 Hz clock */
RTC->DR = v;
RTC->ISR =~ RTC_ISR_INIT; /* start RTC */
RTC->WPR = 0; /* enable RTC write protection */
RTC->WPR = 0;
__enable_irq();
}
/* value 1..7, 0 is default (do not set) */
void set_contrast(void)
{
uint8_t v = gui_data.contrast;
if ( v > 0 )
{
v = v * 36;
u8g2_SetContrast(gui_menu.u8g2, v);
}
}

View File

@@ -0,0 +1,47 @@
/*
key.c
*/
#include <stdint.h>
#include "stm32l031xx.h" /* IRQ disable/enable */
#include "key.h"
#define KEY_QUEUE_MASK 0x0f
#define KEY_QUEUE_MAX (KEY_QUEUE_MASK+1)
uint8_t volatile key_queue[KEY_QUEUE_MAX];
uint8_t volatile key_queue_start = 0;
uint8_t volatile key_queue_end = 0;
int key_add(uint8_t key)
{
uint8_t new_end;
new_end = key_queue_end;
new_end++;
new_end &= KEY_QUEUE_MASK;
if ( new_end == key_queue_start )
return 0; /* buffer is full */
key_queue[key_queue_end] = key;
key_queue_end = new_end;
return 1;
}
uint8_t key_get(void)
{
uint8_t key;
uint8_t new_start;
if ( key_queue_start == key_queue_end )
{
return KEY_NONE;
}
//__disable_irq();
key = key_queue[key_queue_start];
new_start = key_queue_start;
new_start++;
new_start &= KEY_QUEUE_MASK;
key_queue_start = new_start;
//__enable_irq();
return key;
}

View File

@@ -0,0 +1,19 @@
/*
key.h
*/
#ifndef _KEY_H
#define KEY_H
#define KEY_NONE 0
#define KEY_SELECT 1
#define KEY_NEXT 2
int key_add(uint8_t key);
uint8_t key_get(void);
extern volatile uint8_t key_queue_start;
extern volatile uint8_t key_queue_end;
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,82 @@
/*
rtc.c
PA0 TAMP2 Button
PA2 TAMP3 Button
*/
#include <string.h>
#include "stm32l031xx.h"
#include "delay.h"
#include "u8g2.h"
#include "rtc.h"
#ifdef NOT_USED
/* read RTC register into bcd array */
void rtc_register_to_bcd(rtc_t *rtc)
{
uint32_t r;
int i;
r = RTC->TR;
i = 0;
do
{
rtc->bcd[i] = r & 15;
r >>= 4;
i++;
} while( i < 6 );
rtc->bcd[1] &= 7; /* seconds */
rtc->bcd[3] &= 7; /* minutes */
rtc->bcd[5] &= 3; /* hours */
r = RTC->DR;
i = 6;
do
{
rtc->bcd[i] = r & 15;
r >>= 4;
i++;
} while( i < 12 );
rtc->bcd[7] &= 3; /* days */
rtc->bcd[9] &= 1; /* months */
}
static uint8_t rtc_bcd_to_uint8(rtc_t *rtc, int idx) U8G2_NOINLINE;
static uint8_t rtc_bcd_to_uint8(rtc_t *rtc, int idx)
{
return rtc->bcd[idx+1]*10 + rtc->bcd[idx];
}
/* convert the content of the bcd array to the ymd&hms vars */
void rtc_bcd_to_ymd_hms(rtc_t *rtc)
{
rtc->sec = rtc_bcd_to_uint8(rtc, 0);
rtc->min = rtc_bcd_to_uint8(rtc, 2);
rtc->hour = rtc_bcd_to_uint8(rtc, 4);
rtc->day = rtc_bcd_to_uint8(rtc, 6);
rtc->month = rtc_bcd_to_uint8(rtc, 8);
rtc->year = rtc_bcd_to_uint8(rtc, 10);
}
void rtc_draw_time(rtc_t *rtc, u8g2_t *u8g2)
{
char s[10];
strcpy(s, u8x8_u8toa(rtc->hour, 2));
strcat(s, ":");
strcat(s, u8x8_u8toa(rtc->min, 2));
strcat(s, ":");
strcat(s, u8x8_u8toa(rtc->sec, 2));
u8g2_SetFont(u8g2, u8g2_font_helvB18_tn);
u8g2_DrawStr(u8g2, 0,23, s);
}
#endif

View File

@@ -0,0 +1,43 @@
/*
rtc.h
*/
#ifndef _RTC_VIEW_H
#define _RTC_VIEW_H
#include "stdint.h"
#define BCD_SEC_UNITS 0
#define BCD_SEC_TENS 1
#define BCD_MIN_UNITS 2
#define BCD_MIN_TENS 3
#define BCD_HOUR_UNITS 4
#define BCD_HOUR_TENS 5
#define BCD_DAY_UNITS 6
#define BCD_DAY_TENS 7
#define BCD_MONTH_UNITS 8
#define BCD_MONTH_TENS 9
#define BCD_YEAR_UNITS 10
#define BCD_YEAR_TENS 11
struct _rtc_struct
{
uint8_t bcd[12];
uint8_t sec; /* 0..59 */
uint8_t min; /* 0..59 */
uint8_t hour; /* 0..23 */
uint8_t day; /* 1..31 */
uint8_t month; /* 1..12 */
uint8_t year; /* 0..99 */
};
typedef struct _rtc_struct rtc_t;
void rtc_register_to_bcd(rtc_t *rtc);
void rtc_bcd_to_ymd_hms(rtc_t *rtc);
void rtc_draw_time(rtc_t *rtc, u8g2_t *u8g2);
#endif

View File

@@ -0,0 +1,245 @@
/*
stm32l031x6.ld
Modified for stm32l0 from the original nokeep.ld script from the
arm-none-eabi examples by olikraus@gmail.com
Assuming, that the original nokeep.ld file is available under
the GNU General Public License, this file is available under the
same license.
There are three modifications:
1. Provide symbols for the stm32l0 startup code
The following symbols are required for the stm32l0 startup
code (e.g. startup_stm32l031xx.s)
_sidata start address for the initialization values of the .data section
_sdata start address for the .data section. defined in linker script
_edata end address for the .data section. defined in linker script
_sbss start address for the .bss section. defined in linker script
_ebss end address for the .bss section. defined in linker script
_estack top address of the stack
2. Stack size estimation / calculation
_Stack_Size has been added to allow better stack size calculation
3. KEEP keywords
Additionall KEEPs added for .init and .fini. Without this KEEP the
generated code will not work, because of the missing _init function.
4. Bugfix: Allign the end of the flash area
*/
_Stack_Size = 0x400; /* stm32l0: estimated amount of stack */
/* Linker script to configure memory regions.
* Need modifying for a specific board.
* FLASH.ORIGIN: starting address of flash
* FLASH.LENGTH: length of flash
* RAM.ORIGIN: starting address of RAM bank 0
* RAM.LENGTH: length of RAM bank 0
*/
MEMORY
{
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 32K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
}
/* Linker script to place sections and symbol values. Should be used together
* with other linker script that defines memory regions FLASH and RAM.
* It references following symbols, which must be defined in code:
* Reset_Handler : Entry of reset handler
*
* It defines following symbols, which code can use without definition:
* __exidx_start
* __exidx_end
* __copy_table_start__
* __copy_table_end__
* __zero_table_start__
* __zero_table_end__
* __etext
* __data_start__
* __preinit_array_start
* __preinit_array_end
* __init_array_start
* __init_array_end
* __fini_array_start
* __fini_array_end
* __data_end__
* __bss_start__
* __bss_end__
* __end__
* end
* __HeapLimit
* __StackLimit
* __StackTop
* __stack
*/
ENTRY(Reset_Handler)
SECTIONS
{
.text :
{
KEEP(*(.isr_vector))
*(.text*)
/* the st32l0 startup code calls __libc_init_array, which calls the _init */
/* ... sooo.... better keep the init and fini sections */
KEEP ( *(.init) )
KEEP ( *(.fini) )
/* .ctors */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)
/* .dtors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)
*(.rodata*)
*(.eh_frame*)
/* allign the end of the flash area */
. = ALIGN(4);
} > FLASH
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
__exidx_end = .;
/* To copy multiple ROM to RAM sections,
* uncomment .copy.table section and,
* define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */
/*
.copy.table :
{
. = ALIGN(4);
__copy_table_start__ = .;
LONG (__etext)
LONG (__data_start__)
LONG (__data_end__ - __data_start__)
LONG (__etext2)
LONG (__data2_start__)
LONG (__data2_end__ - __data2_start__)
__copy_table_end__ = .;
} > FLASH
*/
/* To clear multiple BSS sections,
* uncomment .zero.table section and,
* define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */
/*
.zero.table :
{
. = ALIGN(4);
__zero_table_start__ = .;
LONG (__bss_start__)
LONG (__bss_end__ - __bss_start__)
LONG (__bss2_start__)
LONG (__bss2_end__ - __bss2_start__)
__zero_table_end__ = .;
} > FLASH
*/
__etext = .;
_sidata = .; /* for stm32l0 startup code */
.data : AT (__etext)
{
__data_start__ = .;
_sdata = .; /* for stm32l0 startup code */
*(vtable)
*(.data*)
. = ALIGN(4);
/* preinit data */
PROVIDE_HIDDEN (__preinit_array_start = .);
*(.preinit_array)
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
/* init data */
PROVIDE_HIDDEN (__init_array_start = .);
*(SORT(.init_array.*))
*(.init_array)
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
/* finit data */
PROVIDE_HIDDEN (__fini_array_start = .);
*(SORT(.fini_array.*))
*(.fini_array)
PROVIDE_HIDDEN (__fini_array_end = .);
*(.jcr)
. = ALIGN(4);
/* All data end */
__data_end__ = .;
_edata = .; /* for stm32l0 startup code */
} > RAM
.bss :
{
. = ALIGN(4);
__bss_start__ = .;
_sbss = .; /* for stm32l0 startup code */
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
_ebss = .; /* for stm32l0 startup code */
} > RAM
.heap (COPY):
{
__end__ = .;
PROVIDE(end = .);
*(.heap*)
__HeapLimit = .;
} > RAM
/* .stack_dummy section doesn't contains any symbols. It is only
* used for linker to calculate size of stack sections, and assign
* values to stack symbols later */
.stack_dummy (COPY):
{
*(.stack*)
. = . + _Stack_Size; /* estimated stack size */
} > RAM
/* Set stack top to end of RAM, and stack limit move down by
* size of stack_dummy section */
__StackTop = ORIGIN(RAM) + LENGTH(RAM);
_estack = __StackTop; /* for stm32l0 startup code */
__StackLimit = __StackTop - SIZEOF(.stack_dummy);
PROVIDE(__stack = __StackTop);
/* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
}

View File

@@ -0,0 +1,271 @@
/*
summer.c
stm32l0 daylight savings time (DST) calculation
US:
Der Energy Policy Act of 2005 (Public Law 109-58) bestimmt in Sec. 110 mit dem Titel Daylight Savings,
dass ab 2007 die Sommerzeit am zweiten Sonntag im März beginnt und am ersten Sonntag im November endet.
EU:
Central European Summer Time (CEST, britisch) oder Central European Daylight Saving Time
(applies to almost all european countries)
Die mitteleuropäische Sommerzeit beginnt jeweils am letzten Sonntag im März um 2:00 Uhr MEZ,
indem die Stundenzählung um eine Stunde von 2:00 Uhr auf 3:00 Uhr vorgestellt wird. Sie endet jeweils am letzten Sonntag im Oktober um
3:00 Uhr MESZ, indem die Stundenzählung um eine Stunde von 3:00 Uhr auf 2:00 Uhr zurückgestellt wird. Die Stunde von 2:00 Uhr bis 3:00 Uhr erscheint im Herbst also zweimal.
*/
#ifdef __unix
#include <stdio.h>
#include <stdint.h>
static uint8_t is_leap_year(uint16_t y)
{
if (
((y % 4 == 0) && (y % 100 != 0)) ||
(y % 400 == 0)
)
return 1;
return 0;
}
uint16_t get_year_day_number(uint16_t y, uint8_t m, uint8_t d)
{
uint8_t tmp1;
uint16_t tmp2;
tmp1 = 0;
if ( m >= 3 )
tmp1++;
tmp2 = m;
tmp2 +=2;
tmp2 *=611;
tmp2 /= 20;
tmp2 += d;
tmp2 -= 91;
tmp1 <<=1;
tmp2 -= tmp1;
if ( tmp1 != 0 )
tmp2 += is_leap_year(y);
return tmp2;
}
uint8_t get_weekday_by_year_day_number(uint16_t y, uint16_t ydn)
{
uint8_t j, c, tmp8;
uint16_t tmp16;
y--;
j = y % 100;
c = y / 100;
tmp16 = c;
tmp16 *= 5;
tmp16 += ydn;
tmp8 = j;
j >>= 2;
c >>= 2;
tmp8 += j;
tmp8 += c;
tmp8 += 28;
tmp16 += tmp8;
tmp16 %= 7;
return tmp16;
}
uint16_t year;
uint16_t month;
uint16_t day;
uint16_t hour;
#else
#include "datecalc.h"
#include "stm32l031xx.h"
#endif
/*
this function does not require gui_date_adjust() to be called
0: no DST (Wintertime)
1: DST (Summertime)
-1: unknown (last sunday in oct, between 2am and 3am )
region
0: do nothing
1: EU
2: US
*/
int is_dst_by_date(uint8_t region)
{
uint16_t ydn;
uint16_t ydn_change_to_wintertime;
uint16_t ydn_change_to_summertime;
#ifndef __unix
uint16_t year;
uint16_t month;
uint16_t day;
uint16_t hour;
/* read date from date register */
year = ((RTC->DR >> 20) & 15);
year *= 10;
year += ((RTC->DR >> 16) & 15);
year += 2000;
month = ((RTC->DR >> 12) & 1);
month *= 10;
month += ((RTC->DR >> 8) & 15);
day = ((RTC->DR >> 4) & 3);
day *= 10;
day += ((RTC->DR) & 15);
/* also get the hour for later comparison */
hour = ((RTC->TR >> 20) & 3); /* assuming 24-hour clock, not sure about PM flag */
hour *= 10;
hour += ((RTC->TR >> 16) & 15);
#endif
/* convert all dates to date numbers of the current year*/
if ( region == 1 ) /* EU */
{
/* European Summer Time: Last Sunday in March and last Sunday in October */
ydn_change_to_summertime = get_year_day_number(year, 3, 31);
ydn_change_to_wintertime = get_year_day_number(year, 10, 31);
}
else if ( region == 2 ) /* US */
{
/* US DST rules: Second Sunday in March and First Sunday in November */
ydn_change_to_summertime = get_year_day_number(year, 2, 28+is_leap_year(year));
ydn_change_to_summertime += 14;
ydn_change_to_wintertime = get_year_day_number(year, 10, 31);
ydn_change_to_wintertime += 7;
}
else
{
return 0;
}
ydn_change_to_summertime -= get_weekday_by_year_day_number(year, ydn_change_to_summertime);
ydn_change_to_wintertime -= get_weekday_by_year_day_number(year, ydn_change_to_wintertime);
ydn = get_year_day_number(year, month, day);
if ( ydn == ydn_change_to_summertime )
if ( hour >= 2 )
return 1; /* yes, it is DST */
if ( ydn == ydn_change_to_wintertime )
{
if ( hour < 2 )
return 1; /* still DST */
if ( hour > 3 )
return 0; /* not DST any more */
return -1; /* not sure whether DST or not */
}
if ( ydn > ydn_change_to_summertime && ydn < ydn_change_to_wintertime )
return 1; /* within DST */
return 0;
}
#ifdef __unix
int main()
{
int dd;
int d = -2;
for( year = 2000; year < 2030; year++ )
{
printf("%d: ", year);
for( month = 3; month <= 11; month ++ )
{
for( day = 1; day<= 31; day++ )
{
hour = 2;
dd = is_dst_by_date(1);
if ( d == 0 && dd == 1 )
{
printf("%d.%d.%d", day, month, year);
}
switch(dd)
{
//case -1: printf("%d.%d.%d", day, month, year); break;
//case 0: printf("w"); break;
//case 1: printf("s"); break;
}
d = dd;
}
}
printf("\n");
}
}
#else
/*
region
0: do nothing
1: EU
2: US
*/
void adjustDST(uint8_t region)
{
int is_dst;
int dst_state;
is_dst = is_dst_by_date(region);
if ( is_dst >= 0 )
{
dst_state = 0;
if ( RTC->CR & RTC_CR_BCK ) /* BKP flag in the CR register */
dst_state = 1;
if ( is_dst != dst_state )
{
__disable_irq();
PWR->CR |= PWR_CR_DBP; /* disable write protection (step 1) */
RTC->WPR = 0x0ca; /* disable RTC write protection (step 2) */
RTC->WPR = 0x053;
if ( is_dst != 0 )
{
RTC->CR |= RTC_CR_BCK; /* the RTC will now run in summer time (set DST flag) */
RTC->CR |= RTC_CR_ADD1H; /* change to DST (Summertime): add one hour */
}
else
{
RTC->CR &= ~RTC_CR_BCK; /* the RTC will now run in winter time (turn off DST flag) */
RTC->CR |= RTC_CR_SUB1H; /* change back to none DST (Wintertime): subtract one hour */
}
RTC->WPR = 0; /* enable RTC write protection (step 2) */
RTC->WPR = 0;
__enable_irq();
}
}
}
#endif

View File

@@ -0,0 +1,112 @@
/*
u8x8cb.c
STM32L031
PA9: Clock
PA10: Data
Both lines have a pullup resistor
*/
#include "stm32l031xx.h"
#include "delay.h"
#include "u8x8.h"
uint8_t u8x8_gpio_and_delay_stm32l0(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
switch(msg)
{
case U8X8_MSG_GPIO_AND_DELAY_INIT:
/* only support for software I2C*/
RCC->IOPENR |= RCC_IOPENR_IOPAEN; /* Enable clock for GPIO Port A */
__NOP();
__NOP();
GPIOA->MODER &= ~GPIO_MODER_MODE10; /* clear mode for PA10 */
//GPIOA->MODER |= GPIO_MODER_MODE10_0; /* Output mode for PA10 */
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_10; /* no open drain for PA10 */
GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED10; /* low speed for PA10 */
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD10; /* no pullup/pulldown for PA10 */
//GPIOA->BSRR = GPIO_BSRR_BS_10; /* atomic set PA10 */
GPIOA->MODER &= ~GPIO_MODER_MODE9; /* clear mode for PA9 */
//GPIOA->MODER |= GPIO_MODER_MODE9_0; /* Output mode for PA9 */
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_9; /* no open drain for PA9 */
GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED9; /* low speed for PA9 */
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD9; /* no pullup/pulldown for PA9 */
//GPIOA->BSRR = GPIO_BSRR_BS_9; /* atomic set PA9 */
break;
case U8X8_MSG_DELAY_NANO:
/* not required for SW I2C */
break;
case U8X8_MSG_DELAY_10MICRO:
/* not used at the moment */
break;
case U8X8_MSG_DELAY_100NANO:
/* not used at the moment */
break;
case U8X8_MSG_DELAY_MILLI:
delay_micro_seconds(arg_int*1000UL);
break;
case U8X8_MSG_DELAY_I2C:
/* arg_int is 1 or 4: 100KHz (5us) or 400KHz (1.25us) */
//delay_micro_seconds(arg_int<=2?5:1);
break;
case U8X8_MSG_GPIO_I2C_CLOCK:
if ( arg_int == 0 )
{
GPIOA->MODER &= ~GPIO_MODER_MODE9; /* clear mode for PA10 */
GPIOA->MODER |= GPIO_MODER_MODE9_0; /* Output mode for PA10 */
GPIOA->BSRR = GPIO_BSRR_BR_9; /* atomic clr PA9 */
}
else
{
//GPIOA->BSRR = GPIO_BSRR_BS_9; /* atomic set PA9 */
GPIOA->MODER &= ~GPIO_MODER_MODE9; /* clear mode for PA9: input mode */
}
break;
case U8X8_MSG_GPIO_I2C_DATA:
if ( arg_int == 0 )
{
GPIOA->MODER &= ~GPIO_MODER_MODE10; /* clear mode for PA10 */
GPIOA->MODER |= GPIO_MODER_MODE10_0; /* Output mode for PA10 */
GPIOA->BSRR = GPIO_BSRR_BR_10; /* atomic clr PA10 */
}
else
{
//GPIOA->BSRR = GPIO_BSRR_BS_10; /* atomic set PA10 */
// input mode
GPIOA->MODER &= ~GPIO_MODER_MODE10; /* clear mode for PA10: input mode */
}
break;
/*
case U8X8_MSG_GPIO_MENU_SELECT:
u8x8_SetGPIOResult(u8x8, Chip_GPIO_GetPinState(LPC_GPIO, KEY_SELECT_PORT, KEY_SELECT_PIN));
break;
case U8X8_MSG_GPIO_MENU_NEXT:
u8x8_SetGPIOResult(u8x8, Chip_GPIO_GetPinState(LPC_GPIO, KEY_NEXT_PORT, KEY_NEXT_PIN));
break;
case U8X8_MSG_GPIO_MENU_PREV:
u8x8_SetGPIOResult(u8x8, Chip_GPIO_GetPinState(LPC_GPIO, KEY_PREV_PORT, KEY_PREV_PIN));
break;
case U8X8_MSG_GPIO_MENU_HOME:
u8x8_SetGPIOResult(u8x8, Chip_GPIO_GetPinState(LPC_GPIO, KEY_HOME_PORT, KEY_HOME_PIN));
break;
*/
default:
u8x8_SetGPIOResult(u8x8, 1);
break;
}
return 1;
}