mirror of
https://github.com/Valeh2012/PersonalVotingMachine
synced 2025-12-08 18:15:11 +02:00
first commit
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
#
|
||||
# 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:=gpio_pulse
|
||||
|
||||
# The source files of the project
|
||||
CSRC:=$(wildcard *.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)
|
||||
# $(SYSSRC:.c=.o) $(U8G2SRC:.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 -I. -I$(SYSINC) -I$(U8G2INC)
|
||||
# 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
|
||||
# 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 -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 $@
|
||||
|
||||
|
||||
@@ -0,0 +1,642 @@
|
||||
/*
|
||||
GPIO pulse generator project for the STM32L031
|
||||
|
||||
I2C:
|
||||
Write 0, <gpio cmd>
|
||||
|
||||
*/
|
||||
|
||||
#include "stm32l031xx.h"
|
||||
#include "core_cm0plus.h"
|
||||
|
||||
/*================================================*/
|
||||
/* forward declaration */
|
||||
void setGPIO( uint8_t n );
|
||||
void clearGPIO(void);
|
||||
|
||||
/*================================================*/
|
||||
/* queue */
|
||||
|
||||
#define GPIO_QUEUE_MAX 128
|
||||
uint8_t gpio_queue_mem[GPIO_QUEUE_MAX];
|
||||
uint8_t gpio_queue_start = 0;
|
||||
uint8_t gpio_queue_end = 0;
|
||||
|
||||
/* this is called from the I2C interrupt procedures */
|
||||
void addCmdToGPIOQueue(uint8_t n)
|
||||
{
|
||||
uint8_t pos;
|
||||
pos = gpio_queue_end ;
|
||||
pos++;
|
||||
if ( pos >= GPIO_QUEUE_MAX )
|
||||
pos = 0;
|
||||
if ( pos == gpio_queue_start )
|
||||
return; // queue overflow
|
||||
gpio_queue_mem[gpio_queue_end] = n;
|
||||
gpio_queue_end = pos;
|
||||
}
|
||||
|
||||
uint8_t isGPIOQueueEmpty(void)
|
||||
{
|
||||
if ( gpio_queue_start == gpio_queue_end )
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get the next command in the queue, return 255 if the queue is empty */
|
||||
uint8_t getCmdFromGPIOQueue(void)
|
||||
{
|
||||
uint8_t r = gpio_queue_mem[gpio_queue_start];
|
||||
if ( isGPIOQueueEmpty() )
|
||||
return 255;
|
||||
return r;
|
||||
}
|
||||
|
||||
void removeCmdFromGPIOQueue(void)
|
||||
{
|
||||
if ( isGPIOQueueEmpty() )
|
||||
return;
|
||||
__disable_irq();
|
||||
gpio_queue_start++;
|
||||
if ( gpio_queue_start >= GPIO_QUEUE_MAX )
|
||||
gpio_queue_start = 0;
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
/*================================================*/
|
||||
/* GPIO output state machine */
|
||||
|
||||
#define GPIO_STATE_IDLE 0
|
||||
#define GPIO_STATE_TURN_ON 1
|
||||
#define GPIO_STATE_WAIT_ON 2
|
||||
#define GPIO_STATE_OFF 3
|
||||
/* time is in ticks + 1 */
|
||||
#define GPIO_STATE_ON_TICKS 0
|
||||
#define GPIO_STATE_OFF_TICKS 4
|
||||
|
||||
volatile uint8_t gpio_state = GPIO_STATE_IDLE;
|
||||
volatile uint8_t gpio_state_machine_output_number = 0;
|
||||
volatile uint8_t gpio_state_machine_counter = 0;
|
||||
|
||||
void gpioNextState(void)
|
||||
{
|
||||
switch(gpio_state)
|
||||
{
|
||||
case GPIO_STATE_IDLE:
|
||||
break;
|
||||
case GPIO_STATE_TURN_ON:
|
||||
setGPIO(gpio_state_machine_output_number);
|
||||
gpio_state_machine_counter = GPIO_STATE_ON_TICKS;
|
||||
gpio_state = GPIO_STATE_WAIT_ON;
|
||||
break;
|
||||
case GPIO_STATE_WAIT_ON:
|
||||
if ( gpio_state_machine_counter == 0 )
|
||||
{
|
||||
clearGPIO();
|
||||
gpio_state_machine_counter = GPIO_STATE_OFF_TICKS;
|
||||
gpio_state = GPIO_STATE_OFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
gpio_state_machine_counter--;
|
||||
}
|
||||
break;
|
||||
case GPIO_STATE_OFF:
|
||||
if ( gpio_state_machine_counter == 0 )
|
||||
{
|
||||
gpio_state = GPIO_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gpio_state_machine_counter--;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
gpio_state = GPIO_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t gpioStartStateMachine(uint8_t gpio_number)
|
||||
{
|
||||
/* can we enable the state machine? */
|
||||
if ( gpio_state != GPIO_STATE_IDLE )
|
||||
return 0; /* not idle, can not start */
|
||||
/* set the gpio number */
|
||||
__disable_irq();
|
||||
gpio_state_machine_output_number = gpio_number;
|
||||
gpio_state = GPIO_STATE_TURN_ON;
|
||||
__enable_irq();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*================================================*/
|
||||
/* Queue & State Machine Connector */
|
||||
|
||||
void processQueue(void)
|
||||
{
|
||||
uint8_t cmd;
|
||||
cmd = getCmdFromGPIOQueue();
|
||||
if ( cmd < 255 )
|
||||
{
|
||||
/* try to start the state machine */
|
||||
if ( gpioStartStateMachine(cmd) != 0 )
|
||||
{
|
||||
/* success, remove the cmd from the queue */
|
||||
removeCmdFromGPIOQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*==============================================*/
|
||||
/* I2C */
|
||||
|
||||
volatile unsigned char i2c_mem[256]; /* contains data, which read or written */
|
||||
volatile unsigned char i2c_idx; /* the current index into i2c_mem */
|
||||
volatile unsigned char i2c_is_write_idx; /* write state */
|
||||
|
||||
volatile uint16_t i2c_total_irq_cnt;
|
||||
volatile uint16_t i2c_TXIS_cnt;
|
||||
volatile uint16_t i2c_RXNE_cnt;
|
||||
|
||||
|
||||
void i2c_mem_reset_write(void)
|
||||
{
|
||||
i2c_is_write_idx = 1;
|
||||
}
|
||||
|
||||
void i2c_mem_init(void)
|
||||
{
|
||||
i2c_idx = 0;
|
||||
i2c_mem_reset_write();
|
||||
}
|
||||
|
||||
void i2c_mem_set_index(unsigned char value)
|
||||
{
|
||||
i2c_idx = value;
|
||||
i2c_is_write_idx = 0;
|
||||
}
|
||||
|
||||
void i2c_mem_write_via_index(unsigned char value)
|
||||
{
|
||||
if ( i2c_idx == 0 )
|
||||
{
|
||||
/* additionall put this byte into the queue */
|
||||
addCmdToGPIOQueue(value);
|
||||
}
|
||||
i2c_mem[i2c_idx++] = value;
|
||||
}
|
||||
|
||||
unsigned char i2c_mem_read(void)
|
||||
{
|
||||
i2c_mem_reset_write();
|
||||
i2c_idx++;
|
||||
return i2c_mem[i2c_idx];
|
||||
}
|
||||
|
||||
void i2c_mem_write(unsigned char value)
|
||||
{
|
||||
if ( i2c_is_write_idx != 0 )
|
||||
{
|
||||
i2c_mem_set_index(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
i2c_is_write_idx = 0;
|
||||
i2c_mem_write_via_index(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* address: I2C address multiplied by 2 */
|
||||
/* Pins PA9 (SCL) and PA10 (SDA) */
|
||||
void i2c_hw_init(unsigned char address)
|
||||
{
|
||||
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; /* Enable clock for I2C */
|
||||
RCC->IOPENR |= RCC_IOPENR_IOPAEN; /* Enable clock for GPIO Port A */
|
||||
|
||||
__NOP(); /* extra delay for clock stabilization required? */
|
||||
__NOP();
|
||||
|
||||
|
||||
/* configure io */
|
||||
GPIOA->MODER &= ~GPIO_MODER_MODE9; /* clear mode for PA9 */
|
||||
GPIOA->MODER |= GPIO_MODER_MODE9_1; /* alt fn */
|
||||
GPIOA->OTYPER |= GPIO_OTYPER_OT_9; /* open drain */
|
||||
GPIOA->AFR[1] &= ~(15<<4); /* Clear Alternate Function PA9 */
|
||||
GPIOA->AFR[1] |= 1<<4; /* I2C Alternate Function PA9 */
|
||||
|
||||
GPIOA->MODER &= ~GPIO_MODER_MODE10; /* clear mode for PA10 */
|
||||
GPIOA->MODER |= GPIO_MODER_MODE10_1; /* alt fn */
|
||||
GPIOA->OTYPER |= GPIO_OTYPER_OT_10; /* open drain */
|
||||
GPIOA->AFR[1] &= ~(15<<8); /* Clear Alternate Function PA10 */
|
||||
GPIOA->AFR[1] |= 1<<8; /* I2C Alternate Function PA10 */
|
||||
|
||||
|
||||
RCC->CCIPR &= ~RCC_CCIPR_I2C1SEL; /* write 00 to the I2C clk selection register */
|
||||
RCC->CCIPR |= RCC_CCIPR_I2C1SEL_0; /* select system clock (01) */
|
||||
|
||||
/* I2C init flow chart: Clear PE bit */
|
||||
|
||||
I2C1->CR1 &= ~I2C_CR1_PE;
|
||||
|
||||
/* I2C init flow chart: Configure filter */
|
||||
|
||||
/* leave at defaults */
|
||||
|
||||
/* I2C init flow chart: Configure timing */
|
||||
/*
|
||||
standard mode 100kHz configuration
|
||||
SYSCLK = I2CCLK = 32 MHz
|
||||
PRESC = 6 bits 28..31
|
||||
SCLL = 0x13 bits 0..7
|
||||
SCLH = 0x0f bits 8..15
|
||||
SDADEL = 0x02 bits 16..19
|
||||
SCLDEL = 0x04 bits 20..23
|
||||
*/
|
||||
I2C1->TIMINGR = 0x60420f13;
|
||||
|
||||
/* I2C init flow chart: Configure NOSTRECH */
|
||||
|
||||
I2C1->CR1 |= I2C_CR1_NOSTRETCH;
|
||||
|
||||
/* I2C init flow chart: Enable I2C */
|
||||
|
||||
I2C1->CR1 |= I2C_CR1_PE;
|
||||
|
||||
|
||||
/* disable OAR1 for reconfiguration */
|
||||
I2C1->OAR1 &= ~I2C_OAR1_OA1EN;
|
||||
|
||||
I2C1->OAR1 = address;
|
||||
|
||||
I2C1->OAR1 |= I2C_OAR1_OA1EN;
|
||||
|
||||
|
||||
/* enable interrupts */
|
||||
I2C1->CR1 |= I2C_CR1_STOPIE;
|
||||
I2C1->CR1 |= I2C_CR1_NACKIE;
|
||||
//I2C1->CR1 |= I2C_CR1_ADDRIE;
|
||||
I2C1->CR1 |= I2C_CR1_RXIE;
|
||||
I2C1->CR1 |= I2C_CR1_TXIE;
|
||||
|
||||
|
||||
|
||||
/* load first value into TXDR register */
|
||||
I2C1->TXDR = i2c_mem[i2c_idx];
|
||||
|
||||
|
||||
/* enable IRQ in NVIC */
|
||||
NVIC_SetPriority(I2C1_IRQn, 0);
|
||||
NVIC_EnableIRQ(I2C1_IRQn);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void i2c_init(unsigned char address)
|
||||
{
|
||||
i2c_mem_init();
|
||||
i2c_hw_init(address);
|
||||
}
|
||||
|
||||
|
||||
void __attribute__ ((interrupt, used)) I2C1_IRQHandler(void)
|
||||
{
|
||||
unsigned long isr = I2C1->ISR;
|
||||
|
||||
i2c_total_irq_cnt ++;
|
||||
|
||||
if ( isr & I2C_ISR_TXIS )
|
||||
{
|
||||
i2c_TXIS_cnt++;
|
||||
I2C1->TXDR = i2c_mem_read();
|
||||
}
|
||||
else if ( isr & I2C_ISR_RXNE )
|
||||
{
|
||||
i2c_RXNE_cnt++;
|
||||
i2c_mem_write(I2C1->RXDR);
|
||||
I2C1->ISR |= I2C_ISR_TXE; // allow overwriting the TCDR with new data
|
||||
I2C1->TXDR = i2c_mem[i2c_idx];
|
||||
}
|
||||
else if ( isr & I2C_ISR_STOPF )
|
||||
{
|
||||
I2C1->ICR = I2C_ICR_STOPCF;
|
||||
I2C1->ISR |= I2C_ISR_TXE; // allow overwriting the TCDR with new data
|
||||
I2C1->TXDR = i2c_mem[i2c_idx];
|
||||
i2c_mem_reset_write();
|
||||
}
|
||||
else if ( isr & I2C_ISR_NACKF )
|
||||
{
|
||||
I2C1->ICR = I2C_ICR_NACKCF;
|
||||
I2C1->ISR |= I2C_ISR_TXE; // allow overwriting the TCDR with new data
|
||||
I2C1->TXDR = i2c_mem[i2c_idx];
|
||||
i2c_mem_reset_write();
|
||||
}
|
||||
else if ( isr & I2C_ISR_ADDR )
|
||||
{
|
||||
/* not required, the addr match interrupt is not enabled */
|
||||
I2C1->ICR = I2C_ICR_ADDRCF;
|
||||
I2C1->ISR |= I2C_ISR_TXE; // allow overwriting the TCDR with new data
|
||||
I2C1->TXDR = i2c_mem[i2c_idx];
|
||||
i2c_mem_reset_write();
|
||||
}
|
||||
|
||||
/* if at any time the addr match is set, clear the flag */
|
||||
/* not sure, whether this is required */
|
||||
if ( isr & I2C_ISR_ADDR )
|
||||
{
|
||||
I2C1->ICR = I2C_ICR_ADDRCF;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*================================================*/
|
||||
|
||||
volatile unsigned long SysTickCount = 0;
|
||||
|
||||
void __attribute__ ((interrupt, used)) SysTick_Handler(void)
|
||||
{
|
||||
SysTickCount++;
|
||||
gpioNextState();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void setHSIClock()
|
||||
{
|
||||
|
||||
|
||||
/* test if the current clock source is something else than HSI */
|
||||
if ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI)
|
||||
{
|
||||
/* enable HSI */
|
||||
RCC->CR |= RCC_CR_HSION;
|
||||
/* wait until HSI becomes ready */
|
||||
while ( (RCC->CR & RCC_CR_HSIRDY) == 0 )
|
||||
;
|
||||
|
||||
/* enable the HSI "divide by 4" bit */
|
||||
RCC->CR |= (uint32_t)(RCC_CR_HSIDIVEN);
|
||||
/* wait until the "divide by 4" flag is enabled */
|
||||
while((RCC->CR & RCC_CR_HSIDIVF) == 0)
|
||||
;
|
||||
|
||||
|
||||
/* then use the HSI clock */
|
||||
RCC->CFGR = (RCC->CFGR & (uint32_t) (~RCC_CFGR_SW)) | RCC_CFGR_SW_HSI;
|
||||
|
||||
/* wait until HSI clock is used */
|
||||
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI)
|
||||
;
|
||||
}
|
||||
|
||||
/* disable PLL */
|
||||
RCC->CR &= (uint32_t)(~RCC_CR_PLLON);
|
||||
/* wait until PLL is inactive */
|
||||
while((RCC->CR & RCC_CR_PLLRDY) != 0)
|
||||
;
|
||||
|
||||
/* set latency to 1 wait state */
|
||||
FLASH->ACR |= FLASH_ACR_LATENCY;
|
||||
|
||||
/* At this point the HSI runs with 4 MHz */
|
||||
/* Multiply by 16 device by 2 --> 32 MHz */
|
||||
RCC->CFGR = (RCC->CFGR & (~(RCC_CFGR_PLLMUL| RCC_CFGR_PLLDIV ))) | (RCC_CFGR_PLLMUL16 | RCC_CFGR_PLLDIV2);
|
||||
|
||||
/* enable PLL */
|
||||
RCC->CR |= RCC_CR_PLLON;
|
||||
|
||||
/* wait until the PLL is ready */
|
||||
while ((RCC->CR & RCC_CR_PLLRDY) == 0)
|
||||
;
|
||||
|
||||
/* use the PLL has clock source */
|
||||
RCC->CFGR |= (uint32_t) (RCC_CFGR_SW_PLL);
|
||||
/* wait until the PLL source is active */
|
||||
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL)
|
||||
;
|
||||
}
|
||||
|
||||
void initGPIO(void)
|
||||
{
|
||||
RCC->IOPENR |= RCC_IOPENR_IOPAEN; /* Enable clock for GPIO Port A */
|
||||
__NOP();
|
||||
__NOP();
|
||||
|
||||
|
||||
GPIOA->MODER &= ~GPIO_MODER_MODE14; /* clear mode */
|
||||
GPIOA->MODER |= GPIO_MODER_MODE14_0; /* Output mode */
|
||||
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_14; /* no Push/Pull */
|
||||
GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED14; /* low speed */
|
||||
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD14; /* no pullup/pulldown */
|
||||
GPIOA->BSRR = GPIO_BSRR_BR_14; /* atomic clr */
|
||||
|
||||
GPIOA->MODER &= ~GPIO_MODER_MODE13; /* clear mode */
|
||||
GPIOA->MODER |= GPIO_MODER_MODE13_0; /* Output mode */
|
||||
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_13; /* no Push/Pull */
|
||||
GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED13; /* low speed */
|
||||
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD13; /* no pullup/pulldown */
|
||||
GPIOA->BSRR = GPIO_BSRR_BR_13; /* atomic clr */
|
||||
|
||||
GPIOA->MODER &= ~GPIO_MODER_MODE7; /* clear mode */
|
||||
GPIOA->MODER |= GPIO_MODER_MODE7_0; /* Output mode */
|
||||
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_7; /* no Push/Pull */
|
||||
GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED7; /* low speed */
|
||||
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD7; /* no pullup/pulldown */
|
||||
GPIOA->BSRR = GPIO_BSRR_BR_7; /* atomic clr */
|
||||
|
||||
GPIOA->MODER &= ~GPIO_MODER_MODE6; /* clear mode */
|
||||
GPIOA->MODER |= GPIO_MODER_MODE6_0; /* Output mode */
|
||||
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_6; /* no Push/Pull */
|
||||
GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED6; /* low speed */
|
||||
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD6; /* no pullup/pulldown */
|
||||
GPIOA->BSRR = GPIO_BSRR_BR_6; /* atomic clr */
|
||||
|
||||
GPIOA->MODER &= ~GPIO_MODER_MODE5; /* clear mode */
|
||||
GPIOA->MODER |= GPIO_MODER_MODE5_0; /* Output mode */
|
||||
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_5; /* no Push/Pull */
|
||||
GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED5; /* low speed */
|
||||
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD5; /* no pullup/pulldown */
|
||||
GPIOA->BSRR = GPIO_BSRR_BR_5; /* atomic clr */
|
||||
|
||||
GPIOA->MODER &= ~GPIO_MODER_MODE4; /* clear mode */
|
||||
GPIOA->MODER |= GPIO_MODER_MODE4_0; /* Output mode */
|
||||
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_4; /* no Push/Pull */
|
||||
GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED4; /* low speed */
|
||||
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD4; /* no pullup/pulldown */
|
||||
GPIOA->BSRR = GPIO_BSRR_BR_4; /* atomic clr */
|
||||
|
||||
GPIOA->MODER &= ~GPIO_MODER_MODE1; /* clear mode */
|
||||
GPIOA->MODER |= GPIO_MODER_MODE1_0; /* Output mode */
|
||||
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_1; /* no Push/Pull */
|
||||
GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED1; /* low speed */
|
||||
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD1; /* no pullup/pulldown */
|
||||
GPIOA->BSRR = GPIO_BSRR_BR_1; /* atomic clr */
|
||||
|
||||
GPIOA->MODER &= ~GPIO_MODER_MODE0; /* clear mode */
|
||||
GPIOA->MODER |= GPIO_MODER_MODE0_0; /* Output mode */
|
||||
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_0; /* no Push/Pull */
|
||||
GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED0; /* low speed */
|
||||
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD0; /* no pullup/pulldown */
|
||||
GPIOA->BSRR = GPIO_BSRR_BR_0; /* atomic clr */
|
||||
|
||||
}
|
||||
|
||||
void clearGPIO(void)
|
||||
{
|
||||
GPIOA->BSRR = GPIO_BSRR_BR_14
|
||||
| GPIO_BSRR_BR_13
|
||||
| GPIO_BSRR_BR_7
|
||||
| GPIO_BSRR_BR_6
|
||||
| GPIO_BSRR_BR_5
|
||||
| GPIO_BSRR_BR_4
|
||||
| GPIO_BSRR_BR_1
|
||||
| GPIO_BSRR_BR_0;
|
||||
}
|
||||
|
||||
/*
|
||||
0: PA14
|
||||
1: PA13
|
||||
2: PA7
|
||||
3: PA6
|
||||
4: PA5
|
||||
5: PA4
|
||||
6: PA1
|
||||
7: PA0
|
||||
*/
|
||||
void setGPIO( uint8_t n )
|
||||
{
|
||||
clearGPIO();
|
||||
switch(n)
|
||||
{
|
||||
case 0: GPIOA->BSRR = GPIO_BSRR_BS_14; break;
|
||||
case 1: GPIOA->BSRR = GPIO_BSRR_BS_13; break;
|
||||
case 2: GPIOA->BSRR = GPIO_BSRR_BS_7; break;
|
||||
case 3: GPIOA->BSRR = GPIO_BSRR_BS_6; break;
|
||||
case 4: GPIOA->BSRR = GPIO_BSRR_BS_5; break;
|
||||
case 5: GPIOA->BSRR = GPIO_BSRR_BS_4; break;
|
||||
case 6: GPIOA->BSRR = GPIO_BSRR_BS_1; break;
|
||||
case 7: GPIOA->BSRR = GPIO_BSRR_BS_0; break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void setAllGPIO(void)
|
||||
{
|
||||
GPIOA->BSRR = GPIO_BSRR_BS_14
|
||||
| GPIO_BSRR_BS_13
|
||||
| GPIO_BSRR_BS_7
|
||||
| GPIO_BSRR_BS_6
|
||||
| GPIO_BSRR_BS_5
|
||||
| GPIO_BSRR_BS_4
|
||||
| GPIO_BSRR_BS_1
|
||||
| GPIO_BSRR_BS_0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
uint8_t i;
|
||||
initGPIO();
|
||||
|
||||
setHSIClock();
|
||||
|
||||
i2c_init(2*17);
|
||||
|
||||
SysTick->LOAD = 32000*100 - 1; // 100 ms
|
||||
SysTick->VAL = 0;
|
||||
SysTick->CTRL = 7; /* enable, generate interrupt (SysTick_Handler), do not divide by 2 */
|
||||
|
||||
|
||||
/*
|
||||
for(;;)
|
||||
{
|
||||
delay_system_ticks(32000*200);
|
||||
setGPIO(7);
|
||||
delay_system_ticks(32000*200);
|
||||
clearGPIO();
|
||||
}
|
||||
*/
|
||||
|
||||
for( i = 0; i < 8; i++ )
|
||||
addCmdToGPIOQueue(i);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
processQueue();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
Reference in New Issue
Block a user