Merge branch 'master' into efm32

Conflicts:
	Doxyfile
	Makefile
This commit is contained in:
chrysn
2012-09-13 22:32:28 +02:00
153 changed files with 12393 additions and 508 deletions

50
lib/Makefile.include Normal file
View File

@@ -0,0 +1,50 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2012 Piotr Esden-Tempski <piotr@esden.net>
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
# Be silent per default, but 'make V=1' will show all compiler calls.
ifneq ($(V),1)
Q := @
endif
all: $(SRCLIBDIR)/$(LIBNAME).a
$(SRCLIBDIR)/$(LIBNAME).a: $(SRCLIBDIR)/$(LIBNAME).ld $(OBJS)
@printf " AR $(shell basename $(@))\n"
$(Q)$(AR) $(ARFLAGS) $(SRCLIBDIR)/$(shell basename $(@)) $(OBJS)
$(SRCLIBDIR)/$(LIBNAME).ld: $(LIBNAME).ld
@printf " CP $(LIBNAME).ld\n"
$(Q)cp $^ $@
$(Q)if [ -f $(LIBNAME)_rom_to_ram.ld ]; then cp $(LIBNAME)_rom_to_ram.ld $(SRCLIBDIR); fi
%.o: %.c
@printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS) -o $@ -c $<
clean:
@printf " CLEAN lib/stm32/f1\n"
$(Q)rm -f *.o *.d
$(Q)rm -f $(SRCLIBDIR)/$(LIBNAME).a
$(Q)rm -f $(SRCLIBDIR)/$(LIBNAME).ld
$(Q)rm -f $(SRCLIBDIR)/$(LIBNAME)_rom_to_ram.ld
.PHONY: clean
-include $(OBJS:.o=.d)

View File

@@ -32,26 +32,4 @@ OBJS = gpio.o vector.o
# VPATH += ../usb
# Be silent per default, but 'make V=1' will show all compiler calls.
ifneq ($(V),1)
Q := @
endif
all: $(LIBNAME).a
$(LIBNAME).a: $(OBJS)
@printf " AR $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(AR) $(ARFLAGS) $@ $^
%.o: %.c
@printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS) -o $@ -c $<
clean:
@printf " CLEAN lib/lpc13xx\n"
$(Q)rm -f *.o *.d
$(Q)rm -f $(LIBNAME).a
.PHONY: clean
-include $(OBJS:.o=.d)
include ../Makefile.include

View File

@@ -24,31 +24,50 @@
/* Enforce emmition of the vector table. */
EXTERN (vector_table)
/* Define the entry point of the output file. */
ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
. = ORIGIN(rom);
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
_etext = .;
. = ALIGN(4);
} >rom
. = ORIGIN(ram);
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support
*/
.ARM.extab : {
*(.ARM.extab*)
} >rom
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >rom
. = ALIGN(4);
_etext = .;
.data : {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
} >ram AT >rom
_data_loadaddr = LOADADDR(.data);
.bss : {
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram AT >rom
} >ram
/*
* The .eh_frame section appears to be used for C++ exception handling.
@@ -56,12 +75,7 @@ SECTIONS
*/
/DISCARD/ : { *(.eh_frame) }
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support - discard it for now.
*/
/DISCARD/ : { *(.ARM.exidx) }
. = ALIGN(4);
end = .;
}

View File

@@ -20,7 +20,7 @@
#define WEAK __attribute__ ((weak))
/* Symbols exported by the linker script(s): */
extern unsigned _etext, _data, _edata, _ebss, _stack;
extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack;
void main(void);
void reset_handler(void);
@@ -61,9 +61,10 @@ void (*const vector_table[]) (void) = {
void reset_handler(void)
{
volatile unsigned *src, *dest;
__asm__("MSR msp, %0" : : "r"(&_stack));
for (src = &_etext, dest = &_data; dest < &_edata; src++, dest++)
for (src = &_data_loadaddr, dest = &_data; dest < &_edata; src++, dest++)
*dest = *src;
while (dest < &_ebss)

View File

@@ -32,27 +32,4 @@ OBJS = gpio.o
# VPATH += ../usb
# Be silent per default, but 'make V=1' will show all compiler calls.
ifneq ($(V),1)
Q := @
endif
all: $(LIBNAME).a
$(LIBNAME).a: $(OBJS)
@printf " AR $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(AR) $(ARFLAGS) $@ $^
%.o: %.c
@printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS) -o $@ -c $<
clean:
@printf " CLEAN lib/lpc13xx\n"
$(Q)rm -f *.o *.d
$(Q)rm -f $(LIBNAME).a
.PHONY: clean
-include $(OBJS:.o=.d)
include ../Makefile.include

View File

@@ -24,31 +24,50 @@
/* Enforce emmition of the vector table. */
EXTERN (vector_table)
/* Define the entry point of the output file. */
ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
. = ORIGIN(rom);
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
_etext = .;
. = ALIGN(4);
} >rom
. = ORIGIN(ram);
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support
*/
.ARM.extab : {
*(.ARM.extab*)
} >rom
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >rom
. = ALIGN(4);
_etext = .;
.data : {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
} >ram AT >rom
_data_loadaddr = LOADADDR(.data);
.bss : {
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram AT >rom
} >ram
/*
* The .eh_frame section appears to be used for C++ exception handling.
@@ -56,12 +75,7 @@ SECTIONS
*/
/DISCARD/ : { *(.eh_frame) }
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support - discard it for now.
*/
/DISCARD/ : { *(.ARM.exidx) }
. = ALIGN(4);
end = .;
}

View File

@@ -32,27 +32,4 @@ OBJS = gpio.o vector.o
# VPATH += ../usb
# Be silent per default, but 'make V=1' will show all compiler calls.
ifneq ($(V),1)
Q := @
endif
all: $(LIBNAME).a
$(LIBNAME).a: $(OBJS)
@printf " AR $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(AR) $(ARFLAGS) $@ $^
%.o: %.c
@printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS) -o $@ -c $<
clean:
@printf " CLEAN lib/lpc17xx\n"
$(Q)rm -f *.o *.d
$(Q)rm -f $(LIBNAME).a
.PHONY: clean
-include $(OBJS:.o=.d)
include ../Makefile.include

View File

@@ -1,4 +1,3 @@
/*
* This file is part of the libopencm3 project.
*
@@ -31,28 +30,44 @@ ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
. = ORIGIN(rom);
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
_etext = .;
. = ALIGN(4);
} >rom
. = ORIGIN(ram);
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support
*/
.ARM.extab : {
*(.ARM.extab*)
} >rom
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >rom
. = ALIGN(4);
_etext = .;
.data : {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
} >ram AT >rom
_data_loadaddr = LOADADDR(.data);
.bss : {
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram AT >rom
} >ram
/*
* The .eh_frame section appears to be used for C++ exception handling.
@@ -60,12 +75,7 @@ SECTIONS
*/
/DISCARD/ : { *(.eh_frame) }
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support - discard it for now.
*/
/DISCARD/ : { *(.ARM.exidx) }
. = ALIGN(4);
end = .;
}

View File

@@ -19,8 +19,8 @@
#define WEAK __attribute__ ((weak))
/* Symbols exported by the linker script(s). */
extern unsigned _etext, _data, _edata, _ebss, _stack;
/* Symbols exported by the linker script(s): */
extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack;
void main(void);
void reset_handler(void);
@@ -60,9 +60,10 @@ void (*const vector_table[]) (void) = {
void reset_handler(void)
{
volatile unsigned *src, *dest;
__asm__("MSR msp, %0" : : "r"(&_stack));
for (src = &_etext, dest = &_data; dest < &_edata; src++, dest++)
for (src = &_data_loadaddr, dest = &_data; dest < &_edata; src++, dest++)
*dest = *src;
while (dest < &_ebss)

38
lib/lpc43xx/Makefile Normal file
View File

@@ -0,0 +1,38 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
## Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
LIBNAME = libopencm3_lpc43xx
PREFIX ?= arm-none-eabi
#PREFIX ?= arm-elf
CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -O2 -g3 -Wall -Wextra -I../../include -fno-common \
-mcpu=cortex-m4 -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD \
-mfloat-abi=hard -mfpu=fpv4-sp-d16
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = gpio.o vector.o scu.o i2c.o ssp.o nvic.o systick.o
# VPATH += ../usb
include ../Makefile.include

35
lib/lpc43xx/gpio.c Normal file
View File

@@ -0,0 +1,35 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/lpc43xx/gpio.h>
void gpio_set(u32 gpioport, u32 gpios)
{
GPIO_SET(gpioport) = gpios;
}
void gpio_clear(u32 gpioport, u32 gpios)
{
GPIO_CLR(gpioport) = gpios;
}
void gpio_toggle(u32 gpioport, u32 gpios)
{
GPIO_NOT(gpioport) = gpios;
}

93
lib/lpc43xx/i2c.c Normal file
View File

@@ -0,0 +1,93 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This is a very minimal I2C driver just to make sure we can get the
* peripheral working.
*/
#include <libopencm3/lpc43xx/i2c.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/cgu.h>
void i2c0_init(void)
{
/* enable input on SCL and SDA pins */
SCU_SFSI2C0 = SCU_I2C0_NOMINAL;
/* use IRC as clock source for APB1 (including I2C0) */
CGU_BASE_APB1_CLK = (CGU_SRC_IRC << CGU_BASE_CLK_SEL_SHIFT);
/* FIXME assuming we're on IRC at 12 MHz */
/* 400 kHz I2C */
I2C0_SCLH = 15;
I2C0_SCLL = 15;
/* 100 kHz I2C */
/*
I2C0_SCLH = 60;
I2C0_SCLL = 60;
*/
/* clear the control bits */
I2C0_CONCLR = (I2C_CONCLR_AAC | I2C_CONCLR_SIC
| I2C_CONCLR_STAC | I2C_CONCLR_I2ENC);
/* enable I2C0 */
I2C0_CONSET = I2C_CONSET_I2EN;
}
/* transmit start bit */
void i2c0_tx_start(void)
{
I2C0_CONCLR = I2C_CONCLR_SIC;
I2C0_CONSET = I2C_CONSET_STA;
while (!(I2C0_CONSET & I2C_CONSET_SI));
I2C0_CONCLR = I2C_CONCLR_STAC;
}
/* transmit data byte */
void i2c0_tx_byte(u8 byte)
{
if (I2C0_CONSET & I2C_CONSET_STA)
I2C0_CONCLR = I2C_CONCLR_STAC;
I2C0_DAT = byte;
I2C0_CONCLR = I2C_CONCLR_SIC;
while (!(I2C0_CONSET & I2C_CONSET_SI));
}
/* receive data byte */
u8 i2c0_rx_byte(void)
{
if (I2C0_CONSET & I2C_CONSET_STA)
I2C0_CONCLR = I2C_CONCLR_STAC;
I2C0_CONCLR = I2C_CONCLR_SIC;
while (!(I2C0_CONSET & I2C_CONSET_SI));
return I2C0_DAT;
}
/* transmit stop bit */
void i2c0_stop(void)
{
if (I2C0_CONSET & I2C_CONSET_STA)
I2C0_CONCLR = I2C_CONCLR_STAC;
I2C0_CONSET = I2C_CONSET_STO;
I2C0_CONCLR = I2C_CONCLR_SIC;
}

View File

@@ -0,0 +1,90 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Generic linker script for LPC43XX targets using libopencm3. */
/* Memory regions must be defined in the ld script which includes this one. */
/* Enforce emmition of the vector table. */
EXTERN (vector_table)
/* Define the entry point of the output file. */
ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
.text : {
. = ALIGN(0x400);
_text_ram = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
} >rom
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support
*/
.ARM.extab : {
*(.ARM.extab*)
} >rom
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >rom
. = ALIGN(4);
_etext = .;
_etext_ram = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */
_etext_rom = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */
.data : {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
} >ram AT >rom
_data_loadaddr = LOADADDR(.data);
.bss : {
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram
/*
* The .eh_frame section appears to be used for C++ exception handling.
* You may need to fix this if you're using C++.
*/
/DISCARD/ : { *(.eh_frame) }
. = ALIGN(4);
end = .;
/* Leave room above stack for IAP to run. */
__StackTop = ORIGIN(ram) + LENGTH(ram) - 32;
PROVIDE(_stack = __StackTop);
}

View File

@@ -0,0 +1,91 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Generic linker script for LPC43XX targets using libopencm3. */
/* Memory regions must be defined in the ld script which includes this one. */
/* Enforce emmition of the vector table. */
EXTERN (vector_table)
/* Define the entry point of the output file. */
ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
.text : {
. = ALIGN(0x400);
_text_ram = (. - ORIGIN(rom)) + ORIGIN(ram); /* Start of Code in RAM */
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
} >rom
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support
*/
.ARM.extab : {
*(.ARM.extab*)
} >rom
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >rom
. = ALIGN(4);
_etext = .;
_etext_ram = (. - ORIGIN(rom)) + ORIGIN(ram);
_etext_rom = (. - ORIGIN(rom)) + ORIGIN(rom_flash);
.data : {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
} >ram_data AT >rom
_data_loadaddr = LOADADDR(.data);
.bss : {
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram_data
/*
* The .eh_frame section appears to be used for C++ exception handling.
* You may need to fix this if you're using C++.
*/
/DISCARD/ : { *(.eh_frame) }
. = ALIGN(4);
end = .;
/* Leave room above stack for IAP to run. */
__StackTop = ORIGIN(ram) + LENGTH(ram) - 32;
PROVIDE(_stack = __StackTop);
}

76
lib/lpc43xx/nvic.c Normal file
View File

@@ -0,0 +1,76 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* Copyright (C) 2012 Fergus Noble <fergusnoble@gmail.com>
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/scs.h>
#include <libopencm3/lpc43xx/nvic.h>
void nvic_enable_irq(u8 irqn)
{
NVIC_ISER(irqn / 32) = (1 << (irqn % 32));
}
void nvic_disable_irq(u8 irqn)
{
NVIC_ICER(irqn / 32) = (1 << (irqn % 32));
}
u8 nvic_get_pending_irq(u8 irqn)
{
return NVIC_ISPR(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
}
void nvic_set_pending_irq(u8 irqn)
{
NVIC_ISPR(irqn / 32) = (1 << (irqn % 32));
}
void nvic_clear_pending_irq(u8 irqn)
{
NVIC_ICPR(irqn / 32) = (1 << (irqn % 32));
}
u8 nvic_get_active_irq(u8 irqn)
{
return NVIC_IABR(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
}
u8 nvic_get_irq_enabled(u8 irqn)
{
return NVIC_ISER(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
}
void nvic_set_priority(u8 irqn, u8 priority)
{
if(irqn>NVIC_M4_QEI_IRQ)
{
/* Cortex-M system interrupts */
SCS_SHPR( (irqn&0xF)-4 ) = priority;
}else
{
/* Device specific interrupts */
NVIC_IPR(irqn) = priority;
}
}
void nvic_generate_software_interrupt(u8 irqn)
{
if (irqn <= 239)
NVIC_STIR |= irqn;
}

30
lib/lpc43xx/scu.c Normal file
View File

@@ -0,0 +1,30 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/lpc43xx/scu.h>
/* For pin_conf_normal value see scu.h define SCU_CONF_XXX or Configuration for different I/O pins types */
void scu_pinmux(scu_grp_pin_t group_pin, u32 scu_conf)
{
MMIO32(group_pin) = scu_conf;
}
/* For other special SCU register USB1, I2C0, ADC0/1, DAC, EMC clock delay See scu.h */
/* For Pin interrupt select register see scu.h SCU_PINTSEL0 & SCU_PINTSEL1 */

160
lib/lpc43xx/ssp.c Normal file
View File

@@ -0,0 +1,160 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/lpc43xx/ssp.h>
#include <libopencm3/lpc43xx/cgu.h>
#define CGU_SRC_32K 0x00
#define CGU_SRC_IRC 0x01
#define CGU_SRC_ENET_RX 0x02
#define CGU_SRC_ENET_TX 0x03
#define CGU_SRC_GP_CLKIN 0x04
#define CGU_SRC_XTAL 0x06
#define CGU_SRC_PLL0USB 0x07
#define CGU_SRC_PLL0AUDIO 0x08
#define CGU_SRC_PLL1 0x09
#define CGU_SRC_IDIVA 0x0C
#define CGU_SRC_IDIVB 0x0D
#define CGU_SRC_IDIVC 0x0E
#define CGU_SRC_IDIVD 0x0F
#define CGU_SRC_IDIVE 0x10
#define CGU_AUTOBLOCK_CLOCK_BIT 11
#define CGU_BASE_CLK_SEL_SHIFT 24 /* clock source selection (5 bits) */
/* Disable SSP */
void ssp_disable(ssp_num_t ssp_num)
{
u32 ssp_port;
if(ssp_num == SSP0_NUM)
{
ssp_port = SSP0;
}else
{
ssp_port = SSP1;
}
/* Disable SSP */
SSP_CR1(ssp_port) = 0x0;
}
/*
* SSP Init function
*/
void ssp_init(ssp_num_t ssp_num,
ssp_datasize_t data_size,
ssp_frame_format_t frame_format,
ssp_cpol_cpha_t cpol_cpha_format,
u8 serial_clock_rate,
u8 clk_prescale,
ssp_mode_t mode,
ssp_master_slave_t master_slave,
ssp_slave_option_t slave_option)
{
u32 ssp_port;
u32 clock;
if(ssp_num == SSP0_NUM)
{
ssp_port = SSP0;
}else
{
ssp_port = SSP1;
}
/* use PLL1 as clock source for SSP1 */
CGU_BASE_SSP1_CLK = (CGU_SRC_PLL1<<CGU_BASE_CLK_SEL_SHIFT) | (1<<CGU_AUTOBLOCK_CLOCK_BIT);
/* Disable SSP before to configure it */
SSP_CR1(ssp_port) = 0x0;
/* Configure SSP */
clock = serial_clock_rate;
SSP_CPSR(ssp_port) = clk_prescale;
SSP_CR0(ssp_port) = (data_size | frame_format | cpol_cpha_format | (clock<<8) );
/* Enable SSP */
SSP_CR1(ssp_port) = (SSP_ENABLE | mode | master_slave | slave_option);
}
/*
* This Function Wait until Data RX Ready, and return Data Read from SSP.
*/
u16 ssp_read(ssp_num_t ssp_num)
{
u32 ssp_port;
if(ssp_num == SSP0_NUM)
{
ssp_port = SSP0;
}else
{
ssp_port = SSP1;
}
/* Wait Until Data Received (Rx FIFO not Empty) */
while( (SSP_SR(ssp_port) & SSP_SR_RNE) == 0);
return SSP_DR(ssp_port);
}
void ssp_wait_until_not_busy(ssp_num_t ssp_num)
{
u32 ssp_port;
if(ssp_num == SSP0_NUM)
{
ssp_port = SSP0;
}else
{
ssp_port = SSP1;
}
while( (SSP_SR(ssp_port) & SSP_SR_BSY) );
}
/* This Function Wait Data TX Ready, and Write Data to SSP */
void ssp_write(ssp_num_t ssp_num, u16 data)
{
u32 ssp_port;
if(ssp_num == SSP0_NUM)
{
ssp_port = SSP0;
}else
{
ssp_port = SSP1;
}
/* Wait Until FIFO not full */
while( (SSP_SR(ssp_port) & SSP_SR_TNF) == 0);
SSP_DR(ssp_port) = data;
/* Wait for not busy, since we're controlling CS# of
* devices manually and need to wait for the data to
* be sent. It may also be important to wait here
* in case we're configuring devices via SPI and also
* with GPIO control -- we need to know when SPI
* commands are effective before altering a device's
* state with GPIO. I'm thinking the MAX2837, for
* example...
*/
ssp_wait_until_not_busy(ssp_num);
}

69
lib/lpc43xx/systick.c Normal file
View File

@@ -0,0 +1,69 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/lpc43xx/systick.h>
void systick_set_reload(u32 value)
{
STK_LOAD = (value & 0x00FFFFFF);
}
u32 systick_get_value(void)
{
return STK_VAL;
}
void systick_set_clocksource(u8 clocksource)
{
STK_CTRL |= clocksource;
}
void systick_interrupt_enable(void)
{
STK_CTRL |= STK_CTRL_TICKINT;
}
void systick_interrupt_disable(void)
{
STK_CTRL &= ~STK_CTRL_TICKINT;
}
void systick_counter_enable(void)
{
STK_CTRL |= STK_CTRL_ENABLE;
}
void systick_counter_disable(void)
{
STK_CTRL &= ~STK_CTRL_ENABLE;
}
u8 systick_get_countflag(void)
{
if (STK_CTRL & STK_CTRL_COUNTFLAG)
return 1;
else
return 0;
}
u32 systick_get_calib(void)
{
return (STK_CALIB&0x00FFFFFF);
}

264
lib/lpc43xx/vector.c Normal file
View File

@@ -0,0 +1,264 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>
* Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#define WEAK __attribute__ ((weak))
/* Symbols exported by the linker script(s): */
extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack;
extern unsigned _etext_ram, _text_ram, _etext_rom;
void main(void);
void reset_handler(void);
void blocking_handler(void);
void null_handler(void);
void WEAK nmi_handler(void);
void WEAK hard_fault_handler(void);
void WEAK mem_manage_handler(void);
void WEAK bus_fault_handler(void);
void WEAK usage_fault_handler(void);
void WEAK sv_call_handler(void);
void WEAK debug_monitor_handler(void);
void WEAK pend_sv_handler(void);
void WEAK sys_tick_handler(void);
void WEAK dac_irqhandler(void);
void WEAK m0core_irqhandler(void);
void WEAK dma_irqhandler(void);
void WEAK ethernet_irqhandler(void);
void WEAK sdio_irqhandler(void);
void WEAK lcd_irqhandler(void);
void WEAK usb0_irqhandler(void);
void WEAK usb1_irqhandler(void);
void WEAK sct_irqhandler(void);
void WEAK ritimer_irqhandler(void);
void WEAK timer0_irqhandler(void);
void WEAK timer1_irqhandler(void);
void WEAK timer2_irqhandler(void);
void WEAK timer3_irqhandler(void);
void WEAK mcpwm_irqhandler(void);
void WEAK adc0_irqhandler(void);
void WEAK i2c0_irqhandler(void);
void WEAK i2c1_irqhandler(void);
void WEAK spi_irqhandler(void);
void WEAK adc1_irqhandler(void);
void WEAK ssp0_irqhandler(void);
void WEAK ssp1_irqhandler(void);
void WEAK usart0_irqhandler(void);
void WEAK uart1_irqhandler(void);
void WEAK usart2_irqhandler(void);
void WEAK usart3_irqhandler(void);
void WEAK i2s0_irqhandler(void);
void WEAK i2s1_irqhandler(void);
void WEAK spifi_irqhandler(void);
void WEAK sgpio_irqhandler(void);
void WEAK pin_int0_irqhandler(void);
void WEAK pin_int1_irqhandler(void);
void WEAK pin_int2_irqhandler(void);
void WEAK pin_int3_irqhandler(void);
void WEAK pin_int4_irqhandler(void);
void WEAK pin_int5_irqhandler(void);
void WEAK pin_int6_irqhandler(void);
void WEAK pin_int7_irqhandler(void);
void WEAK gint0_irqhandler(void);
void WEAK gint1_irqhandler(void);
void WEAK eventrouter_irqhandler(void);
void WEAK c_can1_irqhandler(void);
void WEAK atimer_irqhandler(void);
void WEAK rtc_irqhandler(void);
void WEAK wwdt_irqhandler(void);
void WEAK c_can0_irqhandler(void);
void WEAK qei_irqhandler(void);
__attribute__ ((section(".vectors")))
void (*const vector_table[]) (void) = {
/* Cortex-M4 interrupts */
(void*)&_stack,
reset_handler,
nmi_handler,
hard_fault_handler,
mem_manage_handler,
bus_fault_handler,
usage_fault_handler,
0, 0, 0, 0, /* reserved */
sv_call_handler,
debug_monitor_handler,
0, /* reserved */
pend_sv_handler,
sys_tick_handler,
/* LPC43xx interrupts */
dac_irqhandler,
m0core_irqhandler,
dma_irqhandler,
0, /* reserved */
0, /* reserved */
ethernet_irqhandler,
sdio_irqhandler,
lcd_irqhandler,
usb0_irqhandler,
usb1_irqhandler,
sct_irqhandler,
ritimer_irqhandler,
timer0_irqhandler,
timer1_irqhandler,
timer2_irqhandler,
timer3_irqhandler,
mcpwm_irqhandler,
adc0_irqhandler,
i2c0_irqhandler,
i2c1_irqhandler,
spi_irqhandler,
adc1_irqhandler,
ssp0_irqhandler,
ssp1_irqhandler,
usart0_irqhandler,
uart1_irqhandler,
usart2_irqhandler,
usart3_irqhandler,
i2s0_irqhandler,
i2s1_irqhandler,
spifi_irqhandler,
sgpio_irqhandler,
pin_int0_irqhandler,
pin_int1_irqhandler,
pin_int2_irqhandler,
pin_int3_irqhandler,
pin_int4_irqhandler,
pin_int5_irqhandler,
pin_int6_irqhandler,
pin_int7_irqhandler,
gint0_irqhandler,
gint1_irqhandler,
eventrouter_irqhandler,
c_can1_irqhandler,
0, /* reserved */
0, /* reserved */
atimer_irqhandler,
rtc_irqhandler,
0, /* reserved */
wwdt_irqhandler,
0, /* reserved */
c_can0_irqhandler,
qei_irqhandler,
};
#define MMIO32(addr) (*(volatile unsigned long*)(addr))
#define CREG_M4MEMMAP MMIO32( (0x40043000 + 0x100) )
void reset_handler(void)
{
volatile unsigned *src, *dest;
__asm__("MSR msp, %0" : : "r"(&_stack));
/* Copy the code from ROM to Real RAM (if enabled) */
if( (&_etext_ram-&_text_ram) > 0 )
{
src = &_etext_rom-(&_etext_ram-&_text_ram);
/* Change Shadow memory to ROM (for Debug Purpose in case Boot has not set correctly the M4MEMMAP because of debug) */
CREG_M4MEMMAP = (unsigned long)src;
for(dest = &_text_ram; dest < &_etext_ram; )
{
*dest++ = *src++;
}
/* Change Shadow memory to Real RAM */
CREG_M4MEMMAP = (unsigned long)&_text_ram;
/* Continue Execution in RAM */
}
for (src = &_data_loadaddr, dest = &_data; dest < &_edata; src++, dest++)
*dest = *src;
while (dest < &_ebss)
*dest++ = 0;
/* Call the application's entry point. */
main();
}
void blocking_handler(void)
{
while (1) ;
}
void null_handler(void)
{
/* Do nothing. */
}
#pragma weak nmi_handler = null_handler
#pragma weak hard_fault_handler = blocking_handler
#pragma weak mem_manage_handler = blocking_handler
#pragma weak bus_fault_handler = blocking_handler
#pragma weak usage_fault_handler = blocking_handler
#pragma weak sv_call_handler = null_handler
#pragma weak debug_monitor_handler = null_handler
#pragma weak pend_sv_handler = null_handler
#pragma weak sys_tick_handler = null_handler
#pragma weak dac_irqhandler = null_handler
#pragma weak m0core_irqhandler = null_handler
#pragma weak dma_irqhandler = null_handler
#pragma weak ethernet_irqhandler = null_handler
#pragma weak sdio_irqhandler = null_handler
#pragma weak lcd_irqhandler = null_handler
#pragma weak usb0_irqhandler = null_handler
#pragma weak usb1_irqhandler = null_handler
#pragma weak sct_irqhandler = null_handler
#pragma weak ritimer_irqhandler = null_handler
#pragma weak timer0_irqhandler = null_handler
#pragma weak timer1_irqhandler = null_handler
#pragma weak timer2_irqhandler = null_handler
#pragma weak timer3_irqhandler = null_handler
#pragma weak mcpwm_irqhandler = null_handler
#pragma weak adc0_irqhandler = null_handler
#pragma weak i2c0_irqhandler = null_handler
#pragma weak i2c1_irqhandler = null_handler
#pragma weak spi_irqhandler = null_handler
#pragma weak adc1_irqhandler = null_handler
#pragma weak ssp0_irqhandler = null_handler
#pragma weak ssp1_irqhandler = null_handler
#pragma weak usart0_irqhandler = null_handler
#pragma weak uart1_irqhandler = null_handler
#pragma weak usart2_irqhandler = null_handler
#pragma weak usart3_irqhandler = null_handler
#pragma weak i2s0_irqhandler = null_handler
#pragma weak i2s1_irqhandler = null_handler
#pragma weak spifi_irqhandler = null_handler
#pragma weak sgpio_irqhandler = null_handler
#pragma weak pin_int0_irqhandler = null_handler
#pragma weak pin_int1_irqhandler = null_handler
#pragma weak pin_int2_irqhandler = null_handler
#pragma weak pin_int3_irqhandler = null_handler
#pragma weak pin_int4_irqhandler = null_handler
#pragma weak pin_int5_irqhandler = null_handler
#pragma weak pin_int6_irqhandler = null_handler
#pragma weak pin_int7_irqhandler = null_handler
#pragma weak gint0_irqhandler = null_handler
#pragma weak gint1_irqhandler = null_handler
#pragma weak eventrouter_irqhandler = null_handler
#pragma weak c_can1_irqhandler = null_handler
#pragma weak atimer_irqhandler = null_handler
#pragma weak rtc_irqhandler = null_handler
#pragma weak wwdt_irqhandler = null_handler
#pragma weak c_can0_irqhandler = null_handler
#pragma weak qei_irqhandler = null_handler

44
lib/stm32/crc.c Normal file
View File

@@ -0,0 +1,44 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@remake.is>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/crc.h>
void crc_reset(void)
{
CRC_CR |= CRC_CR_RESET;
}
u32 crc_calculate(u32 data)
{
CRC_DR = data;
// Data sheet says this blocks until it's ready....
return CRC_DR;
}
u32 crc_calculate_block(u32 *datap, int size)
{
int i;
for (i = 0; i < size; i++) {
CRC_DR = datap[i];
}
return CRC_DR;
}

520
lib/stm32/dac.c Normal file
View File

@@ -0,0 +1,520 @@
/** @defgroup STM32F_dac_file DAC
@ingroup STM32F_files
@brief <b>libopencm3 STM32Fxx Digital to Analog Converter</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies
@date 18 August 2012
This library supports the Digital to Analog Conversion System in the
STM32F series of ARM Cortex Microcontrollers by ST Microelectronics.
The DAC is present only in a limited set of devices, notably some
of the connection line, high density and XL devices.
Two DAC channels are available, however unlike the ADC channels these
are separate DAC devices controlled by the same register block.
The DAC is on APB1. Its clock must be enabled in RCC and the GPIO
ports set to alternate function output before it can be used.
The digital output driver is disabled so the output driver mode
(push-pull/open drain) is arbitrary.
The DAC has a holding (buffer) register and an output register from
which the analog output is derived. The holding register must be
loaded first. If triggering is enabled the output register is loaded
from the holding register after a trigger occurs. If triggering is
not enabled the holding register contents are transferred directly
to the output register.
@note To avoid nonlinearities, do not allow outputs to range close
to zero or V_analog.
@section dac_api_dual Dual Channel Conversion
There are dual modes in which both DACs are used to output data
simultaneously or independently on both channels. The data must be
presented according to the formats described in the datasheets. A
convenience function @ref dac_load_data_buffer_dual is provided
for software controlled use.
A variety of modes are available depending on whether independent
or simultaneous output is desired, and whether waveforms are to be
superimposed. Refer to the datasheets.
If DMA is used, only enable it for one of the channels. The DMA
requests will then serve data in dual format to the data register
dedicated to dual mode. The data will then be split and loaded to the
appropriate DAC following the next trigger. There are three registers
available, one for each of the formats: 12 bit right-aligned, 12 bit
left-aligned and 8 bit right-aligned. The desired format is determined
by specifying the appropriate register to the DMA controller.
@section dac_api_basic_ex Basic DAC handling API.
Set the DAC's GPIO port to any alternate function output mode. Enable the
DAC clock. Enable the DAC, set a trigger source and load the buffer
with the first value. After the DAC is triggered, load the buffer with
the next value. This example uses software triggering and added noise.
The trigger and further buffer load calls are made when data is to be
sent out.
@code
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO4);
rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_DACEN);
dac_disable(CHANNEL_1);
dac_set_waveform_characteristics(DAC_CR_MAMP1_8);
dac_set_waveform_generation(DAC_CR_WAVE1_NOISE);
dac_enable(CHANNEL_1);
dac_set_trigger_source(DAC_CR_TSEL1_SW);
dac_load_data_buffer_single(0, RIGHT12, CHANNEL_1);
....
dac_software_trigger(CHANNEL_1);
dac_load_data_buffer_single(value, RIGHT12, CHANNEL_1);
@endcode
@section dac_api_dma_ex Simultaneous Dual DAC with DMA.
This example in part sets up the DAC channel 1 DMA (DMA2 channel 3) to read
16 bit data from memory into the right-aligned 8 bit dual register DAC_DHR8RD.
Both DAC channels are enabled, and both triggers are set to the same timer
2 input as required for simultaneous operation. DMA is enabled for DAC channel
1 only to ensure that only one DMA request is generated.
@code
dma_set_memory_size(DMA2,DMA_CHANNEL3,DMA_CCR_MSIZE_16BIT);
dma_set_peripheral_size(DMA2,DMA_CHANNEL3,DMA_CCR_PSIZE_16BIT);
dma_set_read_from_memory(DMA2,DMA_CHANNEL3);
dma_set_peripheral_address(DMA2,DMA_CHANNEL3,(u32) &DAC_DHR8RD);
dma_enable_channel(DMA2,DMA_CHANNEL3);
...
dac_trigger_enable(CHANNEL_D);
dac_set_trigger_source(DAC_CR_TSEL1_T2 | DAC_CR_TSEL2_T2);
dac_dma_enable(CHANNEL_1);
dac_enable(CHANNEL_D);
@endcode
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Ken Sarkies
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/dac.h>
#define MASK8 0xFF
#define MASK12 0xFFF
/*-----------------------------------------------------------------------------*/
/** @brief DAC Channel Enable.
Enable a digital to analog converter channel. After setting this enable, the DAC
requires a t<sub>wakeup</sub> time typically around 10 microseconds before it
actually wakes up.
@param[in] dac_channel enum ::data_channel.
*/
void dac_enable(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_CR |= DAC_CR_EN1;
break;
case CHANNEL_2:
DAC_CR |= DAC_CR_EN2;
break;
case CHANNEL_D:
DAC_CR |= (DAC_CR_EN1 | DAC_CR_EN2);
break;
}
}
/*-----------------------------------------------------------------------------*/
/** @brief DAC Channel Disable.
Disable a digital to analog converter channel.
@param[in] dac_channel enum ::data_channel.
*/
void dac_disable(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_CR &= ~DAC_CR_EN1;
break;
case CHANNEL_2:
DAC_CR &= ~DAC_CR_EN2;
break;
case CHANNEL_D:
DAC_CR &= ~(DAC_CR_EN1 | DAC_CR_EN2);
break;
}
}
/*-----------------------------------------------------------------------------*/
/** @brief DAC Channel Output Buffer Enable.
Enable a digital to analog converter channel output drive buffer. This is an optional
amplifying buffer that provides additional drive for the output signal. The
buffer is enabled by default after a reset and needs to be explicitly disabled
if required.
@param[in] dac_channel enum ::data_channel.
*/
void dac_buffer_enable(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_CR |= DAC_CR_BOFF1;
break;
case CHANNEL_2:
DAC_CR |= DAC_CR_BOFF2;
break;
case CHANNEL_D:
DAC_CR |= (DAC_CR_BOFF1 | DAC_CR_BOFF2);
break;
}
}
/*-----------------------------------------------------------------------------*/
/** @brief DAC Channel Output Buffer Disable.
Disable a digital to analog converter channel output drive buffer. Disabling this will
reduce power consumption slightly and will increase the output impedance of the DAC.
The buffers are enabled by default after a reset.
@param[in] dac_channel enum ::data_channel.
*/
void dac_buffer_disable(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_CR &= ~DAC_CR_BOFF1;
break;
case CHANNEL_2:
DAC_CR &= ~DAC_CR_BOFF2;
break;
case CHANNEL_D:
DAC_CR &= ~(DAC_CR_BOFF1 | DAC_CR_BOFF2);
break;
}
}
/*-----------------------------------------------------------------------------*/
/** @brief DAC Channel DMA Enable.
Enable a digital to analog converter channel DMA mode (connected to DMA2 channel
3 for DAC channel 1 and DMA2 channel 4 for DAC channel 2). A DMA request is
generated following an external trigger.
@param[in] dac_channel enum ::data_channel.
*/
void dac_dma_enable(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_CR |= DAC_CR_DMAEN1;
break;
case CHANNEL_2:
DAC_CR |= DAC_CR_DMAEN2;
break;
case CHANNEL_D:
DAC_CR |= (DAC_CR_DMAEN1 | DAC_CR_DMAEN2);
break;
}
}
/*-----------------------------------------------------------------------------*/
/** @brief DAC Channel DMA Disable.
Disable a digital to analog converter channel DMA mode.
@param[in] dac_channel enum ::data_channel.
*/
void dac_dma_disable(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_CR &= ~DAC_CR_DMAEN1;
break;
case CHANNEL_2:
DAC_CR &= ~DAC_CR_DMAEN2;
break;
case CHANNEL_D:
DAC_CR &= ~(DAC_CR_DMAEN1 | DAC_CR_DMAEN2);
break;
}
}
/*-----------------------------------------------------------------------------*/
/** @brief DAC Channel Trigger Enable.
Enable a digital to analog converter channel external trigger mode. This allows an
external trigger to initiate register transfers from the buffer register to the DAC
output register, followed by a DMA transfer to the buffer register if DMA is enabled.
The trigger source must also be selected.
@param[in] dac_channel enum ::data_channel.
*/
void dac_trigger_enable(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_CR |= DAC_CR_TEN1;
break;
case CHANNEL_2:
DAC_CR |= DAC_CR_TEN2;
break;
case CHANNEL_D:
DAC_CR |= (DAC_CR_TEN1 | DAC_CR_TEN2);
break;
}
}
/*-----------------------------------------------------------------------------*/
/** @brief DAC Channel Trigger Disable.
Disable a digital to analog converter channel external trigger.
@param[in] dac_channel enum ::data_channel.
*/
void dac_trigger_disable(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_CR &= ~DAC_CR_TEN1;
break;
case CHANNEL_2:
DAC_CR &= ~DAC_CR_TEN2;
break;
case CHANNEL_D:
DAC_CR &= ~(DAC_CR_TEN1 | DAC_CR_TEN2);
break;
}
}
/*-----------------------------------------------------------------------------*/
/** @brief Set DAC Channel Trigger Source.
Sets the digital to analog converter trigger source, which can be taken from various
timers, an external trigger or a software trigger.
@param[in] dac_trig_src u32. Taken from @ref dac_trig2_sel or @ref dac_trig1_sel or
a logical OR of one of each of these to set both channels simultaneously.
*/
void dac_set_trigger_source(u32 dac_trig_src)
{
DAC_CR |= dac_trig_src;
}
/*-----------------------------------------------------------------------------*/
/** @brief Enable and Set DAC Channel Waveform Generation.
Enable the digital to analog converter waveform generation as either pseudo-random
noise or triangular wave. These signals are superimposed on existing output values
in the DAC output registers.
@note The DAC trigger must be enabled for this to work.
@param[in] dac_wave_ens u32. Taken from @ref dac_wave1_en or @ref dac_wave2_en or
a logical OR of one of each of these to set both channels simultaneously.
*/
void dac_set_waveform_generation(u32 dac_wave_ens)
{
DAC_CR |= dac_wave_ens;
}
/*-----------------------------------------------------------------------------*/
/** @brief Disable DAC Channel Waveform Generation.
Disable a digital to analog converter channel superimposed waveform generation.
@param[in] dac_channel enum ::data_channel.
*/
void dac_disable_waveform_generation(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_CR &= ~DAC_CR_WAVE1_DIS;
break;
case CHANNEL_2:
DAC_CR &= ~DAC_CR_WAVE2_DIS;
break;
case CHANNEL_D:
DAC_CR &= ~(DAC_CR_WAVE1_DIS | DAC_CR_WAVE2_DIS);
break;
}
}
/*-----------------------------------------------------------------------------*/
/** @brief Set DAC Channel LFSR Mask or Triangle Wave Amplitude.
Sets the digital to analog converter superimposed waveform generation characteristics.
@li If the noise generation mode is set, this sets the length of the PRBS sequence and
hence the amplitude of the output noise signal. Default setting is length 1.
@li If the triangle wave generation mode is set, this sets the amplitude of the
output signal as 2^(n)-1 where n is the parameter value. Default setting is 1.
@note High amplitude levels of these waveforms can overload the DAC and distort the
signal output.
@note This must be called before enabling the DAC as the settings will then become read-only.
@note The DAC trigger must be enabled for this to work.
@param[in] dac_mamp u32. Taken from @ref dac_mamp2 or @ref dac_mamp1 or a logical OR
of one of each of these to set both channels simultaneously.
*/
void dac_set_waveform_characteristics(u32 dac_mamp)
{
DAC_CR |= dac_mamp;
}
/*-----------------------------------------------------------------------------*/
/** @brief Load DAC Data Register.
Loads the appropriate digital to analog converter data register with 12 or 8 bit
data to be converted on a channel. The data can be aligned as follows:
@li right-aligned 8 bit data in bits 0-7
@li right-aligned 12 bit data in bits 0-11
@li left aligned 12 bit data in bits 4-15
This function can also be used to load the dual channel registers if the data is
formatted according to the datasheets:
@li right-aligned 8 bit data in bits 0-7 for channel 1 and 8-15 for channel 2
@li right-aligned 12 bit data in bits 0-11 for channel 1 and 16-27 for channel 2
@li left aligned 12 bit data in bits 4-15 for channel 1 and 20-31 for channel 2
@param[in] dac_data u32 with appropriate alignment.
@param[in] dac_data_format enum ::data_align. Alignment and size.
@param[in] dac_channel enum ::data_channel.
*/
void dac_load_data_buffer_single(u32 dac_data, data_align dac_data_format, data_channel dac_channel)
{
if (dac_channel == CHANNEL_1)
{
switch (dac_data_format) {
case RIGHT8:
DAC_DHR8R1 = dac_data;
break;
case RIGHT12:
DAC_DHR12R1 = dac_data;
break;
case LEFT12:
DAC_DHR12L1 = dac_data;
break;
}
}
else if (dac_channel == CHANNEL_2)
{
switch (dac_data_format) {
case RIGHT8:
DAC_DHR8R2 = dac_data;
break;
case RIGHT12:
DAC_DHR12R2 = dac_data;
break;
case LEFT12:
DAC_DHR12L2 = dac_data;
break;
}
}
else
switch (dac_data_format) {
case RIGHT8:
DAC_DHR8RD = dac_data;
break;
case RIGHT12:
DAC_DHR12RD = dac_data;
break;
case LEFT12:
DAC_DHR12LD = dac_data;
break;
}
}
/*-----------------------------------------------------------------------------*/
/** @brief Load DAC Dual Data Register.
Loads the appropriate digital to analog converter dual data register with 12 or
8 bit data to be converted for both channels. This allows high bandwidth
simultaneous or independent analog output. The data in both channels are aligned
identically.
@param[in] dac_data1 u32 for channel 1 with appropriate alignment.
@param[in] dac_data2 u32 for channel 2 with appropriate alignment.
@param[in] dac_data_format enum ::data_align. Right or left aligned, and 8 or 12 bit.
*/
void dac_load_data_buffer_dual(u32 dac_data1, u32 dac_data2, data_align dac_data_format)
{
switch (dac_data_format) {
case RIGHT8:
DAC_DHR8RD = ((dac_data1 & MASK8) | ((dac_data2 & MASK8) << 8));
break;
case RIGHT12:
DAC_DHR12RD = ((dac_data1 & MASK12) | ((dac_data2 & MASK12) << 12));
break;
case LEFT12:
DAC_DHR12LD = ((dac_data1 & MASK12) | ((dac_data2 & MASK12) << 16));
break;
}
}
/*-----------------------------------------------------------------------------*/
/** @brief Trigger the DAC by a Software Trigger.
If the trigger source is set to be a software trigger, cause a trigger to occur.
The trigger is cleared by hardware after conversion.
@param[in] dac_channel enum ::data_channel.
*/
void dac_software_trigger(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_SWTRIGR |= DAC_SWTRIGR_SWTRIG1;
break;
case CHANNEL_2:
DAC_SWTRIGR |= DAC_SWTRIGR_SWTRIG2;
break;
case CHANNEL_D:
DAC_SWTRIGR |= (DAC_SWTRIGR_SWTRIG1 | DAC_SWTRIGR_SWTRIG2);
break;
}
}
/**@}*/

View File

@@ -31,31 +31,9 @@ ARFLAGS = rcs
OBJS = vector.o rcc.o gpio.o usart.o adc.o spi.o flash.o nvic.o \
rtc.o i2c.o dma.o systick.o exti.o scb.o ethernet.o \
usb_f103.o usb.o usb_control.o usb_standard.o can.o \
timer.o usb_f107.o
timer.o usb_f107.o desig.o crc.o
VPATH += ../../usb:../
# Be silent per default, but 'make V=1' will show all compiler calls.
ifneq ($(V),1)
Q := @
endif
all: $(LIBNAME).a
$(LIBNAME).a: $(OBJS)
@printf " AR $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(AR) $(ARFLAGS) $@ $^
%.o: %.c
@printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS) -o $@ -c $<
clean:
@printf " CLEAN lib/stm32/f1\n"
$(Q)rm -f *.o *.d
$(Q)rm -f $(LIBNAME).a
.PHONY: clean
-include $(OBJS:.o=.d)
include ../../Makefile.include

View File

@@ -1,3 +1,70 @@
/** @defgroup STM32F1xx_adc_file ADC
@ingroup STM32F1xx
@brief <b>libopencm3 STM32F1xx Analog to Digital Converters</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2009 Edward Cheeseman <evbuilder@users.sourceforge.net>
@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies <ksarkies@internode.on.net>
@date 18 August 2012
This library supports the A/D Converter Control System in the STM32F1xx series
of ARM Cortex Microcontrollers by ST Microelectronics.
Devices can have up to three A/D converters each with their own set of registers.
However all the A/D converters share a common clock which is prescaled from the APB2
clock by default by a minimum factor of 2 to a maximum of 8.
Each A/D converter has up to 18 channels:
@li On ADC1 the analog channels 16 and 17 are internally connected to the temperature
sensor and V<sub>REFINT</sub>, respectively.
@li On ADC2 the analog channels 16 and 17 are internally connected to V<sub>SS</sub>.
@li On ADC3 the analog channels 9, 14, 15, 16 and 17 are internally connected to V<sub>SS</sub>.
The conversions can occur as a one-off conversion whereby the process stops once
conversion is complete. The conversions can also be continuous wherein a new
conversion starts immediately the previous conversion has ended.
Conversion can occur as a single channel conversion or a scan of a group of
channels in either continuous or one-off mode. If more than one channel is converted
in a scan group, DMA must be used to transfer the data as there is only one
result register available. An interrupt can be set to occur at the end of
conversion, which occurs after all channels have been scanned.
A discontinuous mode allows a subgroup of group of a channels to be converted in
bursts of a given length.
Injected conversions allow a second group of channels to be converted separately
from the regular group. An interrupt can be set to occur at the end of
conversion, which occurs after all channels have been scanned.
@section adc_api_ex Basic ADC Handling API.
Example 1: Simple single channel conversion polled. Enable the peripheral clock
and ADC, reset ADC and set the prescaler divider. Set dual mode to independent.
@code
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_ADC1EN);
adc_power_on(ADC1);
adc_calibration(ADC1);
rcc_peripheral_reset(&RCC_APB2RSTR, RCC_APB2RSTR_ADC1RST);
rcc_peripheral_clear_reset(&RCC_APB2RSTR, RCC_APB2RSTR_ADC1RST);
rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV2);
adc_set_dual_mode(ADC_CR1_DUALMOD_IND);
adc_disable_scan_mode(ADC1);
adc_set_single_conversion_mode(ADC1);
adc_set_sample_time(ADC1, ADC_CHANNEL0, ADC_SMPR1_SMP_1DOT5CYC);
adc_set_single_channel(ADC1, ADC_CHANNEL0);
adc_start_conversion_regular(ADC1);
while (! adc_eoc(ADC1));
reg16 = adc_read_regular(ADC1);
@endcode
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
@@ -27,10 +94,12 @@
* rcc_peripheral_clear_reset(&RCC_APB2RSTR, ADC1RST);
*
* rcc_set_adc_clk(ADC_PRE_PLCK2_DIV2);
* adc_set_mode(ADC1, TODO);
* adc_set_dual_mode(ADC1, TODO);
* reg16 = adc_read(ADC1, ADC_CH_0);
*/
/**@{*/
#include <libopencm3/stm32/f1/adc.h>
void rcc_set_adc_clk(u32 prescaler)
@@ -50,6 +119,14 @@ void adc_set_mode(u32 block, /* TODO */ u8 mode)
mode = mode;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Read from a Conversion Result Register
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] reg Unsigned int8. Register number (1 ... 4).
@returns Unsigned int32 conversion result.
*/
void adc_read(u32 block, u32 channel)
{
/* TODO */
@@ -59,61 +136,177 @@ void adc_read(u32 block, u32 channel)
channel = channel;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog for Regular Conversions
The analog watchdog allows the monitoring of an analog signal between two threshold
levels. The thresholds must be preset. Comparison is done before data alignment
takes place, so the thresholds are left-aligned.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_analog_watchdog_regular(u32 adc)
{
ADC_CR1(adc) |= ADC_CR1_AWDEN;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Disable Analog Watchdog for Regular Conversions
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_analog_watchdog_regular(u32 adc)
{
ADC_CR1(adc) &= ~ADC_CR1_AWDEN;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog for Injected Conversions
The analog watchdog allows the monitoring of an analog signal between two threshold
levels. The thresholds must be preset. Comparison is done before data alignment
takes place, so the thresholds are left-aligned.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_analog_watchdog_injected(u32 adc)
{
ADC_CR1(adc) |= ADC_CR1_JAWDEN;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Disable Analog Watchdog for Injected Conversions
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_analog_watchdog_injected(u32 adc)
{
ADC_CR1(adc) &= ~ADC_CR1_JAWDEN;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Enable Discontinuous Mode for Regular Conversions
In this mode the ADC converts, on each trigger, a subgroup of up to 8 of the
defined regular channel group. The subgroup is defined by the number of
consecutive channels to be converted. After a subgroup has been converted
the next trigger will start conversion of the immediately following subgroup
of the same length or until the whole group has all been converted. When the
the whole group has been converted, the next trigger will restart conversion
of the subgroup at the beginning of the whole group.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] length Unsigned int8. Number of channels in the group @ref adc_cr1_discnum
*/
void adc_enable_discontinous_mode_regular(u32 adc)
{
ADC_CR1(adc) |= ADC_CR1_DISCEN;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Disable Discontinuous Mode for Regular Conversions
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_discontinous_mode_regular(u32 adc)
{
ADC_CR1(adc) &= ~ADC_CR1_DISCEN;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Enable Discontinuous Mode for Injected Conversions
In this mode the ADC converts sequentially one channel of the defined group of
injected channels, cycling back to the first channel in the group once the
entire group has been converted.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_discontinous_mode_injected(u32 adc)
{
ADC_CR1(adc) |= ADC_CR1_JDISCEN;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Disable Discontinuous Mode for Injected Conversions
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_discontinous_mode_injected(u32 adc)
{
ADC_CR1(adc) &= ~ADC_CR1_JDISCEN;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Enable Automatic Injected Conversions
The ADC converts a defined injected group of channels immediately after the
regular channels have been converted. The external trigger on the injected
channels is disabled as required.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_automatic_injected_group_conversion(u32 adc)
{
ADC_CR1(adc) |= ADC_CR1_JAUTO;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Disable Automatic Injected Conversions
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_automatic_injected_group_conversion(u32 adc)
{
ADC_CR1(adc) &= ~ADC_CR1_JAUTO;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog for All Regular and/or Injected Channels
The analog watchdog allows the monitoring of an analog signal between two threshold
levels. The thresholds must be preset. Comparison is done before data alignment
takes place, so the thresholds are left-aligned.
@note The analog watchdog must be enabled for either or both of the regular or
injected channels. If neither are enabled, the analog watchdog feature will be
disabled.
@ref adc_enable_analog_watchdog_injected, @ref adc_enable_analog_watchdog_regular.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_analog_watchdog_on_all_channels(u32 adc)
{
ADC_CR1(adc) |= ADC_CR1_AWDSGL;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog for a Selected Channel
The analog watchdog allows the monitoring of an analog signal between two threshold
levels. The thresholds must be preset. Comparison is done before data alignment
takes place, so the thresholds are left-aligned.
@note The analog watchdog must be enabled for either or both of the regular or
injected channels. If neither are enabled, the analog watchdog feature will be
disabled. If both are enabled, the same channel number is monitored.
@ref adc_enable_analog_watchdog_injected, @ref adc_enable_analog_watchdog_regular.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] channel Unsigned int8. ADC channel number @ref adc_watchdog_channel
*/
void adc_enable_analog_watchdog_on_selected_channel(u32 adc, u8 channel)
{
u32 reg32;
@@ -125,56 +318,140 @@ void adc_enable_analog_watchdog_on_selected_channel(u32 adc, u8 channel)
ADC_CR1(adc) &= ~ADC_CR1_AWDSGL;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Set Scan Mode
In this mode a conversion consists of a scan of the predefined set of channels,
regular and injected, each channel conversion immediately following the
previous one. It can use single, continuous or discontinuous mode.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_scan_mode(u32 adc)
{
ADC_CR1(adc) |= ADC_CR1_SCAN;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Disable Scan Mode
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_scan_mode(u32 adc)
{
ADC_CR1(adc) &= ~ADC_CR1_SCAN;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Enable Injected End-Of-Conversion Interrupt
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_jeoc_interrupt(u32 adc)
{
ADC_CR1(adc) |= ADC_CR1_JEOCIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Disable Injected End-Of-Conversion Interrupt
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_jeoc_interrupt(u32 adc)
{
ADC_CR1(adc) &= ~ADC_CR1_JEOCIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog Interrupt
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_awd_interrupt(u32 adc)
{
ADC_CR1(adc) |= ADC_CR1_AWDIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Disable Analog Watchdog Interrupt
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_awd_interrupt(u32 adc)
{
ADC_CR1(adc) &= ~ADC_CR1_AWDIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Enable Regular End-Of-Conversion Interrupt
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_eoc_interrupt(u32 adc)
{
ADC_CR1(adc) |= ADC_CR1_EOCIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Disable Regular End-Of-Conversion Interrupt
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_eoc_interrupt(u32 adc)
{
ADC_CR1(adc) &= ~ADC_CR1_EOCIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Enable The Temperature Sensor
This enables both the sensor and the reference voltage measurements on channels
16 and 17.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_temperature_sensor(u32 adc)
{
ADC_CR2(adc) |= ADC_CR2_TSVREFE;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Disable The Temperature Sensor
Disabling this will reduce power consumption from the sensor and the reference
voltage measurements.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_temperature_sensor(u32 adc)
{
ADC_CR2(adc) &= ~ADC_CR2_TSVREFE;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Software Triggered Conversion on Regular Channels
This starts conversion on a set of defined regular channels if the ADC trigger
is set to be a software trigger. It is cleared by hardware once conversion
starts.
Note this is a software trigger and requires triggering to be enabled and the
trigger source to be set appropriately otherwise conversion will not start.
This is not the same as the ADC start conversion operation.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_start_conversion_regular(u32 adc)
{
/* Start conversion on regular channels. */
@@ -184,6 +461,20 @@ void adc_start_conversion_regular(u32 adc)
while (ADC_CR2(adc) & ADC_CR2_SWSTART);
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Software Triggered Conversion on Injected Channels
This starts conversion on a set of defined injected channels if the ADC trigger
is set to be a software trigger. It is cleared by hardware once conversion
starts.
Note this is a software trigger and requires triggering to be enabled and the
trigger source to be set appropriately otherwise conversion will not start.
This is not the same as the ADC start conversion operation.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_start_conversion_injected(u32 adc)
{
/* Start conversion on injected channels. */
@@ -193,6 +484,36 @@ void adc_start_conversion_injected(u32 adc)
while (ADC_CR2(adc) & ADC_CR2_JSWSTART);
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Enable an External Trigger for Regular Channels
This enables an external trigger for set of defined regular channels.
For ADC1 and ADC2
@li Timer 1 CC1 event
@li Timer 1 CC2 event
@li Timer 1 CC3 event
@li Timer 2 CC2 event
@li Timer 3 TRGO event
@li Timer 4 CC4 event
@li EXTI (TIM8_TRGO is also possible on some devices, see datasheet)
@li Software Start
For ADC3
@li Timer 3 CC1 event
@li Timer 2 CC3 event
@li Timer 1 CC3 event
@li Timer 8 CC1 event
@li Timer 8 TRGO event
@li Timer 5 CC1 event
@li Timer 5 CC3 event
@li Software Start
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] trigger Unsigned int8. Trigger identifier @ref adc_trigger_regular_12
for ADC1 and ADC2, or @ref adc_trigger_regular_3 for ADC3
*/
void adc_enable_external_trigger_regular(u32 adc, u32 trigger)
{
u32 reg32;
@@ -204,11 +525,47 @@ void adc_enable_external_trigger_regular(u32 adc, u32 trigger)
ADC_CR2(adc) |= ADC_CR2_EXTTRIG;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Disable an External Trigger for Regular Channels
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_external_trigger_regular(u32 adc)
{
ADC_CR2(adc) &= ~ADC_CR2_EXTTRIG;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Enable an External Trigger for Injected Channels
This enables an external trigger for set of defined injected channels.
For ADC1 and ADC2
@li Timer 1 TRGO event
@li Timer 1 CC4 event
@li Timer 2 TRGO event
@li Timer 2 CC1 event
@li Timer 3 CC4 event
@li Timer 4 TRGO event
@li EXTI (TIM8 CC4 is also possible on some devices, see datasheet)
@li Software Start
For ADC3
@li Timer 1 TRGO event
@li Timer 1 CC4 event
@li Timer 4 CC3 event
@li Timer 8 CC2 event
@li Timer 8 CC4 event
@li Timer 5 TRGO event
@li Timer 5 CC4 event
@li Software Start
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] trigger Unsigned int8. Trigger identifier @ref adc_trigger_injected_12
for ADC1 and ADC2, or @ref adc_trigger_injected_3 for ADC3
*/
void adc_enable_external_trigger_injected(u32 adc, u32 trigger)
{
u32 reg32;
@@ -220,65 +577,169 @@ void adc_enable_external_trigger_injected(u32 adc, u32 trigger)
ADC_CR2(adc) |= ADC_CR2_JEXTTRIG;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Disable an External Trigger for Injected Channels
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_external_trigger_injected(u32 adc)
{
ADC_CR2(adc) &= ~ADC_CR2_JEXTTRIG;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Set the Data as Left Aligned
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_set_left_aligned(u32 adc)
{
ADC_CR2(adc) |= ADC_CR2_ALIGN;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Set the Data as Right Aligned
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_set_right_aligned(u32 adc)
{
ADC_CR2(adc) &= ~ADC_CR2_ALIGN;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Enable DMA Transfers
Only available for ADC1 through DMA1 channel1, and ADC3 through DMA2 channel5.
ADC2 will use DMA if it is set as slave in dual mode with ADC1 in DMA transfer
mode.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_dma(u32 adc)
{
if ((adc == ADC1) | (adc == ADC3))
ADC_CR2(adc) |= ADC_CR2_DMA;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Disable DMA Transfers
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_dma(u32 adc)
{
if ((adc == ADC1) | (adc == ADC3))
ADC_CR2(adc) &= ~ADC_CR2_DMA;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Initialize Calibration Registers
This resets the calibration registers. It is not clear if this is required to be
done before every calibration operation.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_reset_calibration(u32 adc)
{
ADC_CR2(adc) |= ADC_CR2_RSTCAL;
while (ADC_CR2(adc) & ADC_CR2_RSTCAL);
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Calibration
The calibration data for the ADC is recomputed. The hardware clears the
calibration status flag when calibration is complete. This function does not return
until this happens and the ADC is ready for use.
The ADC must have been powered down for at least 2 ADC clock cycles, then powered on.
before calibration starts
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_calibration(u32 adc)
{
ADC_CR2(adc) |= ADC_CR2_CAL;
while (ADC_CR2(adc) & ADC_CR2_CAL);
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Enable Continuous Conversion Mode
In this mode the ADC starts a new conversion of a single channel or a channel
group immediately following completion of the previous channel group conversion.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_set_continous_conversion_mode(u32 adc)
{
ADC_CR2(adc) |= ADC_CR2_CONT;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Enable Single Conversion Mode
In this mode the ADC performs a conversion of one channel or a channel group
and stops.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_set_single_conversion_mode(u32 adc)
{
ADC_CR2(adc) &= ~ADC_CR2_CONT;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Power On
If the ADC is in power-down mode then it is powered up. The application needs
to wait a time of about 3 microseconds for stabilization before using the ADC.
If the ADC is already on this function call will initiate a conversion.
@todo fix this.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_on(u32 adc)
{
ADC_CR2(adc) |= ADC_CR2_ADON;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Off
Turn off the ADC to reduce power consumption to a few microamps.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_off(u32 adc)
{
ADC_CR2(adc) &= ~ADC_CR2_ADON;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Set the Sample Time for a Single Channel
The sampling time can be selected in ADC clock cycles from 1.5 to 239.5.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] channel Unsigned int8. ADC Channel integer 0..18 or from @ref adc_channel
@param[in] time Unsigned int8. Sampling time selection from @ref adc_sample_rg
*/
void adc_set_conversion_time(u32 adc, u8 channel, u8 time)
{
u32 reg32;
@@ -296,6 +757,16 @@ void adc_set_conversion_time(u32 adc, u8 channel, u8 time)
}
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Set the Sample Time for All Channels
The sampling time can be selected in ADC clock cycles from 1.5 to 239.5, same for
all channels.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] time Unsigned int8. Sampling time selection from @ref adc_sample_rg
*/
void adc_set_conversion_time_on_all_channels(u32 adc, u8 time)
{
u8 i;
@@ -310,6 +781,13 @@ void adc_set_conversion_time_on_all_channels(u32 adc, u8 time)
ADC_SMPR1(adc) = reg32;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Set Analog Watchdog Upper Threshold
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] threshold Unsigned int8. Upper threshold value
*/
void adc_set_watchdog_high_threshold(u32 adc, u16 threshold)
{
u32 reg32 = 0;
@@ -319,6 +797,13 @@ void adc_set_watchdog_high_threshold(u32 adc, u16 threshold)
ADC_HTR(adc) = reg32;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Set Analog Watchdog Lower Threshold
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] threshold Unsigned int8. Lower threshold value
*/
void adc_set_watchdog_low_threshold(u32 adc, u16 threshold)
{
u32 reg32 = 0;
@@ -328,6 +813,18 @@ void adc_set_watchdog_low_threshold(u32 adc, u16 threshold)
ADC_LTR(adc) = reg32;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Set a Regular Channel Conversion Sequence
Define a sequence of channels to be converted as a regular group with a length
from 1 to 16 channels. If this is called during conversion, the current conversion
is reset and conversion begins again with the newly defined group.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] length Unsigned int8. Number of channels in the group.
@param[in] channel Unsigned int8[]. Set of channels in sequence, integers 0..18.
*/
void adc_set_regular_sequence(u32 adc, u8 length, u8 channel[])
{
u32 reg32_1 = 0, reg32_2 = 0, reg32_3 = 0;
@@ -352,6 +849,18 @@ void adc_set_regular_sequence(u32 adc, u8 length, u8 channel[])
ADC_SQR3(adc) = reg32_3;
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Set an Injected Channel Conversion Sequence
Defines a sequence of channels to be converted as an injected group with a length
from 1 to 4 channels. If this is called during conversion, the current conversion
is reset and conversion begins again with the newly defined group.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] length Unsigned int8. Number of channels in the group.
@param[in] channel Unsigned int8[]. Set of channels in sequence, integers 0..18
*/
void adc_set_injected_sequence(u32 adc, u8 length, u8 channel[])
{
u32 reg32 = 0;
@@ -368,3 +877,6 @@ void adc_set_injected_sequence(u32 adc, u8 length, u8 channel[])
ADC_JSQR(adc) = reg32;
}
/**@}*/

37
lib/stm32/f1/desig.c Normal file
View File

@@ -0,0 +1,37 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@ŧweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/f1/desig.h>
u16 desig_get_flash_size(void)
{
return DESIG_FLASH_SIZE;
}
void desig_get_unique_id(u32 result[])
{
// Could also just return a pointer to the start? read it as they wish?
u16 bits15_0 = DESIG_UID_15_0;
u32 bits31_16 = DESIG_UID_31_16;
u32 bits63_32 = DESIG_UID_63_32;
u32 bits95_64 = DESIG_UID_95_64;
result[0] = bits95_64;
result[1] = bits63_32;
result[2] = bits31_16 << 16 | bits15_0;
}

View File

@@ -1,3 +1,24 @@
/** @defgroup STM32F1xx-dma-file DMA
@ingroup STM32F1xx
@brief <b>libopencm3 STM32F1xx DMA Controller</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
@date 18 August 2012
This library supports the DMA
Control System in the STM32F1xx series of ARM Cortex Microcontrollers
by ST Microelectronics. It can provide for two DMA controllers,
one with 7 channels and one with 5. Channels are hardware dedicated
and each is shared with a number of different sources (only one can be
used at a time, under the responsibility of the programmer).
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
@@ -17,8 +38,19 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/f1/dma.h>
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Reset
The channel is disabled and configuration registers are cleared.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_channel_reset(u32 dma, u8 channel)
{
/* Disable channel. */
@@ -35,18 +67,51 @@ void dma_channel_reset(u32 dma, u8 channel)
DMA_IFCR(dma) |= DMA_IFCR_CIF(channel);
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Memory to Memory Transfers
Memory to memory transfers do not require a trigger to activate each transfer.
Transfers begin immediately the channel has been enabled, and proceed without
intervention.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_enable_mem2mem_mode(u32 dma, u8 channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_MEM2MEM;
DMA_CCR(dma, channel) &= ~DMA_CCR_CIRC;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Set Priority
Channel Priority has four levels: low to very high. This has precedence over the
hardware priority.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
@param[in] prio unsigned int32. Priority level @ref dma_ch_pri.
*/
void dma_set_priority(u32 dma, u8 channel, u32 prio)
{
DMA_CCR(dma, channel) &= ~(DMA_CCR_PL_MASK);
DMA_CCR(dma, channel) |= prio;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Set Memory Word Width
Set the memory word width 8 bits, 16 bits, or 32 bits. Refer to datasheet for
alignment information if the source and destination widths do not match.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
@param[in] mem_size unsigned int32. Memory word width @ref dma_ch_memwidth.
*/
void dma_set_memory_size(u32 dma, u8 channel, u32 mem_size)
{
@@ -54,89 +119,249 @@ void dma_set_memory_size(u32 dma, u8 channel, u32 mem_size)
DMA_CCR(dma, channel) |= mem_size;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Set Peripheral Word Width
Set the peripheral word width 8 bits, 16 bits, or 32 bits. Refer to datasheet for
alignment information if the source and destination widths do not match, or
if the peripheral does not support byte or half-word writes.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
@param[in] peripheral_size unsigned int32. Peripheral word width @ref dma_ch_perwidth.
*/
void dma_set_peripheral_size(u32 dma, u8 channel, u32 peripheral_size)
{
DMA_CCR(dma, channel) &= ~(DMA_CCR_PSIZE_MASK);
DMA_CCR(dma, channel) |= peripheral_size;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Memory Increment after Transfer
Following each transfer the current memory address is incremented by
1, 2 or 4 depending on the data size set in @ref dma_set_memory_size. The
value held by the base memory address register is unchanged.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_enable_memory_increment_mode(u32 dma, u8 channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_MINC;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Disable Memory Increment after Transfer
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_enable_peripheral_increment_mode(u32 dma, u8 channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_PINC;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Memory Circular Mode
After the number of bytes/words to be transferred has been completed, the
original transfer block size, memory and peripheral base addresses are
reloaded and the process repeats.
@note This cannot be used with memory to memory mode, which is explictly
disabled here.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_enable_circular_mode(u32 dma, u8 channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_CIRC;
DMA_CCR(dma, channel) &= ~DMA_CCR_MEM2MEM;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Transfers from a Peripheral
The data direction is set to read from a peripheral.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_set_read_from_peripheral(u32 dma, u8 channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_DIR;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Transfers from Memory
The data direction is set to read from memory.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_set_read_from_memory(u32 dma, u8 channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_DIR;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Interrupt on Transfer Error
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_enable_transfer_error_interrupt(u32 dma, u8 channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_TEIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Disable Interrupt on Transfer Error
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_disable_transfer_error_interrupt(u32 dma, u8 channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_TEIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Interrupt on Transfer Half Complete
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_enable_half_transfer_interrupt(u32 dma, u8 channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_HTIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Disable Interrupt on Transfer Half Complete
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_disable_half_transfer_interrupt(u32 dma, u8 channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_HTIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Interrupt on Transfer Complete
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_enable_transfer_complete_interrupt(u32 dma, u8 channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_TCIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Disable Interrupt on Transfer Complete
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_disable_transfer_complete_interrupt(u32 dma, u8 channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_TCIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Enable
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_enable_channel(u32 dma, u8 channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_EN;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Disable
@note The DMA channel registers retain their values when the channel is disabled.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_disable_channel(u32 dma, u8 channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_EN;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Set the Peripheral Address
Set the address of the peripheral register to or from which data is to be transferred.
Refer to the documentation for the specific peripheral.
@note The DMA channel must be disabled before setting this address. This function
has no effect if the channel is enabled.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
@param[in] address unsigned int32. Peripheral Address.
*/
void dma_set_peripheral_address(u32 dma, u8 channel, u32 address)
{
DMA_CPAR(dma, channel) = (u32) address;
if (!(DMA_CCR(dma, channel) & DMA_CCR_EN))
DMA_CPAR(dma, channel) = (u32) address;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Set the Base Memory Address
@note The DMA channel must be disabled before setting this address. This function
has no effect if the channel is enabled.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
@param[in] address unsigned int32. Memory Initial Address.
*/
void dma_set_memory_address(u32 dma, u8 channel, u32 address)
{
DMA_CMAR(dma, channel) = (u32) address;
if (!(DMA_CCR(dma, channel) & DMA_CCR_EN))
DMA_CMAR(dma, channel) = (u32) address;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Set the Transfer Block Size
@note The DMA channel must be disabled before setting this count value. The count
is not changed if the channel is enabled.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
@param[in] number unsigned int16. Number of data words to transfer (65535 maximum).
*/
void dma_set_number_of_data(u32 dma, u8 channel, u16 number)
{
DMA_CNDTR(dma, channel) = number;
}
/**@}*/

View File

@@ -1,3 +1,61 @@
/** @defgroup STM32F1xx_gpio_file GPIO
@ingroup STM32F1xx
@brief <b>libopencm3 STM32F1xx General Purpose I/O</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies <ksarkies@internode.on.net>
@date 18 August 2012
This library supports the General Purpose I/O System in the STM32F1xx series
of ARM Cortex Microcontrollers by ST Microelectronics.
Each I/O port has 16 individually configurable bits. Many I/O pins share GPIO
functionality with a number of alternate functions and must be configured to the
alternate function mode if these are to be accessed. A feature is available to
remap alternative functions to a limited set of alternative pins in the event
of a clash of requirements.
The data registers associated with each port for input and output are 32 bit with
the upper 16 bits unused. The output buffer must be written as a 32 bit word, but
individual bits may be set or reset separately in atomic operations to avoid race
conditions during interrupts. Bits may also be individually locked to prevent
accidental configuration changes. Once locked the configuration cannot be changed
until after the next reset.
Each port bit can be configured as analog or digital input, the latter can be
floating or pulled up or down. As outputs they can be configured as either
push-pull or open drain, digital I/O or alternate function, and with maximum
output speeds of 2MHz, 10MHz, or 50MHz.
On reset all ports are configured as digital floating input.
@section gpio_api_ex Basic GPIO Handling API.
Example 1: Push-pull digital output actions on ports C2 and C9
@code
gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO2 | GPIO9);
gpio_set(GPIOC, GPIO2 | GPIO9);
gpio_clear(GPIOC, GPIO2);
gpio_toggle(GPIOC, GPIO2 | GPIO9);
gpio_port_write(GPIOC, 0x204);
@endcode
Example 1: Digital input on port C12
@code
gpio_set_mode(GPIOC, GPIO_MODE_INPUT, GPIO_CNF_INPUT, GPIO12);
reg16 = gpio_port_read(GPIOC);
@endcode
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
@@ -33,9 +91,23 @@
* TODO:
* - GPIO remapping support
*/
/**@{*/
#include <libopencm3/stm32/f1/gpio.h>
/*-----------------------------------------------------------------------------*/
/** @brief Set GPIO Pin Mode
Sets the mode (input/output) and configuration (analog/digitial and
open drain/push pull), for a set of GPIO pins on a given GPIO port.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] mode Unsigned int8. Pin mode @ref gpio_mode
@param[in] cnf Unsigned int8. Pin configuration @ref gpio_cnf
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be set, use logical OR '|' to separate them.
*/
void gpio_set_mode(u32 gpioport, u8 mode, u8 cnf, u16 gpios)
{
u16 i, offset = 0;
@@ -73,69 +145,99 @@ void gpio_set_mode(u32 gpioport, u8 mode, u8 cnf, u16 gpios)
GPIO_CRH(gpioport) = crh;
}
/**
* Set one or more pins of the given GPIO port to 1.
*
* @param gpioport The GPIO port to use (GPIOA - GPIOG).
* @param gpios The GPIO pin(s) to set to 1 (GPIO0 - GPIO15, or GPIO_ALL).
* If multiple pins shall be set, use '|' to separate them.
*/
/*-----------------------------------------------------------------------------*/
/** @brief Set a Group of Pins Atomic
Set one or more pins of the given GPIO port to 1 in an atomic operation.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be changed, use logical OR '|' to separate them.
*/
void gpio_set(u32 gpioport, u16 gpios)
{
GPIO_BSRR(gpioport) = gpios;
}
/**
* Clear one or more pins of the given GPIO port to 0.
*
* @param gpioport The GPIO port to use (GPIOA - GPIOG).
* @param gpios The GPIO pin(s) to set to 0 (GPIO0 - GPIO15, or GPIO_ALL).
* If multiple pins shall be cleared, use '|' to separate them.
*/
/*-----------------------------------------------------------------------------*/
/** @brief Clear a Group of Pins Atomic
Clear one or more pins of the given GPIO port to 0 in an atomic operation.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be changed, use logical OR '|' to separate them.
*/
void gpio_clear(u32 gpioport, u16 gpios)
{
GPIO_BRR(gpioport) = gpios;
}
/*-----------------------------------------------------------------------------*/
/** @brief Read a Group of Pins.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be read, use logical OR '|' to separate them.
@return Unsigned int16 value of the pin values. The bit position of the pin value
returned corresponds to the pin number.
*/
u16 gpio_get(u32 gpioport, u16 gpios)
{
return gpio_port_read(gpioport) & gpios;
}
/**
* Toggle one or more pins of the given GPIO port.
*
* @param gpioport The GPIO port to use (GPIOA - GPIOG).
* @param gpios The GPIO pin(s) to toggle (GPIO0 - GPIO15, or GPIO_ALL).
* If multiple pins shall be toggled, use '|' to separate them.
*/
/*-----------------------------------------------------------------------------*/
/** @brief Toggle a Group of Pins
Toggle one or more pins of the given GPIO port. This is not an atomic operation.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be changed, use logical OR '|' to separate them.
*/
void gpio_toggle(u32 gpioport, u16 gpios)
{
GPIO_ODR(gpioport) ^= gpios;
}
/**
* Read the current value of the given GPIO port.
*
* @param gpioport The GPIO port to read (GPIOA - GPIOG).
* @return The value of the current GPIO port.
*/
/*-----------------------------------------------------------------------------*/
/** @brief Read from a Port
Read the current value of the given GPIO port. Only the lower 16 bits contain
valid pin data.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@return Unsigned int16. The value held in the specified GPIO port.
*/
u16 gpio_port_read(u32 gpioport)
{
return (u16)GPIO_IDR(gpioport);
}
/**
* Write to the given GPIO port.
*
* @param gpioport The GPIO port to write to (GPIOA - GPIOG).
* @param data The data to write to the specified GPIO port.
*/
/*-----------------------------------------------------------------------------*/
/** @brief Write to a Port
Write a value to the given GPIO port.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] data Unsigned int16. The value to be written to the GPIO port.
*/
void gpio_port_write(u32 gpioport, u16 data)
{
GPIO_ODR(gpioport) = data;
}
/*-----------------------------------------------------------------------------*/
/** @brief Lock the Configuration of a Group of Pins
The configuration of one or more pins of the given GPIO port is locked. There is
no mechanism to unlock these via software. Unlocking occurs at the next reset.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be locked, use logical OR '|' to separate them.
*/
void gpio_port_config_lock(u32 gpioport, u16 gpios)
{
u32 reg32;
@@ -147,5 +249,69 @@ void gpio_port_config_lock(u32 gpioport, u16 gpios)
reg32 = GPIO_LCKR(gpioport); /* Read LCKK. */
reg32 = GPIO_LCKR(gpioport); /* Read LCKK again. */
/* Tell the compiler the variable is actually used. It will get optimized out anyways. */
reg32 = reg32;
/* If (reg32 & GPIO_LCKK) is true, the lock is now active. */
}
/*-----------------------------------------------------------------------------*/
/** @brief Map the EVENTOUT signal
Enable the EVENTOUT signal and select the port and pin to be used.
@param[in] evoutport Unsigned int8. Port for EVENTOUT signal @ref afio_evcr_port
@param[in] evoutpin Unsigned int8. Pin for EVENTOUT signal @ref afio_evcr_pin
*/
void gpio_set_eventout(u8 evoutport, u8 evoutpin)
{
AFIO_EVCR = AFIO_EVCR_EVOE | evoutport | evoutpin;
}
/*-----------------------------------------------------------------------------*/
/** @brief Map Alternate Function Port Bits (Main Set)
A number of alternate function ports can be remapped to defined alternative
port bits to avoid clashes in cases where multiple alternate functions are present.
Refer to the datasheets for the particular mapping desired. This provides the main
set of remap functionality. See @ref gpio_secondary_remap for a number of lesser used
remaps.
The AFIO remapping feature is used only with the STM32F10x series.
@note The Serial Wire JTAG disable controls allow certain GPIO ports to become available
in place of some of the SWJ signals. Full SWJ capability is obtained by setting this to
zero. The value of this must be specified for every call to this function as its current
value cannot be ascertained from the hardware.
@param[in] swjdisable Unsigned int8. Disable parts of the SWJ capability @ref afio_swj_disable.
@param[in] maps Unsigned int32. Logical OR of map enable controls from @ref afio_remap,
@ref afio_remap_can1, @ref afio_remap_tim3, @ref afio_remap_tim2, @ref afio_remap_tim1,
@ref afio_remap_usart3. For connectivity line devices only @ref afio_remap_cld are
also available.
*/
void gpio_primary_remap(u8 swjdisable, u32 maps)
{
AFIO_MAPR = swjdisable | (maps & 0x1FFFFF);
}
/*-----------------------------------------------------------------------------*/
/** @brief Map Alternate Function Port Bits (Secondary Set)
A number of alternate function ports can be remapped to defined alternative
port bits to avoid clashes in cases where multiple alternate functions are present.
Refer to the datasheets for the particular mapping desired. This provides the second
smaller and less used set of remap functionality. See @ref gpio_primary_remap for
the main set of remaps.
The AFIO remapping feature is used only with the STM32F10x series.
@param[in] maps Unsigned int32. Logical OR of map enable controls from @ref afio_remap2
*/
void gpio_secondary_remap(u32 maps)
{
AFIO_MAPR2 = maps;
}
/**@}*/

View File

@@ -30,21 +30,18 @@ ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
. = ORIGIN(rom);
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
_etext = .;
} >rom
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support
*/
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support
*/
.ARM.extab : {
*(.ARM.extab*)
} >rom
@@ -54,21 +51,23 @@ SECTIONS
__exidx_end = .;
} >rom
. = ORIGIN(ram);
. = ALIGN(4);
_etext = .;
.data : AT (__exidx_end) {
.data : {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
} >ram
} >ram AT >rom
_data_loadaddr = LOADADDR(.data);
.bss : {
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram AT >rom
} >ram
/*
* The .eh_frame section appears to be used for C++ exception handling.

217
lib/stm32/f1/pwr.c Normal file
View File

@@ -0,0 +1,217 @@
/** @defgroup STM32F1xx-pwr-file PWR
@ingroup STM32F1xx
@brief <b>libopencm3 STM32F1xx Power Control</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies <ksarkies@internode.on.net>
@date 18 August 2012
This library supports the power control system for the
STM32F1 series of ARM Cortex Microcontrollers by ST Microelectronics.
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Ken Sarkies <ksarkies@internode.on.net>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/pwr.h>
/*---------------------------------------------------------------------------*/
/** @brief Disable Backup Domain Write Protection.
This allows backup domain registers to be changed. These registers are write
protected after a reset.
*/
void pwr_disable_backup_domain_write_protect(void)
{
PWR_CR |= PWR_CR_DBP;
}
/*---------------------------------------------------------------------------*/
/** @brief Re-enable Backup Domain Write Protection.
This protects backup domain registers from inadvertent change.
*/
void pwr_enable_backup_domain_write_protect(void)
{
PWR_CR &= ~PWR_CR_DBP;
}
/*---------------------------------------------------------------------------*/
/** @brief Enable Power Voltage Detector.
This provides voltage level threshold detection. The result of detection is
provided in the power voltage detector output flag (see @ref pwr_voltage_high)
or by setting the EXTI16 interrupt (see datasheet for configuration details).
@param[in] pvd_level u32. Taken from @ref pwr_pls.
*/
void pwr_enable_power_voltage_detect(u32 pvd_level)
{
PWR_CR &= ~PWR_CR_PLS_MASK;
PWR_CR |= (PWR_CR_PVDE | pvd_level);
}
/*---------------------------------------------------------------------------*/
/** @brief Disable Power Voltage Detector.
*/
void pwr_disable_power_voltage_detect(void)
{
PWR_CR &= ~PWR_CR_PVDE;
}
/*---------------------------------------------------------------------------*/
/** @brief Clear the Standby Flag.
This is set when the processor returns from a standby mode.
*/
void pwr_clear_standby_flag(void)
{
PWR_CR |= PWR_CR_CSBF;
}
/*---------------------------------------------------------------------------*/
/** @brief Clear the Wakeup Flag.
This is set when the processor receives a wakeup signal.
*/
void pwr_clear_wakeup_flag(void)
{
PWR_CR |= PWR_CR_CWUF;
}
/*---------------------------------------------------------------------------*/
/** @brief Set Standby Mode in Deep Sleep.
*/
void pwr_set_standby_mode(void)
{
PWR_CR |= PWR_CR_PDDS;
}
/*---------------------------------------------------------------------------*/
/** @brief Set Stop Mode in Deep Sleep.
*/
void pwr_set_stop_mode(void)
{
PWR_CR &= ~PWR_CR_PDDS;
}
/*---------------------------------------------------------------------------*/
/** @brief Voltage Regulator On in Stop Mode.
*/
void pwr_voltage_regulator_on_in_stop(void)
{
PWR_CR &= ~PWR_CR_LPDS;
}
/*---------------------------------------------------------------------------*/
/** @brief Voltage Regulator Low Power in Stop Mode.
*/
void pwr_voltage_regulator_low_power_in_stop(void)
{
PWR_CR |= PWR_CR_LPDS;
}
/*---------------------------------------------------------------------------*/
/** @brief Enable Wakeup Pin.
The wakeup pin is used for waking the processor from standby mode.
*/
void pwr_enable_wakeup_pin(void)
{
PWR_CSR |= PWR_CR_EWUP;
}
/*---------------------------------------------------------------------------*/
/** @brief Release Wakeup Pin.
The wakeup pin is used for general purpose I/O.
*/
void pwr_disable_wakeup_pin(void)
{
PWR_CSR &= ~PWR_CR_EWUP;
}
/*---------------------------------------------------------------------------*/
/** @brief Get Voltage Detector Output.
The voltage detector threshold must be set when the power voltage detector is
enabled, see @ref pwr_enable_power_voltage_detect.
@returns boolean: TRUE if the power voltage is above the preset voltage
threshold.
*/
bool pwr_voltage_high(void)
{
return (PWR_CSR & PWR_CR_PVDO);
}
/*---------------------------------------------------------------------------*/
/** @brief Get Standby Flag.
The standby flag is set when the processor returns from a standby state. It is
cleared by software (see @ref pwr_clear_standby_flag).
@returns boolean: TRUE if the processor was in standby state.
*/
bool pwr_get_standby_flag(void)
{
return (PWR_CSR & PWR_CR_SBF);
}
/*---------------------------------------------------------------------------*/
/** @brief Get Wakeup Flag.
The wakeup flag is set when a wakeup event has been received. It is
cleared by software (see @ref pwr_clear_wakeup_flag).
@returns boolean: TRUE if a wakeup event was received.
*/
bool pwr_get_wakeup_flag(void)
{
return (PWR_CSR & PWR_CR_WUF);
}
/**@}*/

View File

@@ -1,3 +1,30 @@
/** @defgroup STM32F1xx-rcc-file RCC
@ingroup STM32F1xx
@brief <b>libopencm3 STM32F1xx Reset and Clock Control</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2009 Federico Ruiz-Ugalde \<memeruiz at gmail dot com\>
@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
@author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
@date 18 August 2012
This library supports the Reset and Clock Control System in the STM32F1xx
series of ARM Cortex Microcontrollers by ST Microelectronics.
@note Full support for connection line devices is not yet provided.
Clock settings and resets for many peripherals are given here rather than in the
corresponding peripheral library.
The library also provides a number of common configurations for the processor
system clock. Not all possible configurations are included.
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
@@ -19,13 +46,24 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/f1/rcc.h>
#include <libopencm3/stm32/f1/flash.h>
/* Set the default ppre1 and ppre2 peripheral clock frequencies after reset. */
/** Default ppre1 peripheral clock frequency after reset. */
u32 rcc_ppre1_frequency = 8000000;
/** Default ppre2 peripheral clock frequency after reset. */
u32 rcc_ppre2_frequency = 8000000;
/*-----------------------------------------------------------------------------*/
/** @brief RCC Clear the Oscillator Ready Interrupt Flag
Clear the interrupt flag that was set when a clock oscillator became ready to use.
@param[in] osc enum ::osc_t. Oscillator ID
*/
void rcc_osc_ready_int_clear(osc_t osc)
{
switch (osc) {
@@ -47,6 +85,12 @@ void rcc_osc_ready_int_clear(osc_t osc)
}
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Enable the Oscillator Ready Interrupt
@param[in] osc enum ::osc_t. Oscillator ID
*/
void rcc_osc_ready_int_enable(osc_t osc)
{
switch (osc) {
@@ -68,6 +112,12 @@ void rcc_osc_ready_int_enable(osc_t osc)
}
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Disable the Oscillator Ready Interrupt
@param[in] osc enum ::osc_t. Oscillator ID
*/
void rcc_osc_ready_int_disable(osc_t osc)
{
switch (osc) {
@@ -89,6 +139,13 @@ void rcc_osc_ready_int_disable(osc_t osc)
}
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Read the Oscillator Ready Interrupt Flag
@param[in] osc enum ::osc_t. Oscillator ID
@returns int. Boolean value for flag set.
*/
int rcc_osc_ready_int_flag(osc_t osc)
{
switch (osc) {
@@ -113,16 +170,33 @@ int rcc_osc_ready_int_flag(osc_t osc)
return -1;
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Clear the Clock Security System Interrupt Flag
*/
void rcc_css_int_clear(void)
{
RCC_CIR |= RCC_CIR_CSSC;
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Read the Clock Security System Interrupt Flag
@returns int. Boolean value for flag set.
*/
int rcc_css_int_flag(void)
{
return ((RCC_CIR & RCC_CIR_CSSF) != 0);
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Wait for Oscillator Ready.
@param[in] osc enum ::osc_t. Oscillator ID
*/
void rcc_wait_for_osc_ready(osc_t osc)
{
switch (osc) {
@@ -144,6 +218,20 @@ void rcc_wait_for_osc_ready(osc_t osc)
}
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Turn on an Oscillator.
Enable an oscillator and power on. Each oscillator requires an amount of time to
settle to a usable state. Refer to datasheets for time delay information. A status
flag is available to indicate when the oscillator becomes ready (see
@ref rcc_osc_ready_int_flag and @ref rcc_wait_for_osc_ready).
@note The LSE clock is in the backup domain and cannot be enabled until the
backup domain write protection has been removed (see @ref pwr_disable_backup_domain_write_protect).
@param[in] osc enum ::osc_t. Oscillator ID
*/
void rcc_osc_on(osc_t osc)
{
switch (osc) {
@@ -165,6 +253,20 @@ void rcc_osc_on(osc_t osc)
}
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Turn off an Oscillator.
Disable an oscillator and power off.
@note An oscillator cannot be turned off if it is selected as the system clock.
@note The LSE clock is in the backup domain and cannot be disabled until the
backup domain write protection has been removed (see
@ref pwr_disable_backup_domain_write_protect) or the backup domain has been
(see reset @ref rcc_backupdomain_reset).
@param[in] osc enum ::osc_t. Oscillator ID
*/
void rcc_osc_off(osc_t osc)
{
switch (osc) {
@@ -186,16 +288,39 @@ void rcc_osc_off(osc_t osc)
}
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Enable the Clock Security System.
*/
void rcc_css_enable(void)
{
RCC_CR |= RCC_CR_CSSON;
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Disable the Clock Security System.
*/
void rcc_css_disable(void)
{
RCC_CR &= ~RCC_CR_CSSON;
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Enable Bypass.
Enable an external clock to bypass the internal clock (high speed and low speed
clocks only). The external clock must be enabled (see @ref rcc_osc_on)
and the internal clock must be disabled (see @ref rcc_osc_off) for this to have effect.
@note The LSE clock is in the backup domain and cannot be bypassed until the
backup domain write protection has been removed (see @ref pwr_disable_backup_domain_write_protect).
@param[in] osc enum ::osc_t. Oscillator ID. Only HSE and LSE have effect.
*/
void rcc_osc_bypass_enable(osc_t osc)
{
switch (osc) {
@@ -213,6 +338,19 @@ void rcc_osc_bypass_enable(osc_t osc)
}
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Disable Bypass.
Re-enable the internal clock (high speed and low speed clocks only). The internal
clock must be disabled (see @ref rcc_osc_off) for this to have effect.
@note The LSE clock is in the backup domain and cannot have bypass removed until the
backup domain write protection has been removed (see @ref pwr_disable_backup_domain_write_protect)
or the backup domain has been reset (see @ref rcc_backupdomain_reset).
@param[in] osc enum ::osc_t. Oscillator ID. Only HSE and LSE have effect.
*/
void rcc_osc_bypass_disable(osc_t osc)
{
switch (osc) {
@@ -230,26 +368,96 @@ void rcc_osc_bypass_disable(osc_t osc)
}
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Enable Peripheral Clocks.
Enable the clock on particular peripherals. There are three registers
involved, each one controlling the enabling of clocks associated with the AHB,
APB1 and APB2 respectively. Several peripherals could be
enabled simultaneously <em>only if they are controlled by the same register</em>.
@param[in] *reg Unsigned int32. Pointer to a Clock Enable Register
(either RCC_AHBENR, RCC_APB1ENR or RCC_APB2ENR)
@param[in] en Unsigned int32. Logical OR of all enables to be set
@li If register is RCC_AHBER, from @ref rcc_ahbenr_en
@li If register is RCC_APB1ENR, from @ref rcc_apb1enr_en
@li If register is RCC_APB2ENR, from @ref rcc_apb2enr_en
*/
void rcc_peripheral_enable_clock(volatile u32 *reg, u32 en)
{
*reg |= en;
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Disable Peripheral Clocks.
Enable the clock on particular peripherals. There are three registers
involved, each one controlling the enabling of clocks associated with the AHB,
APB1 and APB2 respectively. Several peripherals could be
disabled simultaneously <em>only if they are controlled by the same register</em>.
@param[in] *reg Unsigned int32. Pointer to a Clock Enable Register
(either RCC_AHBENR, RCC_APB1ENR or RCC_APB2ENR)
@param[in] en Unsigned int32. Logical OR of all enables to be used for disabling.
@li If register is RCC_AHBER, from @ref rcc_ahbenr_en
@li If register is RCC_APB1ENR, from @ref rcc_apb1enr_en
@li If register is RCC_APB2ENR, from @ref rcc_apb2enr_en
*/
void rcc_peripheral_disable_clock(volatile u32 *reg, u32 en)
{
*reg &= ~en;
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Reset Peripherals.
Reset particular peripherals. There are three registers
involved, each one controlling reset of peripherals associated with the AHB,
APB1 and APB2 respectively. Several peripherals could be reset simultaneously
<em>only if they are controlled by the same register</em>.
@param[in] *reg Unsigned int32. Pointer to a Reset Register
(either RCC_AHBENR, RCC_APB1ENR or RCC_APB2ENR)
@param[in] reset Unsigned int32. Logical OR of all resets.
@li If register is RCC_AHBRSTR, from @ref rcc_ahbrstr_rst
@li If register is RCC_APB1RSTR, from @ref rcc_apb1rstr_rst
@li If register is RCC_APB2RSTR, from @ref rcc_apb2rstr_rst
*/
void rcc_peripheral_reset(volatile u32 *reg, u32 reset)
{
*reg |= reset;
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Remove Reset on Peripherals.
Remove the reset on particular peripherals. There are three registers
involved, each one controlling reset of peripherals associated with the AHB,
APB1 and APB2 respectively. Several peripherals could have the reset removed
simultaneously <em>only if they are controlled by the same register</em>.
@param[in] *reg Unsigned int32. Pointer to a Reset Register
(either RCC_AHBENR, RCC_APB1ENR or RCC_APB2ENR)
@param[in] clear_reset Unsigned int32. Logical OR of all resets to be removed:
@li If register is RCC_AHBRSTR, from @ref rcc_ahbrstr_rst
@li If register is RCC_APB1RSTR, from @ref rcc_apb1rstr_rst
@li If register is RCC_APB2RSTR, from @ref rcc_apb2rstr_rst
*/
void rcc_peripheral_clear_reset(volatile u32 *reg, u32 clear_reset)
{
*reg &= ~clear_reset;
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Set the Source for the System Clock.
@param[in] clk Unsigned int32. System Clock Selection @ref rcc_cfgr_scs
*/
void rcc_set_sysclk_source(u32 clk)
{
u32 reg32;
@@ -259,6 +467,14 @@ void rcc_set_sysclk_source(u32 clk)
RCC_CFGR = (reg32 | clk);
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Set the PLL Multiplication Factor.
@note This only has effect when the PLL is disabled.
@param[in] mul Unsigned int32. PLL multiplication factor @ref rcc_cfgr_pmf
*/
void rcc_set_pll_multiplication_factor(u32 mul)
{
u32 reg32;
@@ -268,6 +484,14 @@ void rcc_set_pll_multiplication_factor(u32 mul)
RCC_CFGR = (reg32 | (mul << 18));
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Set the PLL Clock Source.
@note This only has effect when the PLL is disabled.
@param[in] pllsrc Unsigned int32. PLL clock source @ref rcc_cfgr_pcs
*/
void rcc_set_pll_source(u32 pllsrc)
{
u32 reg32;
@@ -277,6 +501,14 @@ void rcc_set_pll_source(u32 pllsrc)
RCC_CFGR = (reg32 | (pllsrc << 16));
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Set the HSE Frequency Divider used as PLL Clock Source.
@note This only has effect when the PLL is disabled.
@param[in] pllxtpre Unsigned int32. HSE division factor @ref rcc_cfgr_hsepre
*/
void rcc_set_pllxtpre(u32 pllxtpre)
{
u32 reg32;
@@ -286,6 +518,14 @@ void rcc_set_pllxtpre(u32 pllxtpre)
RCC_CFGR = (reg32 | (pllxtpre << 17));
}
/*-----------------------------------------------------------------------------*/
/** @brief ADC Setup the A/D Clock
The ADC's have a common clock prescale setting.
@param[in] adcpre u32. Prescale divider taken from @ref rcc_cfgr_adcpre
*/
void rcc_set_adcpre(u32 adcpre)
{
u32 reg32;
@@ -295,6 +535,12 @@ void rcc_set_adcpre(u32 adcpre)
RCC_CFGR = (reg32 | (adcpre << 14));
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Set the APB2 Prescale Factor.
@param[in] ppre2 Unsigned int32. APB2 prescale factor @ref rcc_cfgr_apb2pre
*/
void rcc_set_ppre2(u32 ppre2)
{
u32 reg32;
@@ -304,6 +550,14 @@ void rcc_set_ppre2(u32 ppre2)
RCC_CFGR = (reg32 | (ppre2 << 11));
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Set the APB1 Prescale Factor.
@note The APB1 clock frequency must not exceed 36MHz.
@param[in] ppre1 Unsigned int32. APB1 prescale factor @ref rcc_cfgr_apb1pre
*/
void rcc_set_ppre1(u32 ppre1)
{
u32 reg32;
@@ -313,6 +567,12 @@ void rcc_set_ppre1(u32 ppre1)
RCC_CFGR = (reg32 | (ppre1 << 8));
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Set the AHB Prescale Factor.
@param[in] hpre Unsigned int32. AHB prescale factor @ref rcc_cfgr_ahbpre
*/
void rcc_set_hpre(u32 hpre)
{
u32 reg32;
@@ -322,6 +582,17 @@ void rcc_set_hpre(u32 hpre)
RCC_CFGR = (reg32 | (hpre << 4));
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Set the USB Prescale Factor.
The prescale factor can be set to 1 (no prescale) for use when the PLL clock is
48MHz, or 1.5 to generate the 48MHz USB clock from a 64MHz PLL clock.
@note This bit cannot be reset while the USB clock is enabled.
@param[in] usbpre Unsigned int32. USB prescale factor @ref rcc_cfgr_usbpre
*/
void rcc_set_usbpre(u32 usbpre)
{
u32 reg32;
@@ -331,16 +602,31 @@ void rcc_set_usbpre(u32 usbpre)
RCC_CFGR = (reg32 | (usbpre << 22));
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Get the System Clock Source.
@returns Unsigned int32. System clock source:
@li 00 indicates HSE
@li 01 indicates LSE
@li 02 indicates PLL
*/
u32 rcc_system_clock_source(void)
{
/* Return the clock source which is used as system clock. */
return ((RCC_CFGR & 0x000c) >> 2);
}
/*-----------------------------------------------------------------------------*/
/*
* These functions are setting up the whole clock system for the most common
* input clock and output clock configurations.
*/
/*-----------------------------------------------------------------------------*/
/** @brief RCC Set System Clock PLL at 64MHz from HSI
*/
void rcc_clock_setup_in_hsi_out_64mhz(void)
{
/* Enable internal high-speed oscillator. */
@@ -388,6 +674,11 @@ void rcc_clock_setup_in_hsi_out_64mhz(void)
rcc_ppre2_frequency = 64000000;
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Set System Clock PLL at 48MHz from HSI
*/
void rcc_clock_setup_in_hsi_out_48mhz(void)
{
/* Enable internal high-speed oscillator. */
@@ -436,6 +727,62 @@ void rcc_clock_setup_in_hsi_out_48mhz(void)
rcc_ppre2_frequency = 48000000;
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Set System Clock PLL at 24MHz from HSI
*/
void rcc_clock_setup_in_hsi_out_24mhz(void) {
/* Enable internal high-speed oscillator. */
rcc_osc_on(HSI);
rcc_wait_for_osc_ready(HSI);
/* Select HSI as SYSCLK source. */
rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
/*
* Set prescalers for AHB, ADC, ABP1, ABP2.
* Do this before touching the PLL (TODO: why?).
*/
rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /* Set. 24MHz Max. 24MHz */
rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV2); /* Set. 12MHz Max. 12MHz */
rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_NODIV); /* Set. 24MHz Max. 24MHz */
rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /* Set. 24MHz Max. 24MHz */
/*
* Sysclk is (will be) running with 24MHz -> 2 waitstates.
* 0WS from 0-24MHz
* 1WS from 24-48MHz
* 2WS from 48-72MHz
*/
flash_set_ws(FLASH_LATENCY_0WS);
/*
* Set the PLL multiplication factor to 6.
* 8MHz (internal) * 6 (multiplier) / 2 (PLLSRC_HSI_CLK_DIV2) = 24MHz
*/
rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL6);
/* Select HSI/2 as PLL source. */
rcc_set_pll_source(RCC_CFGR_PLLSRC_HSI_CLK_DIV2);
/* Enable PLL oscillator and wait for it to stabilize. */
rcc_osc_on(PLL);
rcc_wait_for_osc_ready(PLL);
/* Select PLL as SYSCLK source. */
rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
/* Set the peripheral clock frequencies used */
rcc_ppre1_frequency = 24000000;
rcc_ppre2_frequency = 24000000;
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Set System Clock PLL at 24MHz from HSE at 8MHz
*/
void rcc_clock_setup_in_hse_8mhz_out_24mhz(void)
{
/* Enable internal high-speed oscillator. */
@@ -494,6 +841,11 @@ void rcc_clock_setup_in_hse_8mhz_out_24mhz(void)
rcc_ppre2_frequency = 24000000;
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Set System Clock PLL at 72MHz from HSE at 8MHz
*/
void rcc_clock_setup_in_hse_8mhz_out_72mhz(void)
{
/* Enable internal high-speed oscillator. */
@@ -552,6 +904,11 @@ void rcc_clock_setup_in_hse_8mhz_out_72mhz(void)
rcc_ppre2_frequency = 72000000;
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Set System Clock PLL at 24MHz from HSE at 12MHz
*/
void rcc_clock_setup_in_hse_12mhz_out_72mhz(void)
{
/* Enable internal high-speed oscillator. */
@@ -610,6 +967,11 @@ void rcc_clock_setup_in_hse_12mhz_out_72mhz(void)
rcc_ppre2_frequency = 72000000;
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Set System Clock PLL at 24MHz from HSE at 16MHz
*/
void rcc_clock_setup_in_hse_16mhz_out_72mhz(void)
{
/* Enable internal high-speed oscillator. */
@@ -668,6 +1030,12 @@ void rcc_clock_setup_in_hse_16mhz_out_72mhz(void)
rcc_ppre2_frequency = 72000000;
}
/*-----------------------------------------------------------------------------*/
/** @brief RCC Reset the backup domain
The backup domain register is reset to disable all controls.
*/
void rcc_backupdomain_reset(void)
{
/* Set the backup domain software reset. */
@@ -676,3 +1044,5 @@ void rcc_backupdomain_reset(void)
/* Clear the backup domain software reset. */
RCC_BDCR &= ~RCC_BDCR_BDRST;
}
/**@}*/

View File

@@ -0,0 +1,31 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Linker script for STM32F100x4, 16K flash, 4K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 16K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 4K
}
/* Include the common ld script. */
INCLUDE libopencm3_stm32f1.ld

View File

@@ -0,0 +1,31 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Linker script for STM32F100x6, 32K flash, 4K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 32K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 4K
}
/* Include the common ld script. */
INCLUDE libopencm3_stm32f1.ld

View File

@@ -0,0 +1,31 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Linker script for STM32F100x8, 64K flash, 8K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 8K
}
/* Include the common ld script. */
INCLUDE libopencm3_stm32f1.ld

View File

@@ -0,0 +1,31 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Linker script for STM32F100xB, 128K flash, 8K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 8K
}
/* Include the common ld script. */
INCLUDE libopencm3_stm32f1.ld

View File

@@ -0,0 +1,31 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Linker script for STM32F100xC, 256K flash, 24K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 256K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 24K
}
/* Include the common ld script. */
INCLUDE libopencm3_stm32f1.ld

View File

@@ -0,0 +1,31 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Linker script for STM32F100xD, 384K flash, 32K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 384K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
}
/* Include the common ld script. */
INCLUDE libopencm3_stm32f1.ld

View File

@@ -0,0 +1,31 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Linker script for STM32F100xE, 512K flash, 32K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
}
/* Include the common ld script. */
INCLUDE libopencm3_stm32f1.ld

File diff suppressed because it is too large Load Diff

View File

@@ -19,8 +19,8 @@
#define WEAK __attribute__ ((weak))
/* Symbols exported by the linker script(s). */
extern unsigned __exidx_end, _data, _edata, _ebss, _stack;
/* Symbols exported by the linker script(s): */
extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack;
void main(void);
void reset_handler(void);
@@ -197,7 +197,7 @@ void reset_handler(void)
__asm__("MSR msp, %0" : : "r"(&_stack));
for (src = &__exidx_end, dest = &_data; dest < &_edata; src++, dest++)
for (src = &_data_loadaddr, dest = &_data; dest < &_edata; src++, dest++)
*dest = *src;
while (dest < &_ebss)

View File

@@ -33,27 +33,4 @@ OBJS = vector.o rcc.o gpio.o usart.o spi.o flash.o nvic.o \
VPATH += ../../usb:../
# Be silent per default, but 'make V=1' will show all compiler calls.
ifneq ($(V),1)
Q := @
endif
all: $(LIBNAME).a
$(LIBNAME).a: $(OBJS)
@printf " AR $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(AR) $(ARFLAGS) $@ $^
%.o: %.c
@printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS) -o $@ -c $<
clean:
@printf " CLEAN lib/stm32/f2\n"
$(Q)rm -f *.o *.d
$(Q)rm -f $(LIBNAME).a
.PHONY: clean
-include $(OBJS:.o=.d)
include ../../Makefile.include

View File

@@ -111,7 +111,7 @@ u16 gpio_get(u32 gpioport, u16 gpios)
void gpio_toggle(u32 gpioport, u16 gpios)
{
GPIO_ODR(gpioport) = GPIO_IDR(gpioport) ^ gpios;
GPIO_ODR(gpioport) ^= gpios;
}
u16 gpio_port_read(u32 gpioport)
@@ -135,5 +135,8 @@ void gpio_port_config_lock(u32 gpioport, u16 gpios)
reg32 = GPIO_LCKR(gpioport); /* Read LCKK. */
reg32 = GPIO_LCKR(gpioport); /* Read LCKK again. */
/* Tell the compiler the variable is actually used. It will get optimized out anyways. */
reg32 = reg32;
/* If (reg32 & GPIO_LCKK) is true, the lock is now active. */
}

View File

@@ -30,21 +30,18 @@ ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
. = ORIGIN(rom);
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
_etext = .;
} >rom
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support
*/
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support
*/
.ARM.extab : {
*(.ARM.extab*)
} >rom
@@ -54,21 +51,23 @@ SECTIONS
__exidx_end = .;
} >rom
. = ORIGIN(ram);
. = ALIGN(4);
_etext = .;
.data : AT (__exidx_end) {
.data : {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
} >ram
} >ram AT >rom
_data_loadaddr = LOADADDR(.data);
.bss : {
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram AT >rom
} >ram
/*
* The .eh_frame section appears to be used for C++ exception handling.

View File

@@ -21,7 +21,7 @@
#define WEAK __attribute__ ((weak))
/* Symbols exported by the linker script(s): */
extern unsigned __exidx_end, _data, _edata, _ebss, _stack;
extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack;
void main(void);
void reset_handler(void);
@@ -224,7 +224,7 @@ void reset_handler(void)
__asm__("MSR msp, %0" : : "r"(&_stack));
for (src = &__exidx_end, dest = &_data; dest < &_edata; src++, dest++)
for (src = &_data_loadaddr, dest = &_data; dest < &_edata; src++, dest++)
*dest = *src;
while (dest < &_ebss)

View File

@@ -34,27 +34,4 @@ OBJS = vector.o rcc.o gpio.o usart.o spi.o flash.o nvic.o \
VPATH += ../../usb:../
# Be silent per default, but 'make V=1' will show all compiler calls.
ifneq ($(V),1)
Q := @
endif
all: $(LIBNAME).a
$(LIBNAME).a: $(OBJS)
@printf " AR $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(AR) $(ARFLAGS) $@ $^
%.o: %.c
@printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS) -o $@ -c $<
clean:
@printf " CLEAN lib/stm32/f4\n"
$(Q)rm -f *.o *.d
$(Q)rm -f $(LIBNAME).a
.PHONY: clean
-include $(OBJS:.o=.d)
include ../../Makefile.include

View File

@@ -111,7 +111,7 @@ u16 gpio_get(u32 gpioport, u16 gpios)
void gpio_toggle(u32 gpioport, u16 gpios)
{
GPIO_ODR(gpioport) = GPIO_IDR(gpioport) ^ gpios;
GPIO_ODR(gpioport) ^= gpios;
}
u16 gpio_port_read(u32 gpioport)
@@ -135,5 +135,8 @@ void gpio_port_config_lock(u32 gpioport, u16 gpios)
reg32 = GPIO_LCKR(gpioport); /* Read LCKK. */
reg32 = GPIO_LCKR(gpioport); /* Read LCKK again. */
/* Tell the compiler the variable is actually used. It will get optimized out anyways. */
reg32 = reg32;
/* If (reg32 & GPIO_LCKK) is true, the lock is now active. */
}

View File

@@ -30,8 +30,6 @@ ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
. = ORIGIN(rom);
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
@@ -40,14 +38,20 @@ SECTIONS
. = ALIGN(4);
} >rom
/* exception index - required due to libgcc.a issuing /0 exceptions */
__exidx_start = .;
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support
*/
.ARM.extab : {
*(.ARM.extab*)
} >rom
.ARM.exidx : {
*(.ARM.exidx*)
} > rom
__exidx_end = .;
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >rom
. = ALIGN(4);
_etext = .;
.data : {
@@ -56,6 +60,7 @@ SECTIONS
. = ALIGN(4);
_edata = .;
} >ram AT >rom
_data_loadaddr = LOADADDR(.data);
.bss : {
*(.bss*) /* Read-write zero initialized data */
@@ -64,10 +69,11 @@ SECTIONS
_ebss = .;
} >ram
/* exception unwind data - required due to libgcc.a issuing /0 exceptions */
.ARM.extab : {
*(.ARM.extab*)
} >ram
/*
* The .eh_frame section appears to be used for C++ exception handling.
* You may need to fix this if you're using C++.
*/
/DISCARD/ : { *(.eh_frame) }
. = ALIGN(4);
end = .;

View File

@@ -21,7 +21,7 @@
#define WEAK __attribute__ ((weak))
/* Symbols exported by the linker script(s): */
extern unsigned _etext, _data, _edata, _ebss, _stack;
extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack;
void main(void);
void reset_handler(void);
@@ -224,7 +224,7 @@ void reset_handler(void)
__asm__("MSR msp, %0" : : "r"(&_stack));
for (src = &_etext, dest = &_data; dest < &_edata; src++, dest++)
for (src = &_data_loadaddr, dest = &_data; dest < &_edata; src++, dest++)
*dest = *src;
while (dest < &_ebss)

144
lib/stm32/iwdg.c Normal file
View File

@@ -0,0 +1,144 @@
/** @defgroup STM32F_iwdg_file IWDG
@ingroup STM32F_files
@brief <b>libopencm3 STM32F1xx Independent Watchdog Timer</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies ksarkies@internode.on.net
@date 18 August 2012
This library supports the Independent Watchdog Timer System in the STM32F1xx
series of ARM Cortex Microcontrollers by ST Microelectronics.
The watchdog timer uses the LSI (low speed internal) clock which is low power
and continues to operate during stop and standby modes. Its frequency is
nominally 32kHz (40kHz for the STM32F1xx series) but can vary from as low
as 17kHz up to 60kHz (refer to datasheet electrical characteristics).
Note that the User Configuration option byte provides a means of automatically
enabling the IWDG timer at power on (with counter value 0xFFF). If the
relevant bit is not set, the IWDG timer must be enabled by software.
@note: Tested: CPU STM32F103RET6, Board ET-ARM Stamp STM32
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/iwdg.h>
#define LSI_FREQUENCY 32000
#define COUNT_LENGTH 12
#define COUNT_MASK ((1 << COUNT_LENGTH)-1)
/*-----------------------------------------------------------------------------*/
/** @brief IWDG Enable Watchdog Timer
The watchdog timer is started. The timeout period defaults to 512 milliseconds
unless it has been previously defined.
*/
void iwdg_start(void)
{
IWDG_KR = IWDG_KR_START;
}
/*-----------------------------------------------------------------------------*/
/** @brief IWDG Set Period in Milliseconds
The countdown period is converted into count and prescale values. The maximum
period is 32.76 seconds; values above this are truncated. Periods less than 1ms
are not supported by this library.
A delay of up to 5 clock cycles of the LSI clock (about 156 microseconds)
can occasionally occur if the prescale or preload registers are currently busy
loading a previous value.
@param[in] period u32 Period in milliseconds (< 32760) from a watchdog reset until
a system reset is issued.
*/
void iwdg_set_period_ms(u32 period)
{
u32 count, prescale, reload, exponent;
/* Set the count to represent ticks of the 32kHz LSI clock */
count = (period << 5);
/* Strip off the first 12 bits to get the prescale value required */
prescale = (count >> 12);
if (prescale > 256) {exponent = IWDG_PR_DIV256; reload = COUNT_MASK;}
else if (prescale > 128) {exponent = IWDG_PR_DIV256; reload = (count >> 8);}
else if (prescale > 64) {exponent = IWDG_PR_DIV128; reload = (count >> 7);}
else if (prescale > 32) {exponent = IWDG_PR_DIV64; reload = (count >> 6);}
else if (prescale > 16) {exponent = IWDG_PR_DIV32; reload = (count >> 5);}
else if (prescale > 8) {exponent = IWDG_PR_DIV16; reload = (count >> 4);}
else if (prescale > 4) {exponent = IWDG_PR_DIV8; reload = (count >> 3);}
else {exponent = IWDG_PR_DIV4; reload = (count >> 2);}
/* Avoid the undefined situation of a zero count */
if (count == 0) count = 1;
while (iwdg_prescaler_busy());
IWDG_KR = IWDG_KR_UNLOCK;
IWDG_PR = exponent;
while (iwdg_reload_busy());
IWDG_KR = IWDG_KR_UNLOCK;
IWDG_RLR = (reload & COUNT_MASK);
}
/*-----------------------------------------------------------------------------*/
/** @brief IWDG Get Reload Register Status
@returns boolean: TRUE if the reload register is busy and unavailable for loading
a new count value.
*/
bool iwdg_reload_busy(void)
{
return (IWDG_SR & IWDG_SR_RVU);
}
/*-----------------------------------------------------------------------------*/
/** @brief IWDG Get Prescaler Register Status
@returns boolean: TRUE if the prescaler register is busy and unavailable for loading
a new period value.
*/
bool iwdg_prescaler_busy(void)
{
return (IWDG_SR & IWDG_SR_PVU);
}
/*-----------------------------------------------------------------------------*/
/** @brief IWDG reset Watchdog Timer
The watchdog timer is reset. The counter restarts from the value in the reload
register.
*/
void iwdg_reset(void)
{
IWDG_KR = IWDG_KR_RESET;
}
/**@}*/

View File

@@ -1,3 +1,26 @@
/** @defgroup STM32F_nvic_file NVIC
@ingroup STM32F_files
@brief <b>libopencm3 STM32F Nested Vectored Interrupt Controller</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
@author @htmlonly &copy; @endhtmlonly 2012 Fergus Noble <fergusnoble@gmail.com>
@date 18 August 2012
The STM32F series provides up to 68 maskable user interrupts for the STM32F10x
series, and 87 for the STM32F2xx and STM32F4xx series.
The NVIC registers are defined by the ARM standards but the STM32F series have some
additional limitations
@see Cortex-M3 Devices Generic User Guide
@see STM32F10xxx Cortex-M3 programming manual
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
@@ -18,50 +41,134 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/nvic.h>
/*-----------------------------------------------------------------------------*/
/** @brief NVIC Enable Interrupt
Enables a user interrupt.
@param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
*/
void nvic_enable_irq(u8 irqn)
{
NVIC_ISER(irqn / 32) = (1 << (irqn % 32));
}
/*-----------------------------------------------------------------------------*/
/** @brief NVIC Disable Interrupt
Disables a user interrupt.
@param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
*/
void nvic_disable_irq(u8 irqn)
{
NVIC_ICER(irqn / 32) = (1 << (irqn % 32));
}
/*-----------------------------------------------------------------------------*/
/** @brief NVIC Return Pending Interrupt
True if the interrupt has occurred and is waiting for service.
@param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
@return Boolean. Interrupt pending.
*/
u8 nvic_get_pending_irq(u8 irqn)
{
return NVIC_ISPR(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
}
/*-----------------------------------------------------------------------------*/
/** @brief NVIC Set Pending Interrupt
Force a user interrupt to a pending state. This has no effect if the interrupt
is already pending.
@param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
*/
void nvic_set_pending_irq(u8 irqn)
{
NVIC_ISPR(irqn / 32) = (1 << (irqn % 32));
}
/*-----------------------------------------------------------------------------*/
/** @brief NVIC Clear Pending Interrupt
Force remove a user interrupt from a pending state. This has no effect if the
interrupt is actively being serviced.
@param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
*/
void nvic_clear_pending_irq(u8 irqn)
{
NVIC_ICPR(irqn / 32) = (1 << (irqn % 32));
}
/*-----------------------------------------------------------------------------*/
/** @brief NVIC Return Active Interrupt
Interrupt has occurred and is currently being serviced.
@param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
@return Boolean. Interrupt active.
*/
u8 nvic_get_active_irq(u8 irqn)
{
return NVIC_IABR(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
}
/*-----------------------------------------------------------------------------*/
/** @brief NVIC Return Enabled Interrupt
@param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
@return Boolean. Interrupt enabled.
*/
u8 nvic_get_irq_enabled(u8 irqn)
{
return NVIC_ISER(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
}
/*-----------------------------------------------------------------------------*/
/** @brief NVIC Set Interrupt Priority
There are 16 priority levels only, given by the upper four bits of the priority
byte, as required by ARM standards. The priority levels are interpreted according
to the pre-emptive priority grouping set in the SCB Application Interrupt and Reset
Control Register (SCB_AIRCR), as done in @ref scb_set_priority_grouping.
@param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
@param[in] priority Unsigned int8. Interrupt priority (0 ... 255 in steps of 16)
*/
void nvic_set_priority(u8 irqn, u8 priority)
{
NVIC_IPR(irqn / 4) |= (priority << ((irqn % 4) * 8));
NVIC_IPR(irqn) = priority;
}
void nvic_generate_software_interrupt(u8 irqn)
/*-----------------------------------------------------------------------------*/
/** @brief NVIC Software Trigger Interrupt
Generate an interrupt from software. This has no effect for unprivileged access
unless the privilege level has been elevated through the System Control Registers.
@param[in] irqn Unsigned int16. Interrupt number (0 ... 239)
*/
void nvic_generate_software_interrupt(u16 irqn)
{
if (irqn <= 239)
NVIC_STIR |= irqn;
}
/**@}*/

View File

@@ -1,3 +1,23 @@
/** @defgroup STM32F_systick_file SysTick
@ingroup STM32F_files
@brief <b>libopencm3 STM32Fxx System Tick Timer</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
@date 19 August 2012
This library supports the System Tick timer in the
STM32F series of ARM Cortex Microcontrollers by ST Microelectronics.
The System Tick timer is part of the ARM Cortex core. It is a 24 bit
down counter that can be configured with an automatical reload value.
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
@@ -17,44 +37,97 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/systick.h>
/*-----------------------------------------------------------------------------*/
/** @brief SysTick Set the Automatic Reload Value.
The counter is set to the reload value when the counter starts and after it
reaches zero.
@param[in] value u32. 24 bit reload value.
*/
void systick_set_reload(u32 value)
{
STK_LOAD = (value & 0x00FFFFFF);
}
/*-----------------------------------------------------------------------------*/
/** @brief SysTick Read the Automatic Reload Value.
@returns 24 bit reload value as u32.
*/
u32 systick_get_value(void)
{
return STK_VAL;
}
/*-----------------------------------------------------------------------------*/
/** @brief Set the SysTick Clock Source.
The clock source can be either the AHB clock or the same clock divided by 8.
@param[in] clocksource u8. Clock source from @ref systick_clksource.
*/
void systick_set_clocksource(u8 clocksource)
{
if (clocksource < 2)
STK_CTRL |= (clocksource << STK_CTRL_CLKSOURCE_LSB);
}
/*-----------------------------------------------------------------------------*/
/** @brief Enable SysTick Interrupt.
*/
void systick_interrupt_enable(void)
{
STK_CTRL |= STK_CTRL_TICKINT;
}
/*-----------------------------------------------------------------------------*/
/** @brief Disable SysTick Interrupt.
*/
void systick_interrupt_disable(void)
{
STK_CTRL &= ~STK_CTRL_TICKINT;
}
/*-----------------------------------------------------------------------------*/
/** @brief Enable SysTick Counter.
*/
void systick_counter_enable(void)
{
STK_CTRL |= STK_CTRL_ENABLE;
}
/*-----------------------------------------------------------------------------*/
/** @brief Disable SysTick Counter.
*/
void systick_counter_disable(void)
{
STK_CTRL &= ~STK_CTRL_ENABLE;
}
/*-----------------------------------------------------------------------------*/
/** @brief SysTick Read the Counter Flag.
The count flag is set when the timer count becomes zero, and is cleared when the
flag is read.
@returns Boolean if flag set.
*/
u8 systick_get_countflag(void)
{
if (STK_CTRL & STK_CTRL_COUNTFLAG)
@@ -62,3 +135,5 @@ u8 systick_get_countflag(void)
else
return 0;
}
/**@}*/