git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@1073 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
parent
51e3bee839
commit
1ea7355d85
|
@ -43,16 +43,18 @@ PROJECT = ch
|
||||||
LDSCRIPT= ch.ld
|
LDSCRIPT= ch.ld
|
||||||
|
|
||||||
# Imported source files
|
# Imported source files
|
||||||
include ../../src/kernel.mk
|
include ../../os/ports/GCC/ARM7/port.mk
|
||||||
|
include ../../os/kernel/kernel.mk
|
||||||
include ../../test/test.mk
|
include ../../test/test.mk
|
||||||
|
|
||||||
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
||||||
# setting.
|
# setting.
|
||||||
CSRC = ../../ports/ARM7/chcore.c \
|
CSRC = ${PORTSRC} \
|
||||||
../../ports/ARM7-AT91SAM7X/pal_lld.c \
|
|
||||||
../../ports/ARM7-AT91SAM7X/sam7x_serial.c \
|
|
||||||
${KERNSRC} \
|
${KERNSRC} \
|
||||||
${TESTSRC} \
|
${TESTSRC} \
|
||||||
|
../../os/io/pal.c \
|
||||||
|
../../os/ports/GCC/ARM7/AT91SAM7X/pal_lld.c \
|
||||||
|
../../os/ports/GCC/ARM7/AT91SAM7X/sam7x_serial.c \
|
||||||
at91lib/aic.c \
|
at91lib/aic.c \
|
||||||
board.c main.c
|
board.c main.c
|
||||||
|
|
||||||
|
@ -81,14 +83,13 @@ TCSRC =
|
||||||
TCPPSRC =
|
TCPPSRC =
|
||||||
|
|
||||||
# List ASM source files here
|
# List ASM source files here
|
||||||
ASMSRC = ../../ports/ARM7/crt0.s \
|
ASMSRC = $(PORTASM) \
|
||||||
../../ports/ARM7-AT91SAM7X/vectors.s \
|
../../os/ports/GCC/ARM7/AT91SAM7X/vectors.s
|
||||||
../../ports/ARM7/chcoreasm.s
|
|
||||||
|
|
||||||
INCDIR = $(KERNINC) $(TESTINC) \
|
INCDIR = $(PORTINC) $(KERNINC) $(TESTINC) \
|
||||||
../../src/lib \
|
../../os/io \
|
||||||
../../ports/ARM7 \
|
../../os/ports/GCC/ARM7/AT91SAM7X \
|
||||||
../../ports/ARM7-AT91SAM7X
|
../../os/various
|
||||||
|
|
||||||
#
|
#
|
||||||
# Project, sources and paths
|
# Project, sources and paths
|
||||||
|
@ -176,4 +177,4 @@ ULIBS =
|
||||||
# End of user defines
|
# End of user defines
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
include ../../ports/ARM/rules.mk
|
include ../../os/ports/GCC/ARM/rules.mk
|
||||||
|
|
|
@ -43,7 +43,8 @@ PROJECT = ch
|
||||||
LDSCRIPT= ch.ld
|
LDSCRIPT= ch.ld
|
||||||
|
|
||||||
# Imported source files
|
# Imported source files
|
||||||
include ../../src/kernel.mk
|
include ../../os/ports/GCC/ARM7/port.mk
|
||||||
|
include ../../os/kernel/kernel.mk
|
||||||
include ../../test/test.mk
|
include ../../test/test.mk
|
||||||
|
|
||||||
# List of the required uIP source files.
|
# List of the required uIP source files.
|
||||||
|
@ -57,14 +58,15 @@ USRC = ../../ext/uip-1.0/uip/uip_arp.c \
|
||||||
|
|
||||||
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
||||||
# setting.
|
# setting.
|
||||||
CSRC = ../../ports/ARM7/chcore.c \
|
CSRC = ${PORTSRC} \
|
||||||
../../ports/ARM7-AT91SAM7X/pal_lld.c \
|
|
||||||
../../ports/ARM7-AT91SAM7X/sam7x_serial.c \
|
|
||||||
../../ports/ARM7-AT91SAM7X/sam7x_emac.c \
|
|
||||||
${KERNSRC} \
|
${KERNSRC} \
|
||||||
${TESTSRC} \
|
${TESTSRC} \
|
||||||
${USRC} \
|
${USRC} \
|
||||||
../../src/lib/evtimer.c \
|
../../os/io/pal.c \
|
||||||
|
../../os/ports/GCC/ARM7/AT91SAM7X/pal_lld.c \
|
||||||
|
../../os/ports/GCC/ARM7/AT91SAM7X/sam7x_serial.c \
|
||||||
|
../../os/ports/GCC/ARM7/AT91SAM7X/sam7x_emac.c \
|
||||||
|
../../os/various/evtimer.c \
|
||||||
at91lib/aic.c \
|
at91lib/aic.c \
|
||||||
web/webthread.c \
|
web/webthread.c \
|
||||||
board.c main.c
|
board.c main.c
|
||||||
|
@ -94,14 +96,13 @@ TCSRC =
|
||||||
TCPPSRC =
|
TCPPSRC =
|
||||||
|
|
||||||
# List ASM source files here
|
# List ASM source files here
|
||||||
ASMSRC = ../../ports/ARM7/crt0.s \
|
ASMSRC = $(PORTASM) \
|
||||||
../../ports/ARM7-AT91SAM7X/vectors.s \
|
../../os/ports/GCC/ARM7/AT91SAM7X/vectors.s
|
||||||
../../ports/ARM7/chcoreasm.s
|
|
||||||
|
|
||||||
INCDIR = $(KERNINC) $(TESTINC) \
|
INCDIR = $(PORTINC) $(KERNINC) $(TESTINC) \
|
||||||
../../src/lib \
|
../../os/io \
|
||||||
../../ports/ARM7 \
|
../../os/ports/GCC/ARM7/AT91SAM7X \
|
||||||
../../ports/ARM7-AT91SAM7X \
|
../../os/various \
|
||||||
./web ../../ext/uip-1.0/uip ../../ext/uip-1.0/apps/webserver
|
./web ../../ext/uip-1.0/uip ../../ext/uip-1.0/apps/webserver
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -190,4 +191,4 @@ ULIBS =
|
||||||
# End of user defines
|
# End of user defines
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
include ../../ports/ARM/rules.mk
|
include ../../os/ports/GCC/ARM/rules.mk
|
||||||
|
|
|
@ -43,18 +43,20 @@ PROJECT = ch
|
||||||
LDSCRIPT = ch.ld
|
LDSCRIPT = ch.ld
|
||||||
|
|
||||||
# Imported source files
|
# Imported source files
|
||||||
include ../../src/kernel.mk
|
include ../../os/ports/GCC/ARM7/port.mk
|
||||||
|
include ../../os/kernel/kernel.mk
|
||||||
include ../../test/test.mk
|
include ../../test/test.mk
|
||||||
|
|
||||||
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
||||||
# setting.
|
# setting.
|
||||||
CSRC = ../../ports/ARM7/chcore.c \
|
CSRC = ${PORTSRC} \
|
||||||
../../ports/ARM7-LPC214x/vic.c \
|
|
||||||
../../ports/ARM7-LPC214x/pal_lld.c \
|
|
||||||
../../ports/ARM7-LPC214x/lpc214x_serial.c \
|
|
||||||
${KERNSRC} \
|
${KERNSRC} \
|
||||||
${TESTSRC} \
|
${TESTSRC} \
|
||||||
../../src/lib/evtimer.c \
|
../../os/io/pal.c \
|
||||||
|
../../os/ports/GCC//ARM7/LPC214x/vic.c \
|
||||||
|
../../os/ports/GCC/ARM7/LPC214x/pal_lld.c \
|
||||||
|
../../os/ports/GCC/ARM7/LPC214x/lpc214x_serial.c \
|
||||||
|
../../os/various/evtimer.c \
|
||||||
board.c
|
board.c
|
||||||
|
|
||||||
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
||||||
|
@ -82,14 +84,13 @@ TCSRC =
|
||||||
TCPPSRC =
|
TCPPSRC =
|
||||||
|
|
||||||
# List ASM source files here
|
# List ASM source files here
|
||||||
ASMSRC = ../../ports/ARM7/crt0.s \
|
ASMSRC = $(PORTASM) \
|
||||||
../../ports/ARM7-LPC214x/vectors.s \
|
../../os/ports/GCC/ARM7/LPC214x/vectors.s
|
||||||
../../ports/ARM7/chcoreasm.s
|
|
||||||
|
|
||||||
INCDIR = $(KERNINC) $(TESTINC) \
|
INCDIR = $(PORTINC) $(KERNINC) $(TESTINC) \
|
||||||
../../src/lib \
|
../../os/io \
|
||||||
../../ports/ARM7 \
|
../../os/ports/GCC/ARM7/LPC214x \
|
||||||
../../ports/ARM7-LPC214x
|
../../os/various
|
||||||
|
|
||||||
#
|
#
|
||||||
# Project, sources and paths
|
# Project, sources and paths
|
||||||
|
@ -177,4 +178,4 @@ ULIBS =
|
||||||
# End of user defines
|
# End of user defines
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
include ../../ports/ARM/rules.mk
|
include ../../os/ports/GCC/ARM/rules.mk
|
||||||
|
|
|
@ -43,15 +43,18 @@ PROJECT = ch
|
||||||
LDSCRIPT = ch.ld
|
LDSCRIPT = ch.ld
|
||||||
|
|
||||||
# Imported source files
|
# Imported source files
|
||||||
include ../../src/kernel.mk
|
include ../../os/ports/GCC/ARM7/port.mk
|
||||||
|
include ../../os/kernel/kernel.mk
|
||||||
#include ../../test/test.mk
|
#include ../../test/test.mk
|
||||||
|
|
||||||
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
||||||
# setting.
|
# setting.
|
||||||
CSRC = ../../ports/ARM7/chcore.c \
|
CSRC = ${PORTSRC} \
|
||||||
../../ports/ARM7-LPC214x/vic.c \
|
|
||||||
../../ports/ARM7-LPC214x/pal_lld.c \
|
|
||||||
${KERNSRC} \
|
${KERNSRC} \
|
||||||
|
${TESTSRC} \
|
||||||
|
../../os/io/pal.c \
|
||||||
|
../../os/ports/GCC//ARM7/LPC214x/vic.c \
|
||||||
|
../../os/ports/GCC/ARM7/LPC214x/pal_lld.c \
|
||||||
board.c main.c
|
board.c main.c
|
||||||
|
|
||||||
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
||||||
|
@ -79,14 +82,13 @@ TCSRC =
|
||||||
TCPPSRC =
|
TCPPSRC =
|
||||||
|
|
||||||
# List ASM source files here
|
# List ASM source files here
|
||||||
ASMSRC = ../../ports/ARM7/crt0.s \
|
ASMSRC = $(PORTASM) \
|
||||||
../../ports/ARM7-LPC214x/vectors.s \
|
../../os/ports/GCC/ARM7/LPC214x/vectors.s
|
||||||
../../ports/ARM7/chcoreasm.s
|
|
||||||
|
|
||||||
INCDIR = $(KERNINC) $(TESTINC) \
|
INCDIR = $(PORTINC) $(KERNINC) $(TESTINC) \
|
||||||
../../src/lib \
|
../../os/io \
|
||||||
../../ports/ARM7 \
|
../../os/ports/GCC/ARM7/LPC214x \
|
||||||
../../ports/ARM7-LPC214x
|
../../os/various
|
||||||
|
|
||||||
#
|
#
|
||||||
# Project, sources and paths
|
# Project, sources and paths
|
||||||
|
@ -174,4 +176,4 @@ ULIBS =
|
||||||
# End of user defines
|
# End of user defines
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
include ../../ports/ARM/rules.mk
|
include ../../os/ports/GCC/ARM/rules.mk
|
||||||
|
|
|
@ -43,20 +43,21 @@ PROJECT = ch
|
||||||
LDSCRIPT = ch.ld
|
LDSCRIPT = ch.ld
|
||||||
|
|
||||||
# Imported source files
|
# Imported source files
|
||||||
include ../../src/kernel.mk
|
include ../../os/ports/GCC/ARM7/port.mk
|
||||||
|
include ../../os/kernel/kernel.mk
|
||||||
include ../../test/test.mk
|
include ../../test/test.mk
|
||||||
|
|
||||||
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
||||||
# setting.
|
# setting.
|
||||||
CSRC = ../../ports/ARM7/chcore.c \
|
CSRC = ${PORTSRC} \
|
||||||
../../ports/ARM7-LPC214x/vic.c \
|
|
||||||
../../ports/ARM7-LPC214x/pal_lld.c \
|
|
||||||
../../ports/ARM7-LPC214x/lpc214x_serial.c \
|
|
||||||
../../ports/ARM7-LPC214x/lpc214x_ssp.c \
|
|
||||||
${KERNSRC} \
|
${KERNSRC} \
|
||||||
${TESTSRC} \
|
${TESTSRC} \
|
||||||
../../src/lib/evtimer.c \
|
../../os/io/pal.c \
|
||||||
../../src/lib/pal.c \
|
../../os/ports/GCC//ARM7/LPC214x/vic.c \
|
||||||
|
../../os/ports/GCC/ARM7/LPC214x/pal_lld.c \
|
||||||
|
../../os/ports/GCC/ARM7/LPC214x/lpc214x_serial.c \
|
||||||
|
../../os/ports/GCC/ARM7/LPC214x/lpc214x_ssp.c \
|
||||||
|
../../os/various/evtimer.c \
|
||||||
board.c buzzer.c mmcsd.c main.c
|
board.c buzzer.c mmcsd.c main.c
|
||||||
|
|
||||||
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
||||||
|
@ -84,14 +85,13 @@ TCSRC =
|
||||||
TCPPSRC =
|
TCPPSRC =
|
||||||
|
|
||||||
# List ASM source files here
|
# List ASM source files here
|
||||||
ASMSRC = ../../ports/ARM7/crt0.s \
|
ASMSRC = $(PORTASM) \
|
||||||
../../ports/ARM7-LPC214x/vectors.s \
|
../../os/ports/GCC/ARM7/LPC214x/vectors.s
|
||||||
../../ports/ARM7/chcoreasm.s
|
|
||||||
|
|
||||||
INCDIR = $(KERNINC) $(TESTINC) \
|
INCDIR = $(PORTINC) $(KERNINC) $(TESTINC) \
|
||||||
../../src/lib \
|
../../os/io \
|
||||||
../../ports/ARM7 \
|
../../os/ports/GCC/ARM7/LPC214x \
|
||||||
../../ports/ARM7-LPC214x
|
../../os/various
|
||||||
|
|
||||||
#
|
#
|
||||||
# Project, sources and paths
|
# Project, sources and paths
|
||||||
|
@ -179,4 +179,4 @@ ULIBS =
|
||||||
# End of user defines
|
# End of user defines
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
include ../../ports/ARM/rules.mk
|
include ../../os/ports/GCC/ARM/rules.mk
|
||||||
|
|
|
@ -56,20 +56,19 @@ PROJECT = ch
|
||||||
LDSCRIPT= ch.ld
|
LDSCRIPT= ch.ld
|
||||||
|
|
||||||
# Imported source files
|
# Imported source files
|
||||||
include ../../src/kernel.mk
|
include ../../os/ports/GCC/ARMCM3/port.mk
|
||||||
|
include ../../os/kernel/kernel.mk
|
||||||
include ../../test/test.mk
|
include ../../test/test.mk
|
||||||
|
|
||||||
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
||||||
# setting.
|
# setting.
|
||||||
CSRC = ../../ports/ARMCM3/cmsis/core_cm3.c \
|
CSRC = ${PORTSRC} \
|
||||||
../../ports/ARMCM3/chcore.c \
|
|
||||||
../../ports/ARMCM3/nvic.c \
|
|
||||||
../../ports/ARMCM3-STM32F103/stm32_serial.c \
|
|
||||||
../../ports/ARMCM3-STM32F103/pal_lld.c \
|
|
||||||
${KERNSRC} \
|
${KERNSRC} \
|
||||||
${TESTSRC} \
|
${TESTSRC} \
|
||||||
../../src/lib/pal.c \
|
../../os/io/pal.c \
|
||||||
../../src/lib/evtimer.c \
|
../../os/ports/GCC/ARMCM3/STM32F103/pal_lld.c \
|
||||||
|
../../os/ports/GCC/ARMCM3/STM32F103/stm32_serial.c \
|
||||||
|
../../os/various/evtimer.c \
|
||||||
board.c main.c
|
board.c main.c
|
||||||
|
|
||||||
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
||||||
|
@ -97,14 +96,13 @@ TCSRC =
|
||||||
TCPPSRC =
|
TCPPSRC =
|
||||||
|
|
||||||
# List ASM source files here
|
# List ASM source files here
|
||||||
ASMSRC = ../../ports/ARMCM3/crt0.s \
|
ASMSRC = $(PORTASM) \
|
||||||
../../ports/ARMCM3-STM32F103/vectors.s
|
../../ports/ARMCM3-STM32F103/vectors.s
|
||||||
|
|
||||||
INCDIR = $(KERNINC) $(TESTINC) \
|
INCDIR = $(PORTINC) $(KERNINC) $(TESTINC) \
|
||||||
../../src/lib \
|
../../os/io \
|
||||||
../../ports/ARMCM3 \
|
../../os/ports/GCC/ARMCM3/STM32F103 \
|
||||||
../../ports/ARMCM3/cmsis \
|
../../os/various \
|
||||||
../../ports/ARMCM3-STM32F103 \
|
|
||||||
./stm32lib/inc
|
./stm32lib/inc
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -199,4 +197,4 @@ ifeq ($(USE_FWLIB),yes)
|
||||||
USE_OPT += -DUSE_STDPERIPH_DRIVER
|
USE_OPT += -DUSE_STDPERIPH_DRIVER
|
||||||
endif
|
endif
|
||||||
|
|
||||||
include ../../ports/ARM/rules.mk
|
include ../../os/ports/GCC/ARM/rules.mk
|
||||||
|
|
|
@ -80,15 +80,17 @@ OBJDIR = .
|
||||||
|
|
||||||
|
|
||||||
# Imported source files
|
# Imported source files
|
||||||
include ../../src/kernel.mk
|
include ../../os/ports/GCC/AVR/port.mk
|
||||||
|
include ../../os/kernel/kernel.mk
|
||||||
include ../../test/test.mk
|
include ../../test/test.mk
|
||||||
|
|
||||||
|
|
||||||
# List C source files here. (C dependencies are automatically generated.)
|
# List C source files here. (C dependencies are automatically generated.)
|
||||||
SRC = ../../ports/AVR/chcore.c ../../ports/AVR/avr_serial.c \
|
SRC = ${PORTSRC} \
|
||||||
${KERNSRC} \
|
${KERNSRC} \
|
||||||
${TESTSRC} \
|
${TESTSRC} \
|
||||||
../../src/lib/evtimer.c \
|
../../os/ports/GCC/AVR/avr_serial.c \
|
||||||
|
../../os/various/evtimer.c \
|
||||||
board.c main.c
|
board.c main.c
|
||||||
|
|
||||||
|
|
||||||
|
@ -123,7 +125,7 @@ DEBUG = dwarf-2
|
||||||
# Each directory must be seperated by a space.
|
# Each directory must be seperated by a space.
|
||||||
# Use forward slashes for directory separators.
|
# Use forward slashes for directory separators.
|
||||||
# For a directory that has spaces, enclose it in quotes.
|
# For a directory that has spaces, enclose it in quotes.
|
||||||
EXTRAINCDIRS = ../../src/include ../../src/lib ../../ports/AVR
|
EXTRAINCDIRS = $(PORTINC) $(KERNINC) $(TESTINC)e ../../os/various
|
||||||
|
|
||||||
|
|
||||||
# Compiler flag to set the C Standard level.
|
# Compiler flag to set the C Standard level.
|
||||||
|
|
|
@ -80,15 +80,17 @@ OBJDIR = .
|
||||||
|
|
||||||
|
|
||||||
# Imported source files
|
# Imported source files
|
||||||
include ../../src/kernel.mk
|
include ../../os/ports/GCC/AVR/port.mk
|
||||||
|
include ../../os/kernel/kernel.mk
|
||||||
include ../../test/test.mk
|
include ../../test/test.mk
|
||||||
|
|
||||||
|
|
||||||
# List C source files here. (C dependencies are automatically generated.)
|
# List C source files here. (C dependencies are automatically generated.)
|
||||||
SRC = ../../ports/AVR/chcore.c ../../ports/AVR/avr_serial.c \
|
SRC = ${PORTSRC} \
|
||||||
${KERNSRC} \
|
${KERNSRC} \
|
||||||
${TESTSRC} \
|
${TESTSRC} \
|
||||||
../../src/lib/evtimer.c \
|
../../os/ports/GCC/AVR/avr_serial.c \
|
||||||
|
../../os/various/evtimer.c \
|
||||||
board.c lcd.c main.c
|
board.c lcd.c main.c
|
||||||
|
|
||||||
|
|
||||||
|
@ -123,7 +125,7 @@ DEBUG = dwarf-2
|
||||||
# Each directory must be seperated by a space.
|
# Each directory must be seperated by a space.
|
||||||
# Use forward slashes for directory separators.
|
# Use forward slashes for directory separators.
|
||||||
# For a directory that has spaces, enclose it in quotes.
|
# For a directory that has spaces, enclose it in quotes.
|
||||||
EXTRAINCDIRS = ../../src/include ../../src/lib ../../ports/AVR
|
EXTRAINCDIRS = $(PORTINC) $(KERNINC) $(TESTINC)e ../../os/various
|
||||||
|
|
||||||
|
|
||||||
# Compiler flag to set the C Standard level.
|
# Compiler flag to set the C Standard level.
|
||||||
|
|
|
@ -39,27 +39,29 @@ PROJECT = ch
|
||||||
LDSCRIPT = mspgcc/msp430x1611.x
|
LDSCRIPT = mspgcc/msp430x1611.x
|
||||||
|
|
||||||
# Imported source files
|
# Imported source files
|
||||||
include ../../src/kernel.mk
|
include ../../os/ports/GCC/MSP430/port.mk
|
||||||
|
include ../../os/kernel/kernel.mk
|
||||||
include ../../test/test.mk
|
include ../../test/test.mk
|
||||||
|
|
||||||
# C sources here.
|
# C sources here.
|
||||||
CSRC = ../../ports/MSP430/chcore.c \
|
CSRC = ${PORTSRC} \
|
||||||
../../ports/MSP430/msp430_serial.c \
|
|
||||||
../../ports/MSP430/pal_lld.c \
|
|
||||||
${KERNSRC} \
|
${KERNSRC} \
|
||||||
${TESTSRC} \
|
${TESTSRC} \
|
||||||
../../src/lib/evtimer.c \
|
../../os/io/pal.c \
|
||||||
|
../../os/ports/GCC/MSP430/pal_lld.c \
|
||||||
|
../../os/ports/GCC/MSP430/msp430_serial.c \
|
||||||
|
../../os/various/evtimer.c \
|
||||||
board.c main.c
|
board.c main.c
|
||||||
|
|
||||||
# C++ sources here.
|
# C++ sources here.
|
||||||
CPPSRC =
|
CPPSRC =
|
||||||
|
|
||||||
# List ASM source files here
|
# List ASM source files here
|
||||||
ASMSRC =
|
ASMSRC = $(PORTASM)
|
||||||
|
|
||||||
INCDIR = $(KERNINC) $(TESTINC) \
|
INCDIR = $(PORTINC) $(KERNINC) $(TESTINC) \
|
||||||
../../src/lib \
|
../../os/io \
|
||||||
../../ports/MSP430
|
../../os/various
|
||||||
|
|
||||||
#
|
#
|
||||||
# Project, sources and paths
|
# Project, sources and paths
|
||||||
|
|
|
@ -56,19 +56,21 @@ UDEFS =
|
||||||
UADEFS =
|
UADEFS =
|
||||||
|
|
||||||
# Imported source files
|
# Imported source files
|
||||||
include ../../src/kernel.mk
|
include ../../os/kernel/kernel.mk
|
||||||
include ../../test/test.mk
|
include ../../test/test.mk
|
||||||
|
|
||||||
# List C source files here
|
# List C source files here
|
||||||
SRC = chcore.c main.c ../../ports/win32/simcom.c \
|
SRC = ${KERNSRC} \
|
||||||
${KERNSRC} \
|
${TESTSRC} \
|
||||||
${TESTSRC}
|
chcore.c \
|
||||||
|
../../os/ports/GCC/win32/simcom.c \
|
||||||
|
main.c
|
||||||
|
|
||||||
# List ASM source files here
|
# List ASM source files here
|
||||||
ASRC =
|
ASRC =
|
||||||
|
|
||||||
# List all user directories here
|
# List all user directories here
|
||||||
UINCDIR = ../../src/include
|
UINCDIR = $(KERNINC) $(TESTINC)
|
||||||
|
|
||||||
# List the user directory to look for the libraries here
|
# List the user directory to look for the libraries here
|
||||||
ULIBDIR =
|
ULIBDIR =
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file pal.c
|
||||||
|
* @brief I/O Ports Abstraction Layer code
|
||||||
|
* @addtogroup PAL
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
#include <pal.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read from an I/O bus.
|
||||||
|
*
|
||||||
|
* @param[in] bus the I/O bus, pointer to a @p IOBus structure
|
||||||
|
* @return The bus logical states.
|
||||||
|
*
|
||||||
|
* @note The operation is not guaranteed to be atomic on all the architectures,
|
||||||
|
* for atomicity and/or portability reasons you may need to enclose port
|
||||||
|
* I/O operations between @p chSysLock() and @p chSysUnlock().
|
||||||
|
* @note The function internally uses the @p palReadGroup() macro. The use of
|
||||||
|
* this function is preferred when you value code size, readability and
|
||||||
|
* error checking over speed.
|
||||||
|
*/
|
||||||
|
ioportmask_t palReadBus(IOBus *bus) {
|
||||||
|
|
||||||
|
chDbgCheck((bus != NULL) &&
|
||||||
|
(bus->bus_offset > PAL_IOPORTS_WIDTH), "palReadBus");
|
||||||
|
|
||||||
|
return palReadGroup(bus->bus_portid, bus->bus_mask, bus->bus_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write to an I/O bus.
|
||||||
|
*
|
||||||
|
* @param[in] bus the I/O bus, pointer to a @p IOBus structure
|
||||||
|
* @param[in] bits the bits to be written on the I/O bus. Values exceeding
|
||||||
|
* the bus width are masked so most significant bits are lost.
|
||||||
|
*
|
||||||
|
* @note The operation is not guaranteed to be atomic on all the architectures,
|
||||||
|
* for atomicity and/or portability reasons you may need to enclose port
|
||||||
|
* I/O operations between @p chSysLock() and @p chSysUnlock().
|
||||||
|
* @note The default implementation is non atomic and not necessarily
|
||||||
|
* optimal. Low level drivers may optimize the function by using
|
||||||
|
* specific hardware or coding.
|
||||||
|
*/
|
||||||
|
void palWriteBus(IOBus *bus, ioportmask_t bits) {
|
||||||
|
|
||||||
|
chDbgCheck((bus != NULL) &&
|
||||||
|
(bus->bus_offset > PAL_IOPORTS_WIDTH), "palWriteBus");
|
||||||
|
|
||||||
|
palWriteGroup(bus->bus_portid, bus->bus_mask, bus->bus_offset, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Programs a bus with the specified mode.
|
||||||
|
*
|
||||||
|
* @param[in] bus the I/O bus, pointer to a @p IOBus structure
|
||||||
|
* @param[in] mode the mode
|
||||||
|
*
|
||||||
|
* @note The operation is not guaranteed to be atomic on all the architectures,
|
||||||
|
* for atomicity and/or portability reasons you may need to enclose port
|
||||||
|
* I/O operations between @p chSysLock() and @p chSysUnlock().
|
||||||
|
* @note The default implementation is non atomic and not necessarily
|
||||||
|
* optimal. Low level drivers may optimize the function by using
|
||||||
|
* specific hardware or coding.
|
||||||
|
*/
|
||||||
|
void palSetBusMode(IOBus *bus, uint_fast8_t mode) {
|
||||||
|
|
||||||
|
chDbgCheck((bus != NULL) &&
|
||||||
|
(bus->bus_offset > PAL_IOPORTS_WIDTH), "palSetBusMode");
|
||||||
|
|
||||||
|
palSetGroupMode(bus->bus_portid, bus->bus_mask, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,460 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file pal.h
|
||||||
|
* @brief I/O Ports Abstraction Layer macros, types and structures
|
||||||
|
* @addtogroup PAL
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PAL_H_
|
||||||
|
#define _PAL_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Bits in a mode word dedicated as mode selector.
|
||||||
|
* @details The other bits are not defined and may be used as device-specific
|
||||||
|
* option bits.
|
||||||
|
*/
|
||||||
|
#define PAL_MODE_MASK 0xF
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief After reset state.
|
||||||
|
* @details The state itself is not specified and is architecture dependent,
|
||||||
|
* it is guaranteed to be equal to the after-reset state. It is
|
||||||
|
* usually an input state.
|
||||||
|
*/
|
||||||
|
#define PAL_MODE_RESET 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Safe state for <b>unconnected</b> pads.
|
||||||
|
* @details The state itself is not specified and is architecture dependent,
|
||||||
|
* it may be mapped on @p PAL_MODE_INPUT_PULLUP,
|
||||||
|
* @p PAL_MODE_INPUT_PULLDOWN or @p PAL_MODE_OUTPUT_PUSHPULL as
|
||||||
|
* example.
|
||||||
|
*/
|
||||||
|
#define PAL_MODE_UNCONNECTED 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Regular input high-Z pad.
|
||||||
|
*/
|
||||||
|
#define PAL_MODE_INPUT 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Input pad with weak pull up resistor.
|
||||||
|
*/
|
||||||
|
#define PAL_MODE_INPUT_PULLUP 3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Input pad with weak pull down resistor.
|
||||||
|
*/
|
||||||
|
#define PAL_MODE_INPUT_PULLDOWN 4
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Push-pull output pad.
|
||||||
|
*/
|
||||||
|
#define PAL_MODE_OUTPUT_PUSHPULL 5
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Open-drain output pad.
|
||||||
|
*/
|
||||||
|
#define PAL_MODE_OUTPUT_OPENDRAIN 6
|
||||||
|
|
||||||
|
#ifndef _PAL_LLD_H_
|
||||||
|
#include "pal_lld.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Logical low state.
|
||||||
|
*/
|
||||||
|
#define PAL_LOW 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Logical high state.
|
||||||
|
*/
|
||||||
|
#define PAL_HIGH 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Port bit helper macro.
|
||||||
|
* @details This macro calculates the mask of a bit within a port.
|
||||||
|
*
|
||||||
|
* @param[in] n the bit position within the port
|
||||||
|
* @return The bit mask.
|
||||||
|
*/
|
||||||
|
#define PAL_PORT_BIT(n) ((ioportmask_t)(1 << (n)))
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Bits group mask helper.
|
||||||
|
* @details This macro calculates the mask of a bits group.
|
||||||
|
*
|
||||||
|
* @param[in] width the group width
|
||||||
|
* @return The group mask.
|
||||||
|
*/
|
||||||
|
#define PAL_GROUP_MASK(width) ((ioportmask_t)(1 << (width)) - 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Data part of a static I/O bus initializer.
|
||||||
|
* @details This macro should be used when statically initializing an I/O bus
|
||||||
|
* that is part of a bigger structure.
|
||||||
|
*
|
||||||
|
* @param name the name of the IOBus variable
|
||||||
|
* @param port the I/O port descriptor
|
||||||
|
* @param width the bus width in bits
|
||||||
|
* @param offset the bus bit offset within the port
|
||||||
|
*/
|
||||||
|
#define _IOBUS_DATA(name, port, width, offset) \
|
||||||
|
{port, PAL_GROUP_MASK(width), offset}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Static I/O bus initializer.
|
||||||
|
*
|
||||||
|
* @param name the name of the IOBus variable
|
||||||
|
* @param port the I/O port descriptor
|
||||||
|
* @param width the bus width in bits
|
||||||
|
* @param offset the bus bit offset within the port
|
||||||
|
*/
|
||||||
|
#define IOBUS_DECL(name, port, width, offset) \
|
||||||
|
IOBus name = _IOBUS_DATA(name, port, width, offset)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief I/O bus descriptor.
|
||||||
|
* @details This structure describes a group of contiguous digital I/O lines
|
||||||
|
* that have to be handled as bus.
|
||||||
|
* @note I/O operations on a bus do not affect I/O lines on the same port but
|
||||||
|
* not belonging to the bus.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** Port identifier. */
|
||||||
|
ioportid_t bus_portid;
|
||||||
|
/** Bus mask aligned to port bit 0. The bus mask implicitly define the bus
|
||||||
|
* width. */
|
||||||
|
ioportmask_t bus_mask;
|
||||||
|
/** Offset, within the port, of the least significant bit of the bus. */
|
||||||
|
uint_fast8_t bus_offset;
|
||||||
|
} IOBus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief PAL subsystem initialization.
|
||||||
|
*
|
||||||
|
* @param[in] config pointer to an architecture specific configuration
|
||||||
|
* structure. This structure is defined in the low level driver
|
||||||
|
* header.
|
||||||
|
*/
|
||||||
|
#define palInit(config) pal_lld_init(config)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads the physical I/O port states.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @return The port logical states.
|
||||||
|
*
|
||||||
|
* @note The default implementation always return zero and computes the
|
||||||
|
* parameter eventual side effects.
|
||||||
|
*/
|
||||||
|
#if !defined(pal_lld_readport) || defined(__DOXYGEN__)
|
||||||
|
#define palReadPort(port) ((void)(port), 0)
|
||||||
|
#else
|
||||||
|
#define palReadPort(port) pal_lld_readport(port)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads the output latch.
|
||||||
|
* @details The purpose of this function is to read back the latched output
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @return The latched logical states.
|
||||||
|
*
|
||||||
|
* @note The default implementation always return zero and computes the
|
||||||
|
* parameter eventual side effects.
|
||||||
|
*/
|
||||||
|
#if !defined(pal_lld_readlatch) || defined(__DOXYGEN__)
|
||||||
|
#define palReadLatch(port) ((void)(port), 0)
|
||||||
|
#else
|
||||||
|
#define palReadLatch(port) pal_lld_readlatch(port)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes a bits mask on a I/O port.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] bits the bits to be written on the specified port
|
||||||
|
*
|
||||||
|
* @note The default implementation does nothing except computing the
|
||||||
|
* parameters eventual side effects.
|
||||||
|
*/
|
||||||
|
#if !defined(pal_lld_writeport) || defined(__DOXYGEN__)
|
||||||
|
#define palWritePort(port, bits) ((void)(port), (void)(bits))
|
||||||
|
#else
|
||||||
|
#define palWritePort(port, bits) pal_lld_writeport(port, bits)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets a bits mask on a I/O port.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] bits the bits to be ORed on the specified port
|
||||||
|
*
|
||||||
|
* @note The operation is not guaranteed to be atomic on all the architectures,
|
||||||
|
* for atomicity and/or portability reasons you may need to enclose port
|
||||||
|
* I/O operations between @p chSysLock() and @p chSysUnlock().
|
||||||
|
* @note The default implementation is non atomic and not necessarily
|
||||||
|
* optimal. Low level drivers may optimize the function by using
|
||||||
|
* specific hardware or coding.
|
||||||
|
*/
|
||||||
|
#if !defined(pal_lld_setport) || defined(__DOXYGEN__)
|
||||||
|
#define palSetPort(port, bits) { \
|
||||||
|
palWritePort(port, palReadLatch(port) | (bits)); \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define palSetPort(port, bits) pal_lld_setport(port, bits)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears a bits mask on a I/O port.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] bits the bits to be cleared on the specified port
|
||||||
|
*
|
||||||
|
* @note The operation is not guaranteed to be atomic on all the architectures,
|
||||||
|
* for atomicity and/or portability reasons you may need to enclose port
|
||||||
|
* I/O operations between @p chSysLock() and @p chSysUnlock().
|
||||||
|
* @note The default implementation is non atomic and not necessarily
|
||||||
|
* optimal. Low level drivers may optimize the function by using
|
||||||
|
* specific hardware or coding.
|
||||||
|
*/
|
||||||
|
#if !defined(pal_lld_clearport) || defined(__DOXYGEN__)
|
||||||
|
#define palClearPort(port, bits) { \
|
||||||
|
palWritePort(port, palReadLatch(port) & ~(bits)); \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define palClearPort(port, bits) pal_lld_clearport(port, bits)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Toggles a bits mask on a I/O port.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] bits the bits to be XORed on the specified port
|
||||||
|
*
|
||||||
|
* @note The operation is not guaranteed to be atomic on all the architectures,
|
||||||
|
* for atomicity and/or portability reasons you may need to enclose port
|
||||||
|
* I/O operations between @p chSysLock() and @p chSysUnlock().
|
||||||
|
* @note The default implementation is non atomic and not necessarily
|
||||||
|
* optimal. Low level drivers may optimize the function by using
|
||||||
|
* specific hardware or coding.
|
||||||
|
*/
|
||||||
|
#if !defined(pal_lld_toggleport) || defined(__DOXYGEN__)
|
||||||
|
#define palTogglePort(port, bits) { \
|
||||||
|
palWritePort(port, palReadLatch(port) ^ (bits)); \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define palTogglePort(port, bits) pal_lld_toggleport(port, bits)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads a group of bits.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] mask the group mask
|
||||||
|
* @param[in] offset the group bit offset within the port
|
||||||
|
* @return The group logical states.
|
||||||
|
*/
|
||||||
|
#if !defined(pal_lld_readgroup) || defined(__DOXYGEN__)
|
||||||
|
#define palReadGroup(port, mask, offset) \
|
||||||
|
((palReadPort(port) >> (offset)) & (mask))
|
||||||
|
#else
|
||||||
|
#define palReadGroup(port, mask, offset) pal_lld_readgroup(port, mask, offset)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes a group of bits.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] mask the group mask
|
||||||
|
* @param[in] offset the group bit offset within the port
|
||||||
|
* @param[in] bits the bits to be written. Values exceeding the group width
|
||||||
|
* are masked.
|
||||||
|
*/
|
||||||
|
#if !defined(pal_lld_writegroup) || defined(__DOXYGEN__)
|
||||||
|
#define palWriteGroup(port, mask, offset, bits) { \
|
||||||
|
palWritePort(port, (palReadLatch(port) & ~((mask) << (offset))) | \
|
||||||
|
(((bits) & (mask)) << (offset))); \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define palWriteGroup(port, mask, offset, bits) \
|
||||||
|
pal_lld_writegroup(port, mask, offset, bits)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pads group mode setup.
|
||||||
|
* @details This function programs a pads group belonging to the same port
|
||||||
|
* with the specified mode.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] mask the group mask
|
||||||
|
* @param[in] mode the setup mode
|
||||||
|
*
|
||||||
|
* @note Programming an unknown or unsupported mode is silently ignored.
|
||||||
|
*/
|
||||||
|
#if !defined(pal_lld_setgroupmode) || defined(__DOXYGEN__)
|
||||||
|
#define palSetGroupMode(port, mask, mode)
|
||||||
|
#else
|
||||||
|
#define palSetGroupMode(port, mask, mode) pal_lld_setgroupmode(port, mask, mode)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads an input pad logical state.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] pad the pad number within the port
|
||||||
|
* @return The logical state.
|
||||||
|
* @retval 0 low logical state.
|
||||||
|
* @retval 1 high logical state.
|
||||||
|
*
|
||||||
|
* @note The default implementation not necessarily optimal. Low level drivers
|
||||||
|
* may optimize the function by using specific hardware or coding.
|
||||||
|
* @note The default implementation internally uses the @p palReadPort().
|
||||||
|
*/
|
||||||
|
#if !defined(pal_lld_readpad) || defined(__DOXYGEN__)
|
||||||
|
#define palReadPad(port, pad) ((palReadPort(port) >> (pad)) & 1)
|
||||||
|
#else
|
||||||
|
#define palReadPad(port, pad) pal_lld_readpad(port, pad)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes a logical state on an output pad.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] pad the pad number within the port
|
||||||
|
* @param[out] bit the logical value, the value must be @p 0 or @p 1
|
||||||
|
*
|
||||||
|
* @note The operation is not guaranteed to be atomic on all the architectures,
|
||||||
|
* for atomicity and/or portability reasons you may need to enclose port
|
||||||
|
* I/O operations between @p chSysLock() and @p chSysUnlock().
|
||||||
|
* @note The default implementation is non atomic and not necessarily
|
||||||
|
* optimal. Low level drivers may optimize the function by using
|
||||||
|
* specific hardware or coding.
|
||||||
|
* @note The default implementation internally uses the @p palReadLatch() and
|
||||||
|
* @p palWritePort().
|
||||||
|
*/
|
||||||
|
#if !defined(pal_lld_writepad) || defined(__DOXYGEN__)
|
||||||
|
#define palWritePad(port, pad, bit) { \
|
||||||
|
palWritePort(port, (palReadLatch(port) & ~PAL_PORT_BIT(pad)) | \
|
||||||
|
(((bit) & 1) << pad)); \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define palWritePad(port, pad, bit) pal_lld_writepad(port, pad, bit)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets a pad logical state to @p 1.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] pad the pad number within the port
|
||||||
|
*
|
||||||
|
* @note The operation is not guaranteed to be atomic on all the architectures,
|
||||||
|
* for atomicity and/or portability reasons you may need to enclose port
|
||||||
|
* I/O operations between @p chSysLock() and @p chSysUnlock().
|
||||||
|
* @note The default implementation is non atomic and not necessarily
|
||||||
|
* optimal. Low level drivers may optimize the function by using
|
||||||
|
* specific hardware or coding.
|
||||||
|
* @note The default implementation internally uses the @p palSetPort().
|
||||||
|
*/
|
||||||
|
#if !defined(pal_lld_setpad) || defined(__DOXYGEN__)
|
||||||
|
#define palSetPad(port, pad) palSetPort(port, PAL_PORT_BIT(pad))
|
||||||
|
#else
|
||||||
|
#define palSetPad(port, pad) pal_lld_setpad(port, pad)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears a pad logical state to @p 0.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] pad the pad number within the port
|
||||||
|
*
|
||||||
|
* @note The operation is not guaranteed to be atomic on all the architectures,
|
||||||
|
* for atomicity and/or portability reasons you may need to enclose port
|
||||||
|
* I/O operations between @p chSysLock() and @p chSysUnlock().
|
||||||
|
* @note The default implementation is non atomic and not necessarily
|
||||||
|
* optimal. Low level drivers may optimize the function by using
|
||||||
|
* specific hardware or coding.
|
||||||
|
* @note The default implementation internally uses the @p palClearPort().
|
||||||
|
*/
|
||||||
|
#if !defined(pal_lld_clearpad) || defined(__DOXYGEN__)
|
||||||
|
#define palClearPad(port, pad) palClearPort(port, PAL_PORT_BIT(pad))
|
||||||
|
#else
|
||||||
|
#define palClearPad(port, pad) pal_lld_clearpad(port, pad)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Toggles a pad logical state.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] pad the pad number within the port
|
||||||
|
*
|
||||||
|
* @note The operation is not guaranteed to be atomic on all the architectures,
|
||||||
|
* for atomicity and/or portability reasons you may need to enclose port
|
||||||
|
* I/O operations between @p chSysLock() and @p chSysUnlock().
|
||||||
|
* @note The default implementation is non atomic and not necessarily
|
||||||
|
* optimal. Low level drivers may optimize the function by using
|
||||||
|
* specific hardware or coding.
|
||||||
|
* @note The default implementation internally uses the @p palTogglePort().
|
||||||
|
*/
|
||||||
|
#if !defined(pal_lld_togglepad) || defined(__DOXYGEN__)
|
||||||
|
#define palTogglePad(port, pad) palTogglePort(port, PAL_PORT_BIT(pad))
|
||||||
|
#else
|
||||||
|
#define palTogglePad(port, pad) pal_lld_togglepad(port, pad)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pad mode setup.
|
||||||
|
* @details This function programs a pad with the specified mode.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] pad the pad number within the port
|
||||||
|
* @param[in] mode the setup mode
|
||||||
|
*
|
||||||
|
* @note The default implementation not necessarily optimal. Low level drivers
|
||||||
|
* may optimize the function by using specific hardware or coding.
|
||||||
|
* @note Programming an unknown or unsupported mode is silently ignored.
|
||||||
|
*/
|
||||||
|
#if !defined(pal_lld_setpadmode) || defined(__DOXYGEN__)
|
||||||
|
#define palSetPadMode(port, pad, mode) \
|
||||||
|
palSetGroupMode(port, PAL_PORT_BIT(pad), mode)
|
||||||
|
#else
|
||||||
|
#define palSetPadMode(port, pad, mode) pal_lld_setpadmode(port, pad, mode)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
ioportmask_t palReadBus(IOBus *bus);
|
||||||
|
void palWriteBus(IOBus *bus, ioportmask_t bits);
|
||||||
|
void palSetBusMode(IOBus *bus, uint_fast8_t mode);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _PAL_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1 @@
|
||||||
|
ChibiOS/RT I/O abstraction code
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ch.h
|
||||||
|
* @brief ChibiOS/RT main include file, it includes everything else.
|
||||||
|
* @addtogroup Kernel
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CH_H_
|
||||||
|
#define _CH_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ChibiOS/RT identification macro.
|
||||||
|
*/
|
||||||
|
#define _CHIBIOS_RT_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel version string.
|
||||||
|
*/
|
||||||
|
#define CH_KERNEL_VERSION "1.3.2unstable"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel version major number.
|
||||||
|
*/
|
||||||
|
#define CH_KERNEL_MAJOR 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel version minor number.
|
||||||
|
*/
|
||||||
|
#define CH_KERNEL_MINOR 3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel version patch number.
|
||||||
|
*/
|
||||||
|
#define CH_KERNEL_PATCH 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Common values.
|
||||||
|
*/
|
||||||
|
#ifndef FALSE
|
||||||
|
#define FALSE 0
|
||||||
|
#endif
|
||||||
|
#ifndef TRUE
|
||||||
|
#define TRUE (!FALSE)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <chconf.h>
|
||||||
|
#include <chtypes.h>
|
||||||
|
#include "lists.h"
|
||||||
|
#include <chcore.h>
|
||||||
|
#include "sys.h"
|
||||||
|
#include "vt.h"
|
||||||
|
#include "scheduler.h"
|
||||||
|
#include "semaphores.h"
|
||||||
|
#include "mutexes.h"
|
||||||
|
#include "condvars.h"
|
||||||
|
#include "events.h"
|
||||||
|
#include "messages.h"
|
||||||
|
#include "mailboxes.h"
|
||||||
|
#include "heap.h"
|
||||||
|
#include "mempools.h"
|
||||||
|
#include "threads.h"
|
||||||
|
#include "inline.h"
|
||||||
|
#include "queues.h"
|
||||||
|
#include "channels.h"
|
||||||
|
#include "serial.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#endif /* _CH_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,292 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file channels.h
|
||||||
|
* @brief I/O channels
|
||||||
|
* @addtogroup Channels
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CHANNELS_H_
|
||||||
|
#define _CHANNELS_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief @p BaseChannel specific methods.
|
||||||
|
*/
|
||||||
|
struct _base_channel_methods {
|
||||||
|
/**
|
||||||
|
* @brief Channel output check.
|
||||||
|
* @see chIOPutWouldBlock()
|
||||||
|
*/
|
||||||
|
bool_t (*putwouldblock)(void *instance);
|
||||||
|
/**
|
||||||
|
* @brief Channel input check.
|
||||||
|
* @see chIOGetWouldBlock()
|
||||||
|
*/
|
||||||
|
bool_t (*getwouldblock)(void *instance);
|
||||||
|
/**
|
||||||
|
* @brief Channel put method with timeout specification.
|
||||||
|
* @see chIOPut()
|
||||||
|
*/
|
||||||
|
msg_t (*put)(void *instance, uint8_t b, systime_t timeout);
|
||||||
|
/**
|
||||||
|
* @brief Channel get method with timeout specification.
|
||||||
|
* @see chIOGet()
|
||||||
|
*/
|
||||||
|
msg_t (*get)(void *instance, systime_t timeout);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief @p BaseChannel specific data.
|
||||||
|
* @note It is empty because @p BaseChannel is only an interface without
|
||||||
|
* implementation.
|
||||||
|
*/
|
||||||
|
struct _base_channel_data {
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief @p BaseChannel virtual methods table.
|
||||||
|
*/
|
||||||
|
struct BaseChannelVMT {
|
||||||
|
/**
|
||||||
|
* @p BaseChannel class specific methods.
|
||||||
|
*/
|
||||||
|
struct _base_channel_methods m0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Base channel class.
|
||||||
|
* @details This class represents a generic, byte-wide, I/O channel.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* Virtual Methods Table.
|
||||||
|
*/
|
||||||
|
const struct BaseChannelVMT *vmt;
|
||||||
|
/**
|
||||||
|
* @p BaseChannel class specific data.
|
||||||
|
*/
|
||||||
|
struct _base_channel_data d0;
|
||||||
|
} BaseChannel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Channel output check.
|
||||||
|
* @details This function verifies if a subsequent @p chIOPut() would block.
|
||||||
|
*
|
||||||
|
* @param[in] ip pointer to a @p BaseChannel or derived class
|
||||||
|
* @return The output queue status:
|
||||||
|
* @retval FALSE if the output queue has space and would not block a write
|
||||||
|
* operation.
|
||||||
|
* @retval TRUE if the output queue is full and would block a write operation.
|
||||||
|
*/
|
||||||
|
#define chIOPutWouldBlock(ip) ((ip)->vmt->m0.putwouldblock(ip))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Channel input check.
|
||||||
|
* @details This function verifies if a subsequent @p chIOGett() would block.
|
||||||
|
*
|
||||||
|
* @param[in] ip pointer to a @p BaseChannel or derived class
|
||||||
|
* @return The input queue status:
|
||||||
|
* @retval FALSE if the input queue contains data and would not block a read
|
||||||
|
* operation.
|
||||||
|
* @retval TRUE if the input queue is empty and would block a read operation.
|
||||||
|
*/
|
||||||
|
#define chIOGetWouldBlock(ip) ((ip)->vmt->m0.getwouldblock(ip))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Channel blocking byte write.
|
||||||
|
* @details This function writes a byte value to a channel. If the channel
|
||||||
|
* is not ready to accept data then the calling thread is suspended.
|
||||||
|
*
|
||||||
|
* @param[in] ip pointer to a @p BaseChannel or derived class
|
||||||
|
* @param[in] b the byte value to be written to the channel
|
||||||
|
* @return The operation status:
|
||||||
|
* @retval Q_OK if the operation succeeded.
|
||||||
|
* @retval Q_RESET if the channel associated queue (if any) was reset.
|
||||||
|
*/
|
||||||
|
#define chIOPut(ip, b) ((ip)->vmt->m0.put(ip, b, TIME_INFINITE))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Channel blocking byte write with timeout.
|
||||||
|
* @details This function writes a byte value to a channel. If the channel
|
||||||
|
* is not ready to accept data then the calling thread is suspended.
|
||||||
|
*
|
||||||
|
* @param[in] ip pointer to a @p BaseChannel or derived class
|
||||||
|
* @param[in] b the byte value to be written to the channel
|
||||||
|
* @param[in] timeout the number of ticks before the operation timeouts,
|
||||||
|
* the following special values are allowed:
|
||||||
|
* - @a TIME_IMMEDIATE immediate timeout.
|
||||||
|
* - @a TIME_INFINITE no timeout.
|
||||||
|
* .
|
||||||
|
* @return The operation status:
|
||||||
|
* @retval Q_OK if the operation succeeded.
|
||||||
|
* @retval Q_TIMEOUT if the specified time expired.
|
||||||
|
* @retval Q_RESET if the channel associated queue (if any) was reset.
|
||||||
|
*/
|
||||||
|
#define chIOPutTimeout(ip, b, timeout) ((ip)->vmt->m0.put(ip, b, timeout))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Channel blocking byte read.
|
||||||
|
* @details This function reads a byte value from a channel. If the data
|
||||||
|
* is not available then the calling thread is suspended.
|
||||||
|
*
|
||||||
|
* @param[in] ip pointer to a @p BaseChannel or derived class
|
||||||
|
* @return A byte value from the queue or:
|
||||||
|
* @retval Q_RESET if the channel associated queue (if any) was reset.
|
||||||
|
*/
|
||||||
|
#define chIOGet(ip) ((ip)->vmt->m0.get(ip, TIME_INFINITE))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Channel blocking byte read with timeout.
|
||||||
|
* @details This function reads a byte value from a channel. If the data
|
||||||
|
* is not available then the calling thread is suspended.
|
||||||
|
*
|
||||||
|
* @param[in] ip pointer to a @p BaseChannel or derived class
|
||||||
|
* @param[in] timeout the number of ticks before the operation timeouts,
|
||||||
|
* the following special values are allowed:
|
||||||
|
* - @a TIME_IMMEDIATE immediate timeout.
|
||||||
|
* - @a TIME_INFINITE no timeout.
|
||||||
|
* .
|
||||||
|
* @return A byte value from the queue or:
|
||||||
|
* @retval Q_TIMEOUT if the specified time expired.
|
||||||
|
* @retval Q_RESET if the channel associated queue (if any) was reset.
|
||||||
|
*/
|
||||||
|
#define chIOGetTimeout(ip, timeout) ((ip)->vmt->m0.get(ip, timeout))
|
||||||
|
|
||||||
|
#if CH_USE_EVENTS
|
||||||
|
/**
|
||||||
|
* @brief @p BaseAsynchronousChannel specific methods.
|
||||||
|
*/
|
||||||
|
struct _base_asynchronous_channel_methods {
|
||||||
|
/**
|
||||||
|
* Channel asynchronous write method.
|
||||||
|
* @see chIOWrite()
|
||||||
|
*/
|
||||||
|
size_t (*write)(void *instance, uint8_t *buffer, size_t n);
|
||||||
|
/**
|
||||||
|
* Channel asynchronous read method.
|
||||||
|
* @see chIORead()
|
||||||
|
*/
|
||||||
|
size_t (*read)(void *instance, uint8_t *buffer, size_t n);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief @p BaseAsynchronousChannel specific data.
|
||||||
|
*/
|
||||||
|
struct _base_asynchronous_channel_data {
|
||||||
|
/**
|
||||||
|
* Data Available @p EventSource. This event is generated when some incoming
|
||||||
|
* data is inserted in the input queue.
|
||||||
|
*/
|
||||||
|
EventSource ievent;
|
||||||
|
/**
|
||||||
|
* Data Transmitted @p EventSource. This event is generated when the
|
||||||
|
* output queue is empty.
|
||||||
|
*/
|
||||||
|
EventSource oevent;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief @p BaseAsynchronousChannel virtual methods table.
|
||||||
|
*/
|
||||||
|
struct BaseAsynchronousChannelVMT {
|
||||||
|
/**
|
||||||
|
* @p BaseChannel class inherited methods.
|
||||||
|
*/
|
||||||
|
struct _base_channel_methods m0;
|
||||||
|
/**
|
||||||
|
* @p BaseAsynchronousChannel class specific methods.
|
||||||
|
*/
|
||||||
|
struct _base_asynchronous_channel_methods m1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends BaseChannel
|
||||||
|
*
|
||||||
|
* @brief Base asynchronous channel class.
|
||||||
|
* @details This class extends @p BaseChannel by adding methods for
|
||||||
|
* asynchronous I/O in an event-driven environment.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* Virtual Methods Table.
|
||||||
|
*/
|
||||||
|
const struct BaseAsynchronousChannelVMT *vmt;
|
||||||
|
/**
|
||||||
|
* @p BaseChannel class inherited data.
|
||||||
|
*/
|
||||||
|
struct _base_channel_data d0;
|
||||||
|
/**
|
||||||
|
* @p BaseAsynchronousChannel class specific data.
|
||||||
|
*/
|
||||||
|
struct _base_asynchronous_channel_data d1;
|
||||||
|
} BaseAsynchronousChannel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Channel non-blocking write.
|
||||||
|
* @details The function writes data from a buffer to a channel. The
|
||||||
|
* transfer is non-blocking and can return zero if the channel is
|
||||||
|
* not read to accept data.
|
||||||
|
*
|
||||||
|
* @param[in] ip pointer to a @p BaseAsynchronousChannel or derived class
|
||||||
|
* @param[out] bp pointer to the buffer where the data is stored
|
||||||
|
* @param[in] n the maximum amount of data to be transferred
|
||||||
|
* @return The number of bytes transferred.
|
||||||
|
*/
|
||||||
|
#define chIOWrite(ip, bp, n) ((ip)->vmt->m1.write(ip, bp, n))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Channel non-blocking read.
|
||||||
|
* @details The function reads data from a channel into a buffer. The
|
||||||
|
* transfer is non-blocking and can return zero if the channel has
|
||||||
|
* no data immediately available.
|
||||||
|
*
|
||||||
|
* @param[in] ip pointer to a @p BaseAsynchronousChannel or derived class
|
||||||
|
* @param[out] bp pointer to the buffer where the input data is copied
|
||||||
|
* @param[in] n the maximum amount of data to be transferred
|
||||||
|
* @return The number of bytes transferred.
|
||||||
|
*/
|
||||||
|
#define chIORead(ip, bp, n) ((ip)->vmt->m1.read(ip, bp, n))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the write event source.
|
||||||
|
* @details The write event source is broadcasted when the channel is ready
|
||||||
|
* for write operations. This usually happens when the internal
|
||||||
|
* output queue becomes empty.
|
||||||
|
* @param[in] ip pointer to a @p BaseAsynchronousChannel or derived class
|
||||||
|
* @return A pointer to an @p EventSource object.
|
||||||
|
*/
|
||||||
|
#define chIOGetWriteEventSource(ip) (&((ip)->vmt->d1.oevent))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the read event source.
|
||||||
|
* @details The read event source is broadcasted when the channel is ready
|
||||||
|
* for read operations. This usually happens when the internal
|
||||||
|
* input queue becomes non-empty.
|
||||||
|
* @param[in] ip pointer to a @p BaseAsynchronousChannel or derived class
|
||||||
|
* @return A pointer to an @p EventSource object.
|
||||||
|
*/
|
||||||
|
#define chIOGetReadEventSource(ip) (&((ip)->vmt->d1.ievent))
|
||||||
|
|
||||||
|
#endif /* CH_USE_EVENTS */
|
||||||
|
|
||||||
|
#endif /* _CHANNELS_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
Concepts and parts of this file are contributed by and Copyright (C) 2008
|
||||||
|
of Leon Woestenberg.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file condvars.h
|
||||||
|
* @brief Condition Variables macros and structures.
|
||||||
|
* @addtogroup CondVars
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CONDVARS_H_
|
||||||
|
#define _CONDVARS_H_
|
||||||
|
|
||||||
|
#if CH_USE_CONDVARS && CH_USE_MUTEXES
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief CondVar structure.
|
||||||
|
*/
|
||||||
|
typedef struct CondVar {
|
||||||
|
ThreadsQueue c_queue; /**< CondVar threads queue.*/
|
||||||
|
} CondVar;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void chCondInit(CondVar *cp);
|
||||||
|
void chCondSignal(CondVar *cp);
|
||||||
|
void chCondSignalI(CondVar *cp);
|
||||||
|
void chCondBroadcast(CondVar *cp);
|
||||||
|
void chCondBroadcastI(CondVar *cp);
|
||||||
|
msg_t chCondWait(CondVar *cp);
|
||||||
|
msg_t chCondWaitS(CondVar *cp);
|
||||||
|
#if CH_USE_CONDVARS_TIMEOUT
|
||||||
|
msg_t chCondWaitTimeout(CondVar *cp, systime_t time);
|
||||||
|
msg_t chCondWaitTimeoutS(CondVar *cp, systime_t time);
|
||||||
|
#endif
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Data part of a static condition variable initializer.
|
||||||
|
* @details This macro should be used when statically initializing a condition
|
||||||
|
* variable that is part of a bigger structure.
|
||||||
|
*/
|
||||||
|
#define _CONDVAR_DATA(name) {_THREADSQUEUE_DATA(name.c_queue)}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Static condition variable initializer.
|
||||||
|
* @details Statically initialized condition variables require no explicit
|
||||||
|
* initialization using @p chCondInit().
|
||||||
|
* @param name the name of the condition variable
|
||||||
|
*/
|
||||||
|
#define CONDVAR_DECL(name) CondVar name = _CONDVAR_DATA(name)
|
||||||
|
|
||||||
|
#endif /* CH_USE_CONDVARS && CH_USE_MUTEXES */
|
||||||
|
|
||||||
|
#endif /* _CONDVARS_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file debug.h
|
||||||
|
* @brief Debug macros and structures.
|
||||||
|
* @addtogroup Debug
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _DEBUG_H_
|
||||||
|
#define _DEBUG_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Trace buffer entries.
|
||||||
|
*/
|
||||||
|
#ifndef TRACE_BUFFER_SIZE
|
||||||
|
#define TRACE_BUFFER_SIZE 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fill value for thread stack area in debug mode.
|
||||||
|
*/
|
||||||
|
#ifndef STACK_FILL_VALUE
|
||||||
|
#define STACK_FILL_VALUE 0x55
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fill value for thread area in debug mode.
|
||||||
|
* @note The chosen default value is 0xFF in order to make evident which
|
||||||
|
* thread fields were not initialized when inspecting the memory with
|
||||||
|
* a debugger. A uninitialized field is not an error in itself but it
|
||||||
|
* better to know it.
|
||||||
|
*/
|
||||||
|
#ifndef THREAD_FILL_VALUE
|
||||||
|
#define THREAD_FILL_VALUE 0xFF
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Trace buffer record.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
void *cse_wtobjp; /**< Object where going to sleep.*/
|
||||||
|
systime_t cse_time; /**< Time of the switch event.*/
|
||||||
|
uint16_t cse_state: 4; /**< Switched out thread state.*/
|
||||||
|
uint16_t cse_tid: 12; /**< Switched in thdread id.*/
|
||||||
|
} CtxSwcEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Trace buffer header.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
unsigned tb_size; /**< Trace buffer size (records).*/
|
||||||
|
CtxSwcEvent *tb_ptr; /**< Pointer to the ring buffer front.*/
|
||||||
|
CtxSwcEvent tb_buffer[TRACE_BUFFER_SIZE]; /**< Ring buffer.*/
|
||||||
|
} TraceBuffer;
|
||||||
|
|
||||||
|
#define __QUOTE_THIS(p) #p
|
||||||
|
|
||||||
|
#if CH_DBG_ENABLE_CHECKS
|
||||||
|
/**
|
||||||
|
* Function parameter check, if the condition check fails then the kernel
|
||||||
|
* panics.
|
||||||
|
* @param c the condition to be verified to be true
|
||||||
|
* @param func the undecorated function name
|
||||||
|
* @note The condition is tested only if the @p CH_DBG_ENABLE_CHECKS switch is
|
||||||
|
* specified in @p chconf.h else the macro does nothing.
|
||||||
|
*/
|
||||||
|
#define chDbgCheck(c, func) { \
|
||||||
|
if (!(c)) \
|
||||||
|
chDbgPanic(__QUOTE_THIS(func)"(), line "__QUOTE_THIS(__LINE__)); \
|
||||||
|
}
|
||||||
|
#else /* !CH_DBG_ENABLE_CHECKS */
|
||||||
|
#define chDbgCheck(c, func) { \
|
||||||
|
(void)(c), (void)__QUOTE_THIS(func)"(), line "__QUOTE_THIS(__LINE__); \
|
||||||
|
}
|
||||||
|
#endif /* !CH_DBG_ENABLE_CHECKS */
|
||||||
|
|
||||||
|
#if CH_DBG_ENABLE_ASSERTS
|
||||||
|
/**
|
||||||
|
* Condition assertion, if the condition check fails then the kernel panics
|
||||||
|
* with the specified message.
|
||||||
|
* @param c the condition to be verified to be true
|
||||||
|
* @param m the text message
|
||||||
|
* @param r a remark string
|
||||||
|
* @note The condition is tested only if the @p CH_DBG_ENABLE_ASSERTS switch is
|
||||||
|
* specified in @p chconf.h else the macro does nothing.
|
||||||
|
* @note The convention for the message is the following:<br>
|
||||||
|
* @<function_name@>(), #@<assert_number@>
|
||||||
|
* @note The remark string is not currently used except for putting a comment
|
||||||
|
* in the code about the assert.
|
||||||
|
*/
|
||||||
|
#define chDbgAssert(c, m, r) { \
|
||||||
|
if (!(c)) \
|
||||||
|
chDbgPanic(m); \
|
||||||
|
}
|
||||||
|
#else /* !CH_DBG_ENABLE_ASSERTS */
|
||||||
|
#define chDbgAssert(c, m, r) {(void)(c);}
|
||||||
|
#endif /* !CH_DBG_ENABLE_ASSERTS */
|
||||||
|
|
||||||
|
#if !(CH_DBG_ENABLE_ASSERTS || CH_DBG_ENABLE_CHECKS || CH_DBG_ENABLE_STACK_CHECK)
|
||||||
|
/* When the debug features are disabled this function is replaced by an empty
|
||||||
|
* macro.*/
|
||||||
|
#define chDbgPanic(msg) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !CH_DBG_ENABLE_TRACE
|
||||||
|
/* When the trace feature is disabled this function is replaced by an empty
|
||||||
|
* macro.*/
|
||||||
|
#define chDbgTrace(otp, ntp) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__DOXYGEN__)
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#if CH_DBG_ENABLE_TRACE
|
||||||
|
extern TraceBuffer trace_buffer;
|
||||||
|
void trace_init(void);
|
||||||
|
void chDbgTrace(Thread *otp, Thread *ntp);
|
||||||
|
#endif
|
||||||
|
#if CH_DBG_ENABLE_ASSERTS || CH_DBG_ENABLE_CHECKS || CH_DBG_ENABLE_STACK_CHECK
|
||||||
|
extern char *panic_msg;
|
||||||
|
void chDbgPanic(char *msg);
|
||||||
|
#endif
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* !defined(__DOXYGEN__) */
|
||||||
|
|
||||||
|
#endif /* _DEBUG_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,145 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file events.h
|
||||||
|
* @brief Events macros and structures.
|
||||||
|
* @addtogroup Events
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _EVENTS_H_
|
||||||
|
#define _EVENTS_H_
|
||||||
|
|
||||||
|
#if CH_USE_EVENTS
|
||||||
|
|
||||||
|
typedef struct EventListener EventListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Event Listener structure.
|
||||||
|
*/
|
||||||
|
struct EventListener {
|
||||||
|
EventListener *el_next; /**< Next Event Listener registered on
|
||||||
|
the Event Source.*/
|
||||||
|
Thread *el_listener; /**< Thread interested in the Event
|
||||||
|
Source.*/
|
||||||
|
eventmask_t el_mask; /**< Event flags mask associated by the
|
||||||
|
thread to the Event Source.*/
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Event Source structure.
|
||||||
|
*/
|
||||||
|
typedef struct EventSource {
|
||||||
|
EventListener *es_next; /**< First Event Listener registered on
|
||||||
|
the Event Source.*/
|
||||||
|
} EventSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Data part of a static event source initializer.
|
||||||
|
* @details This macro should be used when statically initializing an event
|
||||||
|
* source that is part of a bigger structure.
|
||||||
|
* @param name the name of the event source variable
|
||||||
|
*/
|
||||||
|
#define _EVENTSOURCE_DATA(name) {(void *)(&name)}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Static event source initializer.
|
||||||
|
* @details Statically initialized event sources require no explicit
|
||||||
|
* initialization using @p chEvtInit().
|
||||||
|
* @param name the name of the event source variable
|
||||||
|
*/
|
||||||
|
#define EVENTSOURCE_DECL(name) EventSource name = _EVENTSOURCE_DATA(name)
|
||||||
|
|
||||||
|
/** All events allowed mask.*/
|
||||||
|
#define ALL_EVENTS -1
|
||||||
|
|
||||||
|
/** Returns the event mask from the event identifier.*/
|
||||||
|
#define EVENT_MASK(eid) (1 << (eid))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers an Event Listener on an Event Source.
|
||||||
|
* @param esp pointer to the @p EventSource structure
|
||||||
|
* @param elp pointer to the @p EventListener structure
|
||||||
|
* @param eid numeric identifier assigned to the Event Listener. The identifier
|
||||||
|
* is used as index for the event callback function.
|
||||||
|
* The value must range between zero and the size, in bit, of the
|
||||||
|
* @p eventid_t type minus one.
|
||||||
|
* @note Multiple Event Listeners can use the same event identifier, the
|
||||||
|
* listener will share the callback function.
|
||||||
|
*/
|
||||||
|
#define chEvtRegister(esp, elp, eid) chEvtRegisterMask(esp, elp, EVENT_MASK(eid))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes an Event Source.
|
||||||
|
* @param esp pointer to the @p EventSource structure
|
||||||
|
* @note Can be called with interrupts disabled or enabled.
|
||||||
|
*/
|
||||||
|
#define chEvtInit(esp) \
|
||||||
|
((esp)->es_next = (EventListener *)(void *)(esp))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies if there is at least one @p EventListener registered on the
|
||||||
|
* @p EventSource.
|
||||||
|
* @param esp pointer to the @p EventSource structure
|
||||||
|
* @note Can be called with interrupts disabled or enabled.
|
||||||
|
*/
|
||||||
|
#define chEvtIsListening(esp) \
|
||||||
|
((void *)(esp) != (void *)(esp)->es_next)
|
||||||
|
|
||||||
|
/** Event Handler callback function.*/
|
||||||
|
typedef void (*evhandler_t)(eventid_t);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void chEvtRegisterMask(EventSource *esp, EventListener *elp, eventmask_t emask);
|
||||||
|
void chEvtUnregister(EventSource *esp, EventListener *elp);
|
||||||
|
eventmask_t chEvtClear(eventmask_t mask);
|
||||||
|
eventmask_t chEvtPend(eventmask_t mask);
|
||||||
|
void chEvtSignal(Thread *tp, eventmask_t mask);
|
||||||
|
void chEvtSignalI(Thread *tp, eventmask_t mask);
|
||||||
|
void chEvtBroadcast(EventSource *esp);
|
||||||
|
void chEvtBroadcastI(EventSource *esp);
|
||||||
|
void chEvtDispatch(const evhandler_t handlers[], eventmask_t mask);
|
||||||
|
#if CH_OPTIMIZE_SPEED || !CH_USE_EVENTS_TIMEOUT
|
||||||
|
eventmask_t chEvtWaitOne(eventmask_t ewmask);
|
||||||
|
eventmask_t chEvtWaitAny(eventmask_t ewmask);
|
||||||
|
eventmask_t chEvtWaitAll(eventmask_t ewmask);
|
||||||
|
#endif
|
||||||
|
#if CH_USE_EVENTS_TIMEOUT
|
||||||
|
eventmask_t chEvtWaitOneTimeout(eventmask_t ewmask, systime_t time);
|
||||||
|
eventmask_t chEvtWaitAnyTimeout(eventmask_t ewmask, systime_t time);
|
||||||
|
eventmask_t chEvtWaitAllTimeout(eventmask_t ewmask, systime_t time);
|
||||||
|
#endif
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !CH_OPTIMIZE_SPEED && CH_USE_EVENTS_TIMEOUT
|
||||||
|
#define chEvtWaitOne(ewmask) chEvtWaitOneTimeout(ewmask, TIME_INFINITE)
|
||||||
|
#define chEvtWaitAny(ewmask) chEvtWaitAnyTimeout(ewmask, TIME_INFINITE)
|
||||||
|
#define chEvtWaitAll(ewmask) chEvtWaitAllTimeout(ewmask, TIME_INFINITE)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* CH_USE_EVENTS */
|
||||||
|
|
||||||
|
#endif /* _EVENTS_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file heap.h
|
||||||
|
* @brief Heap macros and structures.
|
||||||
|
* @addtogroup Heap
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HEAP_H_
|
||||||
|
#define _HEAP_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void heap_init(void);
|
||||||
|
void *chHeapAlloc(size_t size);
|
||||||
|
void chHeapFree(void *p);
|
||||||
|
size_t chHeapStatus(size_t *sizep);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _HEAP_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INLINE_H_
|
||||||
|
#define _INLINE_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file inline.h
|
||||||
|
* @brief Kernel inlined functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inlined functions if CH_OPTIMIZE_SPEED is enabled.
|
||||||
|
* Note: static inlined functions do not duplicate the code in every module
|
||||||
|
* this is true for GCC, not sure about other compilers.
|
||||||
|
*/
|
||||||
|
#if CH_OPTIMIZE_SPEED
|
||||||
|
static INLINE void prio_insert(Thread *tp, ThreadsQueue *tqp) {
|
||||||
|
|
||||||
|
Thread *cp = (Thread *)tqp;
|
||||||
|
do {
|
||||||
|
cp = cp->p_next;
|
||||||
|
} while ((cp != (Thread *)tqp) && (cp->p_prio >= tp->p_prio));
|
||||||
|
tp->p_prev = (tp->p_next = cp)->p_prev;
|
||||||
|
tp->p_prev->p_next = cp->p_prev = tp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE void queue_insert(Thread *tp, ThreadsQueue *tqp) {
|
||||||
|
|
||||||
|
tp->p_prev = (tp->p_next = (Thread *)tqp)->p_prev;
|
||||||
|
tp->p_prev->p_next = tqp->p_prev = tp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE Thread *fifo_remove(ThreadsQueue *tqp) {
|
||||||
|
Thread *tp = tqp->p_next;
|
||||||
|
|
||||||
|
(tqp->p_next = tp->p_next)->p_prev = (Thread *)tqp;
|
||||||
|
return tp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE Thread *lifo_remove(ThreadsQueue *tqp) {
|
||||||
|
Thread *tp = tqp->p_prev;
|
||||||
|
|
||||||
|
(tqp->p_prev = tp->p_prev)->p_next = (Thread *)tqp;
|
||||||
|
return tp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE Thread *dequeue(Thread *tp) {
|
||||||
|
|
||||||
|
tp->p_prev->p_next = tp->p_next;
|
||||||
|
tp->p_next->p_prev = tp->p_prev;
|
||||||
|
return tp;
|
||||||
|
}
|
||||||
|
#endif /* CH_OPTIMIZE_SPEED */
|
||||||
|
|
||||||
|
#endif /* _INLINE_H_ */
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file lists.h
|
||||||
|
* @brief Thread queues/lists macros and structures.
|
||||||
|
* @addtogroup ThreadLists
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LISTS_H_
|
||||||
|
#define _LISTS_H_
|
||||||
|
|
||||||
|
typedef struct Thread Thread;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Threads queue initialization.
|
||||||
|
*/
|
||||||
|
#define queue_init(tqp) ((tqp)->p_next = (tqp)->p_prev = (Thread *)(tqp));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Macro evaluating to @p TRUE if the specified threads queue is empty.
|
||||||
|
*/
|
||||||
|
#define isempty(p) ((p)->p_next == (Thread *)(p))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Macro evaluating to @p TRUE if the specified threads queue is not empty.
|
||||||
|
*/
|
||||||
|
#define notempty(p) ((p)->p_next != (Thread *)(p))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Data part of a static threads queue initializer.
|
||||||
|
* @details This macro should be used when statically initializing a threads
|
||||||
|
* queue that is part of a bigger structure.
|
||||||
|
* @param name the name of the threads queue variable
|
||||||
|
*/
|
||||||
|
#define _THREADSQUEUE_DATA(name) {(Thread *)&name, (Thread *)&name}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Static threads queue initializer.
|
||||||
|
* @details Statically initialized threads queues require no explicit
|
||||||
|
* initialization using @p queue_init().
|
||||||
|
* @param name the name of the threads queue variable
|
||||||
|
*/
|
||||||
|
#define THREADSQUEUE_DECL(name) ThreadsQueue name = _THREADSQUEUE_DATA(name)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generic threads bidirectional linked list header and element.
|
||||||
|
* @extends ThreadsList
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
Thread *p_next; /**< First @p Thread in the queue, or
|
||||||
|
@p ThreadQueue when empty.*/
|
||||||
|
Thread *p_prev; /**< Last @p Thread in the queue, or
|
||||||
|
@p ThreadQueue when empty.*/
|
||||||
|
} ThreadsQueue;
|
||||||
|
|
||||||
|
#if !CH_OPTIMIZE_SPEED
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void prio_insert(Thread *tp, ThreadsQueue *tqp);
|
||||||
|
void queue_insert(Thread *tp, ThreadsQueue *tqp);
|
||||||
|
Thread *fifo_remove(ThreadsQueue *tqp);
|
||||||
|
Thread *lifo_remove(ThreadsQueue *tqp);
|
||||||
|
Thread *dequeue(Thread *tp);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !CH_OPTIMIZE_SPEED */
|
||||||
|
|
||||||
|
#endif /* _LISTS_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file mailboxes.h
|
||||||
|
* @brief Mailboxes macros and structures.
|
||||||
|
* @addtogroup Mailboxes
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MAILBOXES_H_
|
||||||
|
#define _MAILBOXES_H_
|
||||||
|
|
||||||
|
#if CH_USE_MAILBOXES
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
msg_t *mb_buffer; /**< Pointer to the mailbox buffer.*/
|
||||||
|
msg_t *mb_top; /**< Pointer to the first location
|
||||||
|
after the buffer.*/
|
||||||
|
msg_t *mb_wrptr; /**< Write pointer.*/
|
||||||
|
msg_t *mb_rdptr; /**< Read pointer.*/
|
||||||
|
Semaphore mb_fullsem; /**< Full counter @p Semaphore.*/
|
||||||
|
Semaphore mb_emptysem; /**< Empty counter @p Semaphore.*/
|
||||||
|
} Mailbox;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void chMBInit(Mailbox *mbp, msg_t *buf, cnt_t n);
|
||||||
|
void chMBReset(Mailbox *mbp);
|
||||||
|
msg_t chMBPost(Mailbox *mbp, msg_t msg, systime_t timeout);
|
||||||
|
msg_t chMBPostS(Mailbox *mbp, msg_t msg, systime_t timeout);
|
||||||
|
msg_t chMBPostAhead(Mailbox *mbp, msg_t msg, systime_t timeout);
|
||||||
|
msg_t chMBPostAheadS(Mailbox *mbp, msg_t msg, systime_t timeout);
|
||||||
|
msg_t chMBFetch(Mailbox *mbp, msg_t *msgp, systime_t timeout);
|
||||||
|
msg_t chMBFetchS(Mailbox *mbp, msg_t *msgp, systime_t timeout);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the mailbox buffer size.
|
||||||
|
* @param[in] mbp the pointer to an initialized Mailbox object
|
||||||
|
*/
|
||||||
|
#define chMBSize(mbp) \
|
||||||
|
((mbp)->mb_top - (mbp)->mb_buffer)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the free space into the mailbox.
|
||||||
|
* @param[in] mbp the pointer to an initialized Mailbox object
|
||||||
|
* @return The number of empty message slots.
|
||||||
|
* @note Can be invoked in any system state but if invoked out of a locked
|
||||||
|
* state then the returned value may change after reading.
|
||||||
|
* @note The returned value can be less than zero when there are waiting
|
||||||
|
* threads on the internal semaphore.
|
||||||
|
*/
|
||||||
|
#define chMBGetEmpty(mbp) chSemGetCounterI(&(mbp)->mb_emptysem)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of messages into the mailbox.
|
||||||
|
* @param[in] mbp the pointer to an initialized Mailbox object
|
||||||
|
* @return The number of queued messages.
|
||||||
|
* @note Can be invoked in any system state but if invoked out of a locked
|
||||||
|
* state then the returned value may change after reading.
|
||||||
|
* @note The returned value can be less than zero when there are waiting
|
||||||
|
* threads on the internal semaphore.
|
||||||
|
*/
|
||||||
|
#define chMBGetFull(mbp) chSemGetCounterI(&(mbp)->mb_fullsem)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the next message in the queue without removing it.
|
||||||
|
* @note A message must be waiting in the queue for this function to work or
|
||||||
|
* it would return garbage. The correct way to use this macro is to
|
||||||
|
* use @p chMBGetFull() and then use this macro, all within a lock state.
|
||||||
|
*/
|
||||||
|
#define chMBPeek(mbp) (*(mbp)->mb_rdptr)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Data part of a static mailbox initializer.
|
||||||
|
* @details This macro should be used when statically initializing a
|
||||||
|
* mailbox that is part of a bigger structure.
|
||||||
|
* @param name the name of the mailbox variable
|
||||||
|
* @param buffer pointer to the mailbox buffer area
|
||||||
|
* @param size size of the mailbox buffer area
|
||||||
|
*/
|
||||||
|
#define _MAILBOX_DATA(name, buffer, size) { \
|
||||||
|
(msg_t *)(buffer), \
|
||||||
|
(msg_t *)(buffer) + size, \
|
||||||
|
(msg_t *)(buffer), \
|
||||||
|
(msg_t *)(buffer), \
|
||||||
|
_SEMAPHORE_DATA(name.mb_fullsem, 0), \
|
||||||
|
_SEMAPHORE_DATA(name.mb_emptysem, size), \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Static mailbox initializer.
|
||||||
|
* @details Statically initialized mailboxes require no explicit
|
||||||
|
* initialization using @p chMBInit().
|
||||||
|
* @param name the name of the mailbox variable
|
||||||
|
* @param buffer pointer to the mailbox buffer area
|
||||||
|
* @param size size of the mailbox buffer area
|
||||||
|
*/
|
||||||
|
#define MAILBOX_DECL(name, buffer, size) \
|
||||||
|
Mailbox name = _MAILBOX_DATA(name, buffer, size)
|
||||||
|
|
||||||
|
#endif /* CH_USE_MAILBOXES */
|
||||||
|
|
||||||
|
#endif /* _MAILBOXES_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file mempools.h
|
||||||
|
* @brief Memory Pools macros and structures.
|
||||||
|
* @addtogroup MemoryPools
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MEMPOOLS_H_
|
||||||
|
#define _MEMPOOLS_H_
|
||||||
|
|
||||||
|
#if CH_USE_MEMPOOLS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Memory pool free object header.
|
||||||
|
*/
|
||||||
|
struct pool_header {
|
||||||
|
struct pool_header *ph_next;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Memory pool descriptor.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
struct pool_header *mp_next; /**< Pointer to the header.*/
|
||||||
|
size_t mp_object_size; /**< Memory pool objects size.*/
|
||||||
|
} MemoryPool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Data part of a static memory pool initializer.
|
||||||
|
* @details This macro should be used when statically initializing a
|
||||||
|
* memory pool that is part of a bigger structure.
|
||||||
|
* @param name the name of the memory pool variable
|
||||||
|
* @param size size of the memory pool contained objects
|
||||||
|
*/
|
||||||
|
#define _MEMORYPOOL_DATA(name, size) {NULL, size}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Static memory pool initializer.
|
||||||
|
* @details Statically initialized memory pools require no explicit
|
||||||
|
* initialization using @p chPoolInit().
|
||||||
|
* @param name the name of the memory pool variable
|
||||||
|
* @param size size of the memory pool contained objects
|
||||||
|
*/
|
||||||
|
#define MEMORYPOOL_DECL(name, size) \
|
||||||
|
MemoryPool name = _MEMORYPOOL_DATA(name, size)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void chPoolInit(MemoryPool *mp, size_t size);
|
||||||
|
void *chPoolAllocI(MemoryPool *mp);
|
||||||
|
void *chPoolAlloc(MemoryPool *mp);
|
||||||
|
void chPoolFreeI(MemoryPool *mp, void *objp);
|
||||||
|
void chPoolFree(MemoryPool *mp, void *objp);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* CH_USE_MEMPOOLS */
|
||||||
|
|
||||||
|
#endif /* _MEMPOOLS_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file messages.h
|
||||||
|
* @brief Messages macros and structures.
|
||||||
|
* @addtogroup Messages
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MESSAGES_H_
|
||||||
|
#define _MESSAGES_H_
|
||||||
|
|
||||||
|
#if CH_USE_MESSAGES
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates to TRUE if the thread has pending messages.
|
||||||
|
*/
|
||||||
|
#define chMsgIsPendingI(tp) \
|
||||||
|
((tp)->p_msgqueue.p_next != (Thread *)&(tp)->p_msgqueue)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first message in the queue.
|
||||||
|
*/
|
||||||
|
#define chMsgGetI(tp) \
|
||||||
|
((tp)->p_msgqueue.p_next->p_msg)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
msg_t chMsgSend(Thread *tp, msg_t msg);
|
||||||
|
msg_t chMsgWait(void);
|
||||||
|
msg_t chMsgGet(void);
|
||||||
|
void chMsgRelease(msg_t msg);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* CH_USE_MESSAGES */
|
||||||
|
|
||||||
|
#endif /* _MESSAGES_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file mutexes.h
|
||||||
|
* @brief Mutexes macros and structures.
|
||||||
|
* @addtogroup Mutexes
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MUTEXES_H_
|
||||||
|
#define _MUTEXES_H_
|
||||||
|
|
||||||
|
#if CH_USE_MUTEXES
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mutex structure.
|
||||||
|
*/
|
||||||
|
typedef struct Mutex {
|
||||||
|
ThreadsQueue m_queue; /**< Queue of the threads sleeping on
|
||||||
|
this Mutex.*/
|
||||||
|
Thread *m_owner; /**< Owner @p Thread pointer or
|
||||||
|
@p NULL.*/
|
||||||
|
struct Mutex *m_next; /**< Next @p Mutex into an owner-list
|
||||||
|
or @p NULL.*/
|
||||||
|
} Mutex;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void chMtxInit(Mutex *mp);
|
||||||
|
void chMtxLock(Mutex *mp);
|
||||||
|
void chMtxLockS(Mutex *mp);
|
||||||
|
bool_t chMtxTryLock(Mutex *mp);
|
||||||
|
bool_t chMtxTryLockS(Mutex *mp);
|
||||||
|
Mutex *chMtxUnlock(void);
|
||||||
|
Mutex *chMtxUnlockS(void);
|
||||||
|
void chMtxUnlockAll(void);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Data part of a static mutex initializer.
|
||||||
|
* @details This macro should be used when statically initializing a mutex
|
||||||
|
* that is part of a bigger structure.
|
||||||
|
* @param name the name of the mutex variable
|
||||||
|
*/
|
||||||
|
#define _MUTEX_DATA(name) {_THREADSQUEUE_DATA(name.m_queue), NULL, NULL}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Static mutex initializer.
|
||||||
|
* @details Statically initialized mutexes require no explicit initialization
|
||||||
|
* using @p chMtxInit().
|
||||||
|
* @param name the name of the mutex variable
|
||||||
|
*/
|
||||||
|
#define MUTEX_DECL(name) Mutex name = _MUTEX_DATA(name)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns @p TRUE if the mutex queue contains at least a waiting thread.
|
||||||
|
*/
|
||||||
|
#define chMtxQueueNotEmptyS(mp) notempty(&(mp)->m_queue)
|
||||||
|
|
||||||
|
#endif /* CH_USE_MUTEXES */
|
||||||
|
|
||||||
|
#endif /* _MUTEXES_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,218 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file queues.h I/O
|
||||||
|
* @brief Queues macros and structures.
|
||||||
|
* @addtogroup IOQueues
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _QUEUES_H_
|
||||||
|
#define _QUEUES_H_
|
||||||
|
|
||||||
|
/** Queue notification callback type. */
|
||||||
|
typedef void (*qnotify_t)(void);
|
||||||
|
|
||||||
|
/** Returned by the queue functions if the operation is successful. */
|
||||||
|
#define Q_OK RDY_OK
|
||||||
|
/** Returned by the queue functions if a timeout occurs. */
|
||||||
|
#define Q_TIMEOUT RDY_TIMEOUT
|
||||||
|
/** Returned by the queue functions if the queue is reset. */
|
||||||
|
#define Q_RESET RDY_RESET
|
||||||
|
/** Returned by the queue functions if the queue is empty. */
|
||||||
|
#define Q_EMPTY -3
|
||||||
|
/** Returned by the queue functions if the queue is full. */
|
||||||
|
#define Q_FULL -4
|
||||||
|
|
||||||
|
#if CH_USE_QUEUES
|
||||||
|
/**
|
||||||
|
* @brief Generic I/O queue structure.
|
||||||
|
* @details This structure represents a generic Input or Output asymmetrical
|
||||||
|
* queue. The queue is asymmetrical because one end is meant to be
|
||||||
|
* accessed from a thread context, and thus can be blocking, the other
|
||||||
|
* end is accessible from interrupt handlers or from within a kernel
|
||||||
|
* lock zone (see <b>I-Locked</b> and <b>S-Locked</b> states in
|
||||||
|
* @ref system_states) and is non-blocking.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint8_t *q_buffer; /**< Pointer to the queue buffer.*/
|
||||||
|
uint8_t *q_top; /**< Pointer to the first location
|
||||||
|
after the buffer.*/
|
||||||
|
uint8_t *q_wrptr; /**< Write pointer.*/
|
||||||
|
uint8_t *q_rdptr; /**< Read pointer.*/
|
||||||
|
Semaphore q_sem; /**< Counter @p Semaphore.*/
|
||||||
|
qnotify_t q_notify; /**< Data notification callback.*/
|
||||||
|
} GenericQueue;
|
||||||
|
|
||||||
|
/** Returns the queue's buffer size. */
|
||||||
|
#define chQSize(q) ((q)->q_top - (q)->q_buffer)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the used space if used on an Input Queue and the empty space if
|
||||||
|
* used on an Output Queue.
|
||||||
|
* @note The returned value can be less than zero when there are waiting
|
||||||
|
* threads on the internal semaphore.
|
||||||
|
*/
|
||||||
|
#define chQSpace(q) chSemGetCounterI(&(q)->q_sem)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Input queue structure.
|
||||||
|
* @details This structure represents a generic asymmetrical input queue.
|
||||||
|
* Writing in the queue is non-blocking and can be performed from
|
||||||
|
* interrupt handlers or from within a kernel lock zone (see
|
||||||
|
* <b>I-Locked</b> and <b>S-Locked</b> states in @ref system_states).
|
||||||
|
* Reading the queue can be a blocking operation and is supposed to
|
||||||
|
* be performed by a system thread.
|
||||||
|
* @extends GenericQueue
|
||||||
|
*/
|
||||||
|
typedef GenericQueue InputQueue;
|
||||||
|
|
||||||
|
/** Evaluates to @p TRUE if the specified Input Queue is empty. */
|
||||||
|
#define chIQIsEmpty(q) (chQSpace(q) <= 0)
|
||||||
|
|
||||||
|
/** Evaluates to @p TRUE if the specified Input Queue is full. */
|
||||||
|
#define chIQIsFull(q) (chQSpace(q) >= chQSize(q))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Input queue read.
|
||||||
|
* @details This function reads a byte value from an input queue. If the queue
|
||||||
|
* is empty then the calling thread is suspended until a byte arrives
|
||||||
|
* in the queue.
|
||||||
|
*
|
||||||
|
* @param[in] iqp pointer to an @p InputQueue structure
|
||||||
|
* @return A byte value from the queue or:
|
||||||
|
* @retval Q_RESET if the queue was reset.
|
||||||
|
*/
|
||||||
|
#define chIQGet(iqp) chIQGetTimeout(iqp, TIME_INFINITE)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Data part of a static input queue initializer.
|
||||||
|
* @details This macro should be used when statically initializing an
|
||||||
|
* input queue that is part of a bigger structure.
|
||||||
|
* @param name the name of the input queue variable
|
||||||
|
* @param buffer pointer to the queue buffer area
|
||||||
|
* @param size size of the queue buffer area
|
||||||
|
* @param inotify input notification callback pointer
|
||||||
|
*/
|
||||||
|
#define _INPUTQUEUE_DATA(name, buffer, size, inotify) { \
|
||||||
|
(uint8_t *)(buffer), \
|
||||||
|
(uint8_t *)(buffer) + size, \
|
||||||
|
(uint8_t *)(buffer), \
|
||||||
|
(uint8_t *)(buffer), \
|
||||||
|
_SEMAPHORE_DATA(name.q_sem, 0), \
|
||||||
|
inotify \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Static input queue initializer.
|
||||||
|
* @details Statically initialized input queues require no explicit
|
||||||
|
* initialization using @p chIQInit().
|
||||||
|
* @param name the name of the input queue variable
|
||||||
|
* @param buffer pointer to the queue buffer area
|
||||||
|
* @param size size of the queue buffer area
|
||||||
|
* @param inotify input notification callback pointer
|
||||||
|
*/
|
||||||
|
#define INPUTQUEUE_DECL(name, buffer, size, inotify) \
|
||||||
|
InputQueue name = _INPUTQUEUE_DATA(name, buffer, size, inotify)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Output queue structure.
|
||||||
|
* @details This structure represents a generic asymmetrical output queue.
|
||||||
|
* Reading from the queue is non-blocking and can be performed from
|
||||||
|
* interrupt handlers or from within a kernel lock zone (see
|
||||||
|
* <b>I-Locked</b> and <b>S-Locked</b> states in @ref system_states).
|
||||||
|
* Writing the queue can be a blocking operation and is supposed to
|
||||||
|
* be performed by a system thread.
|
||||||
|
* @extends GenericQueue
|
||||||
|
*/
|
||||||
|
typedef GenericQueue OutputQueue;
|
||||||
|
|
||||||
|
/** Evaluates to @p TRUE if the specified Output Queue is empty. */
|
||||||
|
#define chOQIsEmpty(q) (chQSpace(q) >= chQSize(q))
|
||||||
|
|
||||||
|
/** Evaluates to @p TRUE if the specified Output Queue is full. */
|
||||||
|
#define chOQIsFull(q) (chQSpace(q) <= 0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Output queue write.
|
||||||
|
* @details This function writes a byte value to an output queue. If the queue
|
||||||
|
* is full then the calling thread is suspended until there is space
|
||||||
|
* in the queue.
|
||||||
|
*
|
||||||
|
* @param[in] oqp pointer to an @p OutputQueue structure
|
||||||
|
* @param[in] b the byte value to be written in the queue
|
||||||
|
* @return The operation status:
|
||||||
|
* @retval Q_OK if the operation succeeded.
|
||||||
|
* @retval Q_RESET if the queue was reset.
|
||||||
|
*/
|
||||||
|
#define chOQPut(oqp, b) chOQPutTimeout(oqp, b, TIME_INFINITE)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Data part of a static output queue initializer.
|
||||||
|
* @details This macro should be used when statically initializing an
|
||||||
|
* output queue that is part of a bigger structure.
|
||||||
|
* @param name the name of the output queue variable.
|
||||||
|
* @param buffer pointer to the queue buffer area
|
||||||
|
* @param size size of the queue buffer area
|
||||||
|
* @param onotify output notification callback pointer
|
||||||
|
*/
|
||||||
|
#define _OUTPUTQUEUE_DATA(name, buffer, size, onotify) { \
|
||||||
|
(uint8_t *)(buffer), \
|
||||||
|
(uint8_t *)(buffer) + size, \
|
||||||
|
(uint8_t *)(buffer), \
|
||||||
|
(uint8_t *)(buffer), \
|
||||||
|
_SEMAPHORE_DATA(name.q_sem, size), \
|
||||||
|
onotify \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Static output queue initializer.
|
||||||
|
* @details Statically initialized output queues require no explicit
|
||||||
|
* initialization using @p chOQInit().
|
||||||
|
* @param name the name of the output queue variable
|
||||||
|
* @param buffer pointer to the queue buffer area
|
||||||
|
* @param size size of the queue buffer area
|
||||||
|
* @param onotify output notification callback pointer
|
||||||
|
*/
|
||||||
|
#define OUTPUTQUEUE_DECL(name, buffer, size, onotify) \
|
||||||
|
InputQueue name = _OUTPUTQUEUE_DATA(name, buffer, size, onotify)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void chIQInit(InputQueue *qp, uint8_t *buffer, size_t size, qnotify_t inotify);
|
||||||
|
void chIQResetI(InputQueue *qp);
|
||||||
|
msg_t chIQPutI(InputQueue *qp, uint8_t b);
|
||||||
|
msg_t chIQGetTimeout(InputQueue *qp, systime_t timeout);
|
||||||
|
size_t chIQRead(InputQueue *qp, uint8_t *buffer, size_t n);
|
||||||
|
|
||||||
|
void chOQInit(OutputQueue *queue, uint8_t *buffer, size_t size, qnotify_t onotify);
|
||||||
|
void chOQResetI(OutputQueue *queue);
|
||||||
|
msg_t chOQPutTimeout(OutputQueue *queue, uint8_t b, systime_t timeout);
|
||||||
|
msg_t chOQGetI(OutputQueue *queue);
|
||||||
|
size_t chOQWrite(OutputQueue *queue, uint8_t *buffer, size_t n);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* CH_USE_QUEUES */
|
||||||
|
|
||||||
|
#endif /* _QUEUES_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file scheduler.h
|
||||||
|
* @brief Scheduler macros and structures.
|
||||||
|
* @addtogroup Scheduler
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SCHEDULER_H_
|
||||||
|
#define _SCHEDULER_H_
|
||||||
|
|
||||||
|
/** Default thread wakeup low level message. */
|
||||||
|
#define RDY_OK 0
|
||||||
|
/** Low level message sent to a thread awakened by a timeout. */
|
||||||
|
#define RDY_TIMEOUT -1
|
||||||
|
/** Low level message sent to a thread awakened by a reset operation. */
|
||||||
|
#define RDY_RESET -2
|
||||||
|
|
||||||
|
#define NOPRIO 0 /**< Ready list header priority.*/
|
||||||
|
#define IDLEPRIO 1 /**< Idle thread priority.*/
|
||||||
|
#define LOWPRIO 2 /**< Lowest user priority.*/
|
||||||
|
#define NORMALPRIO 64 /**< Normal user priority.*/
|
||||||
|
#define HIGHPRIO 127 /**< Highest user priority.*/
|
||||||
|
#define ABSPRIO 255 /**< Greatest possible priority.*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zero time specification for some syscalls with a timeout
|
||||||
|
* specification.
|
||||||
|
* @note Not all functions accept @p TIME_IMMEDIATE as timeout parameter,
|
||||||
|
* see the specific function documentation.
|
||||||
|
*/
|
||||||
|
#define TIME_IMMEDIATE ((systime_t)-1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Infinite time specification for all the syscalls with a timeout
|
||||||
|
* specification.
|
||||||
|
*/
|
||||||
|
#define TIME_INFINITE ((systime_t)0)
|
||||||
|
|
||||||
|
/** The priority of the first thread on the given ready list. */
|
||||||
|
#define firstprio(rlp) ((rlp)->p_next->p_prio)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ready list header.
|
||||||
|
*
|
||||||
|
* @extends ThreadsQueue
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
Thread *p_next; /**< Next @p Thread in the ready list.*/
|
||||||
|
Thread *p_prev; /**< Previous @p Thread in the ready
|
||||||
|
list.*/
|
||||||
|
/* End of the fields shared with the ThreadsQueue structure. */
|
||||||
|
tprio_t r_prio; /**< This field must be initialized to
|
||||||
|
zero.*/
|
||||||
|
/* End of the fields shared with the Thread structure. */
|
||||||
|
#if CH_USE_ROUNDROBIN
|
||||||
|
cnt_t r_preempt; /**< Round robin counter.*/
|
||||||
|
#endif
|
||||||
|
#ifndef CH_CURRP_REGISTER_CACHE
|
||||||
|
Thread *r_current; /**< The currently running thread.*/
|
||||||
|
#endif
|
||||||
|
} ReadyList;
|
||||||
|
|
||||||
|
extern ReadyList rlist;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scheduler APIs.
|
||||||
|
*/
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void scheduler_init(void);
|
||||||
|
Thread *chSchReadyI(Thread *tp);
|
||||||
|
void chSchGoSleepS(tstate_t newstate);
|
||||||
|
msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time);
|
||||||
|
void chSchWakeupS(Thread *tp, msg_t msg);
|
||||||
|
void chSchDoRescheduleI(void);
|
||||||
|
void chSchRescheduleS(void);
|
||||||
|
bool_t chSchRescRequiredI(void);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CH_CURRP_REGISTER_CACHE
|
||||||
|
register Thread *currp asm(CH_CURRP_REGISTER_CACHE);
|
||||||
|
#else
|
||||||
|
#define currp rlist.r_current
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _SCHEDULER_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file semaphores.h
|
||||||
|
* @brief Semaphores macros and structures.
|
||||||
|
* @addtogroup Semaphores
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SEMAPHORES_H_
|
||||||
|
#define _SEMAPHORES_H_
|
||||||
|
|
||||||
|
#if CH_USE_SEMAPHORES
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Semaphore structure.
|
||||||
|
*/
|
||||||
|
typedef struct Semaphore {
|
||||||
|
ThreadsQueue s_queue; /**< Queue of the threads sleeping on
|
||||||
|
this semaphore.*/
|
||||||
|
cnt_t s_cnt; /**< The semaphore counter.*/
|
||||||
|
} Semaphore;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void chSemInit(Semaphore *sp, cnt_t n);
|
||||||
|
void chSemReset(Semaphore *sp, cnt_t n);
|
||||||
|
void chSemResetI(Semaphore *sp, cnt_t n);
|
||||||
|
msg_t chSemWait(Semaphore *sp);
|
||||||
|
msg_t chSemWaitS(Semaphore *sp);
|
||||||
|
msg_t chSemWaitTimeout(Semaphore *sp, systime_t time);
|
||||||
|
msg_t chSemWaitTimeoutS(Semaphore *sp, systime_t time);
|
||||||
|
void chSemSignal(Semaphore *sp);
|
||||||
|
void chSemSignalI(Semaphore *sp);
|
||||||
|
#if CH_USE_SEMSW
|
||||||
|
msg_t chSemSignalWait(Semaphore *sps, Semaphore *spw);
|
||||||
|
#endif
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Data part of a static semaphore initializer.
|
||||||
|
* @details This macro should be used when statically initializing a semaphore
|
||||||
|
* that is part of a bigger structure.
|
||||||
|
* @param name the name of the semaphore variable
|
||||||
|
* @param n the counter initial value, this value must be non-negative
|
||||||
|
*/
|
||||||
|
#define _SEMAPHORE_DATA(name, n) {_THREADSQUEUE_DATA(name.s_queue), n}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Static semaphore initializer.
|
||||||
|
* @details Statically initialized semaphores require no explicit initialization
|
||||||
|
* using @p chSemInit().
|
||||||
|
* @param name the name of the semaphore variable
|
||||||
|
* @param n the counter initial value, this value must be non-negative
|
||||||
|
*/
|
||||||
|
#define SEMAPHORE_DECL(name, n) Semaphore name = _SEMAPHORE_DATA(name, n)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decreases the semaphore counter, this macro can be used when it is ensured
|
||||||
|
* that the counter would not become negative.
|
||||||
|
*/
|
||||||
|
#define chSemFastWaitI(sp) ((sp)->s_cnt--)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increases the semaphore counter, this macro can be used when the counter is
|
||||||
|
* not negative.
|
||||||
|
*/
|
||||||
|
#define chSemFastSignalI(sp) ((sp)->s_cnt++)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the semaphore counter current value.
|
||||||
|
*/
|
||||||
|
#define chSemGetCounterI(sp) ((sp)->s_cnt)
|
||||||
|
|
||||||
|
#endif /* CH_USE_SEMAPHORES */
|
||||||
|
|
||||||
|
#endif /* _SEMAPHORES_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,217 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file serial.h
|
||||||
|
* @brief Serial Drivers macros and structures.
|
||||||
|
* @addtogroup Serial
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SERIAL_H_
|
||||||
|
#define _SERIAL_H_
|
||||||
|
|
||||||
|
#if CH_USE_SERIAL_FULLDUPLEX
|
||||||
|
|
||||||
|
/** No pending conditions.*/
|
||||||
|
#define SD_NO_ERROR 0
|
||||||
|
/** Connection happened.*/
|
||||||
|
#define SD_CONNECTED 1
|
||||||
|
/** Disconnection happened.*/
|
||||||
|
#define SD_DISCONNECTED 2
|
||||||
|
/** Parity error happened.*/
|
||||||
|
#define SD_PARITY_ERROR 4
|
||||||
|
/** Framing error happened.*/
|
||||||
|
#define SD_FRAMING_ERROR 8
|
||||||
|
/** Overflow happened.*/
|
||||||
|
#define SD_OVERRUN_ERROR 16
|
||||||
|
/** Break detected.*/
|
||||||
|
#define SD_BREAK_DETECTED 32
|
||||||
|
|
||||||
|
/** Serial Driver condition flags type.*/
|
||||||
|
typedef uint8_t dflags_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief @p FullDuplexDriver specific methods.
|
||||||
|
*/
|
||||||
|
struct _full_duplex_driver_methods {
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief @p FullDuplexDriver specific data.
|
||||||
|
*/
|
||||||
|
struct _full_duplex_driver_data {
|
||||||
|
/**
|
||||||
|
* Input queue, incoming data can be read from this input queue by
|
||||||
|
* using the queues APIs.
|
||||||
|
*/
|
||||||
|
InputQueue iqueue;
|
||||||
|
/**
|
||||||
|
* Output queue, outgoing data can be written to this output queue by
|
||||||
|
* using the queues APIs.
|
||||||
|
*/
|
||||||
|
OutputQueue oqueue;
|
||||||
|
/**
|
||||||
|
* Status Change @p EventSource. This event is generated when one or more
|
||||||
|
* condition flags change.
|
||||||
|
*/
|
||||||
|
EventSource sevent;
|
||||||
|
/**
|
||||||
|
* I/O driver status flags.
|
||||||
|
*/
|
||||||
|
dflags_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief @p FullDuplexDriver virtual methods table.
|
||||||
|
*/
|
||||||
|
struct FullDuplexDriverVMT {
|
||||||
|
/**
|
||||||
|
* @p BaseChannel class inherited methods.
|
||||||
|
*/
|
||||||
|
struct _base_channel_methods m0;
|
||||||
|
/**
|
||||||
|
* @p BaseAsynchronousChannel class inherited methods.
|
||||||
|
*/
|
||||||
|
struct _base_asynchronous_channel_methods m1;
|
||||||
|
/**
|
||||||
|
* @p FullDuplexDriver specific methods.
|
||||||
|
*/
|
||||||
|
struct _full_duplex_driver_methods m2;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends BaseAsynchronousChannel
|
||||||
|
*
|
||||||
|
* @brief Full duplex serial driver class.
|
||||||
|
* @details This class extends @p GenericSerialDriver by adding physical I/O
|
||||||
|
* queues.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* Virtual Methods Table.
|
||||||
|
*/
|
||||||
|
const struct FullDuplexDriverVMT *vmt;
|
||||||
|
/**
|
||||||
|
* @p BaseChannel class inherited data.
|
||||||
|
*/
|
||||||
|
struct _base_channel_data d0;
|
||||||
|
/**
|
||||||
|
* @p BaseAsynchronousChannel class inherited data.
|
||||||
|
*/
|
||||||
|
struct _base_asynchronous_channel_data d1;
|
||||||
|
/**
|
||||||
|
* @p FullDuplexDriver specific data.
|
||||||
|
*/
|
||||||
|
struct _full_duplex_driver_data d2;
|
||||||
|
} FullDuplexDriver;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void chFDDInit(FullDuplexDriver *sd,
|
||||||
|
uint8_t *ib, size_t isize, qnotify_t inotify,
|
||||||
|
uint8_t *ob, size_t osize, qnotify_t onotify);
|
||||||
|
void chFDDIncomingDataI(FullDuplexDriver *sd, uint8_t b);
|
||||||
|
msg_t chFDDRequestDataI(FullDuplexDriver *sd);
|
||||||
|
void chFDDAddFlagsI(FullDuplexDriver *sd, dflags_t mask);
|
||||||
|
dflags_t chFDDGetAndClearFlags(FullDuplexDriver *sd);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Direct output check on a @p FullDuplexDriver.
|
||||||
|
* @details This function bypasses the indirect access to the channel and
|
||||||
|
* checks directly the output queue. This is faster but cannot
|
||||||
|
* be used to check different channels implementations.
|
||||||
|
* @see chIOPutWouldBlock()
|
||||||
|
*/
|
||||||
|
#define chFDDPutWouldBlock(sd) chOQIsFull(&(sd)->d2.oqueue)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Direct input check on a @p FullDuplexDriver.
|
||||||
|
* @details This function bypasses the indirect access to the channel and
|
||||||
|
* checks directly the input queue. This is faster but cannot
|
||||||
|
* be used to check different channels implementations.
|
||||||
|
* @see chIOGetWouldBlock()
|
||||||
|
*/
|
||||||
|
#define chFDDGetWouldBlock(sd) chIQIsEmpty(&(sd)->d2.iqueue)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Direct blocking write to a @p FullDuplexDriver.
|
||||||
|
* @details This function bypasses the indirect access to the channel and
|
||||||
|
* writes directly on the output queue. This is faster but cannot
|
||||||
|
* be used to write to different channels implementations.
|
||||||
|
* @see chIOPut()
|
||||||
|
*/
|
||||||
|
#define chFDDPut(sd, b) chOQPut(&(sd)->d2.oqueue, b)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Direct blocking write on a @p FullDuplexDriver with timeout
|
||||||
|
* specification.
|
||||||
|
* @details This function bypasses the indirect access to the channel and
|
||||||
|
* writes directly on the output queue. This is faster but cannot
|
||||||
|
* be used to write to different channels implementations.
|
||||||
|
* @see chIOPutTimeout()
|
||||||
|
*/
|
||||||
|
#define chFDDPutTimeout(sd, b, t) chOQPutTimeout(&(sd)->d2.iqueue, b, t)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Direct blocking read from a @p FullDuplexDriver.
|
||||||
|
* @details This function bypasses the indirect access to the channel and
|
||||||
|
* reads directly from the input queue. This is faster but cannot
|
||||||
|
* be used to read from different channels implementations.
|
||||||
|
* @see chIOGet()
|
||||||
|
*/
|
||||||
|
#define chFDDGet(sd) chIQGet(&(sd)->d2.iqueue)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Direct blocking read from a @p FullDuplexDriver with timeout
|
||||||
|
* specification.
|
||||||
|
* @details This function bypasses the indirect access to the channel and
|
||||||
|
* reads directly from the input queue. This is faster but cannot
|
||||||
|
* be used to read from different channels implementations.
|
||||||
|
* @see chIOGetTimeout()
|
||||||
|
*/
|
||||||
|
#define chFDDGetTimeout(sd, t) chIQGetTimeout(&(sd)->d2.iqueue, t)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Direct non-blocking write to a @p FullDuplexDriver.
|
||||||
|
* @details This function bypasses the indirect access to the channel and
|
||||||
|
* writes directly to the output queue. This is faster but cannot
|
||||||
|
* be used to write from different channels implementations.
|
||||||
|
* @see chIOWrite()
|
||||||
|
*/
|
||||||
|
#define chFDDWrite(sd, b, n) chOQWrite(&(sd)->d2.oqueue, b, n)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Direct non-blocking read on a @p FullDuplexDriver.
|
||||||
|
* @details This function bypasses the indirect access to the channel and
|
||||||
|
* reads directly from the input queue. This is faster but cannot
|
||||||
|
* be used to read from different channels implementations.
|
||||||
|
* @see chIORead()
|
||||||
|
*/
|
||||||
|
#define chFDDRead(sd, b, n) chIQRead(&(sd)->d2.iqueue, b, n)
|
||||||
|
|
||||||
|
#endif /* CH_USE_SERIAL_FULLDUPLEX */
|
||||||
|
|
||||||
|
#endif /* _SERIAL_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,184 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file sys.h
|
||||||
|
* @brief System related macros and structures.
|
||||||
|
* @addtogroup System
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS_H_
|
||||||
|
#define _SYS_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Halts the system.
|
||||||
|
* @details This function is invoked by the operating system when an
|
||||||
|
* unrecoverable error is detected (as example because a programming error in
|
||||||
|
* the application code that triggers an assertion while in debug mode).
|
||||||
|
*/
|
||||||
|
#define chSysHalt() port_halt()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Performs a context switch.
|
||||||
|
*
|
||||||
|
* @param otp the thread to be switched out
|
||||||
|
* @param ntp the thread to be switched in
|
||||||
|
*/
|
||||||
|
#define chSysSwitchI(otp, ntp) port_switch(otp, ntp)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Raises the system interrupt priority mask to the maximum level.
|
||||||
|
* @details All the maskable interrupt sources are disabled regardless their
|
||||||
|
* hardware priority.
|
||||||
|
*
|
||||||
|
* @note The implementation is architecture dependent, it may just disable the
|
||||||
|
* interrupts or be exactly equivalent to @p chSysDisable().
|
||||||
|
* @note Do not invoke this API from within a kernel lock.
|
||||||
|
*/
|
||||||
|
#define chSysDisable() port_disable()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Raises the system interrupt priority mask to system level.
|
||||||
|
* @details The interrupt sources that should not be able to preempt the kernel
|
||||||
|
* are disabled, interrupt sources with higher priority are still enabled.
|
||||||
|
*
|
||||||
|
* @note The implementation is architecture dependent, it may just disable the
|
||||||
|
* interrupts.
|
||||||
|
* @note Do not invoke this API from within a kernel lock.
|
||||||
|
* @note This API is no replacement for @p chSysLock(), the @p chSysLock()
|
||||||
|
* could do more than just disable the interrupts.
|
||||||
|
*/
|
||||||
|
#define chSysSuspend() port_suspend()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Lowers the system interrupt priority mask to user level.
|
||||||
|
* @details All the interrupt sources are enabled.
|
||||||
|
*
|
||||||
|
* @note The implementation is architecture dependent, it may just enable the
|
||||||
|
* interrupts.
|
||||||
|
* @note Do not invoke this API from within a kernel lock.
|
||||||
|
* @note This API is no replacement for @p chSysUnlock(), the @p chSysUnlock()
|
||||||
|
* could do more than just enable the interrupts.
|
||||||
|
*/
|
||||||
|
#define chSysEnable() port_enable()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enters the kernel lock mode.
|
||||||
|
*
|
||||||
|
* @note The use of kernel lock mode is not recommended in the user code, it is
|
||||||
|
* a better idea to use the semaphores or mutexes instead.
|
||||||
|
* @see CH_USE_NESTED_LOCKS
|
||||||
|
*/
|
||||||
|
#if CH_USE_NESTED_LOCKS || defined(__DOXYGEN__)
|
||||||
|
#if CH_OPTIMIZE_SPEED || defined(__DOXYGEN__)
|
||||||
|
#define chSysLock() { \
|
||||||
|
if (currp->p_locks++ == 0) \
|
||||||
|
port_lock(); \
|
||||||
|
}
|
||||||
|
#endif /* CH_OPTIMIZE_SPEED */
|
||||||
|
#else /* !CH_USE_NESTED_LOCKS */
|
||||||
|
#define chSysLock() port_lock()
|
||||||
|
#endif /* !CH_USE_NESTED_LOCKS */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Leaves the kernel lock mode.
|
||||||
|
*
|
||||||
|
* @note The use of kernel lock mode is not recommended in the user code, it is
|
||||||
|
* a better idea to use the semaphores or mutexes instead.
|
||||||
|
* @see CH_USE_NESTED_LOCKS
|
||||||
|
*/
|
||||||
|
#if CH_USE_NESTED_LOCKS || defined(__DOXYGEN__)
|
||||||
|
#if CH_OPTIMIZE_SPEED || defined(__DOXYGEN__)
|
||||||
|
#define chSysUnlock() { \
|
||||||
|
if (--currp->p_locks == 0) \
|
||||||
|
port_unlock(); \
|
||||||
|
}
|
||||||
|
#endif /* CH_OPTIMIZE_SPEED */
|
||||||
|
#else /* !CH_USE_NESTED_LOCKS */
|
||||||
|
#define chSysUnlock() port_unlock()
|
||||||
|
#endif /* !CH_USE_NESTED_LOCKS */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enters the kernel lock mode from within an interrupt handler.
|
||||||
|
*
|
||||||
|
* @note This API may do nothing on some architectures, it is required because
|
||||||
|
* on ports that support preemptable interrupt handlers it is required to
|
||||||
|
* raise the interrupt mask to the same level of the system mutual
|
||||||
|
* exclusion zone.<br>
|
||||||
|
* It is good practice to invoke this API before invoking any I-class
|
||||||
|
* syscall from an interrupt handler.
|
||||||
|
* @note This API must be invoked exclusively from interrupt handlers.
|
||||||
|
*/
|
||||||
|
#define chSysLockFromIsr() port_lock_from_isr()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Leaves the kernel lock mode from within an interrupt handler.
|
||||||
|
*
|
||||||
|
* @note This API may do nothing on some architectures, it is required because
|
||||||
|
* on ports that support preemptable interrupt handlers it is required to
|
||||||
|
* raise the interrupt mask to the same level of the system mutual
|
||||||
|
* exclusion zone.<br>
|
||||||
|
* It is good practice to invoke this API after invoking any I-class
|
||||||
|
* syscall from an interrupt handler.
|
||||||
|
* @note This API must be invoked exclusively from interrupt handlers.
|
||||||
|
*/
|
||||||
|
#define chSysUnlockFromIsr() port_unlock_from_isr()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IRQ handler enter code.
|
||||||
|
*
|
||||||
|
* @note Usually IRQ handlers functions are also declared naked.
|
||||||
|
* @note On some architectures this macro can be empty.
|
||||||
|
*/
|
||||||
|
#define CH_IRQ_PROLOGUE() PORT_IRQ_PROLOGUE()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IRQ handler exit code.
|
||||||
|
*
|
||||||
|
* @note Usually IRQ handlers function are also declared naked.
|
||||||
|
* @note This macro usually performs the final reschedulation by using
|
||||||
|
* @p chSchRescRequiredI() and @p chSchDoRescheduleI().
|
||||||
|
*/
|
||||||
|
#define CH_IRQ_EPILOGUE() PORT_IRQ_EPILOGUE()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Standard IRQ handler declaration.
|
||||||
|
*
|
||||||
|
* @note @p id can be a function name or a vector number depending on the
|
||||||
|
* port implementation.
|
||||||
|
*/
|
||||||
|
#define CH_IRQ_HANDLER(id) PORT_IRQ_HANDLER(id)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void chSysInit(void);
|
||||||
|
void chSysTimerHandlerI(void);
|
||||||
|
#if CH_USE_NESTED_LOCKS && !CH_OPTIMIZE_SPEED
|
||||||
|
void chSysLock(void);
|
||||||
|
void chSysUnlock(void);
|
||||||
|
#endif /* CH_USE_NESTED_LOCKS && !CH_OPTIMIZE_SPEED */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _SYS_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,269 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file threads.h
|
||||||
|
* @brief Threads macros and structures.
|
||||||
|
* @addtogroup Threads
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _THREADS_H_
|
||||||
|
#define _THREADS_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Structure representing a thread.
|
||||||
|
*
|
||||||
|
* @extends ThreadsQueue
|
||||||
|
* @note Not all the listed fields are always needed, by switching off some
|
||||||
|
* not needed ChibiOS/RT subsystems it is possible to save RAM space by
|
||||||
|
* shrinking the @p Thread structure.
|
||||||
|
*/
|
||||||
|
struct Thread {
|
||||||
|
Thread *p_next; /**< Next @p Thread in the threads
|
||||||
|
list/queue.*/
|
||||||
|
/* End of the fields shared with the ThreadsList structure. */
|
||||||
|
Thread *p_prev; /**< Previous @p Thread in the threads
|
||||||
|
queue.*/
|
||||||
|
/* End of the fields shared with the ThreadsQueue structure. */
|
||||||
|
tprio_t p_prio; /**< Thread priority.*/
|
||||||
|
/* End of the fields shared with the ReadyList structure. */
|
||||||
|
tstate_t p_state; /**< Current thread state.*/
|
||||||
|
tmode_t p_flags; /**< Various flags.*/
|
||||||
|
struct context p_ctx; /**< Processor context.*/
|
||||||
|
#if CH_USE_NESTED_LOCKS
|
||||||
|
cnt_t p_locks; /**< Number of nested locks.*/
|
||||||
|
#endif
|
||||||
|
#if CH_DBG_THREADS_PROFILING
|
||||||
|
volatile systime_t p_time; /**< Consumed time.
|
||||||
|
@note This field can overflow.*/
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* The following fields are merged in unions because they are all
|
||||||
|
* state-specific fields. This trick saves some extra space for each
|
||||||
|
* thread in the system.
|
||||||
|
*/
|
||||||
|
union {
|
||||||
|
msg_t p_rdymsg; /**< Thread wakeup code.*/
|
||||||
|
msg_t p_exitcode; /**< The thread exit code
|
||||||
|
(@p PREXIT state).*/
|
||||||
|
void *p_wtobjp; /**< Generic kernel object pointer used
|
||||||
|
for opaque access.*/
|
||||||
|
#if CH_USE_SEMAPHORES
|
||||||
|
Semaphore *p_wtsemp; /**< Semaphore where the thread is
|
||||||
|
waiting on (@p PRWTSEM state).*/
|
||||||
|
#endif
|
||||||
|
#if CH_USE_MUTEXES
|
||||||
|
Mutex *p_wtmtxp; /**< Mutex where the thread is waiting
|
||||||
|
on (@p PRWTMTX state).*/
|
||||||
|
#endif
|
||||||
|
#if CH_USE_CONDVARS
|
||||||
|
CondVar *p_wtcondp; /**< CondVar where the thread is
|
||||||
|
waiting on (@p PRWTCOND state).*/
|
||||||
|
#endif
|
||||||
|
#if CH_USE_MESSAGES
|
||||||
|
Thread *p_wtthdp; /**< Destination thread for message
|
||||||
|
send @p PRSNDMSG state).*/
|
||||||
|
#endif
|
||||||
|
#if CH_USE_EVENTS
|
||||||
|
eventmask_t p_ewmask; /**< Enabled events mask (@p PRWTOREVT
|
||||||
|
or @p PRWTANDEVT states).*/
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
* Start of the optional fields.
|
||||||
|
*/
|
||||||
|
#if CH_USE_WAITEXIT
|
||||||
|
Thread *p_waiting; /**< Thread waiting for termination.*/
|
||||||
|
#endif
|
||||||
|
#if CH_USE_MESSAGES
|
||||||
|
ThreadsQueue p_msgqueue; /**< Message queue.*/
|
||||||
|
msg_t p_msg; /**< The message.*/
|
||||||
|
#endif
|
||||||
|
#if CH_USE_EVENTS
|
||||||
|
eventmask_t p_epending; /**< Pending events mask.*/
|
||||||
|
#endif
|
||||||
|
#if CH_USE_MUTEXES
|
||||||
|
Mutex *p_mtxlist; /**< List of the mutexes owned by this
|
||||||
|
thread, @p NULL terminated.*/
|
||||||
|
tprio_t p_realprio; /**< Thread's own, non-inherited,
|
||||||
|
priority.*/
|
||||||
|
#endif
|
||||||
|
#if CH_USE_DYNAMIC && CH_USE_MEMPOOLS
|
||||||
|
void *p_mpool; /**< Memory Pool where the thread
|
||||||
|
workspace is returned.*/
|
||||||
|
#endif
|
||||||
|
/* Extra fields defined in chconf.h */
|
||||||
|
THREAD_EXT_FIELDS
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Thread state: Ready to run, waiting on the ready list.*/
|
||||||
|
#define PRREADY 0
|
||||||
|
/** Thread state: Currently running. */
|
||||||
|
#define PRCURR 1
|
||||||
|
/** Thread state: Thread created in suspended state. */
|
||||||
|
#define PRSUSPENDED 2
|
||||||
|
/** Thread state: Waiting on a semaphore. */
|
||||||
|
#define PRWTSEM 3
|
||||||
|
/** Thread state: Waiting on a mutex. */
|
||||||
|
#define PRWTMTX 4
|
||||||
|
/** Thread state: Waiting in @p chThdSleep() or @p chThdSleepUntil(). */
|
||||||
|
#define PRWTCOND 5
|
||||||
|
/** Thread state: Waiting in @p chCondWait(). */
|
||||||
|
#define PRSLEEP 6
|
||||||
|
/** Thread state: Waiting in @p chThdWait(). */
|
||||||
|
#define PRWAIT 7
|
||||||
|
/** Thread state: Waiting in @p chEvtWaitOneTimeout() or
|
||||||
|
@p chEvtWaitAnyTimeout(). */
|
||||||
|
#define PRWTOREVT 8
|
||||||
|
/** Thread state: Waiting in @p chEvtWaitAllTimeout(). */
|
||||||
|
#define PRWTANDEVT 9
|
||||||
|
/** Thread state: Waiting in @p chMsgSend(). */
|
||||||
|
#define PRSNDMSG 10
|
||||||
|
/** Thread state: Waiting in @p chMsgWait(). */
|
||||||
|
#define PRWTMSG 11
|
||||||
|
/** Thread state: After termination.*/
|
||||||
|
#define PREXIT 12
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Various flags into the thread p_flags field.
|
||||||
|
*/
|
||||||
|
#define P_MEM_MODE_MASK 3 /* Thread memory mode mask. */
|
||||||
|
#define P_MEM_MODE_STATIC 0 /* Thread memory mode: static. */
|
||||||
|
#define P_MEM_MODE_HEAP 1 /* Thread memory mode: heap. */
|
||||||
|
#define P_MEM_MODE_MEMPOOL 2 /* Thread memory mode: mempool. */
|
||||||
|
#define P_TERMINATE 4 /* Termination requested. */
|
||||||
|
|
||||||
|
/* Not an API, don't use into the application code.*/
|
||||||
|
Thread *init_thread(Thread *tp, tprio_t prio);
|
||||||
|
|
||||||
|
/** Thread function.*/
|
||||||
|
typedef msg_t (*tfunc_t)(void *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Threads APIs.
|
||||||
|
*/
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
Thread *chThdInit(void *wsp, size_t size,
|
||||||
|
tprio_t prio, tfunc_t pf, void *arg);
|
||||||
|
Thread *chThdCreateStatic(void *wsp, size_t size,
|
||||||
|
tprio_t prio, tfunc_t pf, void *arg);
|
||||||
|
#if CH_USE_DYNAMIC && CH_USE_WAITEXIT && CH_USE_HEAP
|
||||||
|
Thread *chThdCreateFromHeap(size_t size, tprio_t prio,
|
||||||
|
tfunc_t pf, void *arg);
|
||||||
|
#endif
|
||||||
|
#if CH_USE_DYNAMIC && CH_USE_WAITEXIT && CH_USE_MEMPOOLS
|
||||||
|
Thread *chThdCreateFromMemoryPool(MemoryPool *mp, tprio_t prio,
|
||||||
|
tfunc_t pf, void *arg);
|
||||||
|
#endif
|
||||||
|
tprio_t chThdSetPriority(tprio_t newprio);
|
||||||
|
Thread *chThdResume(Thread *tp);
|
||||||
|
void chThdTerminate(Thread *tp);
|
||||||
|
void chThdSleep(systime_t time);
|
||||||
|
void chThdSleepUntil(systime_t time);
|
||||||
|
void chThdExit(msg_t msg);
|
||||||
|
#if CH_USE_WAITEXIT
|
||||||
|
msg_t chThdWait(Thread *tp);
|
||||||
|
#endif
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Returns the pointer to the @p Thread currently in execution.*/
|
||||||
|
#define chThdSelf() currp
|
||||||
|
|
||||||
|
/** Returns the current thread priority.*/
|
||||||
|
#define chThdGetPriority() (currp->p_prio)
|
||||||
|
|
||||||
|
/** Returns the pointer to the @p Thread local storage area, if any.*/
|
||||||
|
#define chThdLS() (void *)(currp + 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies if the specified thread is in the @p PREXIT state.
|
||||||
|
*
|
||||||
|
* @param[in] tp the pointer to the thread
|
||||||
|
* @retval TRUE thread terminated.
|
||||||
|
* @retval FALSE thread not terminated.
|
||||||
|
*/
|
||||||
|
#define chThdTerminated(tp) ((tp)->p_state == PREXIT)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies if the current thread has a termination request pending.
|
||||||
|
*
|
||||||
|
* @retval TRUE termination request pended.
|
||||||
|
* @retval FALSE termination request not pended.
|
||||||
|
*/
|
||||||
|
#define chThdShouldTerminate() (currp->p_flags & P_TERMINATE)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resumes a thread created with @p chThdInit().
|
||||||
|
*
|
||||||
|
* @param[in] tp the pointer to the thread
|
||||||
|
*/
|
||||||
|
#define chThdResumeI(tp) chSchReadyI(tp)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Suspends the invoking thread for the specified time.
|
||||||
|
*
|
||||||
|
* @param[in] time the delay in system ticks, the special values are handled as
|
||||||
|
* follow:
|
||||||
|
* - @a TIME_INFINITE the thread enters an infinite sleep
|
||||||
|
* state.
|
||||||
|
* - @a TIME_IMMEDIATE this value is accepted but interpreted
|
||||||
|
* as a normal time specification not as an immediate timeout
|
||||||
|
* specification.
|
||||||
|
* .
|
||||||
|
*/
|
||||||
|
#define chThdSleepS(time) chSchGoSleepTimeoutS(PRSLEEP, time)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delays the invoking thread for the specified number of seconds.
|
||||||
|
*
|
||||||
|
* @param[in] sec the time in seconds
|
||||||
|
* @note The specified time is rounded up to a value allowed by the real
|
||||||
|
* system clock.
|
||||||
|
* @note The maximum specified value is implementation dependent.
|
||||||
|
*/
|
||||||
|
#define chThdSleepSeconds(sec) chThdSleep(S2ST(sec))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delays the invoking thread for the specified number of milliseconds.
|
||||||
|
*
|
||||||
|
* @param[in] msec the time in milliseconds
|
||||||
|
* @note The specified time is rounded up to a value allowed by the real
|
||||||
|
* system clock.
|
||||||
|
* @note The maximum specified value is implementation dependent.
|
||||||
|
*/
|
||||||
|
#define chThdSleepMilliseconds(msec) chThdSleep(MS2ST(msec))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delays the invoking thread for the specified number of microseconds.
|
||||||
|
*
|
||||||
|
* @param[in] usec the time in microseconds
|
||||||
|
* @note The specified time is rounded up to a value allowed by the real
|
||||||
|
* system clock.
|
||||||
|
* @note The maximum specified value is implementation dependent.
|
||||||
|
*/
|
||||||
|
#define chThdSleepMicroseconds(usec) chThdSleep(US2ST(usec))
|
||||||
|
|
||||||
|
#endif /* _THREADS_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file vt.h
|
||||||
|
* @brief Time macros and structures.
|
||||||
|
* @addtogroup Time
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _VT_H_
|
||||||
|
#define _VT_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time conversion utility. Converts from seconds to system ticks number.
|
||||||
|
*/
|
||||||
|
#define S2ST(sec) ((systime_t)((sec) * CH_FREQUENCY))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time conversion utility. Converts from milliseconds to system ticks number.
|
||||||
|
* @note The result is rounded upward to the next tick boundary.
|
||||||
|
*/
|
||||||
|
#define MS2ST(msec) ((systime_t)(((((msec) - 1L) * CH_FREQUENCY) / 1000L) + 1L))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time conversion utility. Converts from microseconds to system ticks number.
|
||||||
|
* @note The result is rounded upward to the next tick boundary.
|
||||||
|
*/
|
||||||
|
#define US2ST(usec) ((systime_t)(((((usec) - 1L) * CH_FREQUENCY) / 1000000L) + 1L))
|
||||||
|
|
||||||
|
/** Virtual Timer callback function.*/
|
||||||
|
typedef void (*vtfunc_t)(void *);
|
||||||
|
|
||||||
|
typedef struct VirtualTimer VirtualTimer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Virtual Timer descriptor structure.
|
||||||
|
* @extends DeltaList
|
||||||
|
*/
|
||||||
|
struct VirtualTimer {
|
||||||
|
VirtualTimer *vt_next; /**< Next timer in the delta list.*/
|
||||||
|
VirtualTimer *vt_prev; /**< Previous timer in the delta list.*/
|
||||||
|
systime_t vt_time; /**< Time delta before timeout.*/
|
||||||
|
vtfunc_t vt_func; /**< Timer callback function pointer.
|
||||||
|
The pointer is reset to zero after
|
||||||
|
the callback is invoked.*/
|
||||||
|
void *vt_par; /**< Timer callback function
|
||||||
|
parameter.*/
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Virtual timers list header.
|
||||||
|
* @note The delta list is implemented as a double link bidirectional list in
|
||||||
|
* order to make the unlink time constant, the reset of a virtual timer
|
||||||
|
* is often used in the code.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
VirtualTimer *vt_next; /**< Next timer in the delta list (the
|
||||||
|
one that will be triggered next).*/
|
||||||
|
VirtualTimer *vt_prev; /**< Last timer in the delta list.*/
|
||||||
|
systime_t vt_time; /**< Must be initialized to -1.*/
|
||||||
|
volatile systime_t vt_systime; /**< System Time counter.*/
|
||||||
|
} VTList;
|
||||||
|
|
||||||
|
extern VTList vtlist;
|
||||||
|
|
||||||
|
#define chVTDoTickI() { \
|
||||||
|
vtlist.vt_systime++; \
|
||||||
|
if (&vtlist != (VTList *)vtlist.vt_next) { \
|
||||||
|
VirtualTimer *vtp; \
|
||||||
|
\
|
||||||
|
--vtlist.vt_next->vt_time; \
|
||||||
|
while (!(vtp = vtlist.vt_next)->vt_time) { \
|
||||||
|
vtfunc_t fn = vtp->vt_func; \
|
||||||
|
vtp->vt_func = NULL; \
|
||||||
|
(vtp->vt_next->vt_prev = (void *)&vtlist)->vt_next = vtp->vt_next;\
|
||||||
|
fn(vtp->vt_par); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Virtual Timers APIs.
|
||||||
|
*/
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void vt_init(void);
|
||||||
|
void chVTSetI(VirtualTimer *vtp, systime_t time, vtfunc_t vtfunc, void *par);
|
||||||
|
void chVTResetI(VirtualTimer *vtp);
|
||||||
|
bool_t chTimeIsWithin(systime_t start, systime_t end);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Returns TRUE if the speciified timer is armed.*/
|
||||||
|
#define chVTIsArmedI(vtp) ((vtp)->vt_func != NULL)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of system ticks since the @p chSysInit() invocation.
|
||||||
|
* @return the system ticks number
|
||||||
|
* @note The counter can reach its maximum and then returns to zero.
|
||||||
|
* @note This function is designed to work with the @p chThdSleepUntil().
|
||||||
|
*/
|
||||||
|
#define chTimeNow() (vtlist.vt_systime)
|
||||||
|
|
||||||
|
#endif /* _VT_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,13 @@
|
||||||
|
# List of all the ChibiOS/RT kernel files, there is no need to remove the files
|
||||||
|
# from this list, you can disable parts of the kernel by editing chconf.h.
|
||||||
|
KERNSRC = ../../os/kernel/src/chsys.c ../../os/kernel/src/chdebug.c \
|
||||||
|
../../os/kernel/src/chlists.c ../../os/kernel/src/chvt.c \
|
||||||
|
../../os/kernel/src/chschd.c ../../os/kernel/src/chthreads.c \
|
||||||
|
../../os/kernel/src/chsem.c ../../os/kernel/src/chmtx.c \
|
||||||
|
../../os/kernel/src/chcond.c ../../os/kernel/src/chevents.c \
|
||||||
|
../../os/kernel/src/chmsg.c ../../os/kernel/src/chmboxes.c \
|
||||||
|
../../os/kernel/src/chqueues.c ../../os/kernel/src/chheap.c \
|
||||||
|
../../os/kernel/src/chmempools.c ../../os/kernel/src/chserial.c
|
||||||
|
|
||||||
|
# Required include directories
|
||||||
|
KERNINC = ../../os/kernel/include
|
|
@ -0,0 +1 @@
|
||||||
|
ChibiOS/RT portable kernel code
|
|
@ -0,0 +1,227 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
Concepts and parts of this file are contributed by and Copyright (C) 2008
|
||||||
|
of Leon Woestenberg.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file chcond.c
|
||||||
|
* @brief Condition Variables code.
|
||||||
|
* @addtogroup CondVars
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
#if CH_USE_CONDVARS && CH_USE_MUTEXES
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes s @p CondVar structure.
|
||||||
|
*
|
||||||
|
* @param[out] cp pointer to a @p CondVar structure
|
||||||
|
* @note This function can be invoked from within an interrupt handler even if
|
||||||
|
* it is not an I-Class API because it does not touch any critical kernel
|
||||||
|
* data structure.
|
||||||
|
*/
|
||||||
|
void chCondInit(CondVar *cp) {
|
||||||
|
|
||||||
|
chDbgCheck(cp != NULL, "chCondInit");
|
||||||
|
|
||||||
|
queue_init(&cp->c_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Signals one thread that is waiting on the condition variable.
|
||||||
|
*
|
||||||
|
* @param[in] cp pointer to the @p CondVar structure
|
||||||
|
*/
|
||||||
|
void chCondSignal(CondVar *cp) {
|
||||||
|
|
||||||
|
chDbgCheck(cp != NULL, "chCondSignal");
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
if (notempty(&cp->c_queue)) /* any thread ? */
|
||||||
|
chSchWakeupS(fifo_remove(&cp->c_queue), RDY_OK);
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Signals one thread that is waiting on the condition variable.
|
||||||
|
*
|
||||||
|
* @param[in] cp pointer to the @p CondVar structure
|
||||||
|
*/
|
||||||
|
void chCondSignalI(CondVar *cp) {
|
||||||
|
|
||||||
|
chDbgCheck(cp != NULL, "chCondSignalI");
|
||||||
|
|
||||||
|
if (notempty(&cp->c_queue)) /* any thread ? */
|
||||||
|
chSchReadyI(fifo_remove(&cp->c_queue))->p_rdymsg = RDY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Signals all threads that are waiting on the condition variable.
|
||||||
|
*
|
||||||
|
* @param[in] cp pointer to the @p CondVar structure
|
||||||
|
*/
|
||||||
|
void chCondBroadcast(CondVar *cp) {
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
chCondBroadcastI(cp);
|
||||||
|
chSchRescheduleS();
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Signals all threads that are waiting on the condition variable.
|
||||||
|
*
|
||||||
|
* @param[in] cp pointer to the @p CondVar structure
|
||||||
|
*/
|
||||||
|
void chCondBroadcastI(CondVar *cp) {
|
||||||
|
|
||||||
|
chDbgCheck(cp != NULL, "chCondBroadcastI");
|
||||||
|
|
||||||
|
/* empties the condition variable queue and inserts all the Threads into the
|
||||||
|
* ready list in FIFO order. The wakeup message is set to @p RDY_RESET in
|
||||||
|
* order to make a chCondBroadcast() detectable from a chCondSignal(). */
|
||||||
|
while (cp->c_queue.p_next != (void *)&cp->c_queue)
|
||||||
|
chSchReadyI(fifo_remove(&cp->c_queue))->p_rdymsg = RDY_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Waits on the condition variable releasing the mutex lock.
|
||||||
|
* @details Releases the mutex, waits on the condition variable, and finally
|
||||||
|
* acquires the mutex again. This is done atomically.
|
||||||
|
*
|
||||||
|
* @param[in] cp pointer to the @p CondVar structure
|
||||||
|
* @return The wakep mode.
|
||||||
|
* @retval RDY_OK if the condvar was signaled using chCondSignal().
|
||||||
|
* @retval RDY_RESET if the condvar was signaled using chCondBroadcast().
|
||||||
|
* @note The thread MUST already have locked the mutex when calling
|
||||||
|
* @p chCondWait().
|
||||||
|
*/
|
||||||
|
msg_t chCondWait(CondVar *cp) {
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
msg = chCondWaitS(cp);
|
||||||
|
chSysUnlock();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Waits on the condition variable releasing the mutex lock.
|
||||||
|
* @details Releases the mutex, waits on the condition variable, and finally
|
||||||
|
* acquires the mutex again. This is done atomically.
|
||||||
|
*
|
||||||
|
* @param[in] cp pointer to the @p CondVar structure
|
||||||
|
* @return The wakep mode.
|
||||||
|
* @retval RDY_OK if the condvar was signaled using chCondSignal().
|
||||||
|
* @retval RDY_RESET if the condvar was signaled using chCondBroadcast().
|
||||||
|
* @note The thread MUST already have locked the mutex when calling
|
||||||
|
* @p chCondWaitS().
|
||||||
|
*/
|
||||||
|
msg_t chCondWaitS(CondVar *cp) {
|
||||||
|
Mutex *mp;
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
|
chDbgCheck(cp != NULL, "chCondWaitS");
|
||||||
|
chDbgAssert(currp->p_mtxlist != NULL,
|
||||||
|
"chCondWaitS(), #1",
|
||||||
|
"not owning a mutex");
|
||||||
|
|
||||||
|
mp = chMtxUnlockS(); /* unlocks the condvar mutex */
|
||||||
|
prio_insert(currp, &cp->c_queue); /* enters the condvar queue */
|
||||||
|
currp->p_wtcondp = cp; /* needed by the tracer */
|
||||||
|
chSchGoSleepS(PRWTCOND); /* waits on the condvar */
|
||||||
|
msg = currp->p_rdymsg; /* fetches the wakeup message */
|
||||||
|
chMtxLockS(mp); /* atomically relocks the mutex */
|
||||||
|
return msg; /* returns the wakeup message */
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CH_USE_CONDVARS_TIMEOUT
|
||||||
|
/**
|
||||||
|
* @brief Waits on the condition variable releasing the mutex lock.
|
||||||
|
* @details Releases the mutex, waits on the condition variable, and finally
|
||||||
|
* acquires the mutex again. This is done atomically.
|
||||||
|
*
|
||||||
|
* @param[in] cp pointer to the @p CondVar structure
|
||||||
|
* @param[in] time the number of ticks before the operation timeouts,
|
||||||
|
* the special value @p TIME_INFINITE is allowed.
|
||||||
|
* It is not possible to specify zero @p TIME_IMMEDIATE
|
||||||
|
* as timeout specification because it would make no sense
|
||||||
|
* in this function.
|
||||||
|
* @return The wakep mode.
|
||||||
|
* @retval RDY_OK if the condvar was signaled using chCondSignal().
|
||||||
|
* @retval RDY_RESET if the condvar was signaled using chCondBroadcast().
|
||||||
|
* @retval RDY_TIMEOUT if the condvar was not signaled within the specified
|
||||||
|
* timeout.
|
||||||
|
* @note The thread MUST already have locked the mutex when calling
|
||||||
|
* @p chCondWaitTimeout().
|
||||||
|
*/
|
||||||
|
msg_t chCondWaitTimeout(CondVar *cp, systime_t time) {
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
msg = chCondWaitTimeoutS(cp, time);
|
||||||
|
chSysUnlock();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Waits on the condition variable releasing the mutex lock.
|
||||||
|
* @details Releases the mutex, waits on the condition variable, and finally
|
||||||
|
* acquires the mutex again. This is done atomically.
|
||||||
|
*
|
||||||
|
* @param[in] cp pointer to the @p CondVar structure
|
||||||
|
* @param[in] time the number of ticks before the operation timeouts,
|
||||||
|
* the special value @p TIME_INFINITE is allowed.
|
||||||
|
* It is not possible to specify zero @p TIME_IMMEDIATE
|
||||||
|
* as timeout specification because it would make no sense
|
||||||
|
* in this function.
|
||||||
|
* @return The wakep mode.
|
||||||
|
* @retval RDY_OK if the condvar was signaled using chCondSignal().
|
||||||
|
* @retval RDY_RESET if the condvar was signaled using chCondBroadcast().
|
||||||
|
* @retval RDY_TIMEOUT if the condvar was not signaled within the specified
|
||||||
|
* timeout.
|
||||||
|
* @note The thread MUST already have locked the mutex when calling
|
||||||
|
* @p chCondWaitTimeoutS().
|
||||||
|
*/
|
||||||
|
msg_t chCondWaitTimeoutS(CondVar *cp, systime_t time) {
|
||||||
|
Mutex *mp;
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
|
chDbgCheck(cp != NULL, "chCondWaitTimeoutS");
|
||||||
|
chDbgAssert(currp->p_mtxlist != NULL,
|
||||||
|
"chCondWaitTimeoutS(), #1",
|
||||||
|
"not owning a mutex");
|
||||||
|
|
||||||
|
mp = chMtxUnlockS(); /* unlocks the condvar mutex */
|
||||||
|
prio_insert(currp, &cp->c_queue); /* enters the condvar queue */
|
||||||
|
currp->p_wtcondp = cp; /* needed by the tracer */
|
||||||
|
chSchGoSleepTimeoutS(PRWTCOND, time); /* waits on the condvar */
|
||||||
|
msg = currp->p_rdymsg; /* fetches the wakeup message */
|
||||||
|
chMtxLockS(mp); /* atomically relocks the mutex */
|
||||||
|
return msg; /* returns the wakeup message */
|
||||||
|
}
|
||||||
|
#endif /* CH_USE_CONDVARS_TIMEOUT */
|
||||||
|
|
||||||
|
#endif /* CH_USE_CONDVARS && CH_USE_MUTEXES */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file chdebug.c
|
||||||
|
* @brief ChibiOS/RT Debug code.
|
||||||
|
* @addtogroup Debug
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
#if CH_DBG_ENABLE_TRACE
|
||||||
|
/**
|
||||||
|
* @brief Public trace buffer.
|
||||||
|
*/
|
||||||
|
TraceBuffer trace_buffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Trace circular buffer subsystem initialization.
|
||||||
|
*/
|
||||||
|
void trace_init(void) {
|
||||||
|
|
||||||
|
trace_buffer.tb_size = TRACE_BUFFER_SIZE;
|
||||||
|
trace_buffer.tb_ptr = &trace_buffer.tb_buffer[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Inserts in the circular debug trace buffer a context switch record.
|
||||||
|
*
|
||||||
|
* @param[in] otp the thread being switched out
|
||||||
|
* @param[in] ntp the thread to be switched in
|
||||||
|
*/
|
||||||
|
void chDbgTrace(Thread *otp, Thread *ntp) {
|
||||||
|
|
||||||
|
trace_buffer.tb_ptr->cse_wtobjp = otp->p_wtobjp;
|
||||||
|
trace_buffer.tb_ptr->cse_time = chTimeNow();
|
||||||
|
trace_buffer.tb_ptr->cse_state = otp->p_state;
|
||||||
|
trace_buffer.tb_ptr->cse_tid = (unsigned)ntp >> 4;
|
||||||
|
if (++trace_buffer.tb_ptr >= &trace_buffer.tb_buffer[TRACE_BUFFER_SIZE])
|
||||||
|
trace_buffer.tb_ptr = &trace_buffer.tb_buffer[0];
|
||||||
|
}
|
||||||
|
#endif /* CH_DBG_ENABLE_TRACE */
|
||||||
|
|
||||||
|
#if CH_DBG_ENABLE_ASSERTS || CH_DBG_ENABLE_CHECKS || CH_DBG_ENABLE_STACK_CHECK
|
||||||
|
/**
|
||||||
|
* @brief Pointer to the panic message.
|
||||||
|
* @details This pointer is meant to be accessed through the debugger, it is
|
||||||
|
* written once and then the system is halted.
|
||||||
|
*/
|
||||||
|
char *panic_msg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prints a panic message on the console and then halts the system.
|
||||||
|
*
|
||||||
|
* @param[in] msg the pointer to the panic message string
|
||||||
|
*/
|
||||||
|
void chDbgPanic(char *msg) {
|
||||||
|
|
||||||
|
panic_msg = msg;
|
||||||
|
chSysHalt();
|
||||||
|
}
|
||||||
|
#endif /* CH_DBG_ENABLE_ASSERTS || CH_DBG_ENABLE_CHECKS || CH_DBG_ENABLE_STACK_CHECK */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,392 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file chevents.c
|
||||||
|
* @brief Events code.
|
||||||
|
* @addtogroup Events
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
#if CH_USE_EVENTS
|
||||||
|
/**
|
||||||
|
* @brief Registers an Event Listener on an Event Source.
|
||||||
|
*
|
||||||
|
* @param[in] esp pointer to the @p EventSource structure
|
||||||
|
* @param[in] elp pointer to the @p EventListener structure
|
||||||
|
* @param[in] emask the mask of event flags to be pended to the thread when the
|
||||||
|
* event source is broadcasted
|
||||||
|
* @note Multiple Event Listeners can specify the same bits to be pended.
|
||||||
|
*/
|
||||||
|
void chEvtRegisterMask(EventSource *esp, EventListener *elp, eventmask_t emask) {
|
||||||
|
|
||||||
|
chDbgCheck((esp != NULL) && (elp != NULL), "chEvtRegisterMask");
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
elp->el_next = esp->es_next;
|
||||||
|
esp->es_next = elp;
|
||||||
|
elp->el_listener = currp;
|
||||||
|
elp->el_mask = emask;
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unregisters an Event Listener from its Event Source.
|
||||||
|
*
|
||||||
|
* @param[in] esp pointer to the @p EventSource structure
|
||||||
|
* @param[in] elp pointer to the @p EventListener structure
|
||||||
|
* @note If the event listener is not registered on the specified event source
|
||||||
|
* then the function does nothing.
|
||||||
|
* @note For optimal performance it is better to perform the unregister
|
||||||
|
* operations in inverse order of the register operations (elements are
|
||||||
|
* found on top of the list).
|
||||||
|
*/
|
||||||
|
void chEvtUnregister(EventSource *esp, EventListener *elp) {
|
||||||
|
EventListener *p;
|
||||||
|
|
||||||
|
chDbgCheck((esp != NULL) && (elp != NULL), "chEvtUnregister");
|
||||||
|
|
||||||
|
p = (EventListener *)esp;
|
||||||
|
chSysLock();
|
||||||
|
while (p->el_next != (EventListener *)esp) {
|
||||||
|
if (p->el_next == elp) {
|
||||||
|
p->el_next = elp->el_next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p = p->el_next;
|
||||||
|
}
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears the pending events specified in the mask.
|
||||||
|
*
|
||||||
|
* @param[in] mask the events to be cleared
|
||||||
|
* @return The pending events that were cleared.
|
||||||
|
*/
|
||||||
|
eventmask_t chEvtClear(eventmask_t mask) {
|
||||||
|
eventmask_t m;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
|
||||||
|
m = currp->p_epending & mask;
|
||||||
|
currp->p_epending &= ~mask;
|
||||||
|
|
||||||
|
chSysUnlock();
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pends a set of event flags on the current thread, this is @b much
|
||||||
|
* faster than using @p chEvtBroadcast() or @p chEvtSignal().
|
||||||
|
*
|
||||||
|
* @param[in] mask the events to be pended
|
||||||
|
* @return The current pending events mask.
|
||||||
|
*/
|
||||||
|
eventmask_t chEvtPend(eventmask_t mask) {
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
|
||||||
|
mask = (currp->p_epending |= mask);
|
||||||
|
|
||||||
|
chSysUnlock();
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pends a set of event flags on the specified @p Thread.
|
||||||
|
*
|
||||||
|
* @param[in] tp the thread to be signaled
|
||||||
|
* @param[in] mask the event flags set to be pended
|
||||||
|
*/
|
||||||
|
void chEvtSignal(Thread *tp, eventmask_t mask) {
|
||||||
|
|
||||||
|
chDbgCheck(tp != NULL, "chEvtSignal");
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
chEvtSignalI(tp, mask);
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pends a set of event flags on the specified @p Thread.
|
||||||
|
*
|
||||||
|
* @param[in] tp the thread to be signaled
|
||||||
|
* @param[in] mask the event flags set to be pended
|
||||||
|
*/
|
||||||
|
void chEvtSignalI(Thread *tp, eventmask_t mask) {
|
||||||
|
|
||||||
|
chDbgCheck(tp != NULL, "chEvtSignalI");
|
||||||
|
|
||||||
|
tp->p_epending |= mask;
|
||||||
|
/* Test on the AND/OR conditions wait states.*/
|
||||||
|
if (((tp->p_state == PRWTOREVT) && ((tp->p_epending & tp->p_ewmask) != 0)) ||
|
||||||
|
((tp->p_state == PRWTANDEVT) && ((tp->p_epending & tp->p_ewmask) == tp->p_ewmask)))
|
||||||
|
chSchReadyI(tp)->p_rdymsg = RDY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Signals all the Event Listeners registered on the specified Event
|
||||||
|
* Source.
|
||||||
|
*
|
||||||
|
* @param[in] esp pointer to the @p EventSource structure
|
||||||
|
*/
|
||||||
|
void chEvtBroadcast(EventSource *esp) {
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
chEvtBroadcastI(esp);
|
||||||
|
chSchRescheduleS();
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Signals all the Event Listeners registered on the specified Event
|
||||||
|
* Source.
|
||||||
|
*
|
||||||
|
* @param[in] esp pointer to the @p EventSource structure
|
||||||
|
*/
|
||||||
|
void chEvtBroadcastI(EventSource *esp) {
|
||||||
|
EventListener *elp;
|
||||||
|
|
||||||
|
chDbgCheck(esp != NULL, "chEvtBroadcastI");
|
||||||
|
|
||||||
|
elp = esp->es_next;
|
||||||
|
while (elp != (EventListener *)esp) {
|
||||||
|
chEvtSignalI(elp->el_listener, elp->el_mask);
|
||||||
|
elp = elp->el_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Invokes the event handlers associated with a mask.
|
||||||
|
*
|
||||||
|
* @param[in] mask mask of the events to be dispatched
|
||||||
|
* @param[in] handlers an array of @p evhandler_t. The array must have size
|
||||||
|
* equal to the number of bits in eventmask_t.
|
||||||
|
*/
|
||||||
|
void chEvtDispatch(const evhandler_t handlers[], eventmask_t mask) {
|
||||||
|
eventid_t eid;
|
||||||
|
|
||||||
|
chDbgCheck(handlers != NULL, "chEvtDispatch");
|
||||||
|
|
||||||
|
eid = 0;
|
||||||
|
while (mask) {
|
||||||
|
if (mask & EVENT_MASK(eid)) {
|
||||||
|
chDbgAssert(handlers[eid] != NULL,
|
||||||
|
"chEvtDispatch(), #1",
|
||||||
|
"null handler");
|
||||||
|
mask &= ~EVENT_MASK(eid);
|
||||||
|
handlers[eid](eid);
|
||||||
|
}
|
||||||
|
eid++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CH_OPTIMIZE_SPEED || !CH_USE_EVENTS_TIMEOUT || defined(__DOXYGEN__)
|
||||||
|
/**
|
||||||
|
* @brief Waits for exactly one of the specified events.
|
||||||
|
* @details The function waits for one event among those specified in
|
||||||
|
* @p ewmask to become pending then the event is cleared and returned.
|
||||||
|
*
|
||||||
|
* @param[in] ewmask mask of the events that the function should wait for,
|
||||||
|
* @p ALL_EVENTS enables all the events
|
||||||
|
* @return The mask of the lowest id served and cleared event.
|
||||||
|
* @note One and only one event is served in the function, the one with the
|
||||||
|
* lowest event id. The function is meant to be invoked into a loop in
|
||||||
|
* order to serve all the pending events.<br>
|
||||||
|
* This means that Event Listeners with a lower event identifier have
|
||||||
|
* an higher priority.
|
||||||
|
*/
|
||||||
|
eventmask_t chEvtWaitOne(eventmask_t ewmask) {
|
||||||
|
eventmask_t m;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
|
||||||
|
if ((m = (currp->p_epending & ewmask)) == 0) {
|
||||||
|
currp->p_ewmask = ewmask;
|
||||||
|
chSchGoSleepS(PRWTOREVT);
|
||||||
|
m = currp->p_epending & ewmask;
|
||||||
|
}
|
||||||
|
m &= -m;
|
||||||
|
currp->p_epending &= ~m;
|
||||||
|
|
||||||
|
chSysUnlock();
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Waits for any of the specified events.
|
||||||
|
* @details The function waits for any event among those specified in
|
||||||
|
* @p ewmask to become pending then the events are cleared and returned.
|
||||||
|
*
|
||||||
|
* @param[in] ewmask mask of the events that the function should wait for,
|
||||||
|
* @p ALL_EVENTS enables all the events
|
||||||
|
* @return The mask of the served and cleared events.
|
||||||
|
*/
|
||||||
|
eventmask_t chEvtWaitAny(eventmask_t ewmask) {
|
||||||
|
eventmask_t m;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
|
||||||
|
if ((m = (currp->p_epending & ewmask)) == 0) {
|
||||||
|
currp->p_ewmask = ewmask;
|
||||||
|
chSchGoSleepS(PRWTOREVT);
|
||||||
|
m = currp->p_epending & ewmask;
|
||||||
|
}
|
||||||
|
currp->p_epending &= ~m;
|
||||||
|
|
||||||
|
chSysUnlock();
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Waits for all the specified events.
|
||||||
|
* @details The function waits for all the events specified in @p ewmask to
|
||||||
|
* become pending then the events are cleared and returned.
|
||||||
|
*
|
||||||
|
* @param[in] ewmask mask of the event ids that the function should wait for
|
||||||
|
* @return The mask of the served and cleared events.
|
||||||
|
*/
|
||||||
|
eventmask_t chEvtWaitAll(eventmask_t ewmask) {
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
|
||||||
|
if ((currp->p_epending & ewmask) != ewmask) {
|
||||||
|
currp->p_ewmask = ewmask;
|
||||||
|
chSchGoSleepS(PRWTANDEVT);
|
||||||
|
}
|
||||||
|
currp->p_epending &= ~ewmask;
|
||||||
|
|
||||||
|
chSysUnlock();
|
||||||
|
return ewmask;
|
||||||
|
}
|
||||||
|
#endif /* CH_OPTIMIZE_SPEED || !CH_USE_EVENTS_TIMEOUT */
|
||||||
|
|
||||||
|
#if CH_USE_EVENTS_TIMEOUT
|
||||||
|
/**
|
||||||
|
* @brief Waits for exactly one of the specified events.
|
||||||
|
* @details The function waits for one event among those specified in
|
||||||
|
* @p ewmask to become pending then the event is cleared and returned.
|
||||||
|
*
|
||||||
|
* @param[in] ewmask mask of the events that the function should wait for,
|
||||||
|
* @p ALL_EVENTS enables all the events
|
||||||
|
* @param[in] time the number of ticks before the operation timeouts,
|
||||||
|
* the following special values are allowed:
|
||||||
|
* - @a TIME_IMMEDIATE immediate timeout.
|
||||||
|
* - @a TIME_INFINITE no timeout.
|
||||||
|
* .
|
||||||
|
* @return The mask of the lowest id served and cleared event.
|
||||||
|
* @retval 0 if the specified timeout expired.
|
||||||
|
* @note One and only one event is served in the function, the one with the
|
||||||
|
* lowest event id. The function is meant to be invoked into a loop in
|
||||||
|
* order to serve all the pending events.<br>
|
||||||
|
* This means that Event Listeners with a lower event identifier have
|
||||||
|
* an higher priority.
|
||||||
|
*/
|
||||||
|
eventmask_t chEvtWaitOneTimeout(eventmask_t ewmask, systime_t time) {
|
||||||
|
eventmask_t m;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
|
||||||
|
if ((m = (currp->p_epending & ewmask)) == 0) {
|
||||||
|
if (TIME_IMMEDIATE == time)
|
||||||
|
return (eventmask_t)0;
|
||||||
|
currp->p_ewmask = ewmask;
|
||||||
|
if (chSchGoSleepTimeoutS(PRWTOREVT, time) < RDY_OK)
|
||||||
|
return (eventmask_t)0;
|
||||||
|
m = currp->p_epending & ewmask;
|
||||||
|
}
|
||||||
|
m &= -m;
|
||||||
|
currp->p_epending &= ~m;
|
||||||
|
|
||||||
|
chSysUnlock();
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Waits for any of the specified events.
|
||||||
|
* @details The function waits for any event among those specified in
|
||||||
|
* @p ewmask to become pending then the events are cleared and
|
||||||
|
* returned.
|
||||||
|
*
|
||||||
|
* @param[in] ewmask mask of the events that the function should wait for,
|
||||||
|
* @p ALL_EVENTS enables all the events
|
||||||
|
* @param[in] time the number of ticks before the operation timeouts,
|
||||||
|
* the following special values are allowed:
|
||||||
|
* - @a TIME_IMMEDIATE immediate timeout.
|
||||||
|
* - @a TIME_INFINITE no timeout.
|
||||||
|
* .
|
||||||
|
* @return The mask of the served and cleared events.
|
||||||
|
* @retval 0 if the specified timeout expired.
|
||||||
|
*/
|
||||||
|
eventmask_t chEvtWaitAnyTimeout(eventmask_t ewmask, systime_t time) {
|
||||||
|
eventmask_t m;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
|
||||||
|
if ((m = (currp->p_epending & ewmask)) == 0) {
|
||||||
|
if (TIME_IMMEDIATE == time)
|
||||||
|
return (eventmask_t)0;
|
||||||
|
currp->p_ewmask = ewmask;
|
||||||
|
if (chSchGoSleepTimeoutS(PRWTOREVT, time) < RDY_OK)
|
||||||
|
return (eventmask_t)0;
|
||||||
|
m = currp->p_epending & ewmask;
|
||||||
|
}
|
||||||
|
currp->p_epending &= ~m;
|
||||||
|
|
||||||
|
chSysUnlock();
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Waits for all the specified events.
|
||||||
|
* @details The function waits for all the events specified in @p ewmask to
|
||||||
|
* become pending then the events are cleared and returned.
|
||||||
|
*
|
||||||
|
* @param[in] ewmask mask of the event ids that the function should wait for
|
||||||
|
* @param[in] time the number of ticks before the operation timeouts,
|
||||||
|
* the following special values are allowed:
|
||||||
|
* - @a TIME_IMMEDIATE immediate timeout.
|
||||||
|
* - @a TIME_INFINITE no timeout.
|
||||||
|
* .
|
||||||
|
* @return The mask of the served and cleared events.
|
||||||
|
* @retval 0 if the specified timeout expired.
|
||||||
|
*/
|
||||||
|
eventmask_t chEvtWaitAllTimeout(eventmask_t ewmask, systime_t time) {
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
|
||||||
|
if ((currp->p_epending & ewmask) != ewmask) {
|
||||||
|
if (TIME_IMMEDIATE == time)
|
||||||
|
return (eventmask_t)0;
|
||||||
|
currp->p_ewmask = ewmask;
|
||||||
|
if (chSchGoSleepTimeoutS(PRWTANDEVT, time) < RDY_OK)
|
||||||
|
return (eventmask_t)0;
|
||||||
|
}
|
||||||
|
currp->p_epending &= ~ewmask;
|
||||||
|
|
||||||
|
chSysUnlock();
|
||||||
|
return ewmask;
|
||||||
|
}
|
||||||
|
#endif /* CH_USE_EVENTS_TIMEOUT */
|
||||||
|
|
||||||
|
#endif /* CH_USE_EVENTS */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,276 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file chheap.c
|
||||||
|
* @brief Heap code.
|
||||||
|
* @addtogroup Heap
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
#if CH_USE_HEAP
|
||||||
|
|
||||||
|
#if !CH_USE_MALLOC_HEAP
|
||||||
|
|
||||||
|
#define MAGIC 0xF5A0
|
||||||
|
#define ALIGN_TYPE void *
|
||||||
|
#define ALIGN_MASK (sizeof(ALIGN_TYPE) - 1)
|
||||||
|
#define ALIGN_SIZE(p) (((size_t)(p) + ALIGN_MASK) & ~ALIGN_MASK)
|
||||||
|
|
||||||
|
struct header {
|
||||||
|
union {
|
||||||
|
struct header *h_next;
|
||||||
|
size_t h_magic;
|
||||||
|
};
|
||||||
|
size_t h_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
struct header free; /* Guaranteed to be not adjacent to the heap */
|
||||||
|
#if CH_USE_MUTEXES
|
||||||
|
#define H_LOCK() chMtxLock(&heap.hmtx)
|
||||||
|
#define H_UNLOCK() chMtxUnlock()
|
||||||
|
Mutex hmtx;
|
||||||
|
#elif CH_USE_SEMAPHORES
|
||||||
|
#define H_LOCK() chSemWait(&heap.hsem)
|
||||||
|
#define H_UNLOCK() chSemSignal(&heap.hsem)
|
||||||
|
Semaphore hsem;
|
||||||
|
#else
|
||||||
|
#error "The heap allocator requires mutexes or semaphores to be enabled"
|
||||||
|
#endif
|
||||||
|
#if CH_HEAP_SIZE > 0
|
||||||
|
union {
|
||||||
|
ALIGN_TYPE alignment;
|
||||||
|
char buffer[ALIGN_SIZE(CH_HEAP_SIZE)];
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
} heap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the allocator subsystem.
|
||||||
|
*
|
||||||
|
* @note Internal use only.
|
||||||
|
*/
|
||||||
|
void heap_init(void) {
|
||||||
|
struct header *hp;
|
||||||
|
|
||||||
|
#if CH_HEAP_SIZE == 0
|
||||||
|
extern char __heap_base__;
|
||||||
|
extern char __heap_end__;
|
||||||
|
|
||||||
|
hp = (void *)&__heap_base__;
|
||||||
|
hp->h_size = &__heap_end__ - &__heap_base__ - sizeof(struct header);
|
||||||
|
#else
|
||||||
|
hp = (void *)&heap.buffer[0];
|
||||||
|
hp->h_size = (&heap.buffer[ALIGN_SIZE(CH_HEAP_SIZE)] - &heap.buffer[0]) -
|
||||||
|
sizeof(struct header);
|
||||||
|
#endif
|
||||||
|
hp->h_next = NULL;
|
||||||
|
heap.free.h_next = hp;
|
||||||
|
heap.free.h_size = 0;
|
||||||
|
#if CH_USE_MUTEXES
|
||||||
|
chMtxInit(&heap.hmtx);
|
||||||
|
#else
|
||||||
|
chSemInit(&heap.hsem, 1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocates a block of memory from the heap by using the first-fit
|
||||||
|
* algorithm.
|
||||||
|
* @details The allocated block is guaranteed to be properly aligned for a
|
||||||
|
* pointer data type.
|
||||||
|
*
|
||||||
|
* @param[in] size the size of the block to be allocated. Note that the
|
||||||
|
* allocated block may be a bit bigger than the requested
|
||||||
|
* size for alignment and fragmentation reasons.
|
||||||
|
* @return A pointer to the allocated block.
|
||||||
|
* @retval NULL if the block cannot be allocated.
|
||||||
|
*/
|
||||||
|
void *chHeapAlloc(size_t size) {
|
||||||
|
struct header *qp, *hp, *fp;
|
||||||
|
|
||||||
|
size = ALIGN_SIZE(size);
|
||||||
|
qp = &heap.free;
|
||||||
|
H_LOCK();
|
||||||
|
|
||||||
|
while (qp->h_next != NULL) {
|
||||||
|
hp = qp->h_next;
|
||||||
|
if (hp->h_size >= size) {
|
||||||
|
if (hp->h_size < size + sizeof(struct header)) {
|
||||||
|
/* Gets the whole block even if it is slightly bigger than the
|
||||||
|
requested size because the fragment would be too small to be
|
||||||
|
useful */
|
||||||
|
qp->h_next = hp->h_next;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Block bigger enough, must split it */
|
||||||
|
fp = (void *)((char *)(hp) + sizeof(struct header) + size);
|
||||||
|
fp->h_next = hp->h_next;
|
||||||
|
fp->h_size = hp->h_size - sizeof(struct header) - size;
|
||||||
|
qp->h_next = fp;
|
||||||
|
hp->h_size = size;
|
||||||
|
}
|
||||||
|
hp->h_magic = MAGIC;
|
||||||
|
|
||||||
|
H_UNLOCK();
|
||||||
|
return (void *)(hp + 1);
|
||||||
|
}
|
||||||
|
qp = hp;
|
||||||
|
}
|
||||||
|
|
||||||
|
H_UNLOCK();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LIMIT(p) (struct header *)((char *)(p) + \
|
||||||
|
sizeof(struct header) + \
|
||||||
|
(p)->h_size)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Frees a previously allocated memory block.
|
||||||
|
*
|
||||||
|
* @param[in] p the memory block pointer
|
||||||
|
*/
|
||||||
|
void chHeapFree(void *p) {
|
||||||
|
struct header *qp, *hp;
|
||||||
|
|
||||||
|
chDbgCheck(p != NULL, "chHeapFree");
|
||||||
|
|
||||||
|
hp = (struct header *)p - 1;
|
||||||
|
chDbgAssert(hp->h_magic == MAGIC,
|
||||||
|
"chHeapFree(), #1",
|
||||||
|
"it is not magic");
|
||||||
|
qp = &heap.free;
|
||||||
|
H_LOCK();
|
||||||
|
|
||||||
|
while (TRUE) {
|
||||||
|
|
||||||
|
chDbgAssert((hp < qp) || (hp >= LIMIT(qp)),
|
||||||
|
"chHeapFree(), #2",
|
||||||
|
"within free block");
|
||||||
|
|
||||||
|
if (((qp == &heap.free) || (hp > qp)) &&
|
||||||
|
((qp->h_next == NULL) || (hp < qp->h_next))) {
|
||||||
|
/* Insertion after qp */
|
||||||
|
hp->h_next = qp->h_next;
|
||||||
|
qp->h_next = hp;
|
||||||
|
/* Verifies if the newly inserted block should be merged */
|
||||||
|
if (LIMIT(hp) == hp->h_next) {
|
||||||
|
/* Merge with the next block */
|
||||||
|
hp->h_size += hp->h_next->h_size + sizeof(struct header);
|
||||||
|
hp->h_next = hp->h_next->h_next;
|
||||||
|
}
|
||||||
|
if ((LIMIT(qp) == hp)) { /* Cannot happen when qp == &heap.free */
|
||||||
|
/* Merge with the previous block */
|
||||||
|
qp->h_size += hp->h_size + sizeof(struct header);
|
||||||
|
qp->h_next = hp->h_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
H_UNLOCK();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qp = qp->h_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reports the heap status.
|
||||||
|
*
|
||||||
|
* @param[in] sizep pointer to a variable that will receive the total
|
||||||
|
* fragmented free space
|
||||||
|
* @return The number of fragments in the heap.
|
||||||
|
* @note This function is meant to be used in the test suite, it should not be
|
||||||
|
* really useful for the application code.
|
||||||
|
* @note This function is not implemented when the @p CH_USE_MALLOC_HEAP
|
||||||
|
* configuration option is used (it always returns zero).
|
||||||
|
*/
|
||||||
|
size_t chHeapStatus(size_t *sizep) {
|
||||||
|
struct header *qp;
|
||||||
|
size_t n, sz;
|
||||||
|
|
||||||
|
H_LOCK();
|
||||||
|
|
||||||
|
sz = 0;
|
||||||
|
for (n = 0, qp = &heap.free; qp->h_next; n++, qp = qp->h_next)
|
||||||
|
sz += qp->h_next->h_size;
|
||||||
|
if (sizep)
|
||||||
|
*sizep = sz;
|
||||||
|
|
||||||
|
H_UNLOCK();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* CH_USE_MALLOC_HEAP */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#if CH_USE_MUTEXES
|
||||||
|
#define H_LOCK() chMtxLock(&hmtx)
|
||||||
|
#define H_UNLOCK() chMtxLock(&hmtx)
|
||||||
|
static Mutex hmtx;
|
||||||
|
#elif CH_USE_SEMAPHORES
|
||||||
|
#define H_LOCK() chSemWait(&hsem)
|
||||||
|
#define H_UNLOCK() chSemSignal(&hsem)
|
||||||
|
static Semaphore hsem;
|
||||||
|
#else
|
||||||
|
#error "The heap allocator requires mutexes or semaphores to be enabled"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void heap_init(void) {
|
||||||
|
|
||||||
|
#if CH_USE_MUTEXES
|
||||||
|
chMtxInit(&hmtx);
|
||||||
|
#else
|
||||||
|
chSemInit(&hsem, 1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void *chHeapAlloc(size_t size) {
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
H_LOCK();
|
||||||
|
p = malloc(size);
|
||||||
|
H_UNLOCK();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void chHeapFree(void *p) {
|
||||||
|
|
||||||
|
chDbgCheck(p != NULL, "chHeapFree");
|
||||||
|
|
||||||
|
H_LOCK();
|
||||||
|
free(p);
|
||||||
|
H_UNLOCK();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t chHeapStatus(size_t *sizep) {
|
||||||
|
|
||||||
|
if (sizep)
|
||||||
|
*sizep = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CH_USE_MALLOC_HEAP */
|
||||||
|
|
||||||
|
#endif /* CH_USE_HEAP */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file chlists.c
|
||||||
|
* @brief Thread queues/lists code.
|
||||||
|
* @addtogroup ThreadLists
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
#if !CH_OPTIMIZE_SPEED || defined(__DOXYGEN__)
|
||||||
|
/**
|
||||||
|
* @brief Inserts a thread into a priority ordered queue.
|
||||||
|
*
|
||||||
|
* @param[in] tp the pointer to the thread to be inserted in the list
|
||||||
|
* @param[in] tqp the pointer to the threads list header
|
||||||
|
* @note The insertion is done by scanning the list from the highest priority
|
||||||
|
* toward the lowest.
|
||||||
|
* @note This function is @b not an API.
|
||||||
|
*/
|
||||||
|
void prio_insert(Thread *tp, ThreadsQueue *tqp) {
|
||||||
|
|
||||||
|
/* cp iterates over the queue */
|
||||||
|
Thread *cp = (Thread *)tqp;
|
||||||
|
do {
|
||||||
|
/* iterate to next thread in queue */
|
||||||
|
cp = cp->p_next;
|
||||||
|
/* not end of queue? and cp has equal or higher priority than tp? */
|
||||||
|
} while ((cp != (Thread *)tqp) && (cp->p_prio >= tp->p_prio));
|
||||||
|
/* insert before cp, point tp to next and prev in queue */
|
||||||
|
tp->p_prev = (tp->p_next = cp)->p_prev;
|
||||||
|
/* make prev point to tp, and cp point back to tp */
|
||||||
|
tp->p_prev->p_next = cp->p_prev = tp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Inserts a Thread into a queue.
|
||||||
|
*
|
||||||
|
* @param[in] tp the pointer to the thread to be inserted in the list
|
||||||
|
* @param[in] tqp the pointer to the threads list header
|
||||||
|
* @note This function is @b not an API.
|
||||||
|
*/
|
||||||
|
void queue_insert(Thread *tp, ThreadsQueue *tqp) {
|
||||||
|
|
||||||
|
tp->p_prev = (tp->p_next = (Thread *)tqp)->p_prev;
|
||||||
|
tp->p_prev->p_next = tqp->p_prev = tp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes the first-out Thread from a queue and returns it.
|
||||||
|
*
|
||||||
|
* @param[in] tqp the pointer to the threads list header
|
||||||
|
* @return The removed thread pointer.
|
||||||
|
* @note This function is @b not an API.
|
||||||
|
*/
|
||||||
|
Thread *fifo_remove(ThreadsQueue *tqp) {
|
||||||
|
Thread *tp = tqp->p_next;
|
||||||
|
|
||||||
|
(tqp->p_next = tp->p_next)->p_prev = (Thread *)tqp;
|
||||||
|
return tp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes the last-out Thread from a queue and returns it.
|
||||||
|
*
|
||||||
|
* @param[in] tqp the pointer to the threads list header
|
||||||
|
* @return The removed thread pointer.
|
||||||
|
* @note This function is @b not an API.
|
||||||
|
*/
|
||||||
|
Thread *lifo_remove(ThreadsQueue *tqp) {
|
||||||
|
Thread *tp = tqp->p_next;
|
||||||
|
|
||||||
|
(tqp->p_next = tp->p_next)->p_prev = (Thread *)tqp;
|
||||||
|
return tp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes a Thread from a queue and returns it.
|
||||||
|
* @details The thread is removed from the queue regardless of its relative
|
||||||
|
* position and regardless the used insertion method.
|
||||||
|
*
|
||||||
|
* @param[in] tp the pointer to the thread to be removed from the queue
|
||||||
|
* @return The removed thread pointer.
|
||||||
|
* @note This function is @b not an API.
|
||||||
|
*/
|
||||||
|
Thread *dequeue(Thread *tp) {
|
||||||
|
|
||||||
|
tp->p_prev->p_next = tp->p_next;
|
||||||
|
tp->p_next->p_prev = tp->p_prev;
|
||||||
|
return tp;
|
||||||
|
}
|
||||||
|
#endif /* CH_OPTIMIZE_SPEED */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,244 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file chmboxes.c
|
||||||
|
* @brief Mailboxes code.
|
||||||
|
* @addtogroup Mailboxes
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
#if CH_USE_MAILBOXES
|
||||||
|
/**
|
||||||
|
* @brief Initializes a Mailbox object.
|
||||||
|
*
|
||||||
|
* @param[out] mbp the pointer to the Mailbox structure to be initialized
|
||||||
|
* @param[in] buf the circular messages buffer
|
||||||
|
* @param[in] n the buffer size as number of @p msg_t
|
||||||
|
*/
|
||||||
|
void chMBInit(Mailbox *mbp, msg_t *buf, cnt_t n) {
|
||||||
|
|
||||||
|
chDbgCheck((mbp != NULL) && (buf != NULL) && (n > 0), "chMBInit");
|
||||||
|
|
||||||
|
mbp->mb_buffer = mbp->mb_wrptr = mbp->mb_rdptr = buf;
|
||||||
|
mbp->mb_top = &buf[n];
|
||||||
|
chSemInit(&mbp->mb_emptysem, n);
|
||||||
|
chSemInit(&mbp->mb_fullsem, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resets a Mailbox object.
|
||||||
|
* @details All the waiting threads are resumed with status @p RDY_RESET and
|
||||||
|
* the queued messages are lost.
|
||||||
|
*
|
||||||
|
* @param[in] mbp the pointer to an initialized Mailbox object
|
||||||
|
*/
|
||||||
|
void chMBReset(Mailbox *mbp) {
|
||||||
|
|
||||||
|
chDbgCheck(mbp != NULL, "chMBReset");
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
mbp->mb_wrptr = mbp->mb_rdptr = mbp->mb_buffer;
|
||||||
|
chSemResetI(&mbp->mb_emptysem, mbp->mb_top - mbp->mb_buffer);
|
||||||
|
chSemResetI(&mbp->mb_fullsem, 0);
|
||||||
|
chSchRescheduleS();
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Posts a message into a mailbox.
|
||||||
|
* @details The invoking thread waits until a empty slot in the mailbox becomes
|
||||||
|
* available or the specified time runs out.
|
||||||
|
*
|
||||||
|
* @param[in] mbp the pointer to an initialized Mailbox object
|
||||||
|
* @param[in] msg the message to be posted on the mailbox
|
||||||
|
* @param[in] time the number of ticks before the operation timeouts,
|
||||||
|
* the following special values are allowed:
|
||||||
|
* - @a TIME_IMMEDIATE immediate timeout.
|
||||||
|
* - @a TIME_INFINITE no timeout.
|
||||||
|
* .
|
||||||
|
* @return The operation status.
|
||||||
|
* @retval RDY_OK if the message was correctly posted.
|
||||||
|
* @retval RDY_RESET if the mailbox was reset while waiting.
|
||||||
|
* @retval RDY_TIMEOUT if the operation timed out.
|
||||||
|
*/
|
||||||
|
msg_t chMBPost(Mailbox *mbp, msg_t msg, systime_t time) {
|
||||||
|
msg_t rdymsg;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
rdymsg = chMBPostS(mbp, msg, time);
|
||||||
|
chSysUnlock();
|
||||||
|
return rdymsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Posts a message into a mailbox.
|
||||||
|
* @details The invoking thread waits until a empty slot in the mailbox becomes
|
||||||
|
* available or the specified time runs out.
|
||||||
|
*
|
||||||
|
* @param[in] mbp the pointer to an initialized Mailbox object
|
||||||
|
* @param[in] msg the message to be posted on the mailbox
|
||||||
|
* @param[in] time the number of ticks before the operation timeouts,
|
||||||
|
* the following special values are allowed:
|
||||||
|
* - @a TIME_IMMEDIATE immediate timeout.
|
||||||
|
* - @a TIME_INFINITE no timeout.
|
||||||
|
* .
|
||||||
|
* @return The operation status.
|
||||||
|
* @retval RDY_OK if the message was correctly posted.
|
||||||
|
* @retval RDY_RESET if the mailbox was reset while waiting.
|
||||||
|
* @retval RDY_TIMEOUT if the operation timed out.
|
||||||
|
*/
|
||||||
|
msg_t chMBPostS(Mailbox *mbp, msg_t msg, systime_t time) {
|
||||||
|
msg_t rdymsg;
|
||||||
|
|
||||||
|
chDbgCheck(mbp != NULL, "chMBPostS");
|
||||||
|
|
||||||
|
rdymsg = chSemWaitTimeoutS(&mbp->mb_emptysem, time);
|
||||||
|
if (rdymsg == RDY_OK) {
|
||||||
|
*mbp->mb_wrptr++ = msg;
|
||||||
|
if (mbp->mb_wrptr >= mbp->mb_top)
|
||||||
|
mbp->mb_wrptr = mbp->mb_buffer;
|
||||||
|
chSemSignalI(&mbp->mb_fullsem);
|
||||||
|
chSchRescheduleS();
|
||||||
|
}
|
||||||
|
return rdymsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Posts an high priority message into a mailbox.
|
||||||
|
* @details The invoking thread waits until a empty slot in the mailbox becomes
|
||||||
|
* available or the specified time runs out.
|
||||||
|
*
|
||||||
|
* @param[in] mbp the pointer to an initialized Mailbox object
|
||||||
|
* @param[in] msg the message to be posted on the mailbox
|
||||||
|
* @param[in] time the number of ticks before the operation timeouts,
|
||||||
|
* the following special values are allowed:
|
||||||
|
* - @a TIME_IMMEDIATE immediate timeout.
|
||||||
|
* - @a TIME_INFINITE no timeout.
|
||||||
|
* .
|
||||||
|
* @return The operation status.
|
||||||
|
* @retval RDY_OK if the message was correctly posted.
|
||||||
|
* @retval RDY_RESET if the mailbox was reset while waiting.
|
||||||
|
* @retval RDY_TIMEOUT if the operation timed out.
|
||||||
|
*/
|
||||||
|
msg_t chMBPostAhead(Mailbox *mbp, msg_t msg, systime_t time) {
|
||||||
|
msg_t rdymsg;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
rdymsg = chMBPostAheadS(mbp, msg, time);
|
||||||
|
chSysUnlock();
|
||||||
|
return rdymsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Posts an high priority message into a mailbox.
|
||||||
|
* @details The invoking thread waits until a empty slot in the mailbox becomes
|
||||||
|
* available or the specified time runs out.
|
||||||
|
*
|
||||||
|
* @param[in] mbp the pointer to an initialized Mailbox object
|
||||||
|
* @param[in] msg the message to be posted on the mailbox
|
||||||
|
* @param[in] time the number of ticks before the operation timeouts,
|
||||||
|
* the following special values are allowed:
|
||||||
|
* - @a TIME_IMMEDIATE immediate timeout.
|
||||||
|
* - @a TIME_INFINITE no timeout.
|
||||||
|
* .
|
||||||
|
* @return The operation status.
|
||||||
|
* @retval RDY_OK if the message was correctly posted.
|
||||||
|
* @retval RDY_RESET if the mailbox was reset while waiting.
|
||||||
|
* @retval RDY_TIMEOUT if the operation timed out.
|
||||||
|
*/
|
||||||
|
msg_t chMBPostAheadS(Mailbox *mbp, msg_t msg, systime_t time) {
|
||||||
|
msg_t rdymsg;
|
||||||
|
|
||||||
|
chDbgCheck(mbp != NULL, "chMBPostAheadS");
|
||||||
|
|
||||||
|
rdymsg = chSemWaitTimeoutS(&mbp->mb_emptysem, time);
|
||||||
|
if (rdymsg == RDY_OK) {
|
||||||
|
if (--mbp->mb_rdptr < mbp->mb_buffer)
|
||||||
|
mbp->mb_rdptr = mbp->mb_top - 1;
|
||||||
|
*mbp->mb_rdptr = msg;
|
||||||
|
chSemSignalI(&mbp->mb_fullsem);
|
||||||
|
chSchRescheduleS();
|
||||||
|
}
|
||||||
|
return rdymsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieves a message from a mailbox.
|
||||||
|
* @details The invoking thread waits until a message is posted in the mailbox
|
||||||
|
* or the specified time runs out.
|
||||||
|
*
|
||||||
|
* @param[in] mbp the pointer to an initialized Mailbox object
|
||||||
|
* @param[out] msgp pointer to a message variable for the received message
|
||||||
|
* @param[in] time the number of ticks before the operation timeouts,
|
||||||
|
* the following special values are allowed:
|
||||||
|
* - @a TIME_IMMEDIATE immediate timeout.
|
||||||
|
* - @a TIME_INFINITE no timeout.
|
||||||
|
* .
|
||||||
|
* @return The operation status.
|
||||||
|
* @retval RDY_OK if a message was correctly fetched.
|
||||||
|
* @retval RDY_RESET if the mailbox was reset while waiting.
|
||||||
|
* @retval RDY_TIMEOUT if the operation timed out.
|
||||||
|
*/
|
||||||
|
msg_t chMBFetch(Mailbox *mbp, msg_t *msgp, systime_t time) {
|
||||||
|
msg_t rdymsg;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
rdymsg = chMBFetchS(mbp, msgp, time);
|
||||||
|
chSysUnlock();
|
||||||
|
return rdymsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieves a message from a mailbox.
|
||||||
|
* @details The invoking thread waits until a message is posted in the mailbox
|
||||||
|
* or the specified time runs out.
|
||||||
|
*
|
||||||
|
* @param[in] mbp the pointer to an initialized Mailbox object
|
||||||
|
* @param[out] msgp pointer to a message variable for the received message
|
||||||
|
* @param[in] time the number of ticks before the operation timeouts,
|
||||||
|
* the following special values are allowed:
|
||||||
|
* - @a TIME_IMMEDIATE immediate timeout.
|
||||||
|
* - @a TIME_INFINITE no timeout.
|
||||||
|
* .
|
||||||
|
* @return The operation status.
|
||||||
|
* @retval RDY_OK if a message was correctly fetched.
|
||||||
|
* @retval RDY_RESET if the mailbox was reset while waiting.
|
||||||
|
* @retval RDY_TIMEOUT if the operation timed out.
|
||||||
|
*/
|
||||||
|
msg_t chMBFetchS(Mailbox *mbp, msg_t *msgp, systime_t time) {
|
||||||
|
msg_t rdymsg;
|
||||||
|
|
||||||
|
chDbgCheck((mbp != NULL) && (msgp != NULL), "chMBFetchS");
|
||||||
|
|
||||||
|
rdymsg = chSemWaitTimeoutS(&mbp->mb_fullsem, time);
|
||||||
|
if (rdymsg == RDY_OK) {
|
||||||
|
*msgp = *mbp->mb_rdptr++;
|
||||||
|
if (mbp->mb_rdptr >= mbp->mb_top)
|
||||||
|
mbp->mb_rdptr = mbp->mb_buffer;
|
||||||
|
chSemSignalI(&mbp->mb_emptysem);
|
||||||
|
chSchRescheduleS();
|
||||||
|
}
|
||||||
|
return rdymsg;
|
||||||
|
}
|
||||||
|
#endif /* CH_USE_MAILBOXES */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file chmempools.c
|
||||||
|
* @brief Memory Pools code.
|
||||||
|
* @addtogroup MemoryPools
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
#if CH_USE_MEMPOOLS
|
||||||
|
/**
|
||||||
|
* @brief Initializes an empty memory pool.
|
||||||
|
*
|
||||||
|
* @param[out] mp pointer to a @p MemoryPool structure
|
||||||
|
* @param[in] size the size of the objects contained in this memory pool,
|
||||||
|
* the minimum accepted size is the size of a pointer to void
|
||||||
|
*/
|
||||||
|
void chPoolInit(MemoryPool *mp, size_t size) {
|
||||||
|
|
||||||
|
chDbgCheck((mp != NULL) && (size >= sizeof(void *)), "chPoolInit");
|
||||||
|
|
||||||
|
mp->mp_next = NULL;
|
||||||
|
mp->mp_object_size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocates an object from a memory pool.
|
||||||
|
*
|
||||||
|
* @param[in] mp pointer to a @p MemoryPool structure
|
||||||
|
* @return The pointer to the allocated object.
|
||||||
|
* @retval NULL if pool is empty.
|
||||||
|
*/
|
||||||
|
void *chPoolAllocI(MemoryPool *mp) {
|
||||||
|
void *objp;
|
||||||
|
|
||||||
|
chDbgCheck(mp != NULL, "chPoolAllocI");
|
||||||
|
|
||||||
|
if ((objp = mp->mp_next) != NULL)
|
||||||
|
mp->mp_next = mp->mp_next->ph_next;
|
||||||
|
|
||||||
|
return objp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocates an object from a memory pool.
|
||||||
|
*
|
||||||
|
* @param[in] mp pointer to a @p MemoryPool structure
|
||||||
|
* @return The pointer to the allocated object.
|
||||||
|
* @retval NULL if pool is empty.
|
||||||
|
*/
|
||||||
|
void *chPoolAlloc(MemoryPool *mp) {
|
||||||
|
void *objp;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
objp = chPoolAllocI(mp);
|
||||||
|
chSysUnlock();
|
||||||
|
return objp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Releases (or adds) an object into (to) a memory pool.
|
||||||
|
*
|
||||||
|
* @param[in] mp pointer to a @p MemoryPool structure
|
||||||
|
* @param[in] objp the pointer to the object to be released or added
|
||||||
|
* @note the object is assumed to be of the right size for the specified
|
||||||
|
* memory pool.
|
||||||
|
*/
|
||||||
|
void chPoolFreeI(MemoryPool *mp, void *objp) {
|
||||||
|
struct pool_header *php = objp;
|
||||||
|
|
||||||
|
chDbgCheck((mp != NULL) && (objp != NULL), "chPoolFreeI");
|
||||||
|
|
||||||
|
php->ph_next = mp->mp_next;
|
||||||
|
mp->mp_next = php;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Releases (or adds) an object into (to) a memory pool.
|
||||||
|
*
|
||||||
|
* @param[in] mp pointer to a @p MemoryPool structure
|
||||||
|
* @param[in] objp the pointer to the object to be released or added
|
||||||
|
* @note the object is assumed to be of the right size for the specified
|
||||||
|
* memory pool.
|
||||||
|
*/
|
||||||
|
void chPoolFree(MemoryPool *mp, void *objp) {
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
chPoolFreeI(mp, objp);
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
#endif /* CH_USE_MEMPOOLS */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file chmsg.c
|
||||||
|
* @brief Messages code.
|
||||||
|
* @addtogroup Messages
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
#if CH_USE_MESSAGES
|
||||||
|
|
||||||
|
#if CH_USE_MESSAGES_PRIORITY
|
||||||
|
#define msg_insert(tp, qp) prio_insert(tp, qp)
|
||||||
|
#else
|
||||||
|
#define msg_insert(tp, qp) queue_insert(tp, qp)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sends a message to the specified thread.
|
||||||
|
* @details The sender is stopped until the receiver executes a
|
||||||
|
* @p chMsgRelease()after receiving the message.
|
||||||
|
*
|
||||||
|
* @param[in] tp the pointer to the thread
|
||||||
|
* @param[in] msg the message
|
||||||
|
* @return The return message from @p chMsgRelease().
|
||||||
|
*/
|
||||||
|
msg_t chMsgSend(Thread *tp, msg_t msg) {
|
||||||
|
|
||||||
|
chDbgCheck(tp != NULL, "chMsgSend");
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
msg_insert(currp, &tp->p_msgqueue);
|
||||||
|
currp->p_msg = msg;
|
||||||
|
currp->p_wtthdp = tp;
|
||||||
|
if (tp->p_state == PRWTMSG)
|
||||||
|
chSchReadyI(tp);
|
||||||
|
chSchGoSleepS(PRSNDMSG);
|
||||||
|
msg = currp->p_rdymsg;
|
||||||
|
chSysUnlock();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Suspends the thread and waits for an incoming message.
|
||||||
|
*
|
||||||
|
* @return The pointer to the message structure. Note, it is always the
|
||||||
|
* message associated to the thread on the top of the messages queue.
|
||||||
|
* @note You can assume that the data contained in the message is stable until
|
||||||
|
* you invoke @p chMsgRelease() because the sending thread is
|
||||||
|
* suspended until then.
|
||||||
|
*/
|
||||||
|
msg_t chMsgWait(void) {
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
if (!chMsgIsPendingI(currp))
|
||||||
|
chSchGoSleepS(PRWTMSG);
|
||||||
|
msg = chMsgGetI(currp);
|
||||||
|
chSysUnlock();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the next message in the queue.
|
||||||
|
*
|
||||||
|
* @return The pointer to the message structure. Note, it is always the
|
||||||
|
* message associated to the thread on the top of the messages queue.
|
||||||
|
* If the queue is empty then @p NULL is returned.
|
||||||
|
* @note You can assume that the data pointed by the message is stable until
|
||||||
|
* you invoke @p chMsgRelease() because the sending thread is
|
||||||
|
* suspended until then. Always remember that the message data is not
|
||||||
|
* copied between the sender and the receiver, just a pointer is passed.
|
||||||
|
*/
|
||||||
|
msg_t chMsgGet(void) {
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
msg = chMsgIsPendingI(currp) ? chMsgGetI(currp) : (msg_t)NULL;
|
||||||
|
chSysUnlock();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Releases the thread waiting on top of the messages queue.
|
||||||
|
*
|
||||||
|
* @param[in] msg the message returned to the message sender
|
||||||
|
* @note You can call this function only if there is a message already in the
|
||||||
|
* queue else the result will be unpredictable (a crash most likely).
|
||||||
|
* Exiting from the @p chMsgWait() ensures you have at least one
|
||||||
|
* message in the queue so it is not a big deal.<br>
|
||||||
|
* The condition is only tested in debug mode in order to make this code
|
||||||
|
* as fast as possible.
|
||||||
|
*/
|
||||||
|
void chMsgRelease(msg_t msg) {
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
chDbgAssert(chMsgIsPendingI(currp),
|
||||||
|
"chMsgRelease(), #1",
|
||||||
|
"no message pending");
|
||||||
|
chSchWakeupS(fifo_remove(&currp->p_msgqueue), msg);
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CH_USE_MESSAGES */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,299 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file chmtx.c
|
||||||
|
* @brief Mutexes code.
|
||||||
|
* @addtogroup Mutexes
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
#if CH_USE_MUTEXES
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes s @p Mutex structure.
|
||||||
|
*
|
||||||
|
* @param[out] mp pointer to a @p Mutex structure
|
||||||
|
* @note This function can be invoked from within an interrupt handler even if
|
||||||
|
* it is not an I-Class API because it does not touch any critical kernel
|
||||||
|
* data structure.
|
||||||
|
*/
|
||||||
|
void chMtxInit(Mutex *mp) {
|
||||||
|
|
||||||
|
chDbgCheck(mp != NULL, "chMtxInit");
|
||||||
|
|
||||||
|
queue_init(&mp->m_queue);
|
||||||
|
mp->m_owner = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Locks the specified mutex.
|
||||||
|
*
|
||||||
|
* @param[in] mp pointer to the @p Mutex structure
|
||||||
|
*/
|
||||||
|
void chMtxLock(Mutex *mp) {
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
|
||||||
|
chMtxLockS(mp);
|
||||||
|
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Locks the specified mutex.
|
||||||
|
*
|
||||||
|
* @param[in] mp pointer to the @p Mutex structure
|
||||||
|
* @note This function must be called within a @p chSysLock() / @p chSysUnlock()
|
||||||
|
* block.
|
||||||
|
*/
|
||||||
|
void chMtxLockS(Mutex *mp) {
|
||||||
|
|
||||||
|
chDbgCheck(mp != NULL, "chMtxLockS");
|
||||||
|
|
||||||
|
/* the mutex is already locked? */
|
||||||
|
if (mp->m_owner != NULL) {
|
||||||
|
/*
|
||||||
|
* Priority inheritance protocol; explores the thread-mutex dependencies
|
||||||
|
* boosting the priority of all the affected threads to equal the priority
|
||||||
|
* of the running thread requesting the mutex.
|
||||||
|
*/
|
||||||
|
Thread *tp = mp->m_owner;
|
||||||
|
/* { tp is the thread currently owning the mutex } */
|
||||||
|
/* the running thread has higher priority than tp? */
|
||||||
|
while (tp->p_prio < currp->p_prio) {
|
||||||
|
/* make priority of thread tp match the running thread's priority */
|
||||||
|
tp->p_prio = currp->p_prio;
|
||||||
|
/*
|
||||||
|
* The following states need priority queues reordering.
|
||||||
|
*/
|
||||||
|
switch (tp->p_state) {
|
||||||
|
/* thread tp is waiting on a mutex? */
|
||||||
|
case PRWTMTX:
|
||||||
|
/* Requeues tp with its new priority on the mutex wait queue. */
|
||||||
|
prio_insert(dequeue(tp), &tp->p_wtmtxp->m_queue);
|
||||||
|
/* boost the owner of this mutex if needed */
|
||||||
|
tp = tp->p_wtmtxp->m_owner;
|
||||||
|
continue;
|
||||||
|
#if CH_USE_CONDVARS
|
||||||
|
case PRWTCOND:
|
||||||
|
/* Requeues tp with its new priority on the condvar queue. */
|
||||||
|
prio_insert(dequeue(tp), &tp->p_wtcondp->c_queue);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if CH_USE_SEMAPHORES_PRIORITY
|
||||||
|
case PRWTSEM:
|
||||||
|
/* Requeues tp with its new priority on the semaphore queue. */
|
||||||
|
prio_insert(dequeue(tp), &tp->p_wtsemp->s_queue);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if CH_USE_MESSAGES_PRIORITY
|
||||||
|
case PRSNDMSG:
|
||||||
|
/* Requeues tp with its new priority on the server thread queue. */
|
||||||
|
prio_insert(dequeue(tp), &tp->p_wtthdp->p_msgqueue);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
/* thread tp is ready? */
|
||||||
|
case PRREADY:
|
||||||
|
/* Requeue tp with its new priority on the ready list. */
|
||||||
|
chSchReadyI(dequeue(tp));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* sleep on the mutex */
|
||||||
|
prio_insert(currp, &mp->m_queue);
|
||||||
|
/* thread remembers the mutex where it is waiting on */
|
||||||
|
currp->p_wtmtxp = mp;
|
||||||
|
chSchGoSleepS(PRWTMTX);
|
||||||
|
chDbgAssert(mp->m_owner == NULL, "chMtxLockS(), #1", "still owned");
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* The mutex is now inserted in the owned mutexes list.
|
||||||
|
*/
|
||||||
|
mp->m_owner = currp;
|
||||||
|
mp->m_next = currp->p_mtxlist;
|
||||||
|
currp->p_mtxlist = mp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tries to lock a mutex.
|
||||||
|
* @details This function does not have any overhead related to
|
||||||
|
* the priority inheritance mechanism because it does not try to
|
||||||
|
* enter a sleep state on the mutex.
|
||||||
|
*
|
||||||
|
* @param[in] mp pointer to the @p Mutex structure
|
||||||
|
* @retval TRUE if the mutex was successfully acquired
|
||||||
|
* @retval FALSE if the lock attempt failed.
|
||||||
|
*/
|
||||||
|
bool_t chMtxTryLock(Mutex *mp) {
|
||||||
|
bool_t b;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
|
||||||
|
b = chMtxTryLockS(mp);
|
||||||
|
|
||||||
|
chSysUnlock();
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tries to lock a mutex.
|
||||||
|
* @details This function does not have any overhead related to
|
||||||
|
* the priority inheritance mechanism because it does not try to
|
||||||
|
* enter a sleep state on the mutex.
|
||||||
|
* @param[in] mp pointer to the @p Mutex structure
|
||||||
|
* @retval TRUE if the mutex was successfully acquired
|
||||||
|
* @retval FALSE if the lock attempt failed.
|
||||||
|
* @note This function must be called within a @p chSysLock() / @p chSysUnlock()
|
||||||
|
* block.
|
||||||
|
*/
|
||||||
|
bool_t chMtxTryLockS(Mutex *mp) {
|
||||||
|
|
||||||
|
chDbgCheck(mp != NULL, "chMtxTryLockS");
|
||||||
|
|
||||||
|
if (mp->m_owner != NULL)
|
||||||
|
return FALSE;
|
||||||
|
mp->m_owner = currp;
|
||||||
|
mp->m_next = currp->p_mtxlist;
|
||||||
|
currp->p_mtxlist = mp;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unlocks the next owned mutex in reverse lock order.
|
||||||
|
*
|
||||||
|
* @return The pointer to the unlocked mutex.
|
||||||
|
*/
|
||||||
|
Mutex *chMtxUnlock(void) {
|
||||||
|
Mutex *ump, *mp;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
chDbgAssert(currp->p_mtxlist != NULL,
|
||||||
|
"chMtxUnlock(), #1",
|
||||||
|
"owned mutexes list empty");
|
||||||
|
chDbgAssert(currp->p_mtxlist->m_owner == currp,
|
||||||
|
"chMtxUnlock(), #2",
|
||||||
|
"ownership failure");
|
||||||
|
/* remove the top Mutex from the Threads's owned mutexes list */
|
||||||
|
ump = currp->p_mtxlist;
|
||||||
|
currp->p_mtxlist = ump->m_next;
|
||||||
|
/* mark the Mutex as not owned */
|
||||||
|
ump->m_owner = NULL;
|
||||||
|
/*
|
||||||
|
* If a thread is waiting on the mutex then the hard part begins.
|
||||||
|
*/
|
||||||
|
if (chMtxQueueNotEmptyS(ump)) {
|
||||||
|
/* get the highest priority thread waiting for the unlocked mutex */
|
||||||
|
Thread *tp = fifo_remove(&ump->m_queue);
|
||||||
|
/*
|
||||||
|
* Recalculates the optimal thread priority by scanning the owned mutexes list.
|
||||||
|
*/
|
||||||
|
tprio_t newprio = currp->p_realprio;
|
||||||
|
/* iterate mp over all the (other) mutexes the current thread still owns */
|
||||||
|
mp = currp->p_mtxlist;
|
||||||
|
while (mp != NULL) {
|
||||||
|
/* mutex mp has a higher priority thread pending? */
|
||||||
|
if (chMtxQueueNotEmptyS(mp) && (mp->m_queue.p_next->p_prio > newprio))
|
||||||
|
/* boost current thread's priority to waiting thread */
|
||||||
|
newprio = mp->m_queue.p_next->p_prio;
|
||||||
|
mp = mp->m_next;
|
||||||
|
}
|
||||||
|
/* (possibly) boost the priority of the current thread */
|
||||||
|
currp->p_prio = newprio;
|
||||||
|
/* awaken the highest priority thread waiting for the unlocked mutex */
|
||||||
|
chSchWakeupS(tp, RDY_OK);
|
||||||
|
}
|
||||||
|
chSysUnlock();
|
||||||
|
return ump;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unlocks the next owned mutex in reverse lock order.
|
||||||
|
*
|
||||||
|
* @return The pointer to the unlocked mutex.
|
||||||
|
* @note This function must be called within a @p chSysLock() / @p chSysUnlock()
|
||||||
|
* block.
|
||||||
|
* @note This function does not reschedule internally.
|
||||||
|
*/
|
||||||
|
Mutex *chMtxUnlockS(void) {
|
||||||
|
Mutex *ump, *mp;
|
||||||
|
|
||||||
|
chDbgAssert(currp->p_mtxlist != NULL,
|
||||||
|
"chMtxUnlockS(), #1",
|
||||||
|
"owned mutexes list empty");
|
||||||
|
chDbgAssert(currp->p_mtxlist->m_owner == currp,
|
||||||
|
"chMtxUnlockS(), #2",
|
||||||
|
"ownership failure");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Removes the top Mutex from the owned mutexes list and marks it as not owned.
|
||||||
|
*/
|
||||||
|
ump = currp->p_mtxlist;
|
||||||
|
currp->p_mtxlist = ump->m_next;
|
||||||
|
ump->m_owner = NULL;
|
||||||
|
/*
|
||||||
|
* If a thread is waiting on the mutex then the hard part begins.
|
||||||
|
*/
|
||||||
|
if (chMtxQueueNotEmptyS(ump)) {
|
||||||
|
Thread *tp = fifo_remove(&ump->m_queue);
|
||||||
|
/*
|
||||||
|
* Recalculates the optimal thread priority by scanning the owned mutexes list.
|
||||||
|
*/
|
||||||
|
tprio_t newprio = currp->p_realprio;
|
||||||
|
mp = currp->p_mtxlist;
|
||||||
|
while (mp != NULL) {
|
||||||
|
if (chMtxQueueNotEmptyS(mp) && (mp->m_queue.p_next->p_prio > newprio))
|
||||||
|
newprio = mp->m_queue.p_next->p_prio;
|
||||||
|
mp = mp->m_next;
|
||||||
|
}
|
||||||
|
currp->p_prio = newprio;
|
||||||
|
chSchReadyI(tp);
|
||||||
|
}
|
||||||
|
return ump;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unlocks all the mutexes owned by the invoking thread.
|
||||||
|
* @details This function is <b>MUCH MORE</b> efficient than releasing the
|
||||||
|
* mutexes one by one and not just because the call overhead,
|
||||||
|
* this function does not have any overhead related to the priority
|
||||||
|
* inheritance mechanism.
|
||||||
|
*/
|
||||||
|
void chMtxUnlockAll(void) {
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
if (currp->p_mtxlist != NULL) {
|
||||||
|
do {
|
||||||
|
Mutex *mp = currp->p_mtxlist;
|
||||||
|
currp->p_mtxlist = mp->m_next;
|
||||||
|
mp->m_owner = NULL;
|
||||||
|
if (chMtxQueueNotEmptyS(mp))
|
||||||
|
chSchReadyI(fifo_remove(&mp->m_queue));
|
||||||
|
} while (currp->p_mtxlist != NULL);
|
||||||
|
currp->p_prio = currp->p_realprio;
|
||||||
|
chSchRescheduleS();
|
||||||
|
}
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CH_USE_MUTEXES */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,304 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file chqueues.c
|
||||||
|
* @brief I/O Queues code.
|
||||||
|
* @addtogroup IOQueues
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
#if CH_USE_QUEUES
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes an input queue.
|
||||||
|
* @details A Semaphore is internally initialized and works as a counter of
|
||||||
|
* the bytes contained in the queue.
|
||||||
|
*
|
||||||
|
* @param[out] iqp pointer to an @p InputQueue structure
|
||||||
|
* @param[in] buffer pointer to a memory area allocated as queue buffer
|
||||||
|
* @param[in] size size of the queue buffer
|
||||||
|
* @param[in] inotify pointer to a callback function that is invoked when
|
||||||
|
* some data is read from the queue. The value can be
|
||||||
|
* @p NULL.
|
||||||
|
*
|
||||||
|
* @note The callback is invoked from within the S-Locked system state,
|
||||||
|
* see @ref system_states.
|
||||||
|
*/
|
||||||
|
void chIQInit(InputQueue *iqp, uint8_t *buffer,
|
||||||
|
size_t size, qnotify_t inotify) {
|
||||||
|
|
||||||
|
iqp->q_buffer = iqp->q_rdptr = iqp->q_wrptr = buffer;
|
||||||
|
iqp->q_top = buffer + size;
|
||||||
|
chSemInit(&iqp->q_sem, 0);
|
||||||
|
iqp->q_notify = inotify;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resets an input queue.
|
||||||
|
* @details All the data in the input queue is erased and lost, any waiting
|
||||||
|
* thread is resumed with status @p Q_RESET.
|
||||||
|
*
|
||||||
|
* @param[in] iqp pointer to an @p InputQueue structure
|
||||||
|
*
|
||||||
|
* @note A reset operation can be used by a low level driver in order to obtain
|
||||||
|
* immediate attention from the high level layers.
|
||||||
|
*/
|
||||||
|
void chIQResetI(InputQueue *iqp) {
|
||||||
|
|
||||||
|
iqp->q_rdptr = iqp->q_wrptr = iqp->q_buffer;
|
||||||
|
chSemResetI(&iqp->q_sem, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Input queue write.
|
||||||
|
* @details A byte value is written into the low end of an input queue.
|
||||||
|
*
|
||||||
|
* @param[in] iqp pointer to an @p InputQueue structure
|
||||||
|
* @param[in] b the byte value to be written in the queue
|
||||||
|
* @return The operation status, it can be one of:
|
||||||
|
* @retval Q_OK if the operation has been completed with success.
|
||||||
|
* @retval Q_FULL if the queue is full and the operation cannot be completed.
|
||||||
|
*/
|
||||||
|
msg_t chIQPutI(InputQueue *iqp, uint8_t b) {
|
||||||
|
|
||||||
|
if (chIQIsFull(iqp))
|
||||||
|
return Q_FULL;
|
||||||
|
|
||||||
|
*iqp->q_wrptr++ = b;
|
||||||
|
if (iqp->q_wrptr >= iqp->q_top)
|
||||||
|
iqp->q_wrptr = iqp->q_buffer;
|
||||||
|
chSemSignalI(&iqp->q_sem);
|
||||||
|
return Q_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Input queue read with timeout.
|
||||||
|
* @details This function reads a byte value from an input queue. If the queue
|
||||||
|
* is empty then the calling thread is suspended until a byte arrives
|
||||||
|
* in the queue or a timeout occurs.
|
||||||
|
*
|
||||||
|
* @param[in] iqp pointer to an @p InputQueue structure
|
||||||
|
* @param[in] timeout the number of ticks before the operation timeouts,
|
||||||
|
* the following special values are allowed:
|
||||||
|
* - @a TIME_IMMEDIATE immediate timeout.
|
||||||
|
* - @a TIME_INFINITE no timeout.
|
||||||
|
* .
|
||||||
|
* @return A byte value from the queue or:
|
||||||
|
* @retval Q_TIMEOUT if the specified time expired.
|
||||||
|
* @retval Q_RESET if the queue was reset.
|
||||||
|
*/
|
||||||
|
msg_t chIQGetTimeout(InputQueue *iqp, systime_t timeout) {
|
||||||
|
uint8_t b;
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
if ((msg = chSemWaitTimeoutS(&iqp->q_sem, timeout)) < RDY_OK) {
|
||||||
|
chSysUnlock();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
b = *iqp->q_rdptr++;
|
||||||
|
if (iqp->q_rdptr >= iqp->q_top)
|
||||||
|
iqp->q_rdptr = iqp->q_buffer;
|
||||||
|
|
||||||
|
if (iqp->q_notify)
|
||||||
|
iqp->q_notify();
|
||||||
|
|
||||||
|
chSysUnlock();
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Non-blocking read.
|
||||||
|
* @details The function reads data from an input queue into a buffer. The
|
||||||
|
* transfer is non-blocking and can return zero if the queue is
|
||||||
|
* empty.
|
||||||
|
*
|
||||||
|
* @param[in] iqp pointer to an @p InputQueue structure
|
||||||
|
* @param[out] buffer pointer to the buffer where the input data is copied
|
||||||
|
* @param[in] n the maximum amount of data to be transferred
|
||||||
|
* @return The number of bytes transferred.
|
||||||
|
*
|
||||||
|
* @note The function is not atomic, if you need atomicity it is suggested
|
||||||
|
* to use a semaphore or a mutex for mutual exclusion.
|
||||||
|
*/
|
||||||
|
size_t chIQRead(InputQueue *iqp, uint8_t *buffer, size_t n) {
|
||||||
|
size_t r = 0;
|
||||||
|
|
||||||
|
while (n--) {
|
||||||
|
chSysLock();
|
||||||
|
if (chIQIsEmpty(iqp)) {
|
||||||
|
chSysUnlock();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
chSemFastWaitI(&iqp->q_sem);
|
||||||
|
*buffer++ = *iqp->q_rdptr++;
|
||||||
|
if (iqp->q_rdptr >= iqp->q_top)
|
||||||
|
iqp->q_rdptr = iqp->q_buffer;
|
||||||
|
chSysUnlock();
|
||||||
|
r++;
|
||||||
|
}
|
||||||
|
if (r && iqp->q_notify) {
|
||||||
|
chSysLock();
|
||||||
|
iqp->q_notify();
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes an output queue.
|
||||||
|
* @details A Semaphore is internally initialized and works as a counter of
|
||||||
|
* the free bytes in the queue.
|
||||||
|
*
|
||||||
|
* @param[out] oqp pointer to an @p OutputQueue structure
|
||||||
|
* @param[in] buffer pointer to a memory area allocated as queue buffer
|
||||||
|
* @param[in] size size of the queue buffer
|
||||||
|
* @param[in] onotify pointer to a callback function that is invoked when
|
||||||
|
* some data is written to the queue. The value can be
|
||||||
|
* @p NULL.
|
||||||
|
*
|
||||||
|
* @note The callback is invoked from within the S-Locked system state,
|
||||||
|
* see @ref system_states.
|
||||||
|
*/
|
||||||
|
void chOQInit(OutputQueue *oqp, uint8_t *buffer,
|
||||||
|
size_t size, qnotify_t onotify) {
|
||||||
|
|
||||||
|
oqp->q_buffer = oqp->q_rdptr = oqp->q_wrptr = buffer;
|
||||||
|
oqp->q_top = buffer + size;
|
||||||
|
chSemInit(&oqp->q_sem, size);
|
||||||
|
oqp->q_notify = onotify;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resets an output queue.
|
||||||
|
* @details All the data in the output queue is erased and lost, any waiting
|
||||||
|
* thread is resumed with status @p Q_RESET.
|
||||||
|
*
|
||||||
|
* @param[in] oqp pointer to an @p OutputQueue structure
|
||||||
|
*
|
||||||
|
* @note A reset operation can be used by a low level driver in order to obtain
|
||||||
|
* immediate attention from the high level layers.
|
||||||
|
*/
|
||||||
|
void chOQResetI(OutputQueue *oqp) {
|
||||||
|
|
||||||
|
oqp->q_rdptr = oqp->q_wrptr = oqp->q_buffer;
|
||||||
|
chSemResetI(&oqp->q_sem, (cnt_t)(oqp->q_top - oqp->q_buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Output queue write with timeout.
|
||||||
|
* @details This function writes a byte value to an output queue. If the queue
|
||||||
|
* is full then the calling thread is suspended until there is space
|
||||||
|
* in the queue or a timeout occurs.
|
||||||
|
*
|
||||||
|
* @param[in] oqp pointer to an @p OutputQueue structure
|
||||||
|
* @param[in] b the byte value to be written in the queue
|
||||||
|
* @param[in] timeout the number of ticks before the operation timeouts,
|
||||||
|
* the following special values are allowed:
|
||||||
|
* - @a TIME_IMMEDIATE immediate timeout.
|
||||||
|
* - @a TIME_INFINITE no timeout.
|
||||||
|
* .
|
||||||
|
* @return The operation status:
|
||||||
|
* @retval Q_OK if the operation succeeded.
|
||||||
|
* @retval Q_TIMEOUT if the specified time expired.
|
||||||
|
* @retval Q_RESET if the queue was reset.
|
||||||
|
*/
|
||||||
|
msg_t chOQPutTimeout(OutputQueue *oqp, uint8_t b, systime_t timeout) {
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
if ((msg = chSemWaitTimeoutS(&oqp->q_sem, timeout)) < RDY_OK) {
|
||||||
|
chSysUnlock();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
*oqp->q_wrptr++ = b;
|
||||||
|
if (oqp->q_wrptr >= oqp->q_top)
|
||||||
|
oqp->q_wrptr = oqp->q_buffer;
|
||||||
|
|
||||||
|
if (oqp->q_notify)
|
||||||
|
oqp->q_notify();
|
||||||
|
|
||||||
|
chSysUnlock();
|
||||||
|
return Q_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Output queue read.
|
||||||
|
* @details A byte value is read from the low end of an output queue.
|
||||||
|
*
|
||||||
|
* @param[in] oqp pointer to an @p OutputQueue structure
|
||||||
|
* @return The byte value from the queue or:
|
||||||
|
* @retval Q_EMPTY if the queue is empty.
|
||||||
|
*/
|
||||||
|
msg_t chOQGetI(OutputQueue *oqp) {
|
||||||
|
uint8_t b;
|
||||||
|
|
||||||
|
if (chOQIsEmpty(oqp))
|
||||||
|
return Q_EMPTY;
|
||||||
|
|
||||||
|
b = *oqp->q_rdptr++;
|
||||||
|
if (oqp->q_rdptr >= oqp->q_top)
|
||||||
|
oqp->q_rdptr = oqp->q_buffer;
|
||||||
|
chSemSignalI(&oqp->q_sem);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Non-blocking write.
|
||||||
|
* @details The function writes data from a buffer to an output queue. The
|
||||||
|
* transfer is non-blocking and can return zero if the queue is
|
||||||
|
* already full.
|
||||||
|
*
|
||||||
|
* @param[in] oqp pointer to an @p OutputQueue structure
|
||||||
|
* @param[out] buffer pointer to the buffer where the output data is stored
|
||||||
|
* @param[in] n the maximum amount of data to be transferred
|
||||||
|
* @return The number of bytes transferred.
|
||||||
|
*
|
||||||
|
* @note The function is not atomic, if you need atomicity it is suggested
|
||||||
|
* to use a semaphore or a mutex for mutual exclusion.
|
||||||
|
*/
|
||||||
|
size_t chOQWrite(OutputQueue *oqp, uint8_t *buffer, size_t n) {
|
||||||
|
|
||||||
|
size_t w = 0;
|
||||||
|
while (n--) {
|
||||||
|
chSysLock();
|
||||||
|
if (chOQIsFull(oqp)) {
|
||||||
|
chSysUnlock();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
chSemFastWaitI(&oqp->q_sem);
|
||||||
|
*oqp->q_wrptr++ = *buffer++;
|
||||||
|
if (oqp->q_wrptr >= oqp->q_top)
|
||||||
|
oqp->q_wrptr = oqp->q_buffer;
|
||||||
|
chSysUnlock();
|
||||||
|
w++;
|
||||||
|
}
|
||||||
|
if (w && oqp->q_notify) {
|
||||||
|
chSysLock();
|
||||||
|
oqp->q_notify();
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
#endif /* CH_USE_QUEUES */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,242 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file chschd.c
|
||||||
|
* @brief Scheduler code.
|
||||||
|
* @addtogroup Scheduler
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
/** @cond never */
|
||||||
|
ReadyList rlist;
|
||||||
|
/** @endcond */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Scheduler initialization.
|
||||||
|
*
|
||||||
|
* @note Internally invoked by the @p chSysInit().
|
||||||
|
*/
|
||||||
|
void scheduler_init(void) {
|
||||||
|
|
||||||
|
queue_init(&rlist);
|
||||||
|
rlist.r_prio = NOPRIO;
|
||||||
|
#if CH_USE_ROUNDROBIN
|
||||||
|
rlist.r_preempt = CH_TIME_QUANTUM;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Inserts a thread in the Ready List.
|
||||||
|
*
|
||||||
|
* @param[in] tp the Thread to be made ready
|
||||||
|
* @return The Thread pointer.
|
||||||
|
* @note The function does not reschedule, the @p chSchRescheduleS() should
|
||||||
|
* be called soon after.
|
||||||
|
*/
|
||||||
|
#if CH_OPTIMIZE_SPEED
|
||||||
|
/* NOTE: it is inlined in this module only.*/
|
||||||
|
INLINE Thread *chSchReadyI(Thread *tp) {
|
||||||
|
#else
|
||||||
|
Thread *chSchReadyI(Thread *tp) {
|
||||||
|
#endif
|
||||||
|
Thread *cp;
|
||||||
|
|
||||||
|
tp->p_state = PRREADY;
|
||||||
|
cp = (Thread *)&rlist;
|
||||||
|
do {
|
||||||
|
cp = cp->p_next;
|
||||||
|
} while (cp->p_prio >= tp->p_prio);
|
||||||
|
/* Insertion on p_prev.*/
|
||||||
|
tp->p_prev = (tp->p_next = cp)->p_prev;
|
||||||
|
tp->p_prev->p_next = cp->p_prev = tp;
|
||||||
|
return tp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Puts the current thread to sleep into the specified state.
|
||||||
|
* @details The thread goes into a sleeping state. The @ref thread_states are
|
||||||
|
* described into @p threads.h.
|
||||||
|
*
|
||||||
|
* @param[in] newstate the new thread state
|
||||||
|
*/
|
||||||
|
void chSchGoSleepS(tstate_t newstate) {
|
||||||
|
Thread *otp;
|
||||||
|
|
||||||
|
(otp = currp)->p_state = newstate;
|
||||||
|
(currp = fifo_remove((void *)&rlist))->p_state = PRCURR;
|
||||||
|
#if CH_USE_ROUNDROBIN
|
||||||
|
rlist.r_preempt = CH_TIME_QUANTUM;
|
||||||
|
#endif
|
||||||
|
chDbgTrace(otp, currp);
|
||||||
|
chSysSwitchI(otp, currp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Timeout wakeup callback.
|
||||||
|
*/
|
||||||
|
static void wakeup(void *p) {
|
||||||
|
Thread *tp = (Thread *)p;
|
||||||
|
|
||||||
|
#if CH_USE_SEMAPHORES || CH_USE_MUTEXES || CH_USE_CONDVARS
|
||||||
|
switch (tp->p_state) {
|
||||||
|
#if CH_USE_SEMAPHORES
|
||||||
|
case PRWTSEM:
|
||||||
|
chSemFastSignalI(tp->p_wtsemp);
|
||||||
|
/* Falls into, intentional. */
|
||||||
|
#endif
|
||||||
|
#if CH_USE_MUTEXES
|
||||||
|
case PRWTMTX:
|
||||||
|
#endif
|
||||||
|
#if CH_USE_CONDVARS
|
||||||
|
case PRWTCOND:
|
||||||
|
#endif
|
||||||
|
/* States requiring dequeuing. */
|
||||||
|
dequeue(tp);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
chSchReadyI(tp)->p_rdymsg = RDY_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Puts the current thread to sleep into the specified state with
|
||||||
|
* timeout specification.
|
||||||
|
* @details The thread goes into a sleeping state, if it is not awakened
|
||||||
|
* explicitly within the specified timeout then it is forcibly
|
||||||
|
* awakened with a @p RDY_TIMEOUT low level message. The @ref
|
||||||
|
* thread_states are described into @p threads.h.
|
||||||
|
*
|
||||||
|
* @param[in] newstate the new thread state
|
||||||
|
* @param[in] time the number of ticks before the operation timeouts, the
|
||||||
|
* special values are handled as follow:
|
||||||
|
* - @a TIME_INFINITE the thread enters an infinite sleep
|
||||||
|
* state, this is equivalent to invoking @p chSchGoSleepS()
|
||||||
|
* but, of course, less efficient.
|
||||||
|
* - @a TIME_IMMEDIATE this value is accepted but interpreted
|
||||||
|
* as a normal time specification not as an immediate timeout
|
||||||
|
* specification.
|
||||||
|
* .
|
||||||
|
* @return The wakeup message.
|
||||||
|
* @retval RDY_TIMEOUT if a timeout occurs.
|
||||||
|
*/
|
||||||
|
msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time) {
|
||||||
|
|
||||||
|
if (TIME_INFINITE != time) {
|
||||||
|
VirtualTimer vt;
|
||||||
|
|
||||||
|
chVTSetI(&vt, time, wakeup, currp);
|
||||||
|
chSchGoSleepS(newstate);
|
||||||
|
if (chVTIsArmedI(&vt))
|
||||||
|
chVTResetI(&vt);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
chSchGoSleepS(newstate);
|
||||||
|
return currp->p_rdymsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wakes up a thread.
|
||||||
|
* @details The thread is inserted into the ready list or immediately made
|
||||||
|
* running depending on its relative priority compared to the current
|
||||||
|
* thread.
|
||||||
|
*
|
||||||
|
* @param[in] ntp the Thread to be made ready
|
||||||
|
* @param[in] msg message to the awakened thread
|
||||||
|
* @note It is equivalent to a @p chSchReadyI() followed by a
|
||||||
|
* @p chSchRescheduleS() but much more efficient.
|
||||||
|
*/
|
||||||
|
void chSchWakeupS(Thread *ntp, msg_t msg) {
|
||||||
|
|
||||||
|
ntp->p_rdymsg = msg;
|
||||||
|
/* If the waken thread has a not-greater priority than the current
|
||||||
|
* one then it is just inserted in the ready list else it made
|
||||||
|
* running immediately and the invoking thread goes in the ready
|
||||||
|
* list instead.*/
|
||||||
|
if (ntp->p_prio <= currp->p_prio)
|
||||||
|
chSchReadyI(ntp);
|
||||||
|
else {
|
||||||
|
Thread *otp = currp;
|
||||||
|
chSchReadyI(otp);
|
||||||
|
(currp = ntp)->p_state = PRCURR;
|
||||||
|
#if CH_USE_ROUNDROBIN
|
||||||
|
rlist.r_preempt = CH_TIME_QUANTUM;
|
||||||
|
#endif
|
||||||
|
chDbgTrace(otp, ntp);
|
||||||
|
chSysSwitchI(otp, ntp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Switches to the first thread on the runnable queue.
|
||||||
|
*
|
||||||
|
* @note It is intended to be called if @p chSchRescRequiredI() evaluates to
|
||||||
|
* @p TRUE.
|
||||||
|
*/
|
||||||
|
void chSchDoRescheduleI(void) {
|
||||||
|
|
||||||
|
Thread *otp = currp;
|
||||||
|
/* pick the first thread from the ready queue and makes it current */
|
||||||
|
(currp = fifo_remove((void *)&rlist))->p_state = PRCURR;
|
||||||
|
chSchReadyI(otp);
|
||||||
|
#if CH_USE_ROUNDROBIN
|
||||||
|
rlist.r_preempt = CH_TIME_QUANTUM;
|
||||||
|
#endif
|
||||||
|
chDbgTrace(otp, currp);
|
||||||
|
chSysSwitchI(otp, currp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Performs a reschedulation if a higher priority thread is runnable.
|
||||||
|
* @details If a thread with a higher priority than the current thread is in
|
||||||
|
* the ready list then make the higher priority thread running.
|
||||||
|
*/
|
||||||
|
void chSchRescheduleS(void) {
|
||||||
|
/* first thread in the runnable queue has higher priority than the running
|
||||||
|
* thread? */
|
||||||
|
if (firstprio(&rlist) > currp->p_prio)
|
||||||
|
chSchDoRescheduleI();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Evaluates if a reschedulation is required.
|
||||||
|
* @details The decision is taken by comparing the relative priorities and
|
||||||
|
* depending on the state of the round robin timeout counter.
|
||||||
|
*
|
||||||
|
* @retval TRUE if there is a thread that should go in running state.
|
||||||
|
* @retval FALSE if a reschedulation is not required.
|
||||||
|
*/
|
||||||
|
bool_t chSchRescRequiredI(void) {
|
||||||
|
tprio_t p1 = firstprio(&rlist);
|
||||||
|
tprio_t p2 = currp->p_prio;
|
||||||
|
#if CH_USE_ROUNDROBIN
|
||||||
|
/* If the running thread has not reached its time quantum, reschedule only
|
||||||
|
* if the first thread on the ready queue has a higher priority.
|
||||||
|
* Otherwise, if the running thread has used up its time quantum, reschedule
|
||||||
|
* if the first thread on the ready queue has equal or higher priority.*/
|
||||||
|
return rlist.r_preempt ? p1 > p2 : p1 >= p2;
|
||||||
|
#else
|
||||||
|
/* If the round robin feature is not enabled then performs a simpler
|
||||||
|
* comparison.*/
|
||||||
|
return p1 > p2;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,257 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file chsem.c
|
||||||
|
* @brief Semaphores code.
|
||||||
|
* @addtogroup Semaphores
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
#if CH_USE_SEMAPHORES
|
||||||
|
|
||||||
|
#if CH_USE_SEMAPHORES_PRIORITY
|
||||||
|
#define sem_insert(tp, qp) prio_insert(tp, qp)
|
||||||
|
#else
|
||||||
|
#define sem_insert(tp, qp) queue_insert(tp, qp)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes a semaphore with the specified counter value.
|
||||||
|
*
|
||||||
|
* @param[out] sp pointer to a @p Semaphore structure
|
||||||
|
* @param[in] n initial value of the semaphore counter. Must be non-negative.
|
||||||
|
* @note This function can be invoked from within an interrupt handler even if
|
||||||
|
* it is not an I-Class API because it does not touch any critical kernel
|
||||||
|
* data structure.
|
||||||
|
*/
|
||||||
|
void chSemInit(Semaphore *sp, cnt_t n) {
|
||||||
|
|
||||||
|
chDbgCheck((sp != NULL) && (n >= 0), "chSemInit");
|
||||||
|
|
||||||
|
queue_init(&sp->s_queue);
|
||||||
|
sp->s_cnt = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Performs a reset operation on the semaphore.
|
||||||
|
*
|
||||||
|
* @param[in] sp pointer to a @p Semaphore structure
|
||||||
|
* @param[in] n the new value of the semaphore counter. The value must be non-negative.
|
||||||
|
* @note The released threads can recognize they were waked up by a reset
|
||||||
|
* instead than a signal because the @p chSemWait() will return
|
||||||
|
* @p RDY_RESET instead of @p RDY_OK.
|
||||||
|
*/
|
||||||
|
void chSemReset(Semaphore *sp, cnt_t n) {
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
chSemResetI(sp, n);
|
||||||
|
chSchRescheduleS();
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Performs a reset operation on the semaphore.
|
||||||
|
*
|
||||||
|
* @param[in] sp pointer to a @p Semaphore structure
|
||||||
|
* @param[in] n the new value of the semaphore counter. The value must be non-negative.
|
||||||
|
* @note The released threads can recognize they were waked up by a reset
|
||||||
|
* instead than a signal because the @p chSemWait() will return
|
||||||
|
* @p RDY_RESET instead of @p RDY_OK.
|
||||||
|
* @note This function does not reschedule.
|
||||||
|
*/
|
||||||
|
void chSemResetI(Semaphore *sp, cnt_t n) {
|
||||||
|
cnt_t cnt;
|
||||||
|
|
||||||
|
chDbgCheck((sp != NULL) && (n >= 0), "chSemResetI");
|
||||||
|
|
||||||
|
cnt = sp->s_cnt;
|
||||||
|
sp->s_cnt = n;
|
||||||
|
while (cnt++ < 0)
|
||||||
|
chSchReadyI(lifo_remove(&sp->s_queue))->p_rdymsg = RDY_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Performs a wait operation on a semaphore.
|
||||||
|
*
|
||||||
|
* @param[in] sp pointer to a @p Semaphore structure
|
||||||
|
* @retval RDY_OK if the semaphore was signaled or not taken.
|
||||||
|
* @retval RDY_RESET if the semaphore was reset using @p chSemReset().
|
||||||
|
*/
|
||||||
|
msg_t chSemWait(Semaphore *sp) {
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
msg = chSemWaitS(sp);
|
||||||
|
chSysUnlock();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Performs a wait operation on a semaphore.
|
||||||
|
*
|
||||||
|
* @param[in] sp pointer to a @p Semaphore structure
|
||||||
|
* @retval RDY_OK if the semaphore was signaled or not taken.
|
||||||
|
* @retval RDY_RESET if the semaphore was reset using @p chSemReset().
|
||||||
|
* @note This function must be called with interrupts disabled.
|
||||||
|
* @note This function cannot be called by an interrupt handler.
|
||||||
|
*/
|
||||||
|
msg_t chSemWaitS(Semaphore *sp) {
|
||||||
|
|
||||||
|
chDbgCheck(sp != NULL, "chSemWaitS");
|
||||||
|
|
||||||
|
if (--sp->s_cnt < 0) {
|
||||||
|
sem_insert(currp, &sp->s_queue);
|
||||||
|
currp->p_wtsemp = sp;
|
||||||
|
chSchGoSleepS(PRWTSEM);
|
||||||
|
return currp->p_rdymsg;
|
||||||
|
}
|
||||||
|
return RDY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Performs a wait operation on a semaphore with timeout specification.
|
||||||
|
*
|
||||||
|
* @param[in] sp pointer to a @p Semaphore structure
|
||||||
|
* @param[in] time the number of ticks before the operation timeouts,
|
||||||
|
* the following special values are allowed:
|
||||||
|
* - @a TIME_IMMEDIATE immediate timeout.
|
||||||
|
* - @a TIME_INFINITE no timeout.
|
||||||
|
* .
|
||||||
|
* @retval RDY_OK if the semaphore was signaled or not taken.
|
||||||
|
* @retval RDY_RESET if the semaphore was reset using @p chSemReset().
|
||||||
|
* @retval RDY_TIMEOUT if the semaphore was not signaled or reset within the
|
||||||
|
* specified timeout.
|
||||||
|
*/
|
||||||
|
msg_t chSemWaitTimeout(Semaphore *sp, systime_t time) {
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
msg = chSemWaitTimeoutS(sp, time);
|
||||||
|
chSysUnlock();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Performs a wait operation on a semaphore with timeout specification.
|
||||||
|
*
|
||||||
|
* @param[in] sp pointer to a @p Semaphore structure
|
||||||
|
* @param[in] time the number of ticks before the operation timeouts,
|
||||||
|
* the following special values are allowed:
|
||||||
|
* - @a TIME_IMMEDIATE immediate timeout.
|
||||||
|
* - @a TIME_INFINITE no timeout.
|
||||||
|
* .
|
||||||
|
* @retval RDY_OK if the semaphore was signaled or not taken.
|
||||||
|
* @retval RDY_RESET if the semaphore was reset using @p chSemReset().
|
||||||
|
* @retval RDY_TIMEOUT if the semaphore was not signaled or reset within the specified
|
||||||
|
* timeout.
|
||||||
|
*/
|
||||||
|
msg_t chSemWaitTimeoutS(Semaphore *sp, systime_t time) {
|
||||||
|
|
||||||
|
chDbgCheck(sp != NULL, "chSemWaitTimeoutS");
|
||||||
|
|
||||||
|
if (--sp->s_cnt < 0) {
|
||||||
|
if (TIME_IMMEDIATE == time) {
|
||||||
|
sp->s_cnt++;
|
||||||
|
return RDY_TIMEOUT;
|
||||||
|
}
|
||||||
|
sem_insert(currp, &sp->s_queue);
|
||||||
|
currp->p_wtsemp = sp;
|
||||||
|
return chSchGoSleepTimeoutS(PRWTSEM, time);
|
||||||
|
}
|
||||||
|
return RDY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Performs a signal operation on a semaphore.
|
||||||
|
*
|
||||||
|
* @param[in] sp pointer to a @p Semaphore structure
|
||||||
|
* @note The function is available only if the @p CH_USE_SEMAPHORES
|
||||||
|
* option is enabled in @p chconf.h.
|
||||||
|
*/
|
||||||
|
void chSemSignal(Semaphore *sp) {
|
||||||
|
|
||||||
|
chDbgCheck(sp != NULL, "chSemSignal");
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
if (sp->s_cnt++ < 0)
|
||||||
|
chSchWakeupS(fifo_remove(&sp->s_queue), RDY_OK);
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Performs a signal operation on a semaphore.
|
||||||
|
*
|
||||||
|
* @param[in] sp pointer to a @p Semaphore structure
|
||||||
|
* @note The function is available only if the @p CH_USE_SEMAPHORES
|
||||||
|
* option is enabled in @p chconf.h.
|
||||||
|
* @note This function does not reschedule.
|
||||||
|
*/
|
||||||
|
void chSemSignalI(Semaphore *sp) {
|
||||||
|
|
||||||
|
chDbgCheck(sp != NULL, "chSemSignalI");
|
||||||
|
|
||||||
|
if (sp->s_cnt++ < 0) {
|
||||||
|
/* NOTE: It is done this way in order to allow a tail call on
|
||||||
|
chSchReadyI().*/
|
||||||
|
Thread *tp = fifo_remove(&sp->s_queue);
|
||||||
|
tp->p_rdymsg = RDY_OK;
|
||||||
|
chSchReadyI(tp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CH_USE_SEMSW
|
||||||
|
/**
|
||||||
|
* @brief Performs atomic signal and wait operations on two semaphores.
|
||||||
|
*
|
||||||
|
* @param[in] sps pointer to a @p Semaphore structure to be signaled
|
||||||
|
* @param[in] spw pointer to a @p Semaphore structure to be wait on
|
||||||
|
* @retval RDY_OK if the semaphore was signaled or not taken.
|
||||||
|
* @retval RDY_RESET if the semaphore was reset using @p chSemReset().
|
||||||
|
* @note The function is available only if the @p CH_USE_SEMSW
|
||||||
|
* option is enabled in @p chconf.h.
|
||||||
|
*/
|
||||||
|
msg_t chSemSignalWait(Semaphore *sps, Semaphore *spw) {
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
|
chDbgCheck((sps != NULL) && (spw != NULL), "chSemSignalWait");
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
if (sps->s_cnt++ < 0)
|
||||||
|
chSchReadyI(fifo_remove(&sps->s_queue))->p_rdymsg = RDY_OK;
|
||||||
|
if (--spw->s_cnt < 0) {
|
||||||
|
sem_insert(currp, &spw->s_queue);
|
||||||
|
currp->p_wtsemp = spw;
|
||||||
|
chSchGoSleepS(PRWTSEM);
|
||||||
|
msg = currp->p_rdymsg;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
chSchRescheduleS();
|
||||||
|
msg = RDY_OK;
|
||||||
|
}
|
||||||
|
chSysUnlock();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
#endif /* CH_USE_SEMSW */
|
||||||
|
|
||||||
|
#endif /* CH_USE_SEMAPHORES */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,168 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file chserial.c
|
||||||
|
* @brief Serial Drivers code.
|
||||||
|
* @addtogroup Serial
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
#if CH_USE_SERIAL_FULLDUPLEX
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interface implementation, the following functions just invoke the equivalent
|
||||||
|
* queue-level function or macro.
|
||||||
|
*/
|
||||||
|
static bool_t putwouldblock(void *instance) {
|
||||||
|
|
||||||
|
return chOQIsFull(&((FullDuplexDriver *)instance)->d2.oqueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool_t getwouldblock(void *instance) {
|
||||||
|
|
||||||
|
return chIQIsEmpty(&((FullDuplexDriver *)instance)->d2.iqueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static msg_t put(void *instance, uint8_t b, systime_t timeout) {
|
||||||
|
|
||||||
|
return chOQPutTimeout(&((FullDuplexDriver *)instance)->d2.oqueue, b, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static msg_t get(void *instance, systime_t timeout) {
|
||||||
|
|
||||||
|
return chIQGetTimeout(&((FullDuplexDriver *)instance)->d2.iqueue, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t write(void *instance, uint8_t *buffer, size_t n) {
|
||||||
|
|
||||||
|
return chOQWrite(&((FullDuplexDriver *)instance)->d2.oqueue, buffer, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t read(void *instance, uint8_t *buffer, size_t n) {
|
||||||
|
|
||||||
|
return chIQRead(&((FullDuplexDriver *)instance)->d2.iqueue, buffer, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct FullDuplexDriverVMT vmt = {
|
||||||
|
{putwouldblock, getwouldblock, put, get},
|
||||||
|
{write, read},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes a generic full duplex driver.
|
||||||
|
* @details The HW dependent part of the initialization has to be performed
|
||||||
|
* outside, usually in the hardware initialization code.
|
||||||
|
*
|
||||||
|
* @param[out] sd pointer to a @p FullDuplexDriver structure
|
||||||
|
* @param[in] ib pointer to a memory area allocated for the Input Queue buffer
|
||||||
|
* @param[in] isize size of the Input Queue buffer
|
||||||
|
* @param[in] inotify pointer to a callback function that is invoked when
|
||||||
|
* some data is read from the Queue. The value can be
|
||||||
|
* @p NULL.
|
||||||
|
* @param[in] ob pointer to a memory area allocated for the Output Queue buffer
|
||||||
|
* @param[in] osize size of the Output Queue buffer
|
||||||
|
* @param[in] onotify pointer to a callback function that is invoked when
|
||||||
|
* some data is written in the Queue. The value can be
|
||||||
|
* @p NULL.
|
||||||
|
*/
|
||||||
|
void chFDDInit(FullDuplexDriver *sd,
|
||||||
|
uint8_t *ib, size_t isize, qnotify_t inotify,
|
||||||
|
uint8_t *ob, size_t osize, qnotify_t onotify) {
|
||||||
|
|
||||||
|
chDbgCheck((sd != NULL) && (ib != NULL) && (ob != NULL) &&
|
||||||
|
(isize > 0) && (osize > 0), "chFDDInit");
|
||||||
|
|
||||||
|
sd->vmt = &vmt;
|
||||||
|
chEvtInit(&sd->d1.ievent);
|
||||||
|
chEvtInit(&sd->d1.oevent);
|
||||||
|
chEvtInit(&sd->d2.sevent);
|
||||||
|
sd->d2.flags = SD_NO_ERROR;
|
||||||
|
chIQInit(&sd->d2.iqueue, ib, isize, inotify);
|
||||||
|
chOQInit(&sd->d2.oqueue, ob, osize, onotify);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handles incoming data.
|
||||||
|
* @details This function must be called from the input interrupt service
|
||||||
|
* routine in order to enqueue incoming data and generate the
|
||||||
|
* related events.
|
||||||
|
* @param[in] sd pointer to a @p FullDuplexDriver structure
|
||||||
|
* @param[in] b the byte to be written in the driver's Input Queue
|
||||||
|
*/
|
||||||
|
void chFDDIncomingDataI(FullDuplexDriver *sd, uint8_t b) {
|
||||||
|
|
||||||
|
if (chIQPutI(&sd->d2.iqueue, b) < Q_OK)
|
||||||
|
chFDDAddFlagsI(sd, SD_OVERRUN_ERROR);
|
||||||
|
else
|
||||||
|
chEvtBroadcastI(&sd->d1.ievent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handles outgoing data.
|
||||||
|
* @details Must be called from the output interrupt service routine in order
|
||||||
|
* to get the next byte to be transmitted.
|
||||||
|
*
|
||||||
|
* @param[in] sd pointer to a @p FullDuplexDriver structure
|
||||||
|
* @return The byte value read from the driver's output queue.
|
||||||
|
* @retval Q_EMPTY if the queue is empty (the lower driver usually disables
|
||||||
|
* the interrupt source when this happens).
|
||||||
|
*/
|
||||||
|
msg_t chFDDRequestDataI(FullDuplexDriver *sd) {
|
||||||
|
|
||||||
|
msg_t b = chOQGetI(&sd->d2.oqueue);
|
||||||
|
if (b < Q_OK)
|
||||||
|
chEvtBroadcastI(&sd->d1.oevent);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handles communication events/errors.
|
||||||
|
* @details Must be called from the I/O interrupt service routine in order to
|
||||||
|
* notify I/O conditions as errors, signals change etc.
|
||||||
|
*
|
||||||
|
* @param[in] sd pointer to a @p FullDuplexDriver structure
|
||||||
|
* @param[in] mask condition flags to be added to the mask
|
||||||
|
*/
|
||||||
|
void chFDDAddFlagsI(FullDuplexDriver *sd, dflags_t mask) {
|
||||||
|
|
||||||
|
sd->d2.flags |= mask;
|
||||||
|
chEvtBroadcastI(&sd->d2.sevent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns and clears the errors mask associated to the driver.
|
||||||
|
*
|
||||||
|
* @param[in] sd pointer to a @p FullDuplexDriver structure
|
||||||
|
* @return The condition flags modified since last time this function was
|
||||||
|
* invoked.
|
||||||
|
*/
|
||||||
|
dflags_t chFDDGetAndClearFlags(FullDuplexDriver *sd) {
|
||||||
|
dflags_t mask;
|
||||||
|
|
||||||
|
mask = sd->d2.flags;
|
||||||
|
sd->d2.flags = SD_NO_ERROR;
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
#endif /* CH_USE_SERIAL_FULLDUPLEX */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file chsys.c
|
||||||
|
* @brief System related code.
|
||||||
|
* @addtogroup System
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
static WORKING_AREA(idle_thread_wa, IDLE_THREAD_STACK_SIZE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function implements the idle thread infinite loop.
|
||||||
|
* @details The function puts the processor in the lowest power mode capable
|
||||||
|
* to serve interrupts.<br>
|
||||||
|
* The priority is internally set to the minimum system value so
|
||||||
|
* that this thread is executed only if there are no other ready
|
||||||
|
* threads in the system.
|
||||||
|
*
|
||||||
|
* @param[in] p the thread parameter, unused in this scenario
|
||||||
|
*/
|
||||||
|
static void idle_thread(void *p) {
|
||||||
|
|
||||||
|
while (TRUE) {
|
||||||
|
port_wait_for_interrupt();
|
||||||
|
IDLE_LOOP_HOOK();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ChibiOS/RT initialization.
|
||||||
|
* @details After executing this function the current instructions stream
|
||||||
|
* becomes the main thread.
|
||||||
|
*
|
||||||
|
* @note Interrupts should be still disabled when @p chSysInit() is invoked
|
||||||
|
* and are internally enabled.
|
||||||
|
* @note The main thread is created with priority @p NORMALPRIO.
|
||||||
|
*/
|
||||||
|
void chSysInit(void) {
|
||||||
|
static Thread mainthread;
|
||||||
|
|
||||||
|
port_init();
|
||||||
|
scheduler_init();
|
||||||
|
vt_init();
|
||||||
|
#if CH_USE_HEAP
|
||||||
|
heap_init();
|
||||||
|
#endif
|
||||||
|
#if CH_DBG_ENABLE_TRACE
|
||||||
|
trace_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now this instructions flow becomes the main thread.
|
||||||
|
*/
|
||||||
|
(currp = init_thread(&mainthread, NORMALPRIO))->p_state = PRCURR;
|
||||||
|
chSysEnable();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This thread has the lowest priority in the system, its role is just to
|
||||||
|
* serve interrupts in its context while keeping the lowest energy saving
|
||||||
|
* mode compatible with the system status.
|
||||||
|
*/
|
||||||
|
chThdCreateStatic(idle_thread_wa, sizeof(idle_thread_wa), IDLEPRIO,
|
||||||
|
(tfunc_t)idle_thread, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handles time ticks for round robin preemption and timer increments.
|
||||||
|
* @details Decrements the remaining time quantum of the running thread
|
||||||
|
* and preempts it when the quantum is used up. Increments system
|
||||||
|
* time and manages the timers.
|
||||||
|
*
|
||||||
|
* @note The frequency of the timer determines the system tick granularity and,
|
||||||
|
* together with the @p CH_TIME_QUANTUM macro, the round robin interval.
|
||||||
|
*/
|
||||||
|
void chSysTimerHandlerI(void) {
|
||||||
|
|
||||||
|
#if CH_USE_ROUNDROBIN
|
||||||
|
/* running thread has not used up quantum yet? */
|
||||||
|
if (rlist.r_preempt > 0)
|
||||||
|
/* decrement remaining quantum */
|
||||||
|
rlist.r_preempt--;
|
||||||
|
#endif
|
||||||
|
#if CH_DBG_THREADS_PROFILING
|
||||||
|
currp->p_time++;
|
||||||
|
#endif
|
||||||
|
chVTDoTickI();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CH_USE_NESTED_LOCKS && !CH_OPTIMIZE_SPEED
|
||||||
|
void chSysLock(void) {
|
||||||
|
|
||||||
|
chDbgAssert(currp->p_locks >= 0,
|
||||||
|
"chSysLock(), #1",
|
||||||
|
"negative nesting counter");
|
||||||
|
if (currp->p_locks++ == 0)
|
||||||
|
port_lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void chSysUnlock(void) {
|
||||||
|
|
||||||
|
chDbgAssert(currp->p_locks > 0,
|
||||||
|
"chSysUnlock(), #1",
|
||||||
|
"non-positive nesting counter");
|
||||||
|
if (--currp->p_locks == 0)
|
||||||
|
port_unlock();
|
||||||
|
}
|
||||||
|
#endif /* CH_USE_NESTED_LOCKS && !CH_OPTIMIZE_SPEED */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,381 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file chthreads.c
|
||||||
|
* @brief Threads code.
|
||||||
|
* @addtogroup Threads
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initializes a thread structure.
|
||||||
|
*/
|
||||||
|
Thread *init_thread(Thread *tp, tprio_t prio) {
|
||||||
|
|
||||||
|
tp->p_flags = P_MEM_MODE_STATIC;
|
||||||
|
tp->p_prio = prio;
|
||||||
|
tp->p_state = PRSUSPENDED;
|
||||||
|
#if CH_USE_NESTED_LOCKS
|
||||||
|
tp->p_locks = 0;
|
||||||
|
#endif
|
||||||
|
#if CH_DBG_THREADS_PROFILING
|
||||||
|
tp->p_time = 0;
|
||||||
|
#endif
|
||||||
|
#if CH_USE_MUTEXES
|
||||||
|
/* realprio is the thread's own, non-inherited, priority */
|
||||||
|
tp->p_realprio = prio;
|
||||||
|
tp->p_mtxlist = NULL;
|
||||||
|
#endif
|
||||||
|
#if CH_USE_WAITEXIT
|
||||||
|
tp->p_waiting = NULL;
|
||||||
|
#endif
|
||||||
|
#if CH_USE_MESSAGES
|
||||||
|
queue_init(&tp->p_msgqueue);
|
||||||
|
#endif
|
||||||
|
#if CH_USE_EVENTS
|
||||||
|
tp->p_epending = 0;
|
||||||
|
#endif
|
||||||
|
THREAD_EXT_INIT(tp);
|
||||||
|
return tp;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CH_DBG_FILL_THREADS
|
||||||
|
static void memfill(uint8_t *startp, uint8_t *endp, uint8_t v) {
|
||||||
|
|
||||||
|
while (startp < endp)
|
||||||
|
*startp++ = v;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes a new thread.
|
||||||
|
* @details The new thread is initialized but not inserted in the ready list,
|
||||||
|
* the initial state is @p PRSUSPENDED.
|
||||||
|
*
|
||||||
|
* @param[out] wsp pointer to a working area dedicated to the thread stack
|
||||||
|
* @param[in] size size of the working area
|
||||||
|
* @param[in] prio the priority level for the new thread
|
||||||
|
* @param[in] pf the thread function
|
||||||
|
* @param[in] arg an argument passed to the thread function. It can be @p NULL.
|
||||||
|
* @return The pointer to the @p Thread structure allocated for the
|
||||||
|
* thread into the working space area.
|
||||||
|
* @note A thread can terminate by calling @p chThdExit() or by simply
|
||||||
|
* returning from its main function.
|
||||||
|
* @note This function can be invoked from within an interrupt handler even if
|
||||||
|
* it is not an I-Class API because it does not touch any critical kernel
|
||||||
|
* data structure.
|
||||||
|
*/
|
||||||
|
Thread *chThdInit(void *wsp, size_t size, tprio_t prio, tfunc_t pf, void *arg) {
|
||||||
|
/* Thread structure is layed out in the lower part of the thread workspace */
|
||||||
|
Thread *tp = wsp;
|
||||||
|
|
||||||
|
chDbgCheck((wsp != NULL) && (size >= THD_WA_SIZE(0)) &&
|
||||||
|
(prio <= HIGHPRIO) && (pf != NULL),
|
||||||
|
"chThdInit");
|
||||||
|
#if CH_DBG_FILL_THREADS
|
||||||
|
memfill((uint8_t *)wsp, (uint8_t *)wsp + sizeof(Thread), THREAD_FILL_VALUE);
|
||||||
|
memfill((uint8_t *)wsp + sizeof(Thread),
|
||||||
|
(uint8_t *)wsp + size, STACK_FILL_VALUE);
|
||||||
|
#endif
|
||||||
|
SETUP_CONTEXT(wsp, size, pf, arg);
|
||||||
|
return init_thread(tp, prio);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a new thread into a static memory area.
|
||||||
|
*
|
||||||
|
* @param[out] wsp pointer to a working area dedicated to the thread
|
||||||
|
* stack
|
||||||
|
* @param[in] size size of the working area
|
||||||
|
* @param[in] prio the priority level for the new thread
|
||||||
|
* @param[in] pf the thread function
|
||||||
|
* @param[in] arg an argument passed to the thread function. It can be @p NULL.
|
||||||
|
* @return The pointer to the @p Thread structure allocated for the
|
||||||
|
* thread into the working space area.
|
||||||
|
* @note A thread can terminate by calling @p chThdExit() or by simply
|
||||||
|
* returning from its main function.
|
||||||
|
*/
|
||||||
|
Thread *chThdCreateStatic(void *wsp, size_t size,
|
||||||
|
tprio_t prio, tfunc_t pf, void *arg) {
|
||||||
|
|
||||||
|
return chThdResume(chThdInit(wsp, size, prio, pf, arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CH_USE_DYNAMIC && CH_USE_WAITEXIT && CH_USE_HEAP
|
||||||
|
/**
|
||||||
|
* @brief Creates a new thread allocating the memory from the heap.
|
||||||
|
*
|
||||||
|
* @param[in] size size of the working area to be allocated
|
||||||
|
* @param[in] prio the priority level for the new thread
|
||||||
|
* @param[in] pf the thread function
|
||||||
|
* @param[in] arg an argument passed to the thread function. It can be @p NULL.
|
||||||
|
* @return The pointer to the @p Thread structure allocated for the
|
||||||
|
* thread into the working space area.
|
||||||
|
* @retval NULL if the memory cannot be allocated.
|
||||||
|
* @note A thread can terminate by calling @p chThdExit() or by simply
|
||||||
|
* returning from its main function.
|
||||||
|
* @note The memory allocated for the thread is not released when the thread
|
||||||
|
* terminates but when a @p chThdWait() is performed.
|
||||||
|
* @note The function is available only if the @p CH_USE_DYNAMIC,
|
||||||
|
* @p CH_USE_HEAP and @p CH_USE_WAITEXIT options are enabled
|
||||||
|
* in @p chconf.h.
|
||||||
|
*/
|
||||||
|
Thread *chThdCreateFromHeap(size_t size, tprio_t prio, tfunc_t pf, void *arg) {
|
||||||
|
void *wsp;
|
||||||
|
Thread *tp;
|
||||||
|
|
||||||
|
wsp = chHeapAlloc(size);
|
||||||
|
if (wsp == NULL)
|
||||||
|
return NULL;
|
||||||
|
tp = chThdInit(wsp, size, prio, pf, arg);
|
||||||
|
tp->p_flags = P_MEM_MODE_HEAP;
|
||||||
|
return chThdResume(tp);
|
||||||
|
}
|
||||||
|
#endif /* CH_USE_DYNAMIC && CH_USE_WAITEXIT && CH_USE_HEAP */
|
||||||
|
|
||||||
|
#if CH_USE_DYNAMIC && CH_USE_WAITEXIT && CH_USE_MEMPOOLS
|
||||||
|
/**
|
||||||
|
* @brief Creates a new thread allocating the memory from the specified Memory
|
||||||
|
* Pool.
|
||||||
|
*
|
||||||
|
* @param[in] mp the memory pool
|
||||||
|
* @param[in] prio the priority level for the new thread
|
||||||
|
* @param[in] pf the thread function
|
||||||
|
* @param[in] arg an argument passed to the thread function. It can be @p NULL.
|
||||||
|
* @return The pointer to the @p Thread structure allocated for the
|
||||||
|
* thread into the working space area or @p NULL if the memory cannot
|
||||||
|
* be allocated.
|
||||||
|
* @retval NULL if the memory pool is empty.
|
||||||
|
* @note A thread can terminate by calling @p chThdExit() or by simply
|
||||||
|
* returning from its main function.
|
||||||
|
* @note The memory allocated for the thread is not released when the thread
|
||||||
|
* terminates but when a @p chThdWait() is performed.
|
||||||
|
* @note The function is available only if the @p CH_USE_DYNAMIC,
|
||||||
|
* @p CH_USE_MEMPOOLS and @p CH_USE_WAITEXIT options are enabled
|
||||||
|
* in @p chconf.h.
|
||||||
|
*/
|
||||||
|
Thread *chThdCreateFromMemoryPool(MemoryPool *mp, tprio_t prio,
|
||||||
|
tfunc_t pf, void *arg) {
|
||||||
|
void *wsp;
|
||||||
|
Thread *tp;
|
||||||
|
|
||||||
|
chDbgCheck(mp != NULL, "chThdCreateFromMemoryPool");
|
||||||
|
|
||||||
|
wsp = chPoolAlloc(mp);
|
||||||
|
if (wsp == NULL)
|
||||||
|
return NULL;
|
||||||
|
tp = chThdInit(wsp, mp->mp_object_size, prio, pf, arg);
|
||||||
|
tp->p_flags = P_MEM_MODE_MEMPOOL;
|
||||||
|
tp->p_mpool = mp;
|
||||||
|
return chThdResume(tp);
|
||||||
|
}
|
||||||
|
#endif /* CH_USE_DYNAMIC && CH_USE_WAITEXIT && CH_USE_MEMPOOLS */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Changes the running thread priority level then reschedules if
|
||||||
|
* necessary.
|
||||||
|
*
|
||||||
|
* @param[in] newprio the new priority level of the running thread
|
||||||
|
* @return The old priority level.
|
||||||
|
* @note The function returns the real thread priority regardless of the
|
||||||
|
* current priority that could be higher than the real priority because
|
||||||
|
* the priority inheritance mechanism.
|
||||||
|
*/
|
||||||
|
tprio_t chThdSetPriority(tprio_t newprio) {
|
||||||
|
tprio_t oldprio;
|
||||||
|
|
||||||
|
chDbgCheck((newprio >= LOWPRIO) && (newprio <= HIGHPRIO),
|
||||||
|
"chThdSetPriority");
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
#if CH_USE_MUTEXES
|
||||||
|
oldprio = currp->p_realprio;
|
||||||
|
if ((currp->p_prio == currp->p_realprio) || (newprio > currp->p_prio))
|
||||||
|
currp->p_prio = newprio;
|
||||||
|
currp->p_realprio = newprio;
|
||||||
|
#else
|
||||||
|
oldprio = currp->p_prio;
|
||||||
|
currp->p_prio = newprio;
|
||||||
|
#endif
|
||||||
|
chSchRescheduleS();
|
||||||
|
chSysUnlock();
|
||||||
|
return oldprio;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resumes a suspended thread.
|
||||||
|
*
|
||||||
|
* @param[in] tp the pointer to the thread
|
||||||
|
* @return The pointer to the thread.
|
||||||
|
* @note This call is supposed to resume threads created with @p chThdInit().
|
||||||
|
* It should not be used on threads suspended using @p chThdSuspend().
|
||||||
|
*/
|
||||||
|
Thread *chThdResume(Thread *tp) {
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
chDbgAssert(tp->p_state == PRSUSPENDED,
|
||||||
|
"chThdResume(), #1",
|
||||||
|
"thread not in PRSUSPENDED state");
|
||||||
|
chSchWakeupS(tp, RDY_OK);
|
||||||
|
chSysUnlock();
|
||||||
|
return tp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Requests a thread termination.
|
||||||
|
*
|
||||||
|
* @param[in] tp the pointer to the thread
|
||||||
|
* @note The thread is not termitated but a termination request is added to
|
||||||
|
* its @p p_flags field. The thread can read this status by
|
||||||
|
* invoking @p chThdShouldTerminate() and then terminate cleanly.
|
||||||
|
*/
|
||||||
|
void chThdTerminate(Thread *tp) {
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
tp->p_flags |= P_TERMINATE;
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Suspends the invoking thread for the specified time.
|
||||||
|
*
|
||||||
|
* @param[in] time the delay in system ticks, the special values are handled as
|
||||||
|
* follow:
|
||||||
|
* - @a TIME_INFINITE the thread enters an infinite sleep
|
||||||
|
* state.
|
||||||
|
* - @a TIME_IMMEDIATE this value is accepted but interpreted
|
||||||
|
* as a normal time specification not as an immediate timeout
|
||||||
|
* specification.
|
||||||
|
* .
|
||||||
|
*/
|
||||||
|
void chThdSleep(systime_t time) {
|
||||||
|
|
||||||
|
chDbgCheck(time != TIME_INFINITE, "chThdSleep");
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
chThdSleepS(time);
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Suspends the invoking thread until the system time arrives to the
|
||||||
|
* specified value.
|
||||||
|
*
|
||||||
|
* @param[in] time the absolute system time
|
||||||
|
*/
|
||||||
|
void chThdSleepUntil(systime_t time) {
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
if ((time -= chTimeNow()) > 0)
|
||||||
|
chThdSleepS(time);
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Terminates the current thread by specifying an exit status code.
|
||||||
|
*
|
||||||
|
* @param[in] msg the thread exit code. The code can be retrieved by using
|
||||||
|
* @p chThdWait().
|
||||||
|
*/
|
||||||
|
void chThdExit(msg_t msg) {
|
||||||
|
Thread *tp = currp;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
tp->p_exitcode = msg;
|
||||||
|
THREAD_EXT_EXIT(tp);
|
||||||
|
#if CH_USE_WAITEXIT
|
||||||
|
if (tp->p_waiting != NULL)
|
||||||
|
chSchReadyI(tp->p_waiting);
|
||||||
|
#endif
|
||||||
|
chSchGoSleepS(PREXIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CH_USE_WAITEXIT
|
||||||
|
/**
|
||||||
|
* @brief Blocks the execution of the invoking thread until the specified
|
||||||
|
* thread terminates then the exit code is returned.
|
||||||
|
* @details The memory used by the exited thread is handled in different ways
|
||||||
|
* depending on the API that spawned the thread:
|
||||||
|
* - If the thread was spawned by @p chThdCreateStatic() or by
|
||||||
|
* @p chThdInit() then nothing happens and the thread working area
|
||||||
|
* is not released or modified in any way. This is the default,
|
||||||
|
* totally static, behavior.
|
||||||
|
* - If the thread was spawned by @p chThdCreateFromHeap() then
|
||||||
|
* the working area is returned to the system heap.
|
||||||
|
* - If the thread was spawned by @p chThdCreateFromMemoryPool()
|
||||||
|
* then the working area is returned to the owning memory pool.
|
||||||
|
* .
|
||||||
|
* @param[in] tp the thread pointer
|
||||||
|
* @return The exit code from the terminated thread
|
||||||
|
* @note After invoking @p chThdWait() the thread pointer becomes invalid and
|
||||||
|
* must not be used as parameter for further system calls.
|
||||||
|
* @note The function is available only if the @p CH_USE_WAITEXIT
|
||||||
|
* option is enabled in @p chconf.h.
|
||||||
|
* @note Only one thread can be waiting for another thread at any time. You
|
||||||
|
* should imagine the threads as having a reference counter that is set
|
||||||
|
* to one when the thread is created, chThdWait() decreases the reference
|
||||||
|
* and the memory is freed when the counter reaches zero. In the current
|
||||||
|
* implementation there is no real reference counter in the thread
|
||||||
|
* structure but it is a planned extension.
|
||||||
|
*/
|
||||||
|
msg_t chThdWait(Thread *tp) {
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
|
chDbgCheck(tp != NULL, "chThdWait");
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
|
||||||
|
chDbgAssert(tp != currp, "chThdWait(), #1", "waiting self");
|
||||||
|
chDbgAssert(tp->p_waiting == NULL, "chThdWait(), #2", "some other thread waiting");
|
||||||
|
|
||||||
|
if (tp->p_state != PREXIT) {
|
||||||
|
tp->p_waiting = currp;
|
||||||
|
chSchGoSleepS(PRWAIT);
|
||||||
|
}
|
||||||
|
msg = tp->p_exitcode;
|
||||||
|
#if !CH_USE_DYNAMIC
|
||||||
|
chSysUnlock();
|
||||||
|
return msg;
|
||||||
|
#else /* CH_USE_DYNAMIC */
|
||||||
|
|
||||||
|
/* Returning memory.*/
|
||||||
|
tmode_t mode = tp->p_flags & P_MEM_MODE_MASK;
|
||||||
|
chSysUnlock();
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
#if CH_USE_HEAP
|
||||||
|
case P_MEM_MODE_HEAP:
|
||||||
|
chHeapFree(tp);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if CH_USE_MEMPOOLS
|
||||||
|
case P_MEM_MODE_MEMPOOL:
|
||||||
|
chPoolFree(tp->p_mpool, tp);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return msg;
|
||||||
|
#endif /* CH_USE_DYNAMIC */
|
||||||
|
}
|
||||||
|
#endif /* CH_USE_WAITEXIT */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file chvt.c
|
||||||
|
* @brief Time and Virtual Timers related code.
|
||||||
|
* @addtogroup Time
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
VTList vtlist;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Virtual Timers initialization.
|
||||||
|
*
|
||||||
|
* @note Internal use only.
|
||||||
|
*/
|
||||||
|
void vt_init(void) {
|
||||||
|
|
||||||
|
vtlist.vt_next = vtlist.vt_prev = (void *)&vtlist;
|
||||||
|
vtlist.vt_time = (systime_t)-1;
|
||||||
|
vtlist.vt_systime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables a virtual timer.
|
||||||
|
*
|
||||||
|
* @param[out] vtp the @p VirtualTimer structure pointer
|
||||||
|
* @param[in] time the number of time ticks, the value @p TIME_INFINITE is not
|
||||||
|
* allowed. The value @p TIME_IMMEDIATE is allowed but
|
||||||
|
* interpreted as a normal time specification not as an
|
||||||
|
* immediate timeout specification.
|
||||||
|
* @param[in] vtfunc the timer callback function. After invoking the callback
|
||||||
|
* the timer is disabled and the structure can be disposed or
|
||||||
|
* reused.
|
||||||
|
* @param[in] par a parameter that will be passed to the callback function
|
||||||
|
* @note The associated function is invoked by an interrupt handler within
|
||||||
|
* the I-Locked state, see @ref system_states.
|
||||||
|
*/
|
||||||
|
void chVTSetI(VirtualTimer *vtp, systime_t time, vtfunc_t vtfunc, void *par) {
|
||||||
|
VirtualTimer *p;
|
||||||
|
|
||||||
|
chDbgCheck((vtp != NULL) && (vtfunc != NULL) && (time != TIME_INFINITE),
|
||||||
|
"chVTSetI");
|
||||||
|
|
||||||
|
vtp->vt_par = par;
|
||||||
|
vtp->vt_func = vtfunc;
|
||||||
|
p = vtlist.vt_next;
|
||||||
|
while (p->vt_time < time) {
|
||||||
|
time -= p->vt_time;
|
||||||
|
p = p->vt_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
vtp->vt_prev = (vtp->vt_next = p)->vt_prev;
|
||||||
|
vtp->vt_prev->vt_next = p->vt_prev = vtp;
|
||||||
|
vtp->vt_time = time;
|
||||||
|
if (p != (void *)&vtlist)
|
||||||
|
p->vt_time -= time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disables a Virtual Timer.
|
||||||
|
*
|
||||||
|
* @param[in] vtp the @p VirtualTimer structure pointer
|
||||||
|
* @note The timer MUST be active when this function is invoked.
|
||||||
|
*/
|
||||||
|
void chVTResetI(VirtualTimer *vtp) {
|
||||||
|
|
||||||
|
chDbgCheck(vtp != NULL, "chVTResetI");
|
||||||
|
chDbgAssert(vtp->vt_func != NULL,
|
||||||
|
"chVTResetI(), #1",
|
||||||
|
"timer not set or already triggered");
|
||||||
|
|
||||||
|
if (vtp->vt_next != (void *)&vtlist)
|
||||||
|
vtp->vt_next->vt_time += vtp->vt_time;
|
||||||
|
vtp->vt_prev->vt_next = vtp->vt_next;
|
||||||
|
vtp->vt_next->vt_prev = vtp->vt_prev;
|
||||||
|
vtp->vt_func = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if the current system time is within the specified time window.
|
||||||
|
*
|
||||||
|
* @param[in] start the start of the time window (inclusive)
|
||||||
|
* @param[in] end the end of the time window (non inclusive)
|
||||||
|
* @retval TRUE current time within the specified time window.
|
||||||
|
* @retval FALSE current time not within the specified time window.
|
||||||
|
* @note When start==end then the function returns always true because the
|
||||||
|
* whole time range is specified.
|
||||||
|
*/
|
||||||
|
bool_t chTimeIsWithin(systime_t start, systime_t end) {
|
||||||
|
|
||||||
|
systime_t time = chTimeNow();
|
||||||
|
return end > start ? (time >= start) && (time < end) :
|
||||||
|
(time >= start) || (time < end);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,136 @@
|
||||||
|
# ARM7 common makefile scripts and rules.
|
||||||
|
|
||||||
|
# Automatic compiler options
|
||||||
|
OPT = $(USE_OPT)
|
||||||
|
CPPOPT = $(USE_CPPOPT)
|
||||||
|
ifeq ($(USE_CURRP_CACHING),yes)
|
||||||
|
OPT += -ffixed-r7 -DCH_CURRP_REGISTER_CACHE='"r7"'
|
||||||
|
endif
|
||||||
|
ifeq ($(USE_LINK_GC),yes)
|
||||||
|
OPT += -ffunction-sections -fdata-sections
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Source files groups
|
||||||
|
ifeq ($(USE_THUMB),yes)
|
||||||
|
TCSRC += $(CSRC)
|
||||||
|
TCPPSRC += $(CPPSRC)
|
||||||
|
else
|
||||||
|
ACSRC += $(CSRC)
|
||||||
|
ACPPSRC += $(CPPSRC)
|
||||||
|
endif
|
||||||
|
ASRC = $(ACSRC)$(ACPPSRC)
|
||||||
|
TSRC = $(TCSRC)$(TCPPSRC)
|
||||||
|
SRC = $(ASRC)$(TSRC)
|
||||||
|
|
||||||
|
# Object files groups
|
||||||
|
ACOBJS = $(ACSRC:.c=.o)
|
||||||
|
ACPPOBJS = $(ACPPSRC:.cpp=.o)
|
||||||
|
TCOBJS = $(TCSRC:.c=.o)
|
||||||
|
TCPPOBJS = $(TCPPSRC:.cpp=.o)
|
||||||
|
ASMOBJS = $(ASMSRC:.s=.o)
|
||||||
|
OBJS = $(ASMOBJS) $(ACOBJS) $(TCOBJS) $(ACPPOBJS) $(TCPPOBJS)
|
||||||
|
|
||||||
|
# Paths
|
||||||
|
IINCDIR = $(patsubst %,-I%,$(INCDIR) $(DINCDIR) $(UINCDIR))
|
||||||
|
LLIBDIR = $(patsubst %,-L%,$(DLIBDIR) $(ULIBDIR))
|
||||||
|
|
||||||
|
# Macros
|
||||||
|
DEFS = $(DDEFS) $(UDEFS)
|
||||||
|
ADEFS = $(DADEFS) $(UADEFS)
|
||||||
|
|
||||||
|
# Libs
|
||||||
|
LIBS = $(DLIBS) $(ULIBS)
|
||||||
|
|
||||||
|
# Various settings
|
||||||
|
MCFLAGS = -mcpu=$(MCU)
|
||||||
|
ODFLAGS = -x --syms
|
||||||
|
ASFLAGS = $(MCFLAGS) -Wa,-amhls=$(<:.s=.lst) $(ADEFS)
|
||||||
|
CFLAGS = $(MCFLAGS) $(OPT) $(CWARN) -Wa,-alms=$(<:.c=.lst) $(DEFS)
|
||||||
|
CPPFLAGS = $(MCFLAGS) $(OPT) $(CPPOPT) $(CPPWARN) -Wa,-alms=$(<:.cpp=.lst) $(DEFS)
|
||||||
|
ifeq ($(LINK_GC),yes)
|
||||||
|
LDFLAGS = $(MCFLAGS) -nostartfiles -T$(LDSCRIPT) -Wl,-Map=$(PROJECT).map,--cref,--no-warn-mismatch,--gc-sections $(LLIBDIR)
|
||||||
|
else
|
||||||
|
LDFLAGS = $(MCFLAGS) -nostartfiles -T$(LDSCRIPT) -Wl,-Map=$(PROJECT).map,--cref,--no-warn-mismatch $(LLIBDIR)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Thumb interwork enabled only if needed because it kills performance.
|
||||||
|
ifneq ($(TSRC),)
|
||||||
|
CFLAGS += -DTHUMB_PRESENT
|
||||||
|
CPPFLAGS += -DTHUMB_PRESENT
|
||||||
|
ASFLAGS += -DTHUMB_PRESENT
|
||||||
|
ifneq ($(ASRC),)
|
||||||
|
# Mixed ARM and THUMB mode.
|
||||||
|
CFLAGS += -mthumb-interwork
|
||||||
|
CPPFLAGS += -mthumb-interwork
|
||||||
|
ASFLAGS += -mthumb-interwork
|
||||||
|
LDFLAGS += -mthumb-interwork
|
||||||
|
else
|
||||||
|
# Pure THUMB mode, THUMB C code cannot be called by ARM asm code directly.
|
||||||
|
CFLAGS += -mno-thumb-interwork -DTHUMB_NO_INTERWORKING
|
||||||
|
CPPFLAGS += -mno-thumb-interwork -DTHUMB_NO_INTERWORKING
|
||||||
|
ASFLAGS += -mno-thumb-interwork -DTHUMB_NO_INTERWORKING -mthumb
|
||||||
|
LDFLAGS += -mno-thumb-interwork -mthumb
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
# Pure ARM mode
|
||||||
|
CPFLAGS += -mno-thumb-interwork
|
||||||
|
CPPFLAGS += -mno-thumb-interwork
|
||||||
|
ASFLAGS += -mno-thumb-interwork
|
||||||
|
LDFLAGS += -mno-thumb-interwork
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Generate dependency information
|
||||||
|
CFLAGS += -MD -MP -MF .dep/$(@F).d
|
||||||
|
CPPFLAGS += -MD -MP -MF .dep/$(@F).d
|
||||||
|
|
||||||
|
#
|
||||||
|
# Makefile rules
|
||||||
|
#
|
||||||
|
|
||||||
|
all: $(OBJS) $(PROJECT).elf $(PROJECT).hex $(PROJECT).bin $(PROJECT).dmp
|
||||||
|
|
||||||
|
$(ACPPOBJS) : %.o : %.cpp
|
||||||
|
@echo
|
||||||
|
$(CPPC) -c $(CPPFLAGS) $(AOPT) -I . $(IINCDIR) $< -o $@
|
||||||
|
|
||||||
|
$(TCPPOBJS) : %.o : %.cpp
|
||||||
|
@echo
|
||||||
|
$(CPPC) -c $(CPPFLAGS) $(TOPT) -I . $(IINCDIR) $< -o $@
|
||||||
|
|
||||||
|
$(ACOBJS) : %.o : %.c
|
||||||
|
@echo
|
||||||
|
$(CC) -c $(CFLAGS) $(AOPT) -I . $(IINCDIR) $< -o $@
|
||||||
|
|
||||||
|
$(TCOBJS) : %.o : %.c
|
||||||
|
@echo
|
||||||
|
$(CC) -c $(CFLAGS) $(TOPT) -I . $(IINCDIR) $< -o $@
|
||||||
|
|
||||||
|
$(ASMOBJS) : %.o : %.s
|
||||||
|
@echo
|
||||||
|
$(AS) -c $(ASFLAGS) -I . $(IINCDIR) $< -o $@
|
||||||
|
|
||||||
|
%elf: $(OBJS)
|
||||||
|
@echo
|
||||||
|
$(LD) $(OBJS) $(LDFLAGS) $(LIBS) -o $@
|
||||||
|
|
||||||
|
%hex: %elf
|
||||||
|
$(HEX) $< $@
|
||||||
|
|
||||||
|
%bin: %elf
|
||||||
|
$(BIN) $< $@
|
||||||
|
|
||||||
|
%dmp: %elf
|
||||||
|
$(OD) $(ODFLAGS) $< > $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm -f $(OBJS)
|
||||||
|
-rm -f $(ACSRC:.c=.lst) $(TCSRC:.c=.lst) $(ACPPSRC:.cpp=.lst) $(TCPPSRC:.cpp=.lst) $(ASMSRC:.s=.lst)
|
||||||
|
-rm -f $(PROJECT).elf $(PROJECT).dmp $(PROJECT).map $(PROJECT).hex $(PROJECT).bin
|
||||||
|
-rm -fR .dep
|
||||||
|
|
||||||
|
#
|
||||||
|
# Include the dependency files, should be the last of the makefile
|
||||||
|
#
|
||||||
|
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
|
||||||
|
|
||||||
|
# *** EOF ***
|
|
@ -0,0 +1,156 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parts of this file are borrowed by the Linux include file linux/mii.h:
|
||||||
|
* Copyright (C) 1996, 1999, 2001 David S. Miller (davem@redhat.com)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MII_H_
|
||||||
|
#define _MII_H_
|
||||||
|
|
||||||
|
/* Generic MII registers. */
|
||||||
|
#define MII_BMCR 0x00 /* Basic mode control register */
|
||||||
|
#define MII_BMSR 0x01 /* Basic mode status register */
|
||||||
|
#define MII_PHYSID1 0x02 /* PHYS ID 1 */
|
||||||
|
#define MII_PHYSID2 0x03 /* PHYS ID 2 */
|
||||||
|
#define MII_ADVERTISE 0x04 /* Advertisement control reg */
|
||||||
|
#define MII_LPA 0x05 /* Link partner ability reg */
|
||||||
|
#define MII_EXPANSION 0x06 /* Expansion register */
|
||||||
|
#define MII_CTRL1000 0x09 /* 1000BASE-T control */
|
||||||
|
#define MII_STAT1000 0x0a /* 1000BASE-T status */
|
||||||
|
#define MII_ESTATUS 0x0f /* Extended Status */
|
||||||
|
#define MII_DCOUNTER 0x12 /* Disconnect counter */
|
||||||
|
#define MII_FCSCOUNTER 0x13 /* False carrier counter */
|
||||||
|
#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */
|
||||||
|
#define MII_RERRCOUNTER 0x15 /* Receive error counter */
|
||||||
|
#define MII_SREVISION 0x16 /* Silicon revision */
|
||||||
|
#define MII_RESV1 0x17 /* Reserved... */
|
||||||
|
#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */
|
||||||
|
#define MII_PHYADDR 0x19 /* PHY address */
|
||||||
|
#define MII_RESV2 0x1a /* Reserved... */
|
||||||
|
#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */
|
||||||
|
#define MII_NCONFIG 0x1c /* Network interface config */
|
||||||
|
|
||||||
|
/* Basic mode control register. */
|
||||||
|
#define BMCR_RESV 0x003f /* Unused... */
|
||||||
|
#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */
|
||||||
|
#define BMCR_CTST 0x0080 /* Collision test */
|
||||||
|
#define BMCR_FULLDPLX 0x0100 /* Full duplex */
|
||||||
|
#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */
|
||||||
|
#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */
|
||||||
|
#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */
|
||||||
|
#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */
|
||||||
|
#define BMCR_SPEED100 0x2000 /* Select 100Mbps */
|
||||||
|
#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */
|
||||||
|
#define BMCR_RESET 0x8000 /* Reset the DP83840 */
|
||||||
|
|
||||||
|
/* Basic mode status register. */
|
||||||
|
#define BMSR_ERCAP 0x0001 /* Ext-reg capability */
|
||||||
|
#define BMSR_JCD 0x0002 /* Jabber detected */
|
||||||
|
#define BMSR_LSTATUS 0x0004 /* Link status */
|
||||||
|
#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */
|
||||||
|
#define BMSR_RFAULT 0x0010 /* Remote fault detected */
|
||||||
|
#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */
|
||||||
|
#define BMSR_RESV 0x00c0 /* Unused... */
|
||||||
|
#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */
|
||||||
|
#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */
|
||||||
|
#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */
|
||||||
|
#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */
|
||||||
|
#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */
|
||||||
|
#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */
|
||||||
|
#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */
|
||||||
|
#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */
|
||||||
|
|
||||||
|
/* Advertisement control register. */
|
||||||
|
#define ADVERTISE_SLCT 0x001f /* Selector bits */
|
||||||
|
#define ADVERTISE_CSMA 0x0001 /* Only selector supported */
|
||||||
|
#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
|
||||||
|
#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */
|
||||||
|
#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
|
||||||
|
#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */
|
||||||
|
#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
|
||||||
|
#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */
|
||||||
|
#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
|
||||||
|
#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */
|
||||||
|
#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
|
||||||
|
#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */
|
||||||
|
#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */
|
||||||
|
#define ADVERTISE_RESV 0x1000 /* Unused... */
|
||||||
|
#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */
|
||||||
|
#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */
|
||||||
|
#define ADVERTISE_NPAGE 0x8000 /* Next page bit */
|
||||||
|
|
||||||
|
#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
|
||||||
|
ADVERTISE_CSMA)
|
||||||
|
#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
|
||||||
|
ADVERTISE_100HALF | ADVERTISE_100FULL)
|
||||||
|
|
||||||
|
/* Link partner ability register. */
|
||||||
|
#define LPA_SLCT 0x001f /* Same as advertise selector */
|
||||||
|
#define LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */
|
||||||
|
#define LPA_1000XFULL 0x0020 /* Can do 1000BASE-X full-duplex */
|
||||||
|
#define LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */
|
||||||
|
#define LPA_1000XHALF 0x0040 /* Can do 1000BASE-X half-duplex */
|
||||||
|
#define LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */
|
||||||
|
#define LPA_1000XPAUSE 0x0080 /* Can do 1000BASE-X pause */
|
||||||
|
#define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */
|
||||||
|
#define LPA_1000XPAUSE_ASYM 0x0100 /* Can do 1000BASE-X pause asym*/
|
||||||
|
#define LPA_100BASE4 0x0200 /* Can do 100mbps 4k packets */
|
||||||
|
#define LPA_PAUSE_CAP 0x0400 /* Can pause */
|
||||||
|
#define LPA_PAUSE_ASYM 0x0800 /* Can pause asymetrically */
|
||||||
|
#define LPA_RESV 0x1000 /* Unused... */
|
||||||
|
#define LPA_RFAULT 0x2000 /* Link partner faulted */
|
||||||
|
#define LPA_LPACK 0x4000 /* Link partner acked us */
|
||||||
|
#define LPA_NPAGE 0x8000 /* Next page bit */
|
||||||
|
|
||||||
|
#define LPA_DUPLEX (LPA_10FULL | LPA_100FULL)
|
||||||
|
#define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4)
|
||||||
|
|
||||||
|
/* Expansion register for auto-negotiation. */
|
||||||
|
#define EXPANSION_NWAY 0x0001 /* Can do N-way auto-nego */
|
||||||
|
#define EXPANSION_LCWP 0x0002 /* Got new RX page code word */
|
||||||
|
#define EXPANSION_ENABLENPAGE 0x0004 /* This enables npage words */
|
||||||
|
#define EXPANSION_NPCAPABLE 0x0008 /* Link partner supports npage */
|
||||||
|
#define EXPANSION_MFAULTS 0x0010 /* Multiple faults detected */
|
||||||
|
#define EXPANSION_RESV 0xffe0 /* Unused... */
|
||||||
|
|
||||||
|
#define ESTATUS_1000_TFULL 0x2000 /* Can do 1000BT Full */
|
||||||
|
#define ESTATUS_1000_THALF 0x1000 /* Can do 1000BT Half */
|
||||||
|
|
||||||
|
/* N-way test register. */
|
||||||
|
#define NWAYTEST_RESV1 0x00ff /* Unused... */
|
||||||
|
#define NWAYTEST_LOOPBACK 0x0100 /* Enable loopback for N-way */
|
||||||
|
#define NWAYTEST_RESV2 0xfe00 /* Unused... */
|
||||||
|
|
||||||
|
/* 1000BASE-T Control register */
|
||||||
|
#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */
|
||||||
|
#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */
|
||||||
|
|
||||||
|
/* 1000BASE-T Status register */
|
||||||
|
#define LPA_1000LOCALRXOK 0x2000 /* Link partner local receiver status */
|
||||||
|
#define LPA_1000REMRXOK 0x1000 /* Link partner remote receiver status */
|
||||||
|
#define LPA_1000FULL 0x0800 /* Link partner 1000BASE-T full duplex */
|
||||||
|
#define LPA_1000HALF 0x0400 /* Link partner 1000BASE-T half duplex */
|
||||||
|
|
||||||
|
#define MII_DM9161_ID 0x0181b8a0
|
||||||
|
#define MII_AM79C875_ID 0x00225540
|
||||||
|
#define MII_MICREL_ID 0x00221610
|
||||||
|
|
||||||
|
#endif /* _MII_H_ */
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7-AT91SAM7X/pal_lld.c
|
||||||
|
* @brief AT91SAM7X PIO low level driver code
|
||||||
|
* @addtogroup AT91SAM7X_PAL
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
#include <pal.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief AT91SAM7X I/O ports configuration.
|
||||||
|
* @details PIO registers initialization.
|
||||||
|
*
|
||||||
|
* @param[in] config the AT91SAM7X ports configuration
|
||||||
|
*/
|
||||||
|
void _pal_lld_init(const AT91SAM7XPIOConfig *config) {
|
||||||
|
|
||||||
|
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_PIOA) | (1 << AT91C_ID_PIOB);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PIOA setup.
|
||||||
|
*/
|
||||||
|
AT91C_BASE_PIOA->PIO_OER = config->P0Data.pusr; /* Pull-up as spec.*/
|
||||||
|
AT91C_BASE_PIOA->PIO_ODR = ~config->P0Data.pusr;
|
||||||
|
AT91C_BASE_PIOA->PIO_PER = 0xFFFFFFFF; /* PIO enabled.*/
|
||||||
|
AT91C_BASE_PIOA->PIO_ODSR = config->P0Data.odsr; /* Data as specified.*/
|
||||||
|
AT91C_BASE_PIOA->PIO_OER = config->P0Data.osr; /* Dir. as specified.*/
|
||||||
|
AT91C_BASE_PIOA->PIO_ODR = ~config->P0Data.osr;
|
||||||
|
AT91C_BASE_PIOA->PIO_IFDR = 0xFFFFFFFF; /* Filter disabled.*/
|
||||||
|
AT91C_BASE_PIOA->PIO_IDR = 0xFFFFFFFF; /* Int. disabled.*/
|
||||||
|
AT91C_BASE_PIOA->PIO_MDDR = 0xFFFFFFFF; /* Push Pull drive.*/
|
||||||
|
AT91C_BASE_PIOA->PIO_ASR = 0xFFFFFFFF; /* Peripheral A.*/
|
||||||
|
AT91C_BASE_PIOA->PIO_OWER = 0xFFFFFFFF; /* Write enabled.*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PIOB setup.
|
||||||
|
*/
|
||||||
|
AT91C_BASE_PIOB->PIO_OER = config->P0Data.pusr; /* Pull-up as spec.*/
|
||||||
|
AT91C_BASE_PIOB->PIO_ODR = ~config->P0Data.pusr;
|
||||||
|
AT91C_BASE_PIOB->PIO_PER = 0xFFFFFFFF; /* PIO enabled.*/
|
||||||
|
AT91C_BASE_PIOB->PIO_ODSR = config->P1Data.odsr; /* Data as specified.*/
|
||||||
|
AT91C_BASE_PIOB->PIO_OER = config->P1Data.osr; /* Dir. as specified.*/
|
||||||
|
AT91C_BASE_PIOB->PIO_ODR = ~config->P1Data.osr;
|
||||||
|
AT91C_BASE_PIOB->PIO_IFDR = 0xFFFFFFFF; /* Filter disabled.*/
|
||||||
|
AT91C_BASE_PIOB->PIO_IDR = 0xFFFFFFFF; /* Int. disabled.*/
|
||||||
|
AT91C_BASE_PIOB->PIO_MDDR = 0xFFFFFFFF; /* Push Pull drive.*/
|
||||||
|
AT91C_BASE_PIOB->PIO_ASR = 0xFFFFFFFF; /* Peripheral A.*/
|
||||||
|
AT91C_BASE_PIOB->PIO_OWER = 0xFFFFFFFF; /* Write enabled.*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pads mode setup.
|
||||||
|
* @details This function programs a pads group belonging to the same port
|
||||||
|
* with the specified mode.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] mask the group mask
|
||||||
|
* @param[in] mode the mode
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
* @note @p PAL_MODE_RESET is implemented as input with pull-up.
|
||||||
|
* @note @p PAL_MODE_UNCONNECTED is implemented as push pull output with high
|
||||||
|
* state.
|
||||||
|
* @note @p PAL_MODE_OUTPUT_OPENDRAIN also enables the pull-up resistor.
|
||||||
|
*/
|
||||||
|
void _pal_lld_setgroupmode(ioportid_t port,
|
||||||
|
ioportmask_t mask,
|
||||||
|
uint_fast8_t mode) {
|
||||||
|
|
||||||
|
switch (mode & PAL_MODE_MASK) {
|
||||||
|
case PAL_MODE_RESET:
|
||||||
|
case PAL_MODE_INPUT_PULLUP:
|
||||||
|
port->PIO_PPUER = mask;
|
||||||
|
port->PIO_ODR = mask;
|
||||||
|
break;
|
||||||
|
case PAL_MODE_INPUT:
|
||||||
|
port->PIO_PPUDR = mask;
|
||||||
|
port->PIO_ODR = mask;
|
||||||
|
break;
|
||||||
|
case PAL_MODE_UNCONNECTED:
|
||||||
|
port->PIO_SODR = mask;
|
||||||
|
/* Falls in */
|
||||||
|
case PAL_MODE_OUTPUT_PUSHPULL:
|
||||||
|
port->PIO_PPUDR = mask;
|
||||||
|
port->PIO_OER = mask;
|
||||||
|
port->PIO_MDDR = mask;
|
||||||
|
break;
|
||||||
|
case PAL_MODE_OUTPUT_OPENDRAIN:
|
||||||
|
port->PIO_PPUER = mask;
|
||||||
|
port->PIO_OER = mask;
|
||||||
|
port->PIO_MDER = mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,245 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7-AT91SAM7X/pal_lld.h
|
||||||
|
* @brief AT91SAM7X PIO low level driver header
|
||||||
|
* @addtogroup AT91SAM7X_PAL
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PAL_LLD_H_
|
||||||
|
#define _PAL_LLD_H_
|
||||||
|
|
||||||
|
#include "at91lib/AT91SAM7X256.h"
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Unsupported modes and specific modes */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
#undef PAL_MODE_INPUT_PULLDOWN
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* I/O Ports Types and constants. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief PIO port setup info.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** Initial value for ODSR register (data).*/
|
||||||
|
uint32_t odsr;
|
||||||
|
/** Initial value for OSR register (direction).*/
|
||||||
|
uint32_t osr;
|
||||||
|
/** Initial value for PUSR register (Pull-ups).*/
|
||||||
|
uint32_t pusr;
|
||||||
|
} at91sam7x_pio_setup_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief AT91SAM7X PIO static initializer.
|
||||||
|
* @details An instance of this structure must be passed to @p palInit() at
|
||||||
|
* system startup time in order to initialized the digital I/O
|
||||||
|
* subsystem. This represents only the initial setup, specific pads
|
||||||
|
* or whole ports can be reprogrammed at later time.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** @brief Port 0 setup data.*/
|
||||||
|
at91sam7x_pio_setup_t P0Data;
|
||||||
|
/** @brief Port 1 setup data.*/
|
||||||
|
at91sam7x_pio_setup_t P1Data;
|
||||||
|
} AT91SAM7XPIOConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Width, in bits, of an I/O port.
|
||||||
|
*/
|
||||||
|
#define PAL_IOPORTS_WIDTH 32
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Digital I/O port sized unsigned type.
|
||||||
|
*/
|
||||||
|
typedef uint32_t ioportmask_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Port Identifier.
|
||||||
|
* @details This type can be a scalar or some kind of pointer, do not make
|
||||||
|
* any assumption about it, use the provided macros when populating
|
||||||
|
* variables of this type.
|
||||||
|
*/
|
||||||
|
typedef AT91PS_PIO ioportid_t;
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* I/O Ports Identifiers. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief PIO port A identifier.
|
||||||
|
*/
|
||||||
|
#define IOPORT_A AT91C_BASE_PIOA
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief PIO port B identifier.
|
||||||
|
*/
|
||||||
|
#define IOPORT_B AT91C_BASE_PIOB
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Implementation, some of the following macros could be implemented as */
|
||||||
|
/* functions, if so please put them in a file named pal_lld.c. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Low level PAL subsystem initialization.
|
||||||
|
*/
|
||||||
|
#define pal_lld_init(config) _pal_lld_init(config)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads the physical I/O port states.
|
||||||
|
* @details This function is implemented by reading the PIO_PDSR register, the
|
||||||
|
* implementation has no side effects.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @return The port bits.
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
#define pal_lld_readport(port) ((port)->PIO_PDSR)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads the output latch.
|
||||||
|
* @details This function is implemented by reading the PIO_ODSR register, the
|
||||||
|
* implementation has no side effects.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @return The latched logical states.
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
#define pal_lld_readlatch(port) ((port)->PIO_ODSR)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes a bits mask on a I/O port.
|
||||||
|
* @details This function is implemented by writing the PIO_ODSR register, the
|
||||||
|
* implementation has no side effects.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] bits the bits to be written on the specified port
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
#define pal_lld_writeport(port, bits) { \
|
||||||
|
(port)->PIO_ODSR = (bits); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets a bits mask on a I/O port.
|
||||||
|
* @details This function is implemented by writing the PIO_SODR register, the
|
||||||
|
* implementation has no side effects.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] bits the bits to be ORed on the specified port
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
#define pal_lld_setport(port, bits) { \
|
||||||
|
(port)->PIO_SODR = (bits); \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears a bits mask on a I/O port.
|
||||||
|
* @details This function is implemented by writing the PIO_CODR register, the
|
||||||
|
* implementation has no side effects.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] bits the bits to be cleared on the specified port
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
#define pal_lld_clearport(port, bits) { \
|
||||||
|
(port)->PIO_CODR = (bits); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes a group of bits.
|
||||||
|
* @details This function is implemented by writing the PIO_OWER, PIO_ODSR and
|
||||||
|
* PIO_OWDR registers, the implementation is not atomic because the
|
||||||
|
* multiple accesses.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] mask the group mask
|
||||||
|
* @param[in] offset the group bit offset within the port
|
||||||
|
* @param[in] bits the bits to be written. Values exceeding the group width
|
||||||
|
* are masked.
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
#define pal_lld_writegroup(port, mask, offset, bits) { \
|
||||||
|
(port)->PIO_OWER = (mask) << (offset); \
|
||||||
|
(port)->PIO_ODSR = (bits) << (offset); \
|
||||||
|
(port)->PIO_OWDR = (mask) << (offset); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pads group mode setup.
|
||||||
|
* @details This function programs a pads group belonging to the same port
|
||||||
|
* with the specified mode.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] mask the group mask
|
||||||
|
* @param[in] mode the mode
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
* @note @p PAL_MODE_UNCONNECTED is implemented as push pull output with high
|
||||||
|
* state.
|
||||||
|
*/
|
||||||
|
#define pal_lld_setgroupmode(port, mask, mode) \
|
||||||
|
_pal_lld_setgroupmode(port, mask, mode)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes a logical state on an output pad.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] pad the pad number within the port
|
||||||
|
* @param[out] bit the logical value, the value must be @p 0 or @p 1
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
#define pal_lld_writepad(port, pad, bit) pal_lld_writegroup(port, 1, pad, bit)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void _pal_lld_init(const AT91SAM7XPIOConfig *config);
|
||||||
|
void _pal_lld_setgroupmode(ioportid_t port,
|
||||||
|
ioportmask_t mask,
|
||||||
|
uint_fast8_t mode);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _PAL_LLD_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup AT91SAM7X AT91SAM7X Support
|
||||||
|
* @brief AT91SAM7X specific support.
|
||||||
|
* @details The AT91SAM7X support includes:
|
||||||
|
* - Buffered, interrupt driven, serial driver.
|
||||||
|
* - EMAC driver with MII support.
|
||||||
|
* - A demo supporting the kernel test suite.
|
||||||
|
* - A Web server demo using the uIP TCP/IP stack.
|
||||||
|
* .
|
||||||
|
* @ingroup ARM7
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup AT91SAM7X_PAL I/O Ports Support
|
||||||
|
* @brief I/O Ports peripherals support.
|
||||||
|
* @details This module supports the AT91SAM7X PIO controller. The controller
|
||||||
|
* supports the following features (see @ref PAL):
|
||||||
|
* - 32 bits wide ports.
|
||||||
|
* - Atomic set/reset functions.
|
||||||
|
* - Output latched regardless of the pad setting.
|
||||||
|
* - Direct read of input pads regardless of the pad setting.
|
||||||
|
* .
|
||||||
|
* <h2>Supported Setup Modes</h2>
|
||||||
|
* - @p PAL_MODE_RESET.
|
||||||
|
* - @p PAL_MODE_UNCONNECTED.
|
||||||
|
* - @p PAL_MODE_INPUT.
|
||||||
|
* - @p PAL_MODE_INPUT_PULLUP.
|
||||||
|
* - @p PAL_MODE_OUTPUT_PUSHPULL.
|
||||||
|
* - @p PAL_MODE_OUTPUT_OPENDRAIN.
|
||||||
|
* .
|
||||||
|
* Any attempt to setup an invalid mode is ignored.
|
||||||
|
*
|
||||||
|
* <h2>Suboptimal Behavior</h2>
|
||||||
|
* Some PIO features are less than optimal:
|
||||||
|
* - Pad/port toggling operations are not atomic.
|
||||||
|
* - Pad/group mode setup is not atomic.
|
||||||
|
* .
|
||||||
|
* @ingroup AT91SAM7X
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup AT91SAM7X_SERIAL USART Support
|
||||||
|
* @brief USART peripherals support.
|
||||||
|
* @details The serial driver supports the AT91SAM7X USART peripherals.
|
||||||
|
*
|
||||||
|
* @ingroup AT91SAM7X
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup AT91SAM7X_EMAC EMAC Support
|
||||||
|
* @brief EMAC peripheral support.
|
||||||
|
*
|
||||||
|
* @ingroup AT91SAM7X
|
||||||
|
*/
|
|
@ -0,0 +1,418 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7-AT91SAM7X/sam7x_emac.c
|
||||||
|
* @brief AT91SAM7X EMAC driver code.
|
||||||
|
* @addtogroup AT91SAM7X_EMAC
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
#include "board.h"
|
||||||
|
#include "sam7x_emac.h"
|
||||||
|
#include "mii.h"
|
||||||
|
#include "at91lib/aic.h"
|
||||||
|
|
||||||
|
EventSource EMACFrameTransmitted; /* A frame was transmitted. */
|
||||||
|
EventSource EMACFrameReceived; /* A frame was received. */
|
||||||
|
|
||||||
|
#ifndef __DOXYGEN__
|
||||||
|
//static int received; /* Buffered frames counter. */
|
||||||
|
static bool_t link_up; /* Last from EMACGetLinkStatus()*/
|
||||||
|
|
||||||
|
static uint8_t default_mac[] = {0xAA, 0x55, 0x13, 0x37, 0x01, 0x10};
|
||||||
|
|
||||||
|
static BufDescriptorEntry rent[EMAC_RECEIVE_BUFFERS] __attribute__((aligned(8)));
|
||||||
|
static uint8_t rbuffers[EMAC_RECEIVE_BUFFERS * EMAC_RECEIVE_BUFFERS_SIZE] __attribute__((aligned(8)));
|
||||||
|
static BufDescriptorEntry *rxptr;
|
||||||
|
|
||||||
|
static BufDescriptorEntry tent[EMAC_TRANSMIT_BUFFERS] __attribute__((aligned(8)));
|
||||||
|
static uint8_t tbuffers[EMAC_TRANSMIT_BUFFERS * EMAC_TRANSMIT_BUFFERS_SIZE] __attribute__((aligned(8)));
|
||||||
|
static BufDescriptorEntry *txptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define AT91C_PB15_ERXDV AT91C_PB15_ERXDV_ECRSDV
|
||||||
|
#define EMAC_PIN_MASK (AT91C_PB0_ETXCK_EREFCK | \
|
||||||
|
AT91C_PB1_ETXEN | AT91C_PB2_ETX0 | \
|
||||||
|
AT91C_PB3_ETX1 | AT91C_PB4_ECRS | \
|
||||||
|
AT91C_PB5_ERX0 | AT91C_PB6_ERX1 | \
|
||||||
|
AT91C_PB7_ERXER | AT91C_PB8_EMDC | \
|
||||||
|
AT91C_PB9_EMDIO | AT91C_PB10_ETX2 | \
|
||||||
|
AT91C_PB11_ETX3 | AT91C_PB12_ETXER | \
|
||||||
|
AT91C_PB13_ERX2 | AT91C_PB14_ERX3 | \
|
||||||
|
AT91C_PB15_ERXDV | AT91C_PB16_ECOL | \
|
||||||
|
AT91C_PB17_ERXCK)
|
||||||
|
|
||||||
|
#define PHY_LATCHED_PINS (AT91C_PB4_ECRS | AT91C_PB5_ERX0 | AT91C_PB6_ERX1 | \
|
||||||
|
AT91C_PB7_ERXER | AT91C_PB13_ERX2 | AT91C_PB14_ERX3 | \
|
||||||
|
AT91C_PB15_ERXDV | AT91C_PB16_ECOL | PIOB_PHY_IRQ_MASK)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PHY utilities.
|
||||||
|
*/
|
||||||
|
static uint32_t phy_get(uint8_t regno) {
|
||||||
|
|
||||||
|
AT91C_BASE_EMAC->EMAC_MAN = (1 << 30) | // SOF = 01
|
||||||
|
(2 << 28) | // RW = 10
|
||||||
|
(PHY_ADDRESS << 23) |
|
||||||
|
(regno << 18) |
|
||||||
|
(2 << 16); // CODE = 10
|
||||||
|
while (!( AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE))
|
||||||
|
;
|
||||||
|
return AT91C_BASE_EMAC->EMAC_MAN & 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static void phy_put(uint8_t regno, uint32_t val) {
|
||||||
|
|
||||||
|
AT91C_BASE_EMAC->EMAC_MAN = (1 << 30) | // SOF = 01
|
||||||
|
(1 << 28) | // RW = 01
|
||||||
|
(PHY_ADDRESS << 23) |
|
||||||
|
(regno << 18) |
|
||||||
|
(2 << 16) | // CODE = 10
|
||||||
|
val;
|
||||||
|
while (!( AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE))
|
||||||
|
;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
#define RSR_BITS (AT91C_EMAC_BNA | AT91C_EMAC_REC | AT91C_EMAC_OVR)
|
||||||
|
#define TSR_BITS (AT91C_EMAC_UBR | AT91C_EMAC_COL | AT91C_EMAC_RLES | \
|
||||||
|
AT91C_EMAC_BEX | AT91C_EMAC_COMP | AT91C_EMAC_UND)
|
||||||
|
|
||||||
|
__attribute__((noinline))
|
||||||
|
static void ServeInterrupt(void) {
|
||||||
|
uint32_t isr, rsr, tsr;
|
||||||
|
|
||||||
|
/* Fix for the EMAC errata */
|
||||||
|
isr = AT91C_BASE_EMAC->EMAC_ISR;
|
||||||
|
rsr = AT91C_BASE_EMAC->EMAC_RSR;
|
||||||
|
tsr = AT91C_BASE_EMAC->EMAC_TSR;
|
||||||
|
|
||||||
|
if ((isr & AT91C_EMAC_RCOMP) || (rsr & RSR_BITS)) {
|
||||||
|
if (rsr & AT91C_EMAC_REC) {
|
||||||
|
// received++;
|
||||||
|
chSysLockFromIsr();
|
||||||
|
chEvtBroadcastI(&EMACFrameReceived);
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
}
|
||||||
|
AT91C_BASE_EMAC->EMAC_RSR = RSR_BITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((isr & AT91C_EMAC_TCOMP) || (tsr & TSR_BITS)) {
|
||||||
|
if (tsr & AT91C_EMAC_COMP) {
|
||||||
|
chSysLockFromIsr();
|
||||||
|
chEvtBroadcastI(&EMACFrameTransmitted);
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
}
|
||||||
|
AT91C_BASE_EMAC->EMAC_TSR = TSR_BITS;
|
||||||
|
}
|
||||||
|
AT91C_BASE_AIC->AIC_EOICR = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CH_IRQ_HANDLER(EMACIrqHandler) {
|
||||||
|
|
||||||
|
CH_IRQ_PROLOGUE();
|
||||||
|
|
||||||
|
ServeInterrupt();
|
||||||
|
|
||||||
|
CH_IRQ_EPILOGUE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EMAC subsystem initialization.
|
||||||
|
*/
|
||||||
|
void emac_init(int prio) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Buffers initialization.
|
||||||
|
*/
|
||||||
|
// received = 0;
|
||||||
|
for (i = 0; i < EMAC_RECEIVE_BUFFERS; i++) {
|
||||||
|
rent[i].w1 = (uint32_t)&rbuffers[i * EMAC_RECEIVE_BUFFERS_SIZE];
|
||||||
|
rent[i].w2 = 0;
|
||||||
|
}
|
||||||
|
rent[EMAC_RECEIVE_BUFFERS - 1].w1 |= W1_R_WRAP;
|
||||||
|
rxptr = rent;
|
||||||
|
for (i = 0; i < EMAC_TRANSMIT_BUFFERS; i++) {
|
||||||
|
tent[i].w1 = (uint32_t)&tbuffers[i * EMAC_TRANSMIT_BUFFERS_SIZE];
|
||||||
|
tent[i].w2 = EMAC_TRANSMIT_BUFFERS_SIZE | W2_T_USED;
|
||||||
|
}
|
||||||
|
tent[EMAC_TRANSMIT_BUFFERS - 1].w2 |= W2_T_WRAP;
|
||||||
|
txptr = tent;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disables the pullups on all the pins that are latched on reset by the PHY.
|
||||||
|
* The status latched into the PHY is:
|
||||||
|
* PHYADDR = 00001
|
||||||
|
* PCS_LPBK = 0 (disabled)
|
||||||
|
* ISOLATE = 0 (disabled)
|
||||||
|
* RMIISEL = 0 (MII mode)
|
||||||
|
* RMIIBTB = 0 (BTB mode disabled)
|
||||||
|
* SPEED = 1 (100mbps)
|
||||||
|
* DUPLEX = 1 (full duplex)
|
||||||
|
* ANEG_EN = 1 (auto negotiation enabled)
|
||||||
|
*/
|
||||||
|
AT91C_BASE_PIOB->PIO_PPUDR = PHY_LATCHED_PINS;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PHY power control.
|
||||||
|
*/
|
||||||
|
AT91C_BASE_PIOB->PIO_OER = PIOB_PHY_PD_MASK; // Becomes an output.
|
||||||
|
AT91C_BASE_PIOB->PIO_PPUDR = PIOB_PHY_PD_MASK; // Default pullup disabled.
|
||||||
|
AT91C_BASE_PIOB->PIO_SODR = PIOB_PHY_PD_MASK; // Output to high level.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PHY reset by pulsing the NRST pin.
|
||||||
|
*/
|
||||||
|
AT91C_BASE_RSTC->RSTC_RMR = 0xA5000100;
|
||||||
|
AT91C_BASE_RSTC->RSTC_RCR = 0xA5000000 | AT91C_RSTC_EXTRST;
|
||||||
|
while (!(AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_NRSTL))
|
||||||
|
;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EMAC pins setup and clock enable. Note, PB18 is not included because it is
|
||||||
|
* used as #PD control and not as EF100.
|
||||||
|
*/
|
||||||
|
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_EMAC;
|
||||||
|
AT91C_BASE_PIOB->PIO_ASR = EMAC_PIN_MASK;
|
||||||
|
AT91C_BASE_PIOB->PIO_PDR = EMAC_PIN_MASK;
|
||||||
|
AT91C_BASE_PIOB->PIO_PPUDR = EMAC_PIN_MASK;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EMAC setup.
|
||||||
|
*/
|
||||||
|
AT91C_BASE_EMAC->EMAC_NCR = 0; // Initial setting.
|
||||||
|
AT91C_BASE_EMAC->EMAC_NCFGR = 2 << 10; // MDC-CLK = MCK / 32
|
||||||
|
AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN; // Enable EMAC in MII mode
|
||||||
|
AT91C_BASE_EMAC->EMAC_RBQP = (AT91_REG)rent; // RX buffers list
|
||||||
|
AT91C_BASE_EMAC->EMAC_TBQP = (AT91_REG)tent; // TX buffers list
|
||||||
|
AT91C_BASE_EMAC->EMAC_RSR = AT91C_EMAC_OVR |
|
||||||
|
AT91C_EMAC_REC |
|
||||||
|
AT91C_EMAC_BNA; // Clears RSR
|
||||||
|
AT91C_BASE_EMAC->EMAC_NCFGR |= AT91C_EMAC_DRFCS; // Initial NCFGR settings
|
||||||
|
AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TE |
|
||||||
|
AT91C_EMAC_RE |
|
||||||
|
AT91C_EMAC_CLRSTAT; // Initial NCR settings
|
||||||
|
EMACSetAddress(default_mac);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PHY detection and settings.
|
||||||
|
*/
|
||||||
|
AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE;
|
||||||
|
if ((phy_get(MII_PHYSID1) != (MII_MICREL_ID >> 16)) ||
|
||||||
|
((phy_get(MII_PHYSID2) & 0xFFF0) != (MII_MICREL_ID & 0xFFF0)))
|
||||||
|
chSysHalt();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Waits for auto-negotiation to end and then detects the link status.
|
||||||
|
*/
|
||||||
|
AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupt setup.
|
||||||
|
*/
|
||||||
|
AT91C_BASE_EMAC->EMAC_IER = AT91C_EMAC_RCOMP | AT91C_EMAC_TCOMP;
|
||||||
|
AIC_ConfigureIT(AT91C_ID_EMAC,
|
||||||
|
AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | prio,
|
||||||
|
EMACIrqHandler);
|
||||||
|
AIC_EnableIT(AT91C_ID_EMAC);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Event sources setup.
|
||||||
|
*/
|
||||||
|
chEvtInit(&EMACFrameTransmitted);
|
||||||
|
chEvtInit(&EMACFrameReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the MAC address.
|
||||||
|
*/
|
||||||
|
void EMACSetAddress(const uint8_t *eaddr) {
|
||||||
|
|
||||||
|
AT91C_BASE_EMAC->EMAC_SA1L = (AT91_REG)((eaddr[3] << 24) | (eaddr[2] << 16) |
|
||||||
|
(eaddr[1] << 8) | eaddr[0]);
|
||||||
|
AT91C_BASE_EMAC->EMAC_SA1H = (AT91_REG)((eaddr[5] << 8) | eaddr[4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns TRUE if the link is active. To be invoked at regular intervals in
|
||||||
|
* order to monitor the link.
|
||||||
|
* @note It is not thread-safe.
|
||||||
|
*/
|
||||||
|
bool_t EMACGetLinkStatus(void) {
|
||||||
|
uint32_t ncfgr, bmsr, bmcr, lpa;
|
||||||
|
|
||||||
|
AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE;
|
||||||
|
(void)phy_get(MII_BMSR);
|
||||||
|
bmsr = phy_get(MII_BMSR);
|
||||||
|
if (!(bmsr & BMSR_LSTATUS)) {
|
||||||
|
AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;
|
||||||
|
return link_up = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ncfgr = AT91C_BASE_EMAC->EMAC_NCFGR & ~(AT91C_EMAC_SPD | AT91C_EMAC_FD);
|
||||||
|
bmcr = phy_get(MII_BMCR);
|
||||||
|
if (bmcr & BMCR_ANENABLE) {
|
||||||
|
lpa = phy_get(MII_LPA);
|
||||||
|
if (lpa & (LPA_100HALF | LPA_100FULL | LPA_100BASE4))
|
||||||
|
ncfgr |= AT91C_EMAC_SPD;
|
||||||
|
if (lpa & (LPA_10FULL | LPA_100FULL))
|
||||||
|
ncfgr |= AT91C_EMAC_FD;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (bmcr & BMCR_SPEED100)
|
||||||
|
ncfgr |= AT91C_EMAC_SPD;
|
||||||
|
if (bmcr & BMCR_FULLDPLX)
|
||||||
|
ncfgr |= AT91C_EMAC_FD;
|
||||||
|
}
|
||||||
|
AT91C_BASE_EMAC->EMAC_NCFGR = ncfgr;
|
||||||
|
AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;
|
||||||
|
return link_up = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocates and locks a buffer for a transmission operation.
|
||||||
|
*/
|
||||||
|
BufDescriptorEntry *EMACGetTransmitBuffer(void) {
|
||||||
|
BufDescriptorEntry *cptr;
|
||||||
|
|
||||||
|
if (!link_up)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
cptr = txptr;
|
||||||
|
if (!(cptr->w2 & W2_T_USED) ||
|
||||||
|
(cptr->w2 & W2_T_LOCKED)) {
|
||||||
|
chSysUnlock();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
cptr->w2 |= W2_T_LOCKED; /* Locks the buffer while copying.*/
|
||||||
|
if (++txptr >= &tent[EMAC_TRANSMIT_BUFFERS])
|
||||||
|
txptr = tent;
|
||||||
|
chSysUnlock();
|
||||||
|
return cptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Transmits a previously allocated buffer and then releases it.
|
||||||
|
*/
|
||||||
|
void EMACTransmit(BufDescriptorEntry *cptr, size_t size) {
|
||||||
|
|
||||||
|
chDbgAssert(size <= EMAC_TRANSMIT_BUFFERS_SIZE,
|
||||||
|
"EMACTransmit(), #1",
|
||||||
|
"unexpected size");
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
if (cptr < &tent[EMAC_TRANSMIT_BUFFERS - 1])
|
||||||
|
cptr->w2 = size | W2_T_LAST_BUFFER;
|
||||||
|
else
|
||||||
|
cptr->w2 = size | W2_T_LAST_BUFFER | W2_T_WRAP;
|
||||||
|
AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TSTART;
|
||||||
|
chSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reads a buffered frame.
|
||||||
|
* Returns TRUE if a frame was present and read else FALSE.
|
||||||
|
* @note It is not thread-safe.
|
||||||
|
*/
|
||||||
|
bool_t EMACReceive(uint8_t *buf, size_t *sizep) {
|
||||||
|
unsigned n;
|
||||||
|
size_t size;
|
||||||
|
uint8_t *p;
|
||||||
|
bool_t overflow, found;
|
||||||
|
|
||||||
|
// chSysLock();
|
||||||
|
// if (received <= 0) {
|
||||||
|
// chSysUnlock();
|
||||||
|
// return FALSE;
|
||||||
|
// }
|
||||||
|
// received--;
|
||||||
|
// chSysUnlock();
|
||||||
|
|
||||||
|
n = EMAC_RECEIVE_BUFFERS;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skips unused buffers, if any.
|
||||||
|
*/
|
||||||
|
skip:
|
||||||
|
while (n && !(rxptr->w1 & W1_R_OWNERSHIP)) {
|
||||||
|
if (++rxptr >= &rent[EMAC_RECEIVE_BUFFERS])
|
||||||
|
rxptr = rent;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skips fragments, if any.
|
||||||
|
*/
|
||||||
|
while (n && (rxptr->w1 & W1_R_OWNERSHIP) && !(rxptr->w2 & W2_R_FRAME_START)) {
|
||||||
|
rxptr->w1 &= ~W1_R_OWNERSHIP;
|
||||||
|
if (++rxptr >= &rent[EMAC_RECEIVE_BUFFERS])
|
||||||
|
rxptr = rent;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
|
||||||
|
restart:
|
||||||
|
p = buf;
|
||||||
|
size = 0;
|
||||||
|
found = overflow = FALSE;
|
||||||
|
while (n && !found) {
|
||||||
|
size_t segsize;
|
||||||
|
|
||||||
|
if (!(rxptr->w1 & W1_R_OWNERSHIP))
|
||||||
|
goto skip; /* Empty buffer for some reason... */
|
||||||
|
|
||||||
|
if (size && (rxptr->w2 & W2_R_FRAME_START))
|
||||||
|
goto restart; /* Another start buffer for some reason... */
|
||||||
|
|
||||||
|
if (rxptr->w2 & W2_R_FRAME_END) {
|
||||||
|
segsize = (rxptr->w2 & W2_T_LENGTH_MASK) - size;
|
||||||
|
if (((rxptr->w2 & W2_T_LENGTH_MASK) > *sizep) ||
|
||||||
|
(segsize > EMAC_RECEIVE_BUFFERS_SIZE))
|
||||||
|
overflow = TRUE;
|
||||||
|
found = TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
segsize = EMAC_RECEIVE_BUFFERS_SIZE;
|
||||||
|
if (size + segsize > *sizep)
|
||||||
|
overflow = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!overflow) {
|
||||||
|
chDbgAssert(segsize <= 128, "EMACReceive(), #1", "");
|
||||||
|
memcpy(p, (void *)(rxptr->w1 & W1_R_ADDRESS_MASK), segsize);
|
||||||
|
p += segsize;
|
||||||
|
size += segsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
rxptr->w1 &= ~W1_R_OWNERSHIP;
|
||||||
|
if (++rxptr >= &rent[EMAC_RECEIVE_BUFFERS])
|
||||||
|
rxptr = rent;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
|
||||||
|
*sizep = size;
|
||||||
|
return found && !overflow;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7-AT91SAM7X/sam7x_emac.h
|
||||||
|
* @brief AT91SAM7X EMAC driver macros and structures.
|
||||||
|
* @addtogroup AT91SAM7X_EMAC
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SAM7X_EMAC_H_
|
||||||
|
#define _SAM7X_EMAC_H_
|
||||||
|
|
||||||
|
#define PHY_ADDRESS 1
|
||||||
|
|
||||||
|
#define EMAC_RECEIVE_BUFFERS 24
|
||||||
|
#define EMAC_RECEIVE_BUFFERS_SIZE 128
|
||||||
|
#define EMAC_TRANSMIT_BUFFERS 2
|
||||||
|
#define EMAC_TRANSMIT_BUFFERS_SIZE 1518
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t w1;
|
||||||
|
uint32_t w2;
|
||||||
|
} BufDescriptorEntry;
|
||||||
|
|
||||||
|
#define W1_R_OWNERSHIP 0x00000001
|
||||||
|
#define W1_R_WRAP 0x00000002
|
||||||
|
#define W1_R_ADDRESS_MASK 0xFFFFFFFC
|
||||||
|
|
||||||
|
#define W2_R_LENGTH_MASK 0x00000FFF
|
||||||
|
#define W2_R_FRAME_START 0x00004000
|
||||||
|
#define W2_R_FRAME_END 0x00008000
|
||||||
|
#define W2_R_CFI 0x00010000
|
||||||
|
#define W2_R_VLAN_PRIO_MASK 0x000E0000
|
||||||
|
#define W2_R_PRIO_TAG_DETECTED 0x00100000
|
||||||
|
#define W2_R_VLAN_TAG_DETECTED 0x00200000
|
||||||
|
#define W2_R_TYPE_ID_MATCH 0x00400000
|
||||||
|
#define W2_R_ADDR4_MATCH 0x00800000
|
||||||
|
#define W2_R_ADDR3_MATCH 0x01000000
|
||||||
|
#define W2_R_ADDR2_MATCH 0x02000000
|
||||||
|
#define W2_R_ADDR1_MATCH 0x04000000
|
||||||
|
#define W2_R_RFU1 0x08000000
|
||||||
|
#define W2_R_ADDR_EXT_MATCH 0x10000000
|
||||||
|
#define W2_R_UNICAST_MATCH 0x20000000
|
||||||
|
#define W2_R_MULTICAST_MATCH 0x40000000
|
||||||
|
#define W2_R_BROADCAST_DETECTED 0x80000000
|
||||||
|
|
||||||
|
#define W2_T_LENGTH_MASK 0x000007FF
|
||||||
|
#define W2_T_LOCKED 0x00000800 /* Not an EMAC flag, used by the driver */
|
||||||
|
#define W2_T_RFU1 0x00003000
|
||||||
|
#define W2_T_LAST_BUFFER 0x00008000
|
||||||
|
#define W2_T_NO_CRC 0x00010000
|
||||||
|
#define W2_T_RFU2 0x07FE0000
|
||||||
|
#define W2_T_BUFFERS_EXHAUSTED 0x08000000
|
||||||
|
#define W2_T_TRANSMIT_UNDERRUN 0x10000000
|
||||||
|
#define W2_T_RETRY_LIMIT_EXC 0x20000000
|
||||||
|
#define W2_T_WRAP 0x40000000
|
||||||
|
#define W2_T_USED 0x80000000
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void emac_init(int prio);
|
||||||
|
void EMACSetAddress(const uint8_t *eaddr);
|
||||||
|
bool_t EMACGetLinkStatus(void);
|
||||||
|
BufDescriptorEntry *EMACGetTransmitBuffer(void);
|
||||||
|
void EMACTransmit(BufDescriptorEntry *cptr, size_t size);
|
||||||
|
bool_t EMACReceive(uint8_t *buf, size_t *sizep);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern EventSource EMACFrameTransmitted, EMACFrameReceived;
|
||||||
|
|
||||||
|
#endif /* _SAM7X_EMAC_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,224 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7-AT91SAM7X/sam7x_serial.c
|
||||||
|
* @brief AT91SAM7X Serial driver code.
|
||||||
|
* @addtogroup AT91SAM7X_SERIAL
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
#include "board.h"
|
||||||
|
#include "sam7x_serial.h"
|
||||||
|
#include "at91lib/aic.h"
|
||||||
|
|
||||||
|
#if USE_SAM7X_USART0 || defined(__DOXYGEN__)
|
||||||
|
/** @brief USART0 serial driver identifier.*/
|
||||||
|
FullDuplexDriver COM1;
|
||||||
|
|
||||||
|
static uint8_t ib1[SERIAL_BUFFERS_SIZE];
|
||||||
|
static uint8_t ob1[SERIAL_BUFFERS_SIZE];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_SAM7X_USART1 || defined(__DOXYGEN__)
|
||||||
|
/** @brief USART1 serial driver identifier.*/
|
||||||
|
FullDuplexDriver COM2;
|
||||||
|
|
||||||
|
static uint8_t ib2[SERIAL_BUFFERS_SIZE];
|
||||||
|
static uint8_t ob2[SERIAL_BUFFERS_SIZE];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void SetError(AT91_REG csr, FullDuplexDriver *com) {
|
||||||
|
dflags_t sts = 0;
|
||||||
|
|
||||||
|
if (csr & AT91C_US_OVRE)
|
||||||
|
sts |= SD_OVERRUN_ERROR;
|
||||||
|
if (csr & AT91C_US_PARE)
|
||||||
|
sts |= SD_PARITY_ERROR;
|
||||||
|
if (csr & AT91C_US_FRAME)
|
||||||
|
sts |= SD_FRAMING_ERROR;
|
||||||
|
if (csr & AT91C_US_RXBRK)
|
||||||
|
sts |= SD_BREAK_DETECTED;
|
||||||
|
chSysLockFromIsr();
|
||||||
|
chFDDAddFlagsI(com, sts);
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @cond never*/
|
||||||
|
__attribute__((noinline))
|
||||||
|
/** @endcond*/
|
||||||
|
/**
|
||||||
|
* @brief Common IRQ handler.
|
||||||
|
* @param[in] u pointer to an USART I/O block
|
||||||
|
* @param[in] com communication channel associated to the USART
|
||||||
|
*/
|
||||||
|
static void ServeInterrupt(AT91PS_USART u, FullDuplexDriver *com) {
|
||||||
|
|
||||||
|
if (u->US_CSR & AT91C_US_RXRDY) {
|
||||||
|
chSysLockFromIsr();
|
||||||
|
chFDDIncomingDataI(com, u->US_RHR);
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
}
|
||||||
|
if (u->US_CSR & AT91C_US_TXRDY) {
|
||||||
|
chSysLockFromIsr();
|
||||||
|
msg_t b = chFDDRequestDataI(com);
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
if (b < Q_OK)
|
||||||
|
u->US_IDR = AT91C_US_TXRDY;
|
||||||
|
else
|
||||||
|
u->US_THR = b;
|
||||||
|
}
|
||||||
|
if (u->US_CSR & (AT91C_US_OVRE | AT91C_US_FRAME | AT91C_US_PARE | AT91C_US_RXBRK)) {
|
||||||
|
SetError(u->US_CSR, com);
|
||||||
|
u->US_CR = AT91C_US_RSTSTA;
|
||||||
|
}
|
||||||
|
AT91C_BASE_AIC->AIC_EOICR = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_SAM7X_USART0 || defined(__DOXYGEN__)
|
||||||
|
CH_IRQ_HANDLER(USART0IrqHandler) {
|
||||||
|
|
||||||
|
CH_IRQ_PROLOGUE();
|
||||||
|
|
||||||
|
ServeInterrupt(AT91C_BASE_US0, &COM1);
|
||||||
|
|
||||||
|
CH_IRQ_EPILOGUE();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OutNotify1(void) {
|
||||||
|
|
||||||
|
AT91C_BASE_US0->US_IER = AT91C_US_TXRDY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_SAM7X_USART1 || defined(__DOXYGEN__)
|
||||||
|
CH_IRQ_HANDLER(USART1IrqHandler) {
|
||||||
|
|
||||||
|
CH_IRQ_PROLOGUE();
|
||||||
|
|
||||||
|
ServeInterrupt(AT91C_BASE_US1, &COM2);
|
||||||
|
|
||||||
|
CH_IRQ_EPILOGUE();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OutNotify2(void) {
|
||||||
|
|
||||||
|
AT91C_BASE_US1->US_IER = AT91C_US_TXRDY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief USART setup.
|
||||||
|
* @param[in] u pointer to an UART I/O block
|
||||||
|
* @param[in] speed serial port speed in bits per second
|
||||||
|
* @param[in] mr the value for the @p MR register
|
||||||
|
* @note Must be invoked with interrupts disabled.
|
||||||
|
* @note Does not reset the I/O queues.
|
||||||
|
*/
|
||||||
|
void usart_setup(AT91PS_USART u, int speed, int mr) {
|
||||||
|
|
||||||
|
/* Disables IRQ sources and stop operations.*/
|
||||||
|
u->US_IDR = 0xFFFFFFFF;
|
||||||
|
u->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX | AT91C_US_RSTSTA;
|
||||||
|
|
||||||
|
/* New parameters setup.*/
|
||||||
|
if (mr & AT91C_US_OVER)
|
||||||
|
u->US_BRGR = MCK / (speed * 8);
|
||||||
|
else
|
||||||
|
u->US_BRGR = MCK / (speed * 16);
|
||||||
|
u->US_MR = mr;
|
||||||
|
u->US_RTOR = 0;
|
||||||
|
u->US_TTGR = 0;
|
||||||
|
|
||||||
|
/* Enables operations and IRQ sources.*/
|
||||||
|
u->US_CR = AT91C_US_RXEN | AT91C_US_TXEN | AT91C_US_DTREN | AT91C_US_RTSEN;
|
||||||
|
u->US_IER = AT91C_US_RXRDY | AT91C_US_OVRE | AT91C_US_FRAME | AT91C_US_PARE |
|
||||||
|
AT91C_US_RXBRK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Serial driver initialization.
|
||||||
|
* @param[in] prio0 priority to be assigned to the USART1 IRQ
|
||||||
|
* @param[in] prio1 priority to be assigned to the USART2 IRQ
|
||||||
|
* @note Handshake pads are not enabled inside this function because they
|
||||||
|
* may have another use, enable them externally if needed.
|
||||||
|
* RX and TX pads are handled inside.
|
||||||
|
*/
|
||||||
|
void serial_init(int prio0, int prio1) {
|
||||||
|
|
||||||
|
#if USE_SAM7X_USART0 || defined(__DOXYGEN__)
|
||||||
|
/* I/O queue setup.*/
|
||||||
|
chFDDInit(&COM1, ib1, sizeof ib1, NULL, ob1, sizeof ob1, OutNotify1);
|
||||||
|
|
||||||
|
/* Switches the I/O pins to the peripheral function A, disables pullups.*/
|
||||||
|
AT91C_BASE_PIOA->PIO_PDR = AT91C_PA0_RXD0 | AT91C_PA1_TXD0;
|
||||||
|
AT91C_BASE_PIOA->PIO_ASR = AT91C_PIO_PA0 | AT91C_PIO_PA1;
|
||||||
|
AT91C_BASE_PIOA->PIO_PPUDR = AT91C_PIO_PA0 | AT91C_PIO_PA1;
|
||||||
|
|
||||||
|
/* Starts the clock and clears possible sources of immediate interrupts.*/
|
||||||
|
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_US0);
|
||||||
|
AT91C_BASE_US0->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX | AT91C_US_RSTSTA;
|
||||||
|
|
||||||
|
/* Interrupts setup.*/
|
||||||
|
AIC_ConfigureIT(AT91C_ID_US0,
|
||||||
|
AT91C_AIC_SRCTYPE_HIGH_LEVEL | prio0,
|
||||||
|
USART0IrqHandler);
|
||||||
|
AIC_EnableIT(AT91C_ID_US0);
|
||||||
|
|
||||||
|
/* Default parameters.*/
|
||||||
|
usart_setup(AT91C_BASE_US0, DEFAULT_USART_BITRATE,
|
||||||
|
AT91C_US_USMODE_NORMAL |
|
||||||
|
AT91C_US_CLKS_CLOCK |
|
||||||
|
AT91C_US_CHRL_8_BITS |
|
||||||
|
AT91C_US_PAR_NONE |
|
||||||
|
AT91C_US_NBSTOP_1_BIT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_SAM7X_USART1 || defined(__DOXYGEN__)
|
||||||
|
/* I/O queues setup.*/
|
||||||
|
chFDDInit(&COM2, ib2, sizeof ib2, NULL, ob2, sizeof ob2, OutNotify2);
|
||||||
|
|
||||||
|
/* Switches the I/O pins to the peripheral function A, disables pullups.*/
|
||||||
|
AT91C_BASE_PIOA->PIO_PDR = AT91C_PA5_RXD1 | AT91C_PA6_TXD1;
|
||||||
|
AT91C_BASE_PIOA->PIO_ASR = AT91C_PIO_PA5 | AT91C_PIO_PA6;
|
||||||
|
AT91C_BASE_PIOA->PIO_PPUDR = AT91C_PIO_PA5 | AT91C_PIO_PA6;
|
||||||
|
|
||||||
|
/* Starts the clock and clears possible sources of immediate interrupts.*/
|
||||||
|
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_US1);
|
||||||
|
AT91C_BASE_US1->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX | AT91C_US_RSTSTA;
|
||||||
|
|
||||||
|
/* Interrupts setup.*/
|
||||||
|
AIC_ConfigureIT(AT91C_ID_US1,
|
||||||
|
AT91C_AIC_SRCTYPE_HIGH_LEVEL | prio1,
|
||||||
|
USART1IrqHandler);
|
||||||
|
AIC_EnableIT(AT91C_ID_US1);
|
||||||
|
|
||||||
|
/* Default parameters.*/
|
||||||
|
usart_setup(AT91C_BASE_US1, DEFAULT_USART_BITRATE,
|
||||||
|
AT91C_US_USMODE_NORMAL |
|
||||||
|
AT91C_US_CLKS_CLOCK |
|
||||||
|
AT91C_US_CHRL_8_BITS |
|
||||||
|
AT91C_US_PAR_NONE |
|
||||||
|
AT91C_US_NBSTOP_1_BIT);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7-AT91SAM7X/sam7x_serial.h
|
||||||
|
* @brief AT91SAM7X Serial driver macros and structures.
|
||||||
|
* @addtogroup AT91SAM7X_SERIAL
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SAM7X_SERIAL_H_
|
||||||
|
#define _SAM7X_SERIAL_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Serial buffers size.
|
||||||
|
* @details Configuration parameter, you can change the depth of the queue
|
||||||
|
* buffers depending on the requirements of your application.
|
||||||
|
* @note The default is 128 bytes for both the transmission and receive buffers.
|
||||||
|
*/
|
||||||
|
#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
|
||||||
|
#define SERIAL_BUFFERS_SIZE 128
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default bit rate.
|
||||||
|
* @details Configuration parameter, at startup the UARTs are configured at
|
||||||
|
* this speed.
|
||||||
|
* @note It is possible to use @p SetUART() in order to change the working
|
||||||
|
* parameters at runtime.
|
||||||
|
*/
|
||||||
|
#if !defined(DEFAULT_USART_BITRATE) || defined(__DOXYGEN__)
|
||||||
|
#define DEFAULT_USART_BITRATE 38400
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief UART0 driver enable switch.
|
||||||
|
* @details If set to @p TRUE the support for USART1 is included.
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
*/
|
||||||
|
#if !defined(USE_SAM7X_USART0) || defined(__DOXYGEN__)
|
||||||
|
#define USE_SAM7X_USART0 TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief UART1 driver enable switch.
|
||||||
|
* @details If set to @p TRUE the support for USART2 is included.
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
*/
|
||||||
|
#if !defined(USE_SAM7X_USART1) || defined(__DOXYGEN__)
|
||||||
|
#define USE_SAM7X_USART1 TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void serial_init(int prio0, int prio1);
|
||||||
|
void usart_setup(AT91PS_USART u, int speed, int mr);
|
||||||
|
CH_IRQ_HANDLER(UART0IrqHandler);
|
||||||
|
CH_IRQ_HANDLER(UART1IrqHandler);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @cond never*/
|
||||||
|
extern FullDuplexDriver COM1, COM2;
|
||||||
|
/** @endcond*/
|
||||||
|
|
||||||
|
#endif /* _SAM7X_SERIAL_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.section vectors
|
||||||
|
.code 32
|
||||||
|
.balign 4
|
||||||
|
/*
|
||||||
|
* System entry points.
|
||||||
|
*/
|
||||||
|
_start:
|
||||||
|
ldr pc, _reset
|
||||||
|
ldr pc, _undefined
|
||||||
|
ldr pc, _swi
|
||||||
|
ldr pc, _prefetch
|
||||||
|
ldr pc, _abort
|
||||||
|
nop
|
||||||
|
ldr pc, [pc,#-0xF20] /* AIC - AIC_IVR */
|
||||||
|
ldr pc, [pc,#-0xF20] /* AIC - AIC_FVR */
|
||||||
|
|
||||||
|
_reset:
|
||||||
|
.word ResetHandler /* In crt0.s */
|
||||||
|
_undefined:
|
||||||
|
.word UndHandler
|
||||||
|
_swi:
|
||||||
|
.word SwiHandler
|
||||||
|
_prefetch:
|
||||||
|
.word PrefetchHandler
|
||||||
|
_abort:
|
||||||
|
.word AbortHandler
|
||||||
|
.word 0
|
||||||
|
.word 0
|
||||||
|
.word 0
|
||||||
|
|
||||||
|
.text
|
||||||
|
.code 32
|
||||||
|
.balign 4
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default exceptions handlers. The handlers are declared weak in order to be
|
||||||
|
* replaced by the real handling code. Everything is defaulted to an infinite
|
||||||
|
* loop.
|
||||||
|
*/
|
||||||
|
.weak UndHandler
|
||||||
|
UndHandler:
|
||||||
|
|
||||||
|
.weak SwiHandler
|
||||||
|
SwiHandler:
|
||||||
|
|
||||||
|
.weak PrefetchHandler
|
||||||
|
PrefetchHandler:
|
||||||
|
|
||||||
|
.weak AbortHandler
|
||||||
|
AbortHandler:
|
||||||
|
|
||||||
|
.weak FiqHandler
|
||||||
|
FiqHandler:
|
||||||
|
|
||||||
|
.loop: b .loop
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _WFI_H_
|
||||||
|
#define _WFI_H_
|
||||||
|
|
||||||
|
#include "at91lib/AT91SAM7X256.h"
|
||||||
|
|
||||||
|
#ifndef port_wait_for_interrupt
|
||||||
|
#if ENABLE_WFI_IDLE != 0
|
||||||
|
#define port_wait_for_interrupt() { \
|
||||||
|
AT91C_BASE_SYS->PMC_SCDR = AT91C_PMC_PCK; \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define port_wait_for_interrupt()
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _WFI_H_ */
|
|
@ -0,0 +1,523 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file lpc214x.h
|
||||||
|
* @brief LPC214x register definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LPC214X_H_
|
||||||
|
#define _LPC214X_H_
|
||||||
|
|
||||||
|
typedef volatile unsigned char IOREG8;
|
||||||
|
typedef volatile unsigned int IOREG32;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* System.
|
||||||
|
*/
|
||||||
|
#define MEMMAP (*((IOREG32 *)0xE01FC040))
|
||||||
|
#define PCON (*((IOREG32 *)0xE01FC0C0))
|
||||||
|
#define PCONP (*((IOREG32 *)0xE01FC0C4))
|
||||||
|
#define VPBDIV (*((IOREG32 *)0xE01FC100))
|
||||||
|
#define EXTINT (*((IOREG32 *)0xE01FC140))
|
||||||
|
#define INTWAKE (*((IOREG32 *)0xE01FC144))
|
||||||
|
#define EXTMODE (*((IOREG32 *)0xE01FC148))
|
||||||
|
#define EXTPOLAR (*((IOREG32 *)0xE01FC14C))
|
||||||
|
#define RSID (*((IOREG32 *)0xE01FC180))
|
||||||
|
#define CSPR (*((IOREG32 *)0xE01FC184))
|
||||||
|
#define SCS (*((IOREG32 *)0xE01FC1A0))
|
||||||
|
|
||||||
|
#define VPD_D4 0
|
||||||
|
#define VPD_D1 1
|
||||||
|
#define VPD_D2 2
|
||||||
|
#define VPD_RESERVED 3
|
||||||
|
|
||||||
|
#define PCTIM0 (1 << 1)
|
||||||
|
#define PCTIM1 (1 << 2)
|
||||||
|
#define PCUART0 (1 << 3)
|
||||||
|
#define PCUART1 (1 << 4)
|
||||||
|
#define PCPWM0 (1 << 5)
|
||||||
|
#define PCI2C0 (1 << 7)
|
||||||
|
#define PCSPI0 (1 << 8)
|
||||||
|
#define PCRTC (1 << 9)
|
||||||
|
#define PCSPI1 (1 << 10)
|
||||||
|
#define PCAD0 (1 << 12)
|
||||||
|
#define PCI2C1 (1 << 19)
|
||||||
|
#define PCAD1 (1 << 20)
|
||||||
|
#define PCUSB (1 << 31)
|
||||||
|
#define PCALL (PCTIM0 | PCTIM1 | PCUART0 | PCUART1 | \
|
||||||
|
PCPWM0 | PCI2C0 | PCSPI0 | PCRTC | PCSPI1 | \
|
||||||
|
PCAD0 | PCI2C1 | PCAD1 | PCUSB)
|
||||||
|
|
||||||
|
#define EINT0 1
|
||||||
|
#define EINT1 2
|
||||||
|
#define EINT2 4
|
||||||
|
#define EINT3 8
|
||||||
|
|
||||||
|
#define EXTWAKE0 1
|
||||||
|
#define EXTWAKE1 2
|
||||||
|
#define EXTWAKE2 4
|
||||||
|
#define EXTWAKE3 8
|
||||||
|
#define USBWAKE 0x20
|
||||||
|
#define BODWAKE 0x4000
|
||||||
|
#define RTCWAKE 0x8000
|
||||||
|
|
||||||
|
#define EXTMODE0 1
|
||||||
|
#define EXTMODE1 2
|
||||||
|
#define EXTMODE2 4
|
||||||
|
#define EXTMODE3 8
|
||||||
|
|
||||||
|
#define EXTPOLAR0 1
|
||||||
|
#define EXTPOLAR1 2
|
||||||
|
#define EXTPOLAR2 4
|
||||||
|
#define EXTPOLAR3 8
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
IOREG32 PLL_CON;
|
||||||
|
IOREG32 PLL_CFG;
|
||||||
|
IOREG32 PLL_STAT;
|
||||||
|
IOREG32 PLL_FEED;
|
||||||
|
} PLL;
|
||||||
|
|
||||||
|
#define PLL0Base ((PLL *)0xE01FC080)
|
||||||
|
#define PLL1Base ((PLL *)0xE01FC0A0)
|
||||||
|
#define PLL0CON (PLL0Base->PLL_CON)
|
||||||
|
#define PLL0CFG (PLL0Base->PLL_CFG)
|
||||||
|
#define PLL0STAT (PLL0Base->PLL_STAT)
|
||||||
|
#define PLL0FEED (PLL0Base->PLL_FEED)
|
||||||
|
#define PLL1CON (PLL1Base->PLL_CON)
|
||||||
|
#define PLL1CFG (PLL1Base->PLL_CFG)
|
||||||
|
#define PLL1STAT (PLL1Base->PLL_STAT)
|
||||||
|
#define PLL1FEED (PLL1Base->PLL_FEED)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pins.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
IOREG32 PS_SEL0;
|
||||||
|
IOREG32 PS_SEL1;
|
||||||
|
IOREG32 PS_SEL2;
|
||||||
|
} PS;
|
||||||
|
|
||||||
|
#define PSBase ((PS *)0xE002C000)
|
||||||
|
#define PINSEL0 (PSBase->PS_SEL0)
|
||||||
|
#define PINSEL1 (PSBase->PS_SEL1)
|
||||||
|
#define PINSEL2 (PSBase->PS_SEL2)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* VIC
|
||||||
|
*/
|
||||||
|
#define SOURCE_WDT 0
|
||||||
|
#define SOURCE_ARMCore0 2
|
||||||
|
#define SOURCE_ARMCore1 3
|
||||||
|
#define SOURCE_Timer0 4
|
||||||
|
#define SOURCE_Timer1 5
|
||||||
|
#define SOURCE_UART0 6
|
||||||
|
#define SOURCE_UART1 7
|
||||||
|
#define SOURCE_PWM0 8
|
||||||
|
#define SOURCE_I2C0 9
|
||||||
|
#define SOURCE_SPI0 10
|
||||||
|
#define SOURCE_SPI1 11
|
||||||
|
#define SOURCE_PLL 12
|
||||||
|
#define SOURCE_RTC 13
|
||||||
|
#define SOURCE_EINT0 14
|
||||||
|
#define SOURCE_EINT1 15
|
||||||
|
#define SOURCE_EINT2 16
|
||||||
|
#define SOURCE_EINT3 17
|
||||||
|
#define SOURCE_ADC0 18
|
||||||
|
#define SOURCE_I2C1 19
|
||||||
|
#define SOURCE_BOD 20
|
||||||
|
#define SOURCE_ADC1 21
|
||||||
|
#define SOURCE_USB 22
|
||||||
|
|
||||||
|
#define INTMASK(n) (1 << (n))
|
||||||
|
#define ALLINTMASK (INTMASK(SOURCE_WDT) | INTMASK(SOURCE_ARMCore0) | \
|
||||||
|
INTMASK(SOURCE_ARMCore1) | INTMASK(SOURCE_Timer0) | \
|
||||||
|
INTMASK(SOURCE_Timer1) | INTMASK(SOURCE_UART0) | \
|
||||||
|
INTMASK(SOURCE_UART1) | INTMASK(SOURCE_PWM0) | \
|
||||||
|
INTMASK(SOURCE_I2C0) | INTMASK(SOURCE_SPI0) | \
|
||||||
|
INTMASK(SOURCE_SPI1) | INTMASK(SOURCE_PLL) | \
|
||||||
|
INTMASK(SOURCE_RTC) | INTMASK(SOURCE_EINT0) | \
|
||||||
|
INTMASK(SOURCE_EINT1) | INTMASK(SOURCE_EINT2) | \
|
||||||
|
INTMASK(SOURCE_EINT3) | INTMASK(SOURCE_ADC0) | \
|
||||||
|
INTMASK(SOURCE_I2C1) | INTMASK(SOURCE_BOD) | \
|
||||||
|
INTMASK(SOURCE_ADC1) | INTMASK(SOURCE_USB))
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
IOREG32 VIC_IRQStatus;
|
||||||
|
IOREG32 VIC_FIQStatus;
|
||||||
|
IOREG32 VIC_RawIntr;
|
||||||
|
IOREG32 VIC_IntSelect;
|
||||||
|
IOREG32 VIC_IntEnable;
|
||||||
|
IOREG32 VIC_IntEnClear;
|
||||||
|
IOREG32 VIC_SoftInt;
|
||||||
|
IOREG32 VIC_SoftIntClear;
|
||||||
|
IOREG32 VIC_Protection;
|
||||||
|
IOREG32 unused1[3];
|
||||||
|
IOREG32 VIC_VectAddr;
|
||||||
|
IOREG32 VIC_DefVectAddr;
|
||||||
|
IOREG32 unused2[50];
|
||||||
|
IOREG32 VIC_VectAddrs[16];
|
||||||
|
IOREG32 unused3[48];
|
||||||
|
IOREG32 VIC_VectCntls[16];
|
||||||
|
} VIC;
|
||||||
|
|
||||||
|
#define VICBase ((VIC *)0xFFFFF000)
|
||||||
|
#define VICVectorsBase ((IOREG32 *)0xFFFFF100)
|
||||||
|
#define VICControlsBase ((IOREG32 *)0xFFFFF200)
|
||||||
|
|
||||||
|
#define VICIRQStatus (VICBase->VIC_IRQStatus)
|
||||||
|
#define VICFIQStatus (VICBase->VIC_FIQStatus)
|
||||||
|
#define VICRawIntr (VICBase->VIC_RawIntr)
|
||||||
|
#define VICIntSelect (VICBase->VIC_IntSelect)
|
||||||
|
#define VICIntEnable (VICBase->VIC_IntEnable)
|
||||||
|
#define VICIntEnClear (VICBase->VIC_IntEnClear)
|
||||||
|
#define VICSoftInt (VICBase->VIC_SoftInt)
|
||||||
|
#define VICSoftIntClear (VICBase->VIC_SoftIntClear)
|
||||||
|
#define VICProtection (VICBase->VIC_Protection)
|
||||||
|
#define VICVectAddr (VICBase->VIC_VectAddr)
|
||||||
|
#define VICDefVectAddr (VICBase->VIC_DefVectAddr)
|
||||||
|
|
||||||
|
#define VICVectAddrs(n) (VICBase->VIC_VectAddrs[n])
|
||||||
|
#define VICVectCntls(n) (VICBase->VIC_VectCntls[n])
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MAM.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
IOREG32 MAM_Control;
|
||||||
|
IOREG32 MAM_Timing;
|
||||||
|
} MAM;
|
||||||
|
|
||||||
|
#define MAMBase ((MAM *)0xE01FC000)
|
||||||
|
#define MAMCR (MAMBase->MAM_Control)
|
||||||
|
#define MAMTIM (MAMBase->MAM_Timing)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPIO - FIO.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
IOREG32 IO_PIN;
|
||||||
|
IOREG32 IO_SET;
|
||||||
|
IOREG32 IO_DIR;
|
||||||
|
IOREG32 IO_CLR;
|
||||||
|
} GPIO;
|
||||||
|
|
||||||
|
#define GPIO0Base ((GPIO *)0xE0028000)
|
||||||
|
#define IO0PIN (GPIO0Base->IO_PIN)
|
||||||
|
#define IO0SET (GPIO0Base->IO_SET)
|
||||||
|
#define IO0DIR (GPIO0Base->IO_DIR)
|
||||||
|
#define IO0CLR (GPIO0Base->IO_CLR)
|
||||||
|
|
||||||
|
#define GPIO1Base ((GPIO *)0xE0028010)
|
||||||
|
#define IO1PIN (GPIO1Base->IO_PIN)
|
||||||
|
#define IO1SET (GPIO1Base->IO_SET)
|
||||||
|
#define IO1DIR (GPIO1Base->IO_DIR)
|
||||||
|
#define IO1CLR (GPIO1Base->IO_CLR)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
IOREG32 FIO_DIR;
|
||||||
|
IOREG32 unused1;
|
||||||
|
IOREG32 unused2;
|
||||||
|
IOREG32 unused3;
|
||||||
|
IOREG32 FIO_MASK;
|
||||||
|
IOREG32 FIO_PIN;
|
||||||
|
IOREG32 FIO_SET;
|
||||||
|
IOREG32 FIO_CLR;
|
||||||
|
} FIO;
|
||||||
|
|
||||||
|
#define FIO0Base ((FIO *)0x3FFFC000)
|
||||||
|
#define FIO0DIR (FIO0Base->FIO_DIR)
|
||||||
|
#define FIO0MASK (FIO0Base->FIO_MASK)
|
||||||
|
#define FIO0PIN (FIO0Base->FIO_PIN)
|
||||||
|
#define FIO0SET (FIO0Base->FIO_SET)
|
||||||
|
#define FIO0CLR (FIO0Base->FIO_CLR)
|
||||||
|
|
||||||
|
#define FIO1Base ((FIO *)0x3FFFC020)
|
||||||
|
#define FIO1DIR (FIO1Base->FIO_DIR)
|
||||||
|
#define FIO1MASK (FIO1Base->FIO_MASK)
|
||||||
|
#define FIO1PIN (FIO1Base->FIO_PIN)
|
||||||
|
#define FIO1SET (FIO1Base->FIO_SET)
|
||||||
|
#define FIO1CLR (FIO1Base->FIO_CLR)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* UART.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
union {
|
||||||
|
IOREG32 UART_RBR;
|
||||||
|
IOREG32 UART_THR;
|
||||||
|
IOREG32 UART_DLL;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
IOREG32 UART_IER;
|
||||||
|
IOREG32 UART_DLM;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
IOREG32 UART_IIR;
|
||||||
|
IOREG32 UART_FCR;
|
||||||
|
};
|
||||||
|
IOREG32 UART_LCR;
|
||||||
|
IOREG32 UART_MCR; // UART1 only
|
||||||
|
IOREG32 UART_LSR;
|
||||||
|
IOREG32 unused18;
|
||||||
|
IOREG32 UART_SCR;
|
||||||
|
IOREG32 UART_ACR;
|
||||||
|
IOREG32 unused24;
|
||||||
|
IOREG32 UART_FDR;
|
||||||
|
IOREG32 unused2C;
|
||||||
|
IOREG32 UART_TER;
|
||||||
|
} UART;
|
||||||
|
|
||||||
|
#define U0Base ((UART *)0xE000C000)
|
||||||
|
#define U0RBR (U0Base->UART_RBR)
|
||||||
|
#define U0THR (U0Base->UART_THR)
|
||||||
|
#define U0DLL (U0Base->UART_DLL)
|
||||||
|
#define U0IER (U0Base->UART_IER)
|
||||||
|
#define U0DLM (U0Base->UART_DLM)
|
||||||
|
#define U0IIR (U0Base->UART_IIR)
|
||||||
|
#define U0FCR (U0Base->UART_FCR)
|
||||||
|
#define U0LCR (U0Base->UART_LCR)
|
||||||
|
#define U0LSR (U0Base->UART_LSR)
|
||||||
|
#define U0SCR (U0Base->UART_SCR)
|
||||||
|
#define U0ACR (U0Base->UART_ACR)
|
||||||
|
#define U0FDR (U0Base->UART_FDR)
|
||||||
|
#define U0TER (U0Base->UART_TER)
|
||||||
|
|
||||||
|
#define U1Base ((UART *)0xE0010000)
|
||||||
|
#define U1RBR (U1Base->UART_RBR)
|
||||||
|
#define U1THR (U1Base->UART_THR)
|
||||||
|
#define U1DLL (U1Base->UART_DLL)
|
||||||
|
#define U1IER (U1Base->UART_IER)
|
||||||
|
#define U1DLM (U1Base->UART_DLM)
|
||||||
|
#define U1IIR (U1Base->UART_IIR)
|
||||||
|
#define U1FCR (U1Base->UART_FCR)
|
||||||
|
#define U1MCR (U1Base->UART_MCR)
|
||||||
|
#define U1LCR (U1Base->UART_LCR)
|
||||||
|
#define U1LSR (U1Base->UART_LSR)
|
||||||
|
#define U1SCR (U1Base->UART_SCR)
|
||||||
|
#define U1ACR (U1Base->UART_ACR)
|
||||||
|
#define U1FDR (U1Base->UART_FDR)
|
||||||
|
#define U1TER (U1Base->UART_TER)
|
||||||
|
|
||||||
|
#define IIR_SRC_MASK 0x0F
|
||||||
|
#define IIR_SRC_NONE 0x01
|
||||||
|
#define IIR_SRC_TX 0x02
|
||||||
|
#define IIR_SRC_RX 0x04
|
||||||
|
#define IIR_SRC_ERROR 0x06
|
||||||
|
#define IIR_SRC_TIMEOUT 0x0C
|
||||||
|
|
||||||
|
#define IER_RBR 1
|
||||||
|
#define IER_THRE 2
|
||||||
|
#define IER_STATUS 4
|
||||||
|
|
||||||
|
#define IIR_INT_PENDING 1
|
||||||
|
|
||||||
|
#define LCR_WL5 0
|
||||||
|
#define LCR_WL6 1
|
||||||
|
#define LCR_WL7 2
|
||||||
|
#define LCR_WL8 3
|
||||||
|
#define LCR_STOP1 0
|
||||||
|
#define LCR_STOP2 4
|
||||||
|
#define LCR_NOPARITY 0
|
||||||
|
#define LCR_PARITYODD 0x08
|
||||||
|
#define LCR_PARITYEVEN 0x18
|
||||||
|
#define LCR_PARITYONE 0x28
|
||||||
|
#define LCR_PARITYZERO 0x38
|
||||||
|
#define LCR_BREAK_ON 0x40
|
||||||
|
#define LCR_DLAB 0x80
|
||||||
|
|
||||||
|
#define FCR_ENABLE 1
|
||||||
|
#define FCR_RXRESET 2
|
||||||
|
#define FCR_TXRESET 4
|
||||||
|
#define FCR_TRIGGER0 0
|
||||||
|
#define FCR_TRIGGER1 0x40
|
||||||
|
#define FCR_TRIGGER2 0x80
|
||||||
|
#define FCR_TRIGGER3 0xC0
|
||||||
|
|
||||||
|
#define LSR_RBR_FULL 1
|
||||||
|
#define LSR_OVERRUN 2
|
||||||
|
#define LSR_PARITY 4
|
||||||
|
#define LSR_FRAMING 8
|
||||||
|
#define LSR_BREAK 0x10
|
||||||
|
#define LSR_THRE 0x20
|
||||||
|
#define LSR_TEMT 0x40
|
||||||
|
#define LSR_RXFE 0x80
|
||||||
|
|
||||||
|
#define TER_ENABLE 0x80
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SSP.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
IOREG32 SSP_CR0;
|
||||||
|
IOREG32 SSP_CR1;
|
||||||
|
IOREG32 SSP_DR;
|
||||||
|
IOREG32 SSP_SR;
|
||||||
|
IOREG32 SSP_CPSR;
|
||||||
|
IOREG32 SSP_IMSC;
|
||||||
|
IOREG32 SSP_RIS;
|
||||||
|
IOREG32 SSP_MIS;
|
||||||
|
IOREG32 SSP_ICR;
|
||||||
|
} SSP;
|
||||||
|
|
||||||
|
#define SSPBase ((SSP *)0xE0068000)
|
||||||
|
#define SSPCR0 (SSPBase->SSP_CR0)
|
||||||
|
#define SSPCR1 (SSPBase->SSP_CR1)
|
||||||
|
#define SSPDR (SSPBase->SSP_DR)
|
||||||
|
#define SSPSR (SSPBase->SSP_SR)
|
||||||
|
#define SSPCPSR (SSPBase->SSP_CPSR)
|
||||||
|
#define SSPIMSC (SSPBase->SSP_IMSC)
|
||||||
|
#define SSPRIS (SSPBase->SSP_RIS)
|
||||||
|
#define SSPMIS (SSPBase->SSP_MIS)
|
||||||
|
#define SSPICR (SSPBase->SSP_ICR)
|
||||||
|
|
||||||
|
#define CR0_DSS4BIT 3
|
||||||
|
#define CR0_DSS5BIT 4
|
||||||
|
#define CR0_DSS6BIT 5
|
||||||
|
#define CR0_DSS7BIT 6
|
||||||
|
#define CR0_DSS8BIT 7
|
||||||
|
#define CR0_DSS9BIT 8
|
||||||
|
#define CR0_DSS10BIT 9
|
||||||
|
#define CR0_DSS11BIT 0xA
|
||||||
|
#define CR0_DSS12BIT 0xB
|
||||||
|
#define CR0_DSS13BIT 0xC
|
||||||
|
#define CR0_DSS14BIT 0xD
|
||||||
|
#define CR0_DSS15BIT 0xE
|
||||||
|
#define CR0_DSS16BIT 0xF
|
||||||
|
#define CR0_FRFSPI 0
|
||||||
|
#define CR0_FRFSSI 0x10
|
||||||
|
#define CR0_FRFMW 0x20
|
||||||
|
#define CR0_CPOL 0x40
|
||||||
|
#define CR0_CPHA 0x80
|
||||||
|
#define CR0_CLOCKRATE(n) ((n) << 8)
|
||||||
|
|
||||||
|
#define CR1_LBM 1
|
||||||
|
#define CR1_SSE 2
|
||||||
|
#define CR1_MS 4
|
||||||
|
#define CR1_SOD 8
|
||||||
|
|
||||||
|
#define SR_TFE 1
|
||||||
|
#define SR_TNF 2
|
||||||
|
#define SR_RNE 4
|
||||||
|
#define SR_RFF 8
|
||||||
|
#define SR_BSY 0x10
|
||||||
|
|
||||||
|
#define IMSC_ROR 1
|
||||||
|
#define IMSC_RT 2
|
||||||
|
#define IMSC_RX 4
|
||||||
|
#define IMSC_TX 8
|
||||||
|
|
||||||
|
#define RIS_ROR 1
|
||||||
|
#define RIS_RT 2
|
||||||
|
#define RIS_RX 4
|
||||||
|
#define RIS_TX 8
|
||||||
|
|
||||||
|
#define MIS_ROR 1
|
||||||
|
#define MIS_RT 2
|
||||||
|
#define MIS_RX 4
|
||||||
|
#define MIS_TX 8
|
||||||
|
|
||||||
|
#define ICR_ROR 1
|
||||||
|
#define ICR_RT 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Timers/Counters.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
IOREG32 TC_IR;
|
||||||
|
IOREG32 TC_TCR;
|
||||||
|
IOREG32 TC_TC;
|
||||||
|
IOREG32 TC_PR;
|
||||||
|
IOREG32 TC_PC;
|
||||||
|
IOREG32 TC_MCR;
|
||||||
|
IOREG32 TC_MR0;
|
||||||
|
IOREG32 TC_MR1;
|
||||||
|
IOREG32 TC_MR2;
|
||||||
|
IOREG32 TC_MR3;
|
||||||
|
IOREG32 TC_CCR;
|
||||||
|
IOREG32 TC_CR0;
|
||||||
|
IOREG32 TC_CR1;
|
||||||
|
IOREG32 TC_CR2;
|
||||||
|
IOREG32 TC_CR3;
|
||||||
|
IOREG32 TC_EMR;
|
||||||
|
IOREG32 TC_CTCR;
|
||||||
|
} TC;
|
||||||
|
|
||||||
|
#define T0Base ((TC *)0xE0004000)
|
||||||
|
#define T0IR (T0Base->TC_IR)
|
||||||
|
#define T0TCR (T0Base->TC_TCR)
|
||||||
|
#define T0TC (T0Base->TC_TC)
|
||||||
|
#define T0PR (T0Base->TC_PR)
|
||||||
|
#define T0PC (T0Base->TC_PC)
|
||||||
|
#define T0MCR (T0Base->TC_MCR)
|
||||||
|
#define T0MR0 (T0Base->TC_MR0)
|
||||||
|
#define T0MR1 (T0Base->TC_MR1)
|
||||||
|
#define T0MR2 (T0Base->TC_MR2)
|
||||||
|
#define T0MR3 (T0Base->TC_MR3)
|
||||||
|
#define T0CCR (T0Base->TC_CCR)
|
||||||
|
#define T0CR0 (T0Base->TC_CR0)
|
||||||
|
#define T0CR1 (T0Base->TC_CR1)
|
||||||
|
#define T0CR2 (T0Base->TC_CR2)
|
||||||
|
#define T0CR3 (T0Base->TC_CR3)
|
||||||
|
#define T0EMR (T0Base->TC_EMR)
|
||||||
|
#define T0CTCR (T0Base->TC_CTCR)
|
||||||
|
|
||||||
|
#define T1Base ((TC *)0xE0008000)
|
||||||
|
#define T1IR (T1Base->TC_IR)
|
||||||
|
#define T1TCR (T1Base->TC_TCR)
|
||||||
|
#define T1TC (T1Base->TC_TC)
|
||||||
|
#define T1PR (T1Base->TC_PR)
|
||||||
|
#define T1PC (T1Base->TC_PC)
|
||||||
|
#define T1MCR (T1Base->TC_MCR)
|
||||||
|
#define T1MR0 (T1Base->TC_MR0)
|
||||||
|
#define T1MR1 (T1Base->TC_MR1)
|
||||||
|
#define T1MR2 (T1Base->TC_MR2)
|
||||||
|
#define T1MR3 (T1Base->TC_MR3)
|
||||||
|
#define T1CCR (T1Base->TC_CCR)
|
||||||
|
#define T1CR0 (T1Base->TC_CR0)
|
||||||
|
#define T1CR1 (T1Base->TC_CR1)
|
||||||
|
#define T1CR2 (T1Base->TC_CR2)
|
||||||
|
#define T1CR3 (T1Base->TC_CR3)
|
||||||
|
#define T1EMR (T1Base->TC_EMR)
|
||||||
|
#define T1CTCR (T1Base->TC_CTCR)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Watchdog.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
IOREG32 WD_MOD;
|
||||||
|
IOREG32 WD_TC;
|
||||||
|
IOREG32 WD_FEED;
|
||||||
|
IOREG32 WD_TV;
|
||||||
|
} WD;
|
||||||
|
|
||||||
|
#define WDBase ((WD *)0xE0000000)
|
||||||
|
#define WDMOD (WDBase->WD_MOD)
|
||||||
|
#define WDTC (WDBase->WD_TC)
|
||||||
|
#define WDFEED (WDBase->WD_FEED)
|
||||||
|
#define WDTV (WDBase->WD_TV)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DAC.
|
||||||
|
*/
|
||||||
|
#define DACR (*((IOREG32 *)0xE006C000))
|
||||||
|
|
||||||
|
#endif /* _LPC214X_H_ */
|
||||||
|
|
|
@ -0,0 +1,268 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7-LPC214x/lpc214x_serial.c
|
||||||
|
* @brief LPC214x Serial driver code.
|
||||||
|
* @addtogroup LPC214x_SERIAL
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
#include "lpc214x.h"
|
||||||
|
#include "vic.h"
|
||||||
|
#include "lpc214x_serial.h"
|
||||||
|
#include "board.h"
|
||||||
|
|
||||||
|
#if USE_LPC214x_UART0 || defined(__DOXYGEN__)
|
||||||
|
/** @brief UART0 serial driver identifier.*/
|
||||||
|
FullDuplexDriver COM1;
|
||||||
|
|
||||||
|
static uint8_t ib1[SERIAL_BUFFERS_SIZE];
|
||||||
|
static uint8_t ob1[SERIAL_BUFFERS_SIZE];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_LPC214x_UART1 || defined(__DOXYGEN__)
|
||||||
|
/** @brief UART1 serial driver identifier.*/
|
||||||
|
FullDuplexDriver COM2;
|
||||||
|
|
||||||
|
static uint8_t ib2[SERIAL_BUFFERS_SIZE];
|
||||||
|
static uint8_t ob2[SERIAL_BUFFERS_SIZE];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Error handling routine.
|
||||||
|
* @param[in] err UART LSR register value
|
||||||
|
* @param[in] com communication channel associated to the USART
|
||||||
|
*/
|
||||||
|
static void SetError(IOREG32 err, FullDuplexDriver *com) {
|
||||||
|
dflags_t sts = 0;
|
||||||
|
|
||||||
|
if (err & LSR_OVERRUN)
|
||||||
|
sts |= SD_OVERRUN_ERROR;
|
||||||
|
if (err & LSR_PARITY)
|
||||||
|
sts |= SD_PARITY_ERROR;
|
||||||
|
if (err & LSR_FRAMING)
|
||||||
|
sts |= SD_FRAMING_ERROR;
|
||||||
|
if (err & LSR_BREAK)
|
||||||
|
sts |= SD_BREAK_DETECTED;
|
||||||
|
chSysLockFromIsr();
|
||||||
|
chFDDAddFlagsI(com, sts);
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @cond never*/
|
||||||
|
__attribute__((noinline))
|
||||||
|
/** @endcond*/
|
||||||
|
/**
|
||||||
|
* @brief Common IRQ handler.
|
||||||
|
* @param[in] u pointer to an UART I/O block
|
||||||
|
* @param[in] com communication channel associated to the UART
|
||||||
|
* @note Tries hard to clear all the pending interrupt sources, we dont want to
|
||||||
|
* go through the whole ISR and have another interrupt soon after.
|
||||||
|
*/
|
||||||
|
static void ServeInterrupt(UART *u, FullDuplexDriver *com) {
|
||||||
|
|
||||||
|
while (TRUE) {
|
||||||
|
|
||||||
|
switch (u->UART_IIR & IIR_SRC_MASK) {
|
||||||
|
case IIR_SRC_NONE:
|
||||||
|
return;
|
||||||
|
case IIR_SRC_ERROR:
|
||||||
|
SetError(u->UART_LSR, com);
|
||||||
|
break;
|
||||||
|
case IIR_SRC_TIMEOUT:
|
||||||
|
case IIR_SRC_RX:
|
||||||
|
while (u->UART_LSR & LSR_RBR_FULL) {
|
||||||
|
chSysLockFromIsr();
|
||||||
|
if (chIQPutI(&com->d2.iqueue, u->UART_RBR) < Q_OK)
|
||||||
|
chFDDAddFlagsI(com, SD_OVERRUN_ERROR);
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
}
|
||||||
|
chSysLockFromIsr();
|
||||||
|
chEvtBroadcastI(&com->d1.ievent);
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
break;
|
||||||
|
case IIR_SRC_TX:
|
||||||
|
{
|
||||||
|
#if UART_FIFO_PRELOAD > 0
|
||||||
|
int i = UART_FIFO_PRELOAD;
|
||||||
|
do {
|
||||||
|
chSysLockFromIsr();
|
||||||
|
msg_t b = chOQGetI(&com->d2.oqueue);
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
if (b < Q_OK) {
|
||||||
|
u->UART_IER &= ~IER_THRE;
|
||||||
|
chSysLockFromIsr();
|
||||||
|
chEvtBroadcastI(&com->d1.oevent);
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
u->UART_THR = b;
|
||||||
|
} while (--i);
|
||||||
|
#else
|
||||||
|
chSysLockFromIsr();
|
||||||
|
msg_t b = chFDDRequestDataI(com);
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
if (b < Q_OK)
|
||||||
|
u->UART_IER &= ~IER_THRE;
|
||||||
|
else
|
||||||
|
u->UART_THR = b;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
u->UART_THR;
|
||||||
|
u->UART_RBR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UART_FIFO_PRELOAD > 0
|
||||||
|
static void preload(UART *u, FullDuplexDriver *com) {
|
||||||
|
|
||||||
|
if (u->UART_LSR & LSR_THRE) {
|
||||||
|
int i = UART_FIFO_PRELOAD;
|
||||||
|
do {
|
||||||
|
chSysLockFromIsr();
|
||||||
|
msg_t b = chOQGetI(&com->d2.oqueue);
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
if (b < Q_OK) {
|
||||||
|
chSysLockFromIsr();
|
||||||
|
chEvtBroadcastI(&com->d1.oevent);
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
u->UART_THR = b;
|
||||||
|
} while (--i);
|
||||||
|
}
|
||||||
|
u->UART_IER |= IER_THRE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_LPC214x_UART0 || defined(__DOXYGEN__)
|
||||||
|
CH_IRQ_HANDLER(UART0IrqHandler) {
|
||||||
|
|
||||||
|
CH_IRQ_PROLOGUE();
|
||||||
|
|
||||||
|
ServeInterrupt(U0Base, &COM1);
|
||||||
|
VICVectAddr = 0;
|
||||||
|
|
||||||
|
CH_IRQ_EPILOGUE();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OutNotify1(void) {
|
||||||
|
#if UART_FIFO_PRELOAD > 0
|
||||||
|
|
||||||
|
preload(U0Base, &COM1);
|
||||||
|
#else
|
||||||
|
UART *u = U0Base;
|
||||||
|
|
||||||
|
if (u->UART_LSR & LSR_THRE) {
|
||||||
|
chSysLockFromIsr();
|
||||||
|
u->UART_THR = chOQGetI(&COM1.sd_oqueue);
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
}
|
||||||
|
u->UART_IER |= IER_THRE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_LPC214x_UART1 || defined(__DOXYGEN__)
|
||||||
|
CH_IRQ_HANDLER(UART1IrqHandler) {
|
||||||
|
|
||||||
|
CH_IRQ_PROLOGUE();
|
||||||
|
|
||||||
|
ServeInterrupt(U1Base, &COM2);
|
||||||
|
VICVectAddr = 0;
|
||||||
|
|
||||||
|
CH_IRQ_EPILOGUE();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OutNotify2(void) {
|
||||||
|
#if UART_FIFO_PRELOAD > 0
|
||||||
|
|
||||||
|
preload(U1Base, &COM2);
|
||||||
|
#else
|
||||||
|
UART *u = U1Base;
|
||||||
|
|
||||||
|
if (u->UART_LSR & LSR_THRE)
|
||||||
|
u->UART_THR = chOQGetI(&COM2.sd_oqueue);
|
||||||
|
u->UART_IER |= IER_THRE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief UART setup.
|
||||||
|
* @param[in] u pointer to an UART I/O block
|
||||||
|
* @param[in] speed serial port speed in bits per second
|
||||||
|
* @param[in] lcr the value for the @p LCR register
|
||||||
|
* @param[in] fcr the value for the @p FCR register
|
||||||
|
* @note Must be invoked with interrupts disabled.
|
||||||
|
* @note Does not reset the I/O queues.
|
||||||
|
*/
|
||||||
|
void uart_setup(UART *u, int speed, int lcr, int fcr) {
|
||||||
|
|
||||||
|
int div = PCLK / (speed << 4);
|
||||||
|
u->UART_LCR = lcr | LCR_DLAB;
|
||||||
|
u->UART_DLL = div;
|
||||||
|
u->UART_DLM = div >> 8;
|
||||||
|
u->UART_LCR = lcr;
|
||||||
|
u->UART_FCR = FCR_ENABLE | FCR_RXRESET | FCR_TXRESET | fcr;
|
||||||
|
u->UART_ACR = 0;
|
||||||
|
u->UART_FDR = 0x10;
|
||||||
|
u->UART_TER = TER_ENABLE;
|
||||||
|
u->UART_IER = IER_RBR | IER_STATUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Serial driver initialization.
|
||||||
|
* @param[in] vector1 IRC vector to be used for UART0
|
||||||
|
* @param[in] vector2 IRC vector to be used for UART1
|
||||||
|
* @note Handshake pads are not enabled inside this function because they
|
||||||
|
* may have another use, enable them externally if needed.
|
||||||
|
* RX and TX pads are handled inside.
|
||||||
|
*/
|
||||||
|
void serial_init(int vector1, int vector2) {
|
||||||
|
|
||||||
|
#if USE_LPC214x_UART0
|
||||||
|
SetVICVector(UART0IrqHandler, vector1, SOURCE_UART0);
|
||||||
|
PCONP = (PCONP & PCALL) | PCUART0;
|
||||||
|
chFDDInit(&COM1, ib1, sizeof ib1, NULL, ob1, sizeof ob1, OutNotify1);
|
||||||
|
uart_setup(U0Base,
|
||||||
|
DEFAULT_UART_BITRATE,
|
||||||
|
LCR_WL8 | LCR_STOP1 | LCR_NOPARITY,
|
||||||
|
FCR_TRIGGER0);
|
||||||
|
VICIntEnable = INTMASK(SOURCE_UART0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_LPC214x_UART1
|
||||||
|
SetVICVector(UART1IrqHandler, vector2, SOURCE_UART1);
|
||||||
|
PCONP = (PCONP & PCALL) | PCUART1;
|
||||||
|
chFDDInit(&COM2, ib2, sizeof ib2, NULL, ob2, sizeof ob2, OutNotify2);
|
||||||
|
uart_setup(U1Base,
|
||||||
|
DEFAULT_UART_BITRATE,
|
||||||
|
LCR_WL8 | LCR_STOP1 | LCR_NOPARITY,
|
||||||
|
FCR_TRIGGER0);
|
||||||
|
VICIntEnable = INTMASK(SOURCE_UART0) | INTMASK(SOURCE_UART1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7-LPC214x/lpc214x_serial.h
|
||||||
|
* @brief LPC214x Serial driver macros and structures.
|
||||||
|
* @addtogroup LPC214x_SERIAL
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LPC214x_SERIAL_H_
|
||||||
|
#define _LPC214x_SERIAL_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Serial buffers size.
|
||||||
|
* @details Configuration parameter, you can change the depth of the queue
|
||||||
|
* buffers depending on the requirements of your application.
|
||||||
|
* @note The default is 128 bytes for both the transmission and receive buffers.
|
||||||
|
*/
|
||||||
|
#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
|
||||||
|
#define SERIAL_BUFFERS_SIZE 128
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default bit rate.
|
||||||
|
* @details Configuration parameter, at startup the UARTs are configured at
|
||||||
|
* this speed.
|
||||||
|
* @note It is possible to use @p SetUART() in order to change the working
|
||||||
|
* parameters at runtime.
|
||||||
|
*/
|
||||||
|
#if !defined(DEFAULT_UART_BITRATE) || defined(__DOXYGEN__)
|
||||||
|
#define DEFAULT_UART_BITRATE 38400
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FIFO preload parameter.
|
||||||
|
* @details Configuration parameter, this values defines how many bytes are
|
||||||
|
* preloaded in the HW transmit FIFO for each interrupt, the maximum value is
|
||||||
|
* 16 the minimum is 2, the value 0 disables the feature.
|
||||||
|
* @note An high value reduces the number of interrupts generated but can
|
||||||
|
* also increase the worst case interrupt response time because the
|
||||||
|
* preload loops.
|
||||||
|
* @note The value zero disables the feature and reverts to a simpler code
|
||||||
|
* that will generate an interrupt for each output byte but is much
|
||||||
|
* smaller and simpler.
|
||||||
|
*/
|
||||||
|
#if !defined(UART_FIFO_PRELOAD) || defined(__DOXYGEN__)
|
||||||
|
#define UART_FIFO_PRELOAD 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief UART0 driver enable switch.
|
||||||
|
* @details If set to @p TRUE the support for USART1 is included.
|
||||||
|
* @note The default is @p TRUE .
|
||||||
|
*/
|
||||||
|
#if !defined(USE_LPC214x_UART0) || defined(__DOXYGEN__)
|
||||||
|
#define USE_LPC214x_UART0 TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief UART1 driver enable switch.
|
||||||
|
* @details If set to @p TRUE the support for USART2 is included.
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
*/
|
||||||
|
#if !defined(USE_LPC214x_UART1) || defined(__DOXYGEN__)
|
||||||
|
#define USE_LPC214x_UART1 TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void serial_init(int vector1, int vector2);
|
||||||
|
void uart_setup(UART *u, int speed, int lcr, int fcr);
|
||||||
|
CH_IRQ_HANDLER(UART0IrqHandler);
|
||||||
|
CH_IRQ_HANDLER(UART1IrqHandler);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @cond never*/
|
||||||
|
extern FullDuplexDriver COM1, COM2;
|
||||||
|
/** @endcond*/
|
||||||
|
|
||||||
|
#endif /* _LPC214x_SERIAL_H_*/
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7-LPC214x/lpc214x_ssp.c
|
||||||
|
* @brief LPC214x SSP driver code.
|
||||||
|
* @addtogroup LPC214x_SSP
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
#include <pal.h>
|
||||||
|
|
||||||
|
#include "lpc214x.h"
|
||||||
|
#include "lpc214x_ssp.h"
|
||||||
|
|
||||||
|
#if LPC214x_SSP_USE_MUTEX
|
||||||
|
static Semaphore me;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Aquires access to the SSP bus.
|
||||||
|
* @note This function also handles the mutual exclusion on the SSP bus if
|
||||||
|
* the @p LPC214x_SSP_USE_MUTEX option is enabled.
|
||||||
|
*/
|
||||||
|
void sspAcquireBus(void) {
|
||||||
|
|
||||||
|
#if LPC214x_SSP_USE_MUTEX
|
||||||
|
chSemWait(&me);
|
||||||
|
#endif
|
||||||
|
palClearPad(IOPORT_A, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Releases the SSP bus.
|
||||||
|
* @note This function also handles the mutual exclusion on the SSP bus if
|
||||||
|
* the @p LPC214x_SSP_USE_MUTEX option is enabled.
|
||||||
|
*/
|
||||||
|
void sspReleaseBus(void) {
|
||||||
|
|
||||||
|
palClearPad(IOPORT_A, 20);
|
||||||
|
#if LPC214x_SSP_USE_MUTEX
|
||||||
|
chSemSignal(&me);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Synchronous SSP transfer.
|
||||||
|
* @param[in] in pointer to the incoming data buffer, if this parameter is set
|
||||||
|
* to @p NULL then the incoming data is discarded
|
||||||
|
* @param[out] out pointer to the outgoing data buffer, if this parameter is
|
||||||
|
* set to @p NULL then 0xFF bytes will be output
|
||||||
|
* @param[in] n the number of bytes to be transferred
|
||||||
|
* @note The transfer is performed in a software loop and is not interrupt
|
||||||
|
* driven for performance reasons, this function should be invoked
|
||||||
|
* by a low priority thread in order to "play nice" with the
|
||||||
|
* rest of the system. This kind of peripheral would really need a
|
||||||
|
* dedicated DMA channel.
|
||||||
|
*/
|
||||||
|
void sspRW(uint8_t *in, uint8_t *out, size_t n) {
|
||||||
|
int icnt, ocnt;
|
||||||
|
|
||||||
|
SSP *ssp = SSPBase;
|
||||||
|
icnt = ocnt = n;
|
||||||
|
while (icnt) {
|
||||||
|
|
||||||
|
if (ssp->SSP_SR & SR_RNE) {
|
||||||
|
if (in)
|
||||||
|
*in++ = ssp->SSP_DR;
|
||||||
|
else
|
||||||
|
ssp->SSP_DR;
|
||||||
|
icnt--;
|
||||||
|
continue; /* Priority over transmission. */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ocnt && (ssp->SSP_SR & SR_TNF)) {
|
||||||
|
if (out)
|
||||||
|
ssp->SSP_DR = *out++;
|
||||||
|
else
|
||||||
|
ssp->SSP_DR = 0xFF;
|
||||||
|
ocnt--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SSP setup.
|
||||||
|
* @param[in] cpsr the value for the @p CPSR register
|
||||||
|
* @param[in] cr0 the value for the @p CR0 register
|
||||||
|
* @param[in] cr1 the value for the @p CR1 register
|
||||||
|
*/
|
||||||
|
void ssp_setup(int cpsr, int cr0, int cr1) {
|
||||||
|
|
||||||
|
SSP *ssp = SSPBase;
|
||||||
|
ssp->SSP_CR1 = 0;
|
||||||
|
ssp->SSP_CR0 = cr0;
|
||||||
|
ssp->SSP_CPSR = cpsr;
|
||||||
|
ssp->SSP_CR1 = cr1 | CR1_SSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SSP subsystem initialization.
|
||||||
|
*/
|
||||||
|
void ssp_init(void) {
|
||||||
|
|
||||||
|
/* Enables the SPI1 clock */
|
||||||
|
PCONP = (PCONP & PCALL) | PCSPI1;
|
||||||
|
|
||||||
|
/* Clock = PCLK / 2 (fastest). */
|
||||||
|
ssp_setup(2, CR0_DSS8BIT | CR0_FRFSPI | CR0_CLOCKRATE(0), 0);
|
||||||
|
|
||||||
|
#if LPC214x_SSP_USE_MUTEX
|
||||||
|
chSemInit(&me, 1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7-LPC214x/lpc214x_ssp.h
|
||||||
|
* @brief LPC214x SSP driver macros and structures.
|
||||||
|
* @addtogroup LPC214x_SSP
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LPC214x_SSP_H_
|
||||||
|
#define _LPC214x_SSP_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SSP bus mutual exclusion control.
|
||||||
|
* @details Configuration parameter, if set to @p TRUE enforces mutual
|
||||||
|
* exclusion when invoking @p sspAcquireBus() and @p sspReleaseBus().
|
||||||
|
* @note The internally used synchronization mechanism is a @p Semaphore.
|
||||||
|
*/
|
||||||
|
#if !defined(LPC214x_SSP_USE_MUTEX) || defined(__DOXYGEN__)
|
||||||
|
#define LPC214x_SSP_USE_MUTEX TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void ssp_init(void);
|
||||||
|
void ssp_setup(int cpsr, int cr0, int cr1);
|
||||||
|
void sspAcquireBus(void);
|
||||||
|
void sspReleaseBus(void);
|
||||||
|
void sspRW(uint8_t *in, uint8_t *out, size_t n);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _LPC214x_SSP_H_*/
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7-LPC214x/pal_lld.c
|
||||||
|
* @brief LPC214x FIO low level driver code
|
||||||
|
* @addtogroup LPC214x_PAL
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
#include <pal.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief LPC214x I/O ports configuration.
|
||||||
|
* @details FIO units and PINSEL registers initialization.
|
||||||
|
*
|
||||||
|
* @param[in] config the LPC214x ports configuration
|
||||||
|
*/
|
||||||
|
void _pal_lld_init(const LPC214xFIOConfig *config) {
|
||||||
|
|
||||||
|
/* Enables the access through the fast registers.*/
|
||||||
|
SCS = 3;
|
||||||
|
|
||||||
|
/* I/O pads initial assignment, device drivers may change this setup at a
|
||||||
|
* later time.*/
|
||||||
|
PINSEL0 = config->pinsel0;
|
||||||
|
PINSEL1 = config->pinsel1;
|
||||||
|
PINSEL2 = config->pinsel2;
|
||||||
|
|
||||||
|
/* I/O pads direction initial setting.*/
|
||||||
|
FIO0Base->FIO_MASK = 0;
|
||||||
|
FIO0Base->FIO_PIN = config->P0Data.pin;
|
||||||
|
FIO0Base->FIO_DIR = config->P0Data.dir;
|
||||||
|
FIO1Base->FIO_MASK = 0;
|
||||||
|
FIO1Base->FIO_PIN = config->P1Data.pin;
|
||||||
|
FIO1Base->FIO_DIR = config->P1Data.dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pads mode setup.
|
||||||
|
* @details This function programs a pads group belonging to the same port
|
||||||
|
* with the specified mode.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] mask the group mask
|
||||||
|
* @param[in] mode the mode
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
* @note @p PAL_MODE_UNCONNECTED is implemented as push pull output with high
|
||||||
|
* state.
|
||||||
|
* @note This function does not alter the @p PINSELx registers. Alternate
|
||||||
|
* functions setup must be handled by device-specific code.
|
||||||
|
*/
|
||||||
|
void _pal_lld_setgroupmode(ioportid_t port,
|
||||||
|
ioportmask_t mask,
|
||||||
|
uint_fast8_t mode) {
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case PAL_MODE_RESET:
|
||||||
|
case PAL_MODE_INPUT:
|
||||||
|
port->FIO_DIR &= ~mask;
|
||||||
|
break;
|
||||||
|
case PAL_MODE_UNCONNECTED:
|
||||||
|
port->FIO_PIN |= mask;
|
||||||
|
case PAL_MODE_OUTPUT_PUSHPULL:
|
||||||
|
port->FIO_DIR |= mask;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,252 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7-LPC214x/pal_lld.h
|
||||||
|
* @brief LPC214x FIO low level driver header
|
||||||
|
* @addtogroup LPC214x_PAL
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PAL_LLD_H_
|
||||||
|
#define _PAL_LLD_H_
|
||||||
|
|
||||||
|
#include "lpc214x.h"
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Unsupported modes and specific modes */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
#undef PAL_MODE_INPUT_PULLUP
|
||||||
|
#undef PAL_MODE_INPUT_PULLDOWN
|
||||||
|
#undef PAL_MODE_OUTPUT_OPENDRAIN
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* I/O Ports Types and constants. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FIO port setup info.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** Initial value for FIO_PIN register.*/
|
||||||
|
uint32_t pin;
|
||||||
|
/** Initial value for FIO_DIR register.*/
|
||||||
|
uint32_t dir;
|
||||||
|
} lpc214x_fio_setup_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief LPC214x FIO static initializer.
|
||||||
|
* @details An instance of this structure must be passed to @p palInit() at
|
||||||
|
* system startup time in order to initialized the digital I/O
|
||||||
|
* subsystem. This represents only the initial setup, specific pads
|
||||||
|
* or whole ports can be reprogrammed at later time.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** @brief PINSEL0 initial value.*/
|
||||||
|
uint32_t pinsel0;
|
||||||
|
/** @brief PINSEL1 initial value.*/
|
||||||
|
uint32_t pinsel1;
|
||||||
|
/** @brief PINSEL2 initial value.*/
|
||||||
|
uint32_t pinsel2;
|
||||||
|
/** @brief Port 0 setup data.*/
|
||||||
|
lpc214x_fio_setup_t P0Data;
|
||||||
|
/** @brief Port 1 setup data.*/
|
||||||
|
lpc214x_fio_setup_t P1Data;
|
||||||
|
} LPC214xFIOConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Width, in bits, of an I/O port.
|
||||||
|
*/
|
||||||
|
#define PAL_IOPORTS_WIDTH 32
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Digital I/O port sized unsigned type.
|
||||||
|
*/
|
||||||
|
typedef uint32_t ioportmask_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Port Identifier.
|
||||||
|
*/
|
||||||
|
typedef FIO * ioportid_t;
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* I/O Ports Identifiers. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FIO port 0 identifier.
|
||||||
|
*/
|
||||||
|
#define IOPORT_A FIO0Base
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FIO port 1 identifier.
|
||||||
|
*/
|
||||||
|
#define IOPORT_B FIO1Base
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Implementation, some of the following macros could be implemented as */
|
||||||
|
/* functions, please put them in a file named ioports_lld.c if so. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FIO subsystem initialization.
|
||||||
|
* @details Enables the access through the fast registers.
|
||||||
|
*/
|
||||||
|
#define pal_lld_init(config) _pal_lld_init(config)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads an I/O port.
|
||||||
|
* @details This function is implemented by reading the FIO PIN register, the
|
||||||
|
* implementation has no side effects.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @return the port bits
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
#define pal_lld_readport(port) ((port)->FIO_PIN)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads the output latch.
|
||||||
|
* @details This function is implemented by reading the FIO SET register, the
|
||||||
|
* implementation has no side effects.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @return The latched logical states.
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
#define pal_lld_readlatch(port) ((port)->FIO_SET)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes a bits mask on a I/O port.
|
||||||
|
* @details This function is implemented by writing the FIO PIN register, the
|
||||||
|
* implementation has no side effects.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] bits the bits to be written on the specified port
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
#define pal_lld_writeport(port, bits) ((port)->FIO_PIN = (bits))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets a bits mask on a I/O port.
|
||||||
|
* @details This function is implemented by writing the FIO SET register, the
|
||||||
|
* implementation has no side effects.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] bits the bits to be ORed on the specified port
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
#define pal_lld_setport(port, bits) ((port)->FIO_SET = (bits))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears a bits mask on a I/O port.
|
||||||
|
* @details This function is implemented by writing the FIO CLR register, the
|
||||||
|
* implementation has no side effects.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] bits the bits to be cleared on the specified port
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
#define pal_lld_clearport(port, bits) ((port)->FIO_CLR = (bits))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes a value on an I/O bus.
|
||||||
|
* @details This function is implemented by writing the FIO PIN and MASK
|
||||||
|
* registers, the implementation is not atomic because the multiple
|
||||||
|
* accesses.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] mask the group mask
|
||||||
|
* @param[in] offset the group bit offset within the port
|
||||||
|
* @param[in] bits the bits to be written. Values exceeding the group width
|
||||||
|
* are masked.
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
#define pal_lld_writegroup(port, mask, offset, bits) { \
|
||||||
|
(port)->FIO_MASK = (mask) << (offset); \
|
||||||
|
(port)->FIO_PIN = (bits) << (offset); \
|
||||||
|
(port)->FIO_MASK = 0; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pads group mode setup.
|
||||||
|
* @details This function programs a pads group belonging to the same port
|
||||||
|
* with the specified mode.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] mask the group mask
|
||||||
|
* @param[in] mode the mode
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
* @note @p PAL_MODE_UNCONNECTED is implemented as push pull output with high
|
||||||
|
* state.
|
||||||
|
* @note This function does not alter the @p PINSELx registers. Alternate
|
||||||
|
* functions setup must be handled by device-specific code.
|
||||||
|
*/
|
||||||
|
#define pal_lld_setgroupmode(port, mask, mode) \
|
||||||
|
_pal_lld_setgroupmode(port, mask, mode)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes a logical state on an output pad.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] pad the pad number within the port
|
||||||
|
* @param[out] bit the logical value, the value must be @p 0 or @p 1
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
#define pal_lld_writepad(port, pad, bit) pal_lld_writegroup(port, 1, pad, bit)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FIO port setup.
|
||||||
|
* @details This function programs the pins direction within a port.
|
||||||
|
*/
|
||||||
|
#define pal_lld_lpc214x_set_direction(port, dir) { \
|
||||||
|
(port)->FIO_DIR = (dir); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void _pal_lld_init(const LPC214xFIOConfig *config);
|
||||||
|
void _pal_lld_setgroupmode(ioportid_t port,
|
||||||
|
ioportmask_t mask,
|
||||||
|
uint_fast8_t mode);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _PAL_LLD_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup LPC214x LPC214x Support
|
||||||
|
* @brief LPC214x specific support.
|
||||||
|
* @details The LPC214x support includes:
|
||||||
|
* - VIC support code.
|
||||||
|
* - I/O ports driver.
|
||||||
|
* - Buffered, interrupt driven, serial driver.
|
||||||
|
* - SSP driver.
|
||||||
|
* - A MMC/SD demo driver.
|
||||||
|
* - A timer driven buzzer demo driver.
|
||||||
|
* - A minimal demo, useful as project template.
|
||||||
|
* - A demo supporting the kernel test suite.
|
||||||
|
* - A C++ demo supporting the kernel test suite.
|
||||||
|
* .
|
||||||
|
* @ingroup ARM7
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup LPC214x_VIC VIC Support
|
||||||
|
* @brief VIC peripheral support.
|
||||||
|
*
|
||||||
|
* @ingroup LPC214x
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup LPC214x_PAL I/O Ports Support
|
||||||
|
* @brief I/O Ports peripherals support.
|
||||||
|
* @details This module supports the LPC214x FIO controller. The controller
|
||||||
|
* supports the following features (see @ref PAL):
|
||||||
|
* - 32 bits wide ports.
|
||||||
|
* - Atomic set/reset functions.
|
||||||
|
* - Output latched regardless of the pad setting.
|
||||||
|
* - Direct read of input pads regardless of the pad setting.
|
||||||
|
* .
|
||||||
|
* <h2>Supported Setup Modes</h2>
|
||||||
|
* - @p PAL_MODE_RESET.
|
||||||
|
* - @p PAL_MODE_UNCONNECTED.
|
||||||
|
* - @p PAL_MODE_INPUT.
|
||||||
|
* - @p PAL_MODE_OUTPUT_PUSHPULL.
|
||||||
|
* .
|
||||||
|
* Any attempt to setup an invalid mode is ignored.
|
||||||
|
*
|
||||||
|
* <h2>Suboptimal Behavior</h2>
|
||||||
|
* - Pad/port toggling operations are not atomic.
|
||||||
|
* - Pad/group mode setup is not atomic.
|
||||||
|
* .
|
||||||
|
* @ingroup LPC214x
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup LPC214x_SERIAL UART Support
|
||||||
|
* @brief UART peripherals support.
|
||||||
|
* @details The serial driver supports the LPC214x UART peripherals.
|
||||||
|
*
|
||||||
|
* @ingroup LPC214x
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup LPC214x_SSP SSP Support
|
||||||
|
* @brief SSP peripheral support.
|
||||||
|
* @details This SPI driver supports the LPC214x SSP peripheral.
|
||||||
|
*
|
||||||
|
* @ingroup LPC214x
|
||||||
|
*/
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.section vectors
|
||||||
|
.code 32
|
||||||
|
.balign 4
|
||||||
|
/*
|
||||||
|
* System entry points.
|
||||||
|
*/
|
||||||
|
_start:
|
||||||
|
ldr pc, _reset
|
||||||
|
ldr pc, _undefined
|
||||||
|
ldr pc, _swi
|
||||||
|
ldr pc, _prefetch
|
||||||
|
ldr pc, _abort
|
||||||
|
nop
|
||||||
|
ldr pc, [pc,#-0xFF0] /* VIC - IRQ Vector Register */
|
||||||
|
ldr pc, _fiq
|
||||||
|
|
||||||
|
_reset:
|
||||||
|
.word ResetHandler /* In crt0.s */
|
||||||
|
_undefined:
|
||||||
|
.word UndHandler
|
||||||
|
_swi:
|
||||||
|
.word SwiHandler
|
||||||
|
_prefetch:
|
||||||
|
.word PrefetchHandler
|
||||||
|
_abort:
|
||||||
|
.word AbortHandler
|
||||||
|
_fiq:
|
||||||
|
.word FiqHandler
|
||||||
|
.word 0
|
||||||
|
.word 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default exceptions handlers. The handlers are declared weak in order to be
|
||||||
|
* replaced by the real handling code. Everything is defaulted to an infinite
|
||||||
|
* loop.
|
||||||
|
*/
|
||||||
|
.weak UndHandler
|
||||||
|
UndHandler:
|
||||||
|
|
||||||
|
.weak SwiHandler
|
||||||
|
SwiHandler:
|
||||||
|
|
||||||
|
.weak PrefetchHandler
|
||||||
|
PrefetchHandler:
|
||||||
|
|
||||||
|
.weak AbortHandler
|
||||||
|
AbortHandler:
|
||||||
|
|
||||||
|
.weak FiqHandler
|
||||||
|
FiqHandler:
|
||||||
|
|
||||||
|
.loop: b .loop
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7-LPC214x/vic.c
|
||||||
|
* @brief LPC214x VIC peripheral support code.
|
||||||
|
* @addtogroup LPC214x_VIC
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
#include "lpc214x.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief VIC Initialization.
|
||||||
|
* @note Better reset everything in the VIC, it is a HUGE source of trouble.
|
||||||
|
*/
|
||||||
|
void vic_init(void) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
VIC *vic = VICBase;
|
||||||
|
vic->VIC_IntSelect = 0; /* All sources assigned to IRQ. */
|
||||||
|
vic->VIC_SoftIntClear = ALLINTMASK; /* No interrupts enforced */
|
||||||
|
vic->VIC_IntEnClear = ALLINTMASK; /* All sources disabled. */
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
vic->VIC_VectCntls[i] = 0;
|
||||||
|
vic->VIC_VectAddrs[i] = 0;
|
||||||
|
vic->VIC_VectAddr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes a VIC vector.
|
||||||
|
* @details Set a vector for an interrupt source and enables it.
|
||||||
|
* @param[in] handler the pointer to the IRQ service routine
|
||||||
|
* @param[in] vector the vector number
|
||||||
|
* @param[in] source the IRQ source to be associated to the vector
|
||||||
|
*/
|
||||||
|
void SetVICVector(void *handler, int vector, int source) {
|
||||||
|
|
||||||
|
VIC *vicp = VICBase;
|
||||||
|
vicp->VIC_VectAddrs[vector] = (IOREG32)handler;
|
||||||
|
vicp->VIC_VectCntls[vector] = (IOREG32)(source | 0x20);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7-LPC214x/vic.h
|
||||||
|
* @brief LPC214x VIC peripheral support code.
|
||||||
|
* @addtogroup LPC214x_VIC
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _VIC_H_
|
||||||
|
#define _VIC_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void vic_init(void);
|
||||||
|
void SetVICVector(void *handler, int vector, int source);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _VIC_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _WFI_H_
|
||||||
|
#define _WFI_H_
|
||||||
|
|
||||||
|
#include "lpc214x.h"
|
||||||
|
|
||||||
|
#ifndef port_wait_for_interrupt
|
||||||
|
#if ENABLE_WFI_IDLE != 0
|
||||||
|
#define port_wait_for_interrupt() { \
|
||||||
|
PCON = 1; \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define port_wait_for_interrupt()
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _WFI_H_ */
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7/chcore.c
|
||||||
|
* @brief ARM7 architecture port code.
|
||||||
|
* @addtogroup ARM7_CORE
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Halts the system.
|
||||||
|
*/
|
||||||
|
/** @cond never */
|
||||||
|
__attribute__((weak))
|
||||||
|
/** @endcond */
|
||||||
|
void port_halt(void) {
|
||||||
|
|
||||||
|
port_disable();
|
||||||
|
while (TRUE) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,331 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7/chcore.h
|
||||||
|
* @brief ARM7 architecture port macros and structures.
|
||||||
|
* @addtogroup ARM7_CORE
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CHCORE_H_
|
||||||
|
#define _CHCORE_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If enabled allows the idle thread to enter a low power mode.
|
||||||
|
*/
|
||||||
|
#ifndef ENABLE_WFI_IDLE
|
||||||
|
#define ENABLE_WFI_IDLE 0
|
||||||
|
#endif
|
||||||
|
#include <wfi.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Macro defining the ARM7 architecture.
|
||||||
|
*/
|
||||||
|
#define CH_ARCHITECTURE_ARM7
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the implemented architecture.
|
||||||
|
*/
|
||||||
|
#define CH_ARCHITECTURE_NAME "ARM7TDMI"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 32 bit stack alignment.
|
||||||
|
*/
|
||||||
|
typedef uint32_t stkalign_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic ARM register.
|
||||||
|
*/
|
||||||
|
typedef void *regarm_t;
|
||||||
|
|
||||||
|
/** @cond never */
|
||||||
|
/**
|
||||||
|
* This structure represents the stack frame saved during a preemption-capable
|
||||||
|
* interrupt handler.
|
||||||
|
*/
|
||||||
|
struct extctx {
|
||||||
|
regarm_t spsr_irq;
|
||||||
|
regarm_t lr_irq;
|
||||||
|
regarm_t r0;
|
||||||
|
regarm_t r1;
|
||||||
|
regarm_t r2;
|
||||||
|
regarm_t r3;
|
||||||
|
regarm_t r12;
|
||||||
|
regarm_t lr_usr;
|
||||||
|
};
|
||||||
|
/** @endcond */
|
||||||
|
|
||||||
|
/** @cond never */
|
||||||
|
/**
|
||||||
|
* This structure represents the inner stack frame during a context switching.
|
||||||
|
*/
|
||||||
|
struct intctx {
|
||||||
|
regarm_t r4;
|
||||||
|
regarm_t r5;
|
||||||
|
regarm_t r6;
|
||||||
|
#ifndef CH_CURRP_REGISTER_CACHE
|
||||||
|
regarm_t r7;
|
||||||
|
#endif
|
||||||
|
regarm_t r8;
|
||||||
|
regarm_t r9;
|
||||||
|
regarm_t r10;
|
||||||
|
regarm_t r11;
|
||||||
|
regarm_t lr;
|
||||||
|
};
|
||||||
|
/** @endcond */
|
||||||
|
|
||||||
|
/** @cond never */
|
||||||
|
/**
|
||||||
|
* In the ARM7 port this structure contains just the copy of the user mode
|
||||||
|
* stack pointer.
|
||||||
|
*/
|
||||||
|
struct context {
|
||||||
|
struct intctx *r13;
|
||||||
|
};
|
||||||
|
/** @endcond */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Platform dependent part of the @p chThdInit() API.
|
||||||
|
*/
|
||||||
|
#define SETUP_CONTEXT(workspace, wsize, pf, arg) { \
|
||||||
|
tp->p_ctx.r13 = (struct intctx *)((uint8_t *)workspace + \
|
||||||
|
wsize - \
|
||||||
|
sizeof(struct intctx)); \
|
||||||
|
tp->p_ctx.r13->r4 = pf; \
|
||||||
|
tp->p_ctx.r13->r5 = arg; \
|
||||||
|
tp->p_ctx.r13->lr = _port_thread_start; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stack size for the system idle thread.
|
||||||
|
*/
|
||||||
|
#ifndef IDLE_THREAD_STACK_SIZE
|
||||||
|
#define IDLE_THREAD_STACK_SIZE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Per-thread stack overhead for interrupts servicing, it is used in the
|
||||||
|
* calculation of the correct working area size.
|
||||||
|
* In this port 0x10 is a safe value, it can be reduced after careful generated
|
||||||
|
* code analysis.
|
||||||
|
*/
|
||||||
|
#ifndef INT_REQUIRED_STACK
|
||||||
|
#define INT_REQUIRED_STACK 0x10
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enforces a correct alignment for a stack area size value.
|
||||||
|
*/
|
||||||
|
#define STACK_ALIGN(n) ((((n) - 1) | (sizeof(stkalign_t) - 1)) + 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the thread working area global size.
|
||||||
|
*/
|
||||||
|
#define THD_WA_SIZE(n) STACK_ALIGN(sizeof(Thread) + \
|
||||||
|
sizeof(struct intctx) + \
|
||||||
|
sizeof(struct extctx) + \
|
||||||
|
(n) + (INT_REQUIRED_STACK))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Macro used to allocate a thread working area aligned as both position and
|
||||||
|
* size.
|
||||||
|
*/
|
||||||
|
#define WORKING_AREA(s, n) stkalign_t s[THD_WA_SIZE(n) / sizeof(stkalign_t)];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IRQ prologue code, inserted at the start of all IRQ handlers enabled to
|
||||||
|
* invoke system APIs.
|
||||||
|
* @note This macro has a different implementation depending if compiled in
|
||||||
|
* ARM or THUMB mode.
|
||||||
|
* @note The THUMB implementation starts with ARM code because interrupt
|
||||||
|
* vectors are always invoked in ARM mode regardless the bit 0
|
||||||
|
* value. The switch in THUMB mode is done in the function prologue so
|
||||||
|
* it is transparent to the user code.
|
||||||
|
*/
|
||||||
|
#ifdef THUMB
|
||||||
|
#define PORT_IRQ_PROLOGUE() { \
|
||||||
|
asm volatile (".code 32 \n\t" \
|
||||||
|
"stmfd sp!, {r0-r3, r12, lr} \n\t" \
|
||||||
|
"add r0, pc, #1 \n\t" \
|
||||||
|
"bx r0 \n\t" \
|
||||||
|
".code 16"); \
|
||||||
|
}
|
||||||
|
#else /* !THUMB */
|
||||||
|
#define PORT_IRQ_PROLOGUE() { \
|
||||||
|
asm volatile ("stmfd sp!, {r0-r3, r12, lr}"); \
|
||||||
|
}
|
||||||
|
#endif /* !THUMB */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IRQ epilogue code, inserted at the end of all IRQ handlers enabled to
|
||||||
|
* invoke system APIs.
|
||||||
|
* @note This macro has a different implementation depending if compiled in
|
||||||
|
* ARM or THUMB mode.
|
||||||
|
*/
|
||||||
|
#ifdef THUMB
|
||||||
|
#define PORT_IRQ_EPILOGUE() { \
|
||||||
|
asm volatile ("ldr r0, =_port_irq_common \n\t" \
|
||||||
|
"bx r0"); \
|
||||||
|
}
|
||||||
|
#else /* !THUMB */
|
||||||
|
#define PORT_IRQ_EPILOGUE() { \
|
||||||
|
asm volatile ("b _port_irq_common"); \
|
||||||
|
}
|
||||||
|
#endif /* !THUMB */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IRQ handler function declaration.
|
||||||
|
*/
|
||||||
|
#define PORT_IRQ_HANDLER(id) __attribute__((naked)) void id(void)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is empty in this port.
|
||||||
|
*/
|
||||||
|
#define port_init()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables the IRQ sources and keeps the FIQ sources enabled.
|
||||||
|
*/
|
||||||
|
#ifdef THUMB
|
||||||
|
//#define port_lock() _port_lock_thumb()
|
||||||
|
#define port_lock() { \
|
||||||
|
asm volatile ("bl _port_lock_thumb" : : : "r3", "lr"); \
|
||||||
|
}
|
||||||
|
#else /* !THUMB */
|
||||||
|
#define port_lock() asm volatile ("msr CPSR_c, #0x9F")
|
||||||
|
#endif /* !THUMB */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables both the IRQ and FIQ sources.
|
||||||
|
*/
|
||||||
|
#ifdef THUMB
|
||||||
|
//#define port_unlock() _port_unlock_thumb()
|
||||||
|
#define port_unlock() { \
|
||||||
|
asm volatile ("bl _port_unlock_thumb" : : : "r3", "lr"); \
|
||||||
|
}
|
||||||
|
#else /* !THUMB */
|
||||||
|
#define port_unlock() asm volatile ("msr CPSR_c, #0x1F")
|
||||||
|
#endif /* !THUMB */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is empty in this port.
|
||||||
|
*/
|
||||||
|
#define port_lock_from_isr()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is empty in this port.
|
||||||
|
*/
|
||||||
|
#define port_unlock_from_isr()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables both the IRQ and FIQ sources.
|
||||||
|
* @note Implements a workaround for spurious interrupts taken from the NXP
|
||||||
|
* LPC214x datasheet.
|
||||||
|
*/
|
||||||
|
#ifdef THUMB
|
||||||
|
//#define port_disable() _port_disable_thumb()
|
||||||
|
#define port_disable() { \
|
||||||
|
asm volatile ("bl _port_disable_thumb" : : : "r3", "lr"); \
|
||||||
|
}
|
||||||
|
#else /* !THUMB */
|
||||||
|
#define port_disable() { \
|
||||||
|
asm volatile ("mrs r3, CPSR \n\t" \
|
||||||
|
"orr r3, #0x80 \n\t" \
|
||||||
|
"msr CPSR_c, r3 \n\t" \
|
||||||
|
"orr r3, #0x40 \n\t" \
|
||||||
|
"msr CPSR_c, r3" : : : "r3"); \
|
||||||
|
}
|
||||||
|
#endif /* !THUMB */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables the IRQ sources and enables the FIQ sources.
|
||||||
|
*/
|
||||||
|
#ifdef THUMB
|
||||||
|
#define port_suspend() { \
|
||||||
|
asm volatile ("bl _port_suspend_thumb" : : : "r3", "lr"); \
|
||||||
|
}
|
||||||
|
#else /* !THUMB */
|
||||||
|
#define port_suspend() asm volatile ("msr CPSR_c, #0x9F")
|
||||||
|
#endif /* !THUMB */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables both the IRQ and FIQ sources.
|
||||||
|
*/
|
||||||
|
#ifdef THUMB
|
||||||
|
#define port_enable() { \
|
||||||
|
asm volatile ("bl _port_enable_thumb" : : : "r3", "lr"); \
|
||||||
|
}
|
||||||
|
#else /* !THUMB */
|
||||||
|
#define port_enable() asm volatile ("msr CPSR_c, #0x1F")
|
||||||
|
#endif /* !THUMB */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a context switch between two threads.
|
||||||
|
* @param otp the thread to be switched out
|
||||||
|
* @param ntp the thread to be switched in
|
||||||
|
*/
|
||||||
|
#ifdef THUMB
|
||||||
|
#if CH_DBG_ENABLE_STACK_CHECK
|
||||||
|
#define port_switch(otp, ntp) { \
|
||||||
|
register Thread *_otp asm ("r0") = (otp); \
|
||||||
|
register Thread *_ntp asm ("r1") = (ntp); \
|
||||||
|
register char *sp asm ("sp"); \
|
||||||
|
if (sp - sizeof(struct intctx) - sizeof(Thread) < (char *)_otp) \
|
||||||
|
asm volatile ("mov r0, #0 \n\t" \
|
||||||
|
"ldr r1, =chDbgPanic \n\t" \
|
||||||
|
"bx r1"); \
|
||||||
|
_port_switch_thumb(_otp, _ntp); \
|
||||||
|
}
|
||||||
|
#else /* !CH_DBG_ENABLE_STACK_CHECK */
|
||||||
|
#define port_switch(otp, ntp) _port_switch_thumb(otp, ntp)
|
||||||
|
#endif /* !CH_DBG_ENABLE_STACK_CHECK */
|
||||||
|
#else /* !THUMB */
|
||||||
|
#if CH_DBG_ENABLE_STACK_CHECK
|
||||||
|
#define port_switch(otp, ntp) { \
|
||||||
|
register Thread *_otp asm ("r0") = (otp); \
|
||||||
|
register Thread *_ntp asm ("r1") = (ntp); \
|
||||||
|
register char *sp asm ("sp"); \
|
||||||
|
if (sp - sizeof(struct intctx) - sizeof(Thread) < (char *)_otp) \
|
||||||
|
asm volatile ("mov r0, #0 \n\t" \
|
||||||
|
"b chDbgPanic"); \
|
||||||
|
_port_switch_arm(_otp, _ntp); \
|
||||||
|
}
|
||||||
|
#else /* !CH_DBG_ENABLE_STACK_CHECK */
|
||||||
|
#define port_switch(otp, ntp) _port_switch_arm(otp, ntp)
|
||||||
|
#endif /* !CH_DBG_ENABLE_STACK_CHECK */
|
||||||
|
#endif /* !THUMB */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void port_halt(void);
|
||||||
|
#ifdef THUMB
|
||||||
|
void _port_switch_thumb(Thread *otp, Thread *ntp);
|
||||||
|
#else /* !THUMB */
|
||||||
|
void _port_switch_arm(Thread *otp, Thread *ntp);
|
||||||
|
#endif /* !THUMB */
|
||||||
|
void _port_thread_start(void);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _CHCORE_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,48 @@
|
||||||
|
1 .file "chcore.c"
|
||||||
|
2 __SREG__ = 0x3f
|
||||||
|
3 __SP_H__ = 0x3e
|
||||||
|
4 __SP_L__ = 0x3d
|
||||||
|
5 __CCP__ = 0x34
|
||||||
|
6 __tmp_reg__ = 0
|
||||||
|
7 __zero_reg__ = 1
|
||||||
|
8 .global __do_copy_data
|
||||||
|
9 .global __do_clear_bss
|
||||||
|
17 .Ltext0:
|
||||||
|
18 .weak port_halt
|
||||||
|
20 port_halt:
|
||||||
|
21 .LFB7:
|
||||||
|
22 .LM1:
|
||||||
|
23 ???? 3F92 push r3
|
||||||
|
24 /* prologue: function */
|
||||||
|
25 /* frame size = 0 */
|
||||||
|
26 .LM2:
|
||||||
|
27 /* #APP */
|
||||||
|
28 ; 37 "../../os/ports/GCC/ARM7/chcore.c" 1
|
||||||
|
29 mrs r3, CPSR
|
||||||
|
30 orr r3, #0x80
|
||||||
|
31 msr CPSR_c, r3
|
||||||
|
32 orr r3, #0x40
|
||||||
|
33 msr CPSR_c, r3
|
||||||
|
34 ; 0 "" 2
|
||||||
|
35 /* #NOAPP */
|
||||||
|
36 .L2:
|
||||||
|
37 ???? 00C0 rjmp .L2
|
||||||
|
38 .LFE7:
|
||||||
|
64 .Letext0:
|
||||||
|
DEFINED SYMBOLS
|
||||||
|
*ABS*:00000000 chcore.c
|
||||||
|
C:\DOCUME~1\Giovanni\IMPOST~1\Temp/ccjonuJz.s:2 *ABS*:0000003f __SREG__
|
||||||
|
C:\DOCUME~1\Giovanni\IMPOST~1\Temp/ccjonuJz.s:3 *ABS*:0000003e __SP_H__
|
||||||
|
C:\DOCUME~1\Giovanni\IMPOST~1\Temp/ccjonuJz.s:4 *ABS*:0000003d __SP_L__
|
||||||
|
C:\DOCUME~1\Giovanni\IMPOST~1\Temp/ccjonuJz.s:5 *ABS*:00000034 __CCP__
|
||||||
|
C:\DOCUME~1\Giovanni\IMPOST~1\Temp/ccjonuJz.s:6 *ABS*:00000000 __tmp_reg__
|
||||||
|
C:\DOCUME~1\Giovanni\IMPOST~1\Temp/ccjonuJz.s:7 *ABS*:00000001 __zero_reg__
|
||||||
|
C:\DOCUME~1\Giovanni\IMPOST~1\Temp/ccjonuJz.s:20 .text:00000000 port_halt
|
||||||
|
C:\DOCUME~1\Giovanni\IMPOST~1\Temp/ccjonuJz.s:39 .text:00000000 L0
|
||||||
|
C:\DOCUME~1\Giovanni\IMPOST~1\Temp/ccjonuJz.s:265 .debug_line:00000000 L0
|
||||||
|
C:\DOCUME~1\Giovanni\IMPOST~1\Temp/ccjonuJz.s:265 .debug_line:0000001d L0
|
||||||
|
C:\DOCUME~1\Giovanni\IMPOST~1\Temp/ccjonuJz.s:265 .debug_line:0000001d L0
|
||||||
|
|
||||||
|
UNDEFINED SYMBOLS
|
||||||
|
__do_copy_data
|
||||||
|
__do_clear_bss
|
|
@ -0,0 +1,234 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7/chcoreasm.s
|
||||||
|
* @brief ARM7 architecture port low level code.
|
||||||
|
* @addtogroup ARM7_CORE
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/** @cond never */
|
||||||
|
|
||||||
|
#include <chconf.h>
|
||||||
|
|
||||||
|
.set MODE_USR, 0x10
|
||||||
|
.set MODE_FIQ, 0x11
|
||||||
|
.set MODE_IRQ, 0x12
|
||||||
|
.set MODE_SVC, 0x13
|
||||||
|
.set MODE_ABT, 0x17
|
||||||
|
.set MODE_UND, 0x1B
|
||||||
|
.set MODE_SYS, 0x1F
|
||||||
|
|
||||||
|
.equ I_BIT, 0x80
|
||||||
|
.equ F_BIT, 0x40
|
||||||
|
|
||||||
|
.text
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupt enable/disable functions, only present if there is THUMB code in
|
||||||
|
* the system because those are inlined in ARM code.
|
||||||
|
*/
|
||||||
|
#ifdef THUMB_PRESENT
|
||||||
|
.balign 16
|
||||||
|
.code 16
|
||||||
|
.thumb_func
|
||||||
|
.global _port_disable_thumb
|
||||||
|
_port_disable_thumb:
|
||||||
|
mov r3, pc
|
||||||
|
bx r3
|
||||||
|
.code 32
|
||||||
|
mrs r3, CPSR
|
||||||
|
orr r3, #I_BIT
|
||||||
|
msr CPSR_c, r3
|
||||||
|
orr r3, #F_BIT
|
||||||
|
msr CPSR_c, r3
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
.code 16
|
||||||
|
.thumb_func
|
||||||
|
.global _port_suspend_thumb
|
||||||
|
_port_suspend_thumb:
|
||||||
|
.thumb_func
|
||||||
|
.global _port_lock_thumb
|
||||||
|
_port_lock_thumb:
|
||||||
|
mov r3, pc
|
||||||
|
bx r3
|
||||||
|
.code 32
|
||||||
|
msr CPSR_c, #MODE_SYS | I_BIT
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
.code 16
|
||||||
|
.thumb_func
|
||||||
|
.global _port_enable_thumb
|
||||||
|
_port_enable_thumb:
|
||||||
|
.thumb_func
|
||||||
|
.global _port_unlock_thumb
|
||||||
|
_port_unlock_thumb:
|
||||||
|
mov r3, pc
|
||||||
|
bx r3
|
||||||
|
.code 32
|
||||||
|
msr CPSR_c, #MODE_SYS
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
#ifdef THUMB_PRESENT
|
||||||
|
.code 16
|
||||||
|
.thumb_func
|
||||||
|
.global _port_switch_thumb
|
||||||
|
_port_switch_thumb:
|
||||||
|
mov r2, pc
|
||||||
|
bx r2
|
||||||
|
// Jumps into _port_switch_arm in ARM mode
|
||||||
|
#endif
|
||||||
|
.code 32
|
||||||
|
.global _port_switch_arm
|
||||||
|
_port_switch_arm:
|
||||||
|
#ifdef CH_CURRP_REGISTER_CACHE
|
||||||
|
stmfd sp!, {r4, r5, r6, r8, r9, r10, r11, lr}
|
||||||
|
str sp, [r0, #16]
|
||||||
|
ldr sp, [r1, #16]
|
||||||
|
#ifdef THUMB_PRESENT
|
||||||
|
ldmfd sp!, {r4, r5, r6, r8, r9, r10, r11, lr}
|
||||||
|
bx lr
|
||||||
|
#else /* !THUMB_PRESENT */
|
||||||
|
ldmfd sp!, {r4, r5, r6, r8, r9, r10, r11, pc}
|
||||||
|
#endif /* !THUMB_PRESENT */
|
||||||
|
#else /* !CH_CURRP_REGISTER_CACHE */
|
||||||
|
stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}
|
||||||
|
str sp, [r0, #16]
|
||||||
|
ldr sp, [r1, #16]
|
||||||
|
#ifdef THUMB_PRESENT
|
||||||
|
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}
|
||||||
|
bx lr
|
||||||
|
#else /* !THUMB_PRESENT */
|
||||||
|
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
|
||||||
|
#endif /* !THUMB_PRESENT */
|
||||||
|
#endif /* !CH_CURRP_REGISTER_CACHE */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Common exit point for all IRQ routines, it performs the rescheduling if
|
||||||
|
* required.
|
||||||
|
* System stack frame structure after a context switch in the
|
||||||
|
* interrupt handler:
|
||||||
|
*
|
||||||
|
* High +------------+
|
||||||
|
* | LR_USR | -+
|
||||||
|
* | R12 | |
|
||||||
|
* | R3 | |
|
||||||
|
* | R2 | | External context: IRQ handler frame
|
||||||
|
* | R1 | |
|
||||||
|
* | R0 | |
|
||||||
|
* | PC | | (user code return address)
|
||||||
|
* | PSR_USR | -+ (user code status)
|
||||||
|
* | .... | <- mk_DoRescheduleI() stack frame, optimize it for space
|
||||||
|
* | LR | -+ (system code return address)
|
||||||
|
* | R11 | |
|
||||||
|
* | R10 | |
|
||||||
|
* | R9 | |
|
||||||
|
* | R8 | | Internal context: mk_SwitchI() frame
|
||||||
|
* | (R7) | | (optional, see CH_CURRP_REGISTER_CACHE)
|
||||||
|
* | R6 | |
|
||||||
|
* | R5 | |
|
||||||
|
* SP-> | R4 | -+
|
||||||
|
* Low +------------+
|
||||||
|
*/
|
||||||
|
.balign 16
|
||||||
|
#ifdef THUMB_NO_INTERWORKING
|
||||||
|
.code 16
|
||||||
|
.thumb_func
|
||||||
|
.globl _port_irq_common
|
||||||
|
_port_irq_common:
|
||||||
|
bl chSchRescRequiredI
|
||||||
|
mov lr, pc
|
||||||
|
bx lr
|
||||||
|
.code 32
|
||||||
|
#else /* !THUMB_NO_INTERWORKING */
|
||||||
|
.code 32
|
||||||
|
.globl _port_irq_common
|
||||||
|
_port_irq_common:
|
||||||
|
bl chSchRescRequiredI
|
||||||
|
#endif /* !THUMB_NO_INTERWORKING */
|
||||||
|
cmp r0, #0 // Simply returns if a
|
||||||
|
ldmeqfd sp!, {r0-r3, r12, lr} // reschedule is not
|
||||||
|
subeqs pc, lr, #4 // required.
|
||||||
|
|
||||||
|
// Saves the IRQ mode registers in the system stack.
|
||||||
|
ldmfd sp!, {r0-r3, r12, lr} // IRQ stack now empty.
|
||||||
|
msr CPSR_c, #MODE_SYS | I_BIT
|
||||||
|
stmfd sp!, {r0-r3, r12, lr} // Registers on System Stack.
|
||||||
|
msr CPSR_c, #MODE_IRQ | I_BIT
|
||||||
|
mrs r0, SPSR
|
||||||
|
mov r1, lr
|
||||||
|
msr CPSR_c, #MODE_SYS | I_BIT
|
||||||
|
stmfd sp!, {r0, r1} // Push R0=SPSR, R1=LR_IRQ.
|
||||||
|
|
||||||
|
// Context switch.
|
||||||
|
#ifdef THUMB_NO_INTERWORKING
|
||||||
|
add r0, pc, #1
|
||||||
|
bx r0
|
||||||
|
.code 16
|
||||||
|
bl chSchDoRescheduleI
|
||||||
|
mov lr, pc
|
||||||
|
bx lr
|
||||||
|
.code 32
|
||||||
|
#else /* !THUMB_NO_INTERWORKING */
|
||||||
|
bl chSchDoRescheduleI
|
||||||
|
#endif /* !THUMB_NO_INTERWORKING */
|
||||||
|
|
||||||
|
// Re-establish the IRQ conditions again.
|
||||||
|
ldmfd sp!, {r0, r1} // Pop R0=SPSR, R1=LR_IRQ.
|
||||||
|
msr CPSR_c, #MODE_IRQ | I_BIT
|
||||||
|
msr SPSR_fsxc, r0
|
||||||
|
mov lr, r1
|
||||||
|
msr CPSR_c, #MODE_SYS | I_BIT
|
||||||
|
ldmfd sp!, {r0-r3, r12, lr}
|
||||||
|
msr CPSR_c, #MODE_IRQ | I_BIT
|
||||||
|
subs pc, lr, #4
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Threads trampoline code.
|
||||||
|
* NOTE: The threads always start in ARM mode then switch to the thread-function mode.
|
||||||
|
*/
|
||||||
|
.balign 16
|
||||||
|
.code 32
|
||||||
|
.globl _port_thread_start
|
||||||
|
_port_thread_start:
|
||||||
|
msr CPSR_c, #MODE_SYS
|
||||||
|
#ifndef THUMB_NO_INTERWORKING
|
||||||
|
mov r0, r5
|
||||||
|
mov lr, pc
|
||||||
|
bx r4
|
||||||
|
bl chThdExit
|
||||||
|
#else /* !THUMB_NO_INTERWORKING */
|
||||||
|
add r0, pc, #1
|
||||||
|
bx r0
|
||||||
|
.code 16
|
||||||
|
mov r0, r5
|
||||||
|
bl jmpr4
|
||||||
|
bl chThdExit
|
||||||
|
jmpr4:
|
||||||
|
bx r4
|
||||||
|
#endif /* !THUMB_NO_INTERWORKING */
|
||||||
|
|
||||||
|
/** @endcond */
|
||||||
|
/** @} */
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7/chtypes.h
|
||||||
|
* @brief ARM7 architecture port system types.
|
||||||
|
* @addtogroup ARM7_CORE
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CHTYPES_H_
|
||||||
|
#define _CHTYPES_H_
|
||||||
|
|
||||||
|
#define __need_NULL
|
||||||
|
#define __need_size_t
|
||||||
|
#define __need_ptrdiff_t
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#if !defined(_STDINT_H) && !defined(__STDINT_H_)
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef int32_t bool_t; /**< Fast boolean type. */
|
||||||
|
typedef uint8_t tmode_t; /**< Thread flags. */
|
||||||
|
typedef uint8_t tstate_t; /**< Thread state. */
|
||||||
|
typedef uint32_t tprio_t; /**< Thread priority. */
|
||||||
|
typedef int32_t msg_t; /**< Inter-thread message. */
|
||||||
|
typedef int32_t eventid_t; /**< Event Id. */
|
||||||
|
typedef uint32_t eventmask_t; /**< Events mask. */
|
||||||
|
typedef uint32_t systime_t; /**< System time. */
|
||||||
|
typedef int32_t cnt_t; /**< Resources counter. */
|
||||||
|
|
||||||
|
#define INLINE inline
|
||||||
|
#define PACK_STRUCT_STRUCT __attribute__((packed))
|
||||||
|
#define PACK_STRUCT_BEGIN
|
||||||
|
#define PACK_STRUCT_END
|
||||||
|
|
||||||
|
#endif /* _CHTYPES_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,218 @@
|
||||||
|
GAS LISTING /cygdrive/c/DOCUME~1/Giovanni/IMPOST~1/Temp/ccgRWKd6.s page 1
|
||||||
|
|
||||||
|
|
||||||
|
1 # 1 "../../os/ports/GCC/ARM7/crt0.s"
|
||||||
|
2 # 1 "<built-in>"
|
||||||
|
1 /*
|
||||||
|
0
|
||||||
|
0
|
||||||
|
2 ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
3
|
||||||
|
4 This file is part of ChibiOS/RT.
|
||||||
|
5
|
||||||
|
6 ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
7 it under the terms of the GNU General Public License as published by
|
||||||
|
8 the Free Software Foundation; either version 3 of the License, or
|
||||||
|
9 (at your option) any later version.
|
||||||
|
10
|
||||||
|
11 ChibiOS/RT is distributed in the hope that it will be useful,
|
||||||
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
14 GNU General Public License for more details.
|
||||||
|
15
|
||||||
|
16 You should have received a copy of the GNU General Public License
|
||||||
|
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
18 */
|
||||||
|
19
|
||||||
|
20 /**
|
||||||
|
21 * @file ports/ARM7/crt0.s
|
||||||
|
22 * @brief Generic ARM7 startup file for ChibiOS/RT.
|
||||||
|
23 * @addtogroup ARM7_CORE
|
||||||
|
24 * @{
|
||||||
|
25 */
|
||||||
|
26 /** @cond never */
|
||||||
|
27
|
||||||
|
28 .set MODE_USR, 0x10
|
||||||
|
29 .set MODE_FIQ, 0x11
|
||||||
|
30 .set MODE_IRQ, 0x12
|
||||||
|
31 .set MODE_SVC, 0x13
|
||||||
|
32 .set MODE_ABT, 0x17
|
||||||
|
33 .set MODE_UND, 0x1B
|
||||||
|
34 .set MODE_SYS, 0x1F
|
||||||
|
35
|
||||||
|
36 .equ I_BIT, 0x80
|
||||||
|
37 .equ F_BIT, 0x40
|
||||||
|
38
|
||||||
|
39 .text
|
||||||
|
40 .code 32
|
||||||
|
41 .balign 4
|
||||||
|
42
|
||||||
|
43 /*
|
||||||
|
44 * Reset handler.
|
||||||
|
45 */
|
||||||
|
46 .global ResetHandler
|
||||||
|
47 ResetHandler:
|
||||||
|
48 /*
|
||||||
|
49 * Stack pointers initialization.
|
||||||
|
50 */
|
||||||
|
51 ldr r0, =__ram_end__
|
||||||
|
52 /* Undefined */
|
||||||
|
53 msr CPSR_c, #MODE_UND | I_BIT | F_BIT
|
||||||
|
GAS LISTING /cygdrive/c/DOCUME~1/Giovanni/IMPOST~1/Temp/ccgRWKd6.s page 2
|
||||||
|
|
||||||
|
|
||||||
|
54 ???? 1040 0000 mov sp, r0
|
||||||
|
55 ldr r1, =__und_stack_size__
|
||||||
|
56 ???? 0080 sub r0, r0, r1
|
||||||
|
57 /* Abort */
|
||||||
|
58 msr CPSR_c, #MODE_ABT | I_BIT | F_BIT
|
||||||
|
59 ???? 1040 0000 mov sp, r0
|
||||||
|
60 ldr r1, =__abt_stack_size__
|
||||||
|
61 ???? 0080 sub r0, r0, r1
|
||||||
|
62 /* FIQ */
|
||||||
|
63 msr CPSR_c, #MODE_FIQ | I_BIT | F_BIT
|
||||||
|
64 ???? 1040 0000 mov sp, r0
|
||||||
|
65 ldr r1, =__fiq_stack_size__
|
||||||
|
66 ???? 0080 sub r0, r0, r1
|
||||||
|
67 /* IRQ */
|
||||||
|
68 msr CPSR_c, #MODE_IRQ | I_BIT | F_BIT
|
||||||
|
69 ???? 1040 0000 mov sp, r0
|
||||||
|
70 ldr r1, =__irq_stack_size__
|
||||||
|
71 ???? 0080 sub r0, r0, r1
|
||||||
|
72 /* Supervisor */
|
||||||
|
73 msr CPSR_c, #MODE_SVC | I_BIT | F_BIT
|
||||||
|
74 ???? 1040 0000 mov sp, r0
|
||||||
|
75 ldr r1, =__svc_stack_size__
|
||||||
|
76 ???? 0080 sub r0, r0, r1
|
||||||
|
77 /* System */
|
||||||
|
78 msr CPSR_c, #MODE_SYS | I_BIT | F_BIT
|
||||||
|
79 ???? 1040 0000 mov sp, r0
|
||||||
|
80 // ldr r1, =__sys_stack_size__
|
||||||
|
81 // sub r0, r0, r1
|
||||||
|
82 /*
|
||||||
|
83 * Early initialization.
|
||||||
|
84 */
|
||||||
|
85 #ifndef THUMB_NO_INTERWORKING
|
||||||
|
86 bl hwinit0
|
||||||
|
87 #else
|
||||||
|
88 add r0, pc, #1
|
||||||
|
89 bx r0
|
||||||
|
90 .code 16
|
||||||
|
91 bl hwinit0
|
||||||
|
92 mov r0, pc
|
||||||
|
93 bx r0
|
||||||
|
94 .code 32
|
||||||
|
95 #endif
|
||||||
|
96 /*
|
||||||
|
97 * Data initialization.
|
||||||
|
98 * NOTE: It assumes that the DATA size is a multiple of 4.
|
||||||
|
99 */
|
||||||
|
100 ldr r1, =_textdata
|
||||||
|
101 ldr r2, =_data
|
||||||
|
102 ldr r3, =_edata
|
||||||
|
103 dataloop:
|
||||||
|
104 ???? 0392 cmp r2, r3
|
||||||
|
105 ldrlo r0, [r1], #4
|
||||||
|
106 strlo r0, [r2], #4
|
||||||
|
107 blo dataloop
|
||||||
|
108 /*
|
||||||
|
109 * BSS initialization.
|
||||||
|
110 * NOTE: It assumes that the BSS size is a multiple of 4.
|
||||||
|
GAS LISTING /cygdrive/c/DOCUME~1/Giovanni/IMPOST~1/Temp/ccgRWKd6.s page 3
|
||||||
|
|
||||||
|
|
||||||
|
111 */
|
||||||
|
112 ???? 0340 mov r0, #0
|
||||||
|
113 ldr r1, =_bss_start
|
||||||
|
114 ldr r2, =_bss_end
|
||||||
|
115 bssloop:
|
||||||
|
116 ???? 0291 cmp r1, r2
|
||||||
|
117 strlo r0, [r1], #4
|
||||||
|
118 blo bssloop
|
||||||
|
119 /*
|
||||||
|
120 * Late initialization.
|
||||||
|
121 */
|
||||||
|
122 #ifdef THUMB_NO_INTERWORKING
|
||||||
|
123 add r0, pc, #1
|
||||||
|
124 bx r0
|
||||||
|
125 .code 16
|
||||||
|
126 bl hwinit1
|
||||||
|
127 mov r0, #0
|
||||||
|
128 mov r1, r0
|
||||||
|
129 bl main
|
||||||
|
130 ldr r1, =MainExitHandler
|
||||||
|
131 bx r1
|
||||||
|
132 .code 32
|
||||||
|
133 #else
|
||||||
|
134 bl hwinit1
|
||||||
|
135 ???? 0340 mov r0, #0
|
||||||
|
136 ???? 0041 mov r1, r0
|
||||||
|
137 bl main
|
||||||
|
138 b MainExitHandler
|
||||||
|
139 #endif
|
||||||
|
140
|
||||||
|
141 /*
|
||||||
|
142 * Default main function exit handler.
|
||||||
|
143 */
|
||||||
|
144 .weak MainExitHandler
|
||||||
|
145 .globl MainExitHandler
|
||||||
|
146 MainExitHandler:
|
||||||
|
147
|
||||||
|
148 .loop: b .loop
|
||||||
|
149
|
||||||
|
150 /*
|
||||||
|
151 * Default early initialization code. It is declared weak in order to be
|
||||||
|
152 * replaced by the real initialization code.
|
||||||
|
153 * Early initialization is performed just after reset before BSS and DATA
|
||||||
|
154 * segments initialization.
|
||||||
|
155 */
|
||||||
|
156 #ifdef THUMB_NO_INTERWORKING
|
||||||
|
157 .thumb_func
|
||||||
|
158 .code 16
|
||||||
|
159 #endif
|
||||||
|
160 .weak hwinit0
|
||||||
|
161 hwinit0:
|
||||||
|
162 bx lr
|
||||||
|
163 .code 32
|
||||||
|
164
|
||||||
|
165 /*
|
||||||
|
166 * Default late initialization code. It is declared weak in order to be
|
||||||
|
167 * replaced by the real initialization code.
|
||||||
|
GAS LISTING /cygdrive/c/DOCUME~1/Giovanni/IMPOST~1/Temp/ccgRWKd6.s page 4
|
||||||
|
|
||||||
|
|
||||||
|
168 * Late initialization is performed after BSS and DATA segments initialization
|
||||||
|
169 * and before invoking the main() function.
|
||||||
|
170 */
|
||||||
|
171 #ifdef THUMB_NO_INTERWORKING
|
||||||
|
172 .thumb_func
|
||||||
|
173 .code 16
|
||||||
|
174 #endif
|
||||||
|
175 .weak hwinit1
|
||||||
|
176 hwinit1:
|
||||||
|
177 bx lr
|
||||||
|
178 .code 32
|
||||||
|
GAS LISTING /cygdrive/c/DOCUME~1/Giovanni/IMPOST~1/Temp/ccgRWKd6.s page 5
|
||||||
|
|
||||||
|
|
||||||
|
DEFINED SYMBOLS
|
||||||
|
*ABS*:00000000 ../../os/ports/GCC/ARM7/crt0.s
|
||||||
|
../../os/ports/GCC/ARM7/crt0.s:28 *ABS*:00000010 MODE_USR
|
||||||
|
../../os/ports/GCC/ARM7/crt0.s:29 *ABS*:00000011 MODE_FIQ
|
||||||
|
../../os/ports/GCC/ARM7/crt0.s:30 *ABS*:00000012 MODE_IRQ
|
||||||
|
../../os/ports/GCC/ARM7/crt0.s:31 *ABS*:00000013 MODE_SVC
|
||||||
|
../../os/ports/GCC/ARM7/crt0.s:32 *ABS*:00000017 MODE_ABT
|
||||||
|
../../os/ports/GCC/ARM7/crt0.s:33 *ABS*:0000001b MODE_UND
|
||||||
|
../../os/ports/GCC/ARM7/crt0.s:34 *ABS*:0000001f MODE_SYS
|
||||||
|
../../os/ports/GCC/ARM7/crt0.s:36 *ABS*:00000080 I_BIT
|
||||||
|
../../os/ports/GCC/ARM7/crt0.s:37 *ABS*:00000040 F_BIT
|
||||||
|
../../os/ports/GCC/ARM7/crt0.s:47 .text:00000000 ResetHandler
|
||||||
|
../../os/ports/GCC/ARM7/crt0.s:103 .text:00000000 dataloop
|
||||||
|
../../os/ports/GCC/ARM7/crt0.s:115 .text:00000000 bssloop
|
||||||
|
../../os/ports/GCC/ARM7/crt0.s:146 .text:00000000 MainExitHandler
|
||||||
|
../../os/ports/GCC/ARM7/crt0.s:148 .text:00000000 .loop
|
||||||
|
../../os/ports/GCC/ARM7/crt0.s:161 .text:00000000 hwinit0
|
||||||
|
../../os/ports/GCC/ARM7/crt0.s:176 .text:00000000 hwinit1
|
||||||
|
|
||||||
|
UNDEFINED SYMBOLS
|
||||||
|
sp
|
|
@ -0,0 +1,181 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARM7/crt0.s
|
||||||
|
* @brief Generic ARM7 startup file for ChibiOS/RT.
|
||||||
|
* @addtogroup ARM7_CORE
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/** @cond never */
|
||||||
|
|
||||||
|
.set MODE_USR, 0x10
|
||||||
|
.set MODE_FIQ, 0x11
|
||||||
|
.set MODE_IRQ, 0x12
|
||||||
|
.set MODE_SVC, 0x13
|
||||||
|
.set MODE_ABT, 0x17
|
||||||
|
.set MODE_UND, 0x1B
|
||||||
|
.set MODE_SYS, 0x1F
|
||||||
|
|
||||||
|
.equ I_BIT, 0x80
|
||||||
|
.equ F_BIT, 0x40
|
||||||
|
|
||||||
|
.text
|
||||||
|
.code 32
|
||||||
|
.balign 4
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset handler.
|
||||||
|
*/
|
||||||
|
.global ResetHandler
|
||||||
|
ResetHandler:
|
||||||
|
/*
|
||||||
|
* Stack pointers initialization.
|
||||||
|
*/
|
||||||
|
ldr r0, =__ram_end__
|
||||||
|
/* Undefined */
|
||||||
|
msr CPSR_c, #MODE_UND | I_BIT | F_BIT
|
||||||
|
mov sp, r0
|
||||||
|
ldr r1, =__und_stack_size__
|
||||||
|
sub r0, r0, r1
|
||||||
|
/* Abort */
|
||||||
|
msr CPSR_c, #MODE_ABT | I_BIT | F_BIT
|
||||||
|
mov sp, r0
|
||||||
|
ldr r1, =__abt_stack_size__
|
||||||
|
sub r0, r0, r1
|
||||||
|
/* FIQ */
|
||||||
|
msr CPSR_c, #MODE_FIQ | I_BIT | F_BIT
|
||||||
|
mov sp, r0
|
||||||
|
ldr r1, =__fiq_stack_size__
|
||||||
|
sub r0, r0, r1
|
||||||
|
/* IRQ */
|
||||||
|
msr CPSR_c, #MODE_IRQ | I_BIT | F_BIT
|
||||||
|
mov sp, r0
|
||||||
|
ldr r1, =__irq_stack_size__
|
||||||
|
sub r0, r0, r1
|
||||||
|
/* Supervisor */
|
||||||
|
msr CPSR_c, #MODE_SVC | I_BIT | F_BIT
|
||||||
|
mov sp, r0
|
||||||
|
ldr r1, =__svc_stack_size__
|
||||||
|
sub r0, r0, r1
|
||||||
|
/* System */
|
||||||
|
msr CPSR_c, #MODE_SYS | I_BIT | F_BIT
|
||||||
|
mov sp, r0
|
||||||
|
// ldr r1, =__sys_stack_size__
|
||||||
|
// sub r0, r0, r1
|
||||||
|
/*
|
||||||
|
* Early initialization.
|
||||||
|
*/
|
||||||
|
#ifndef THUMB_NO_INTERWORKING
|
||||||
|
bl hwinit0
|
||||||
|
#else
|
||||||
|
add r0, pc, #1
|
||||||
|
bx r0
|
||||||
|
.code 16
|
||||||
|
bl hwinit0
|
||||||
|
mov r0, pc
|
||||||
|
bx r0
|
||||||
|
.code 32
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Data initialization.
|
||||||
|
* NOTE: It assumes that the DATA size is a multiple of 4.
|
||||||
|
*/
|
||||||
|
ldr r1, =_textdata
|
||||||
|
ldr r2, =_data
|
||||||
|
ldr r3, =_edata
|
||||||
|
dataloop:
|
||||||
|
cmp r2, r3
|
||||||
|
ldrlo r0, [r1], #4
|
||||||
|
strlo r0, [r2], #4
|
||||||
|
blo dataloop
|
||||||
|
/*
|
||||||
|
* BSS initialization.
|
||||||
|
* NOTE: It assumes that the BSS size is a multiple of 4.
|
||||||
|
*/
|
||||||
|
mov r0, #0
|
||||||
|
ldr r1, =_bss_start
|
||||||
|
ldr r2, =_bss_end
|
||||||
|
bssloop:
|
||||||
|
cmp r1, r2
|
||||||
|
strlo r0, [r1], #4
|
||||||
|
blo bssloop
|
||||||
|
/*
|
||||||
|
* Late initialization.
|
||||||
|
*/
|
||||||
|
#ifdef THUMB_NO_INTERWORKING
|
||||||
|
add r0, pc, #1
|
||||||
|
bx r0
|
||||||
|
.code 16
|
||||||
|
bl hwinit1
|
||||||
|
mov r0, #0
|
||||||
|
mov r1, r0
|
||||||
|
bl main
|
||||||
|
ldr r1, =MainExitHandler
|
||||||
|
bx r1
|
||||||
|
.code 32
|
||||||
|
#else
|
||||||
|
bl hwinit1
|
||||||
|
mov r0, #0
|
||||||
|
mov r1, r0
|
||||||
|
bl main
|
||||||
|
b MainExitHandler
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default main function exit handler.
|
||||||
|
*/
|
||||||
|
.weak MainExitHandler
|
||||||
|
.globl MainExitHandler
|
||||||
|
MainExitHandler:
|
||||||
|
|
||||||
|
.loop: b .loop
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default early initialization code. It is declared weak in order to be
|
||||||
|
* replaced by the real initialization code.
|
||||||
|
* Early initialization is performed just after reset before BSS and DATA
|
||||||
|
* segments initialization.
|
||||||
|
*/
|
||||||
|
#ifdef THUMB_NO_INTERWORKING
|
||||||
|
.thumb_func
|
||||||
|
.code 16
|
||||||
|
#endif
|
||||||
|
.weak hwinit0
|
||||||
|
hwinit0:
|
||||||
|
bx lr
|
||||||
|
.code 32
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default late initialization code. It is declared weak in order to be
|
||||||
|
* replaced by the real initialization code.
|
||||||
|
* Late initialization is performed after BSS and DATA segments initialization
|
||||||
|
* and before invoking the main() function.
|
||||||
|
*/
|
||||||
|
#ifdef THUMB_NO_INTERWORKING
|
||||||
|
.thumb_func
|
||||||
|
.code 16
|
||||||
|
#endif
|
||||||
|
.weak hwinit1
|
||||||
|
hwinit1:
|
||||||
|
bx lr
|
||||||
|
.code 32
|
||||||
|
|
||||||
|
/** @endcond */
|
||||||
|
/** @} */
|
|
@ -0,0 +1,200 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup ARM7 ARM7TDMI
|
||||||
|
* @details The ARM7 architecture is quite complex for a microcontroller and
|
||||||
|
* some explanations are required about the port choices.
|
||||||
|
*
|
||||||
|
* @section ARM7_NOTES The ARM7 modes
|
||||||
|
* The ARM7 port supports three modes:
|
||||||
|
* - Pure ARM mode, this is the preferred mode for code speed. The code size
|
||||||
|
* is larger however. This mode is enabled when all the modules are compiled
|
||||||
|
* in ARM mode, see the Makefiles.
|
||||||
|
* - Pure THUMB mode, this is the preferred mode for code size. In this mode
|
||||||
|
* the execution speed is slower than the ARM mode. This mode is enabled
|
||||||
|
* when all the modules are compiled in THUMB mode, see the Makefiles.
|
||||||
|
* - Interworking mode, when in the system there are ARM modules mixed with
|
||||||
|
* THUMB modules then the interworking compiler option is enabled. This is
|
||||||
|
* usually the slowest mode and the code size is not as good as in pure
|
||||||
|
* THUMB mode.
|
||||||
|
* .
|
||||||
|
* @section ARM7_STATES Mapping of the System States in the ARM7 port
|
||||||
|
* The ChibiOS/RT logical @ref system_states are mapped as follow in the ARM7
|
||||||
|
* port:
|
||||||
|
* - <b>Init</b>. This state is represented by the startup code and the
|
||||||
|
* initialization code before @p chSysInit() is executed. It has not a
|
||||||
|
* special hardware state associated, usually the CPU goes through several
|
||||||
|
* hardware states during the startup phase.
|
||||||
|
* - <b>Normal</b>. This is the state the system has after executing
|
||||||
|
* @p chSysInit(). In this state the ARM7TDMI has both the interrupt sources
|
||||||
|
* (IRQ and FIQ) enabled and is running in ARM System Mode.
|
||||||
|
* - <b>Suspended</b>. In this state the IRQ sources are disabled but the FIQ
|
||||||
|
* sources are served, the core is running in ARM System Mode.
|
||||||
|
* - <b>Disabled</b>. Both the IRQ and FIQ sources are disabled, the core is
|
||||||
|
* running in ARM System Mode.
|
||||||
|
* - <b>Sleep</b>. The ARM7 code does not have any built-in low power mode but
|
||||||
|
* there are clock stop modes implemented in custom ways by the various
|
||||||
|
* silicon vendors. This state is implemented in each microcontroller support
|
||||||
|
* code in a different way, the core is running (or freezed...) in ARM
|
||||||
|
* System Mode.
|
||||||
|
* - <b>S-Locked</b>. IRQ sources disabled, core running in ARM System Mode.
|
||||||
|
* - <b>I-Locked</b>. IRQ sources disabled, core running in ARM IRQ Mode. Note
|
||||||
|
* that this state is not different from the SRI state in this port, the
|
||||||
|
* @p chSysLockI() and @p chSysUnlockI() APIs do nothing (still use them in
|
||||||
|
* order to formally change state because this may change).
|
||||||
|
* - <b>Serving Regular Interrupt</b>. IRQ sources disabled, core running in
|
||||||
|
* ARM IRQ Mode. See also the I-Locked state.
|
||||||
|
* - <b>Serving Fast Interrupt</b>. IRQ and FIQ sources disabled, core running
|
||||||
|
* in ARM FIQ Mode.
|
||||||
|
* - <b>Serving Non-Maskable Interrupt</b>. There are no asynchronous NMI
|
||||||
|
* sources in ARM7 architecture but synchronous SVC, ABT and UND exception
|
||||||
|
* handlers can be seen as belonging to this category.
|
||||||
|
* - <b>Halted</b>. Implemented as an infinite loop after disabling both IRQ
|
||||||
|
* and FIQ sources. The ARM state is whatever the processor was running when
|
||||||
|
* @p chSysHalt() was invoked.
|
||||||
|
* .
|
||||||
|
* @section ARM7_NOTES The ARM7 port notes
|
||||||
|
* The ARM7 port makes some assumptions on the application code organization:
|
||||||
|
* - The @p main() function is invoked in system mode.
|
||||||
|
* - Each thread has a private user/system stack, the system has a single
|
||||||
|
* interrupt stack where all the interrupts are processed.
|
||||||
|
* - The threads are started in system mode.
|
||||||
|
* - The threads code can run in system mode or user mode, however the
|
||||||
|
* code running in user mode cannot invoke the ChibiOS/RT APIs directly
|
||||||
|
* because privileged instructions are used inside.<br>
|
||||||
|
* The kernel APIs can be eventually invoked by using a SWI entry point
|
||||||
|
* that handles the switch in system mode and the return in user mode.
|
||||||
|
* - Other modes are not preempt-able because the system code assumes the
|
||||||
|
* threads running in system mode. When running in supervisor or other
|
||||||
|
* modes make sure that the interrupts are globally disabled.
|
||||||
|
* - Interrupts nesting is not supported in the ARM7 code because their
|
||||||
|
* implementation, even if possible, is not really efficient in this
|
||||||
|
* architecture.
|
||||||
|
* - FIQ sources can preempt the kernel (by design) so it is not possible to
|
||||||
|
* invoke the kernel APIs from inside a FIQ handler. FIQ handlers are not
|
||||||
|
* affected by the kernel activity so there is not added jitter.
|
||||||
|
* .
|
||||||
|
* @section ARM7_IH ARM7 Interrupt Handlers
|
||||||
|
* ARM7 Interrupt handlers do not save function-saved registers so you need to
|
||||||
|
* make sure your code saves them or does not use them (this happens
|
||||||
|
* because in the ARM7 port all the OS interrupt handler functions are declared
|
||||||
|
* naked).<br>
|
||||||
|
* Function-trashed registers (R0-R3, R12, LR, SR) are saved/restored by the
|
||||||
|
* system macros @p CH_IRQ_PROLOGUE() and @p CH_IRQ_EPILOGUE().<br>
|
||||||
|
* The easiest way to ensure this is to just invoke a normal function from
|
||||||
|
* within the interrupt handler, the function code will save all the required
|
||||||
|
* registers.<br>
|
||||||
|
* Example:
|
||||||
|
* @code
|
||||||
|
* CH_IRQ_HANDLER(irq_handler) {
|
||||||
|
* CH_IRQ_PROLOGUE();
|
||||||
|
*
|
||||||
|
* serve_interrupt();
|
||||||
|
*
|
||||||
|
* VICVectAddr = 0; // This is LPC214x-specific.
|
||||||
|
* CH_IRQ_EPILOGUE();
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
* This is not a bug but an implementation choice, this solution allows to
|
||||||
|
* have interrupt handlers compiled in thumb mode without have to use an
|
||||||
|
* interworking mode (the mode switch is hidden in the macros), this
|
||||||
|
* greatly improves code efficiency and size. You can look at the serial
|
||||||
|
* driver for real examples of interrupt handlers.
|
||||||
|
*
|
||||||
|
* @ingroup Ports
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup ARM7_CONF Configuration Options
|
||||||
|
* @brief ARM7 specific configuration options.
|
||||||
|
* @details The ARM7 port allows some architecture-specific configurations
|
||||||
|
* settings that can be specified externally, as example on the compiler
|
||||||
|
* command line:
|
||||||
|
* - @p INT_REQUIRED_STACK, this value represent the amount of stack space used
|
||||||
|
* by an interrupt handler between the @p extctx and @p intctx
|
||||||
|
* structures.<br>
|
||||||
|
* In practice this value is the stack space used by the chSchDoReschedule()
|
||||||
|
* stack frame.<br>
|
||||||
|
* This value can be affected by a variety of external things like compiler
|
||||||
|
* version, compiler options, kernel settings (speed/size) and so on.<br>
|
||||||
|
* The default for this value is @p 0x10 which should be a safe value, you
|
||||||
|
* can trim this down by defining the macro externally. This would save
|
||||||
|
* some valuable RAM space for each thread present in the system.<br>
|
||||||
|
* The default value is set into <b>./ports/ARM7/chcore.h</b>.
|
||||||
|
* .
|
||||||
|
* @ingroup ARM7
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup ARM7_CORE Core Port Implementation
|
||||||
|
* @brief ARM7 specific port code, structures and macros.
|
||||||
|
*
|
||||||
|
* @ingroup ARM7
|
||||||
|
* @file ports/ARM7/chtypes.h Port types.
|
||||||
|
* @file ports/ARM7/chcore.h Port related structures and macros.
|
||||||
|
* @file ports/ARM7/chcore.c Port related code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup ARM7_STARTUP Startup Support
|
||||||
|
* @brief ARM7 startup code support.
|
||||||
|
* @details ChibiOS/RT provides its own generic startup file for the ARM7 port.
|
||||||
|
* Of course it is not mandatory to use it but care should be taken about the
|
||||||
|
* startup phase details.
|
||||||
|
*
|
||||||
|
* <h2>Startup Process</h2>
|
||||||
|
* The startup process, as implemented, is the following:
|
||||||
|
* -# The stacks are initialized by assigning them the sizes defined in the
|
||||||
|
* linker script (usually named @p ch.ld). Stack areas are allocated from
|
||||||
|
* the highest RAM location downward.
|
||||||
|
* -# The ARM state is switched to System with both IRQ and FIQ sources
|
||||||
|
* disabled.
|
||||||
|
* -# An early initialization routine @p hwinit0 is invoked, if the symbol is
|
||||||
|
* not defined then an empty default routine is executed (weak symbol).
|
||||||
|
* -# DATA and BSS segments are initialized.
|
||||||
|
* -# A late initialization routine @p hwinit1 is invoked, if the symbol not
|
||||||
|
* defined then an empty default routine is executed (weak symbol).<br>
|
||||||
|
* This late initialization function is also the proper place for a
|
||||||
|
* @a bootloader, if your application requires one.
|
||||||
|
* -# The @p main() function is invoked with the parameters @p argc and @p argv
|
||||||
|
* set to zero.
|
||||||
|
* -# Should the @p main() function return a branch is performed to the weak
|
||||||
|
* symbol MainExitHandler. The default code is an endless empty loop.
|
||||||
|
* .
|
||||||
|
* <h2>Expected linker symbols</h2>
|
||||||
|
* The startup code starts at the symbol @p ResetHandler and expects the
|
||||||
|
* following symbols to be defined in the linker script:
|
||||||
|
* - @p __ram_end__ RAM end location +1.
|
||||||
|
* - @p __und_stack_size__ Undefined Instruction stack size.
|
||||||
|
* - @p __abt_stack_size__ Memory Abort stack size.
|
||||||
|
* - @p __fiq_stack_size__ FIQ service stack size.
|
||||||
|
* - @p __irq_stack_size__ IRQ service stack size.
|
||||||
|
* - @p __svc_stack_size__ SVC service stack size.
|
||||||
|
* - @p __sys_stack_size__ System/User stack size. This is the stack area used
|
||||||
|
* by the @p main() function.
|
||||||
|
* - @p _textdata address of the data segment source read only data.
|
||||||
|
* - @p _data data segment start location.
|
||||||
|
* - @p _edata data segment end location +1.
|
||||||
|
* - @p _bss_start BSS start location.
|
||||||
|
* - @p _bss_end BSS end location +1.
|
||||||
|
* .
|
||||||
|
* @ingroup ARM7
|
||||||
|
* @file ports/ARM7/crt0.s Startup code.
|
||||||
|
*/
|
|
@ -0,0 +1,7 @@
|
||||||
|
# List of the ChibiOS/RT Cortex-M3 port files.
|
||||||
|
PORTSRC = ../../os/ports/GCC/ARM7/chcore.c
|
||||||
|
|
||||||
|
PORTASM = ../../os/ports/GCC/ARM7/crt0.s \
|
||||||
|
../../os/ports/GCC/ARM7/chcoreasm.s
|
||||||
|
|
||||||
|
PORTINC = ../../os/ports/GCC/ARM7
|
|
@ -0,0 +1,158 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARMCM3-STM32F103/pal_lld.c
|
||||||
|
* @brief STM32 GPIO low level driver code
|
||||||
|
* @addtogroup STM32F103_PAL
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
#include <pal.h>
|
||||||
|
|
||||||
|
#if defined(STM32F10X_LD)
|
||||||
|
#define APB2_RST_MASK (RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPBRST | \
|
||||||
|
RCC_APB2RSTR_IOPCRST | RCC_APB2RSTR_IOPDRST | \
|
||||||
|
RCC_APB2RSTR_AFIORST)
|
||||||
|
#define APB2_EN_MASK (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | \
|
||||||
|
RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | \
|
||||||
|
RCC_APB2ENR_AFIOEN)
|
||||||
|
#elif defined(STM32F10X_HD)
|
||||||
|
#define APB2_RST_MASK (RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPBRST | \
|
||||||
|
RCC_APB2RSTR_IOPCRST | RCC_APB2RSTR_IOPDRST | \
|
||||||
|
RCC_APB2RSTR_IOPERST | RCC_APB2RSTR_IOPFRST | \
|
||||||
|
RCC_APB2RSTR_IOPGRST | RCC_APB2RSTR_AFIORST);
|
||||||
|
#define APB2_EN_MASK (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | \
|
||||||
|
RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | \
|
||||||
|
RCC_APB2ENR_IOPEEN | RCC_APB2ENR_IOPFEN | \
|
||||||
|
RCC_APB2ENR_IOPGEN | RCC_APB2ENR_AFIOEN)
|
||||||
|
#else
|
||||||
|
/* Defaults on Medium Density devices.*/
|
||||||
|
#define APB2_RST_MASK (RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPBRST | \
|
||||||
|
RCC_APB2RSTR_IOPCRST | RCC_APB2RSTR_IOPDRST | \
|
||||||
|
RCC_APB2RSTR_IOPERST | RCC_APB2RSTR_AFIORST);
|
||||||
|
#define APB2_EN_MASK (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | \
|
||||||
|
RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | \
|
||||||
|
RCC_APB2ENR_IOPEEN | RCC_APB2ENR_AFIOEN)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief STM32 I/O ports configuration.
|
||||||
|
* @details Ports A-D(E, F, G) clocks enabled, AFIO clock enabled.
|
||||||
|
*
|
||||||
|
* @param[in] config the STM32 ports configuration
|
||||||
|
*/
|
||||||
|
void _pal_lld_init(const STM32GPIOConfig *config) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enables the GPIO related clocks.
|
||||||
|
*/
|
||||||
|
RCC->APB2ENR |= APB2_EN_MASK;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resets the GPIO ports and AFIO.
|
||||||
|
*/
|
||||||
|
RCC->APB2RSTR = APB2_RST_MASK;
|
||||||
|
RCC->APB2RSTR = 0;
|
||||||
|
|
||||||
|
IOPORT_A->ODR = config->PAData.odr;
|
||||||
|
IOPORT_A->CRH = config->PAData.crh;
|
||||||
|
IOPORT_A->CRL = config->PAData.crl;
|
||||||
|
IOPORT_B->ODR = config->PBData.odr;
|
||||||
|
IOPORT_B->CRH = config->PBData.crh;
|
||||||
|
IOPORT_B->CRL = config->PBData.crl;
|
||||||
|
IOPORT_C->ODR = config->PCData.odr;
|
||||||
|
IOPORT_C->CRH = config->PCData.crh;
|
||||||
|
IOPORT_C->CRL = config->PCData.crl;
|
||||||
|
IOPORT_D->ODR = config->PDData.odr;
|
||||||
|
IOPORT_D->CRH = config->PDData.crh;
|
||||||
|
IOPORT_D->CRL = config->PDData.crl;
|
||||||
|
#if !defined(STM32F10X_LD) || defined(__DOXYGEN__)
|
||||||
|
IOPORT_E->ODR = config->PEData.odr;
|
||||||
|
IOPORT_E->CRH = config->PEData.crh;
|
||||||
|
IOPORT_E->CRL = config->PEData.crl;
|
||||||
|
#endif
|
||||||
|
#if defined(STM32F10X_HD) || defined(__DOXYGEN__)
|
||||||
|
IOPORT_F->ODR = config->PFData.odr;
|
||||||
|
IOPORT_F->CRH = config->PFData.crh;
|
||||||
|
IOPORT_F->CRL = config->PFData.crl;
|
||||||
|
IOPORT_G->ODR = config->PGData.odr;
|
||||||
|
IOPORT_G->CRH = config->PGData.crh;
|
||||||
|
IOPORT_G->CRL = config->PGData.crl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pads mode setup.
|
||||||
|
* @details This function programs a pads group belonging to the same port
|
||||||
|
* with the specified mode.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] mask the group mask
|
||||||
|
* @param[in] mode the mode
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
* @note @p PAL_MODE_UNCONNECTED is implemented as push pull output at 2MHz.
|
||||||
|
* @note Writing on pads programmed as pull-up or pull-down has the side
|
||||||
|
* effect to modify the resistor setting because the output latched data
|
||||||
|
* is used for the resistor selection.
|
||||||
|
*/
|
||||||
|
void _pal_lld_setgroupmode(ioportid_t port,
|
||||||
|
ioportmask_t mask,
|
||||||
|
uint_fast8_t mode) {
|
||||||
|
static const uint8_t cfgtab[] = {
|
||||||
|
4, /* PAL_MODE_RESET, implemented as input.*/
|
||||||
|
2, /* PAL_MODE_UNCONNECTED, implemented as push pull output 2MHz.*/
|
||||||
|
4, /* PAL_MODE_INPUT */
|
||||||
|
8, /* PAL_MODE_INPUT_PULLUP */
|
||||||
|
8, /* PAL_MODE_INPUT_PULLDOWN */
|
||||||
|
3, /* PAL_MODE_OUTPUT_PUSHPULL, 50MHz.*/
|
||||||
|
7, /* PAL_MODE_OUTPUT_OPENDRAIN, 50MHz.*/
|
||||||
|
};
|
||||||
|
uint32_t mh, ml, crh, crl, cfg;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
if (mode == PAL_MODE_INPUT_PULLUP)
|
||||||
|
port->BSRR = mask;
|
||||||
|
else if (mode == PAL_MODE_INPUT_PULLDOWN)
|
||||||
|
port->BRR = mask;
|
||||||
|
cfg = cfgtab[mode];
|
||||||
|
mh = ml = crh = crl = 0;
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
ml <<= 4;
|
||||||
|
mh <<= 4;
|
||||||
|
crl <<= 4;
|
||||||
|
crh <<= 4;
|
||||||
|
if ((mask & 1) == 0)
|
||||||
|
ml |= 0xf;
|
||||||
|
else
|
||||||
|
crl |= cfg;
|
||||||
|
if ((mask & 0x10000) == 0)
|
||||||
|
mh |= 0xf;
|
||||||
|
else
|
||||||
|
crh |= cfg;
|
||||||
|
mask >>= 1;
|
||||||
|
}
|
||||||
|
port->CRH = (port->CRH & mh) | crh;
|
||||||
|
port->CRL = (port->CRL & ml) | crl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,307 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARMCM3-STM32F103/pal_lld.h
|
||||||
|
* @brief STM32 GPIO low level driver header
|
||||||
|
* @addtogroup STM32F103_PAL
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PAL_LLD_H_
|
||||||
|
#define _PAL_LLD_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tricks required to make the TRUE/FALSE declaration inside the library
|
||||||
|
* compatible.
|
||||||
|
*/
|
||||||
|
#ifndef __STM32F10x_H
|
||||||
|
#undef FALSE
|
||||||
|
#undef TRUE
|
||||||
|
#include <stm32f10x.h>
|
||||||
|
#define FALSE 0
|
||||||
|
#define TRUE (!FALSE)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* I/O Ports Types and constants. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GPIO port setup info.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** Initial value for ODR register.*/
|
||||||
|
uint32_t odr;
|
||||||
|
/** Initial value for CRL register.*/
|
||||||
|
uint32_t crl;
|
||||||
|
/** Initial value for CRH register.*/
|
||||||
|
uint32_t crh;
|
||||||
|
} stm32_gpio_setup_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief STM32 GPIO static initializer.
|
||||||
|
* @details An instance of this structure must be passed to @p palInit() at
|
||||||
|
* system startup time in order to initialized the digital I/O
|
||||||
|
* subsystem. This represents only the initial setup, specific pads
|
||||||
|
* or whole ports can be reprogrammed at later time.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** @brief Port A setup data.*/
|
||||||
|
stm32_gpio_setup_t PAData;
|
||||||
|
/** @brief Port B setup data.*/
|
||||||
|
stm32_gpio_setup_t PBData;
|
||||||
|
/** @brief Port C setup data.*/
|
||||||
|
stm32_gpio_setup_t PCData;
|
||||||
|
/** @brief Port D setup data.*/
|
||||||
|
stm32_gpio_setup_t PDData;
|
||||||
|
#if !defined(STM32F10X_LD) || defined(__DOXYGEN__)
|
||||||
|
/** @brief Port E setup data.*/
|
||||||
|
stm32_gpio_setup_t PEData;
|
||||||
|
#endif
|
||||||
|
#if defined(STM32F10X_HD) || defined(__DOXYGEN__)
|
||||||
|
/** @brief Port F setup data.*/
|
||||||
|
stm32_gpio_setup_t PFData;
|
||||||
|
/** @brief Port G setup data.*/
|
||||||
|
stm32_gpio_setup_t PGData;
|
||||||
|
#endif
|
||||||
|
} STM32GPIOConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Width, in bits, of an I/O port.
|
||||||
|
*/
|
||||||
|
#define PAL_IOPORTS_WIDTH 16
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Whole port mask.
|
||||||
|
* @brief This macro specifies all the valid bits into a port.
|
||||||
|
*/
|
||||||
|
#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFF)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Digital I/O port sized unsigned type.
|
||||||
|
*/
|
||||||
|
typedef uint32_t ioportmask_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Port Identifier.
|
||||||
|
* @details This type can be a scalar or some kind of pointer, do not make
|
||||||
|
* any assumption about it, use the provided macros when populating
|
||||||
|
* variables of this type.
|
||||||
|
*/
|
||||||
|
typedef GPIO_TypeDef * ioportid_t;
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* I/O Ports Identifiers. */
|
||||||
|
/* The low level driver wraps the definitions already present in the STM32 */
|
||||||
|
/* firmware library. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GPIO port A identifier.
|
||||||
|
*/
|
||||||
|
#define IOPORT_A GPIOA
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GPIO port B identifier.
|
||||||
|
*/
|
||||||
|
#define IOPORT_B GPIOB
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GPIO port C identifier.
|
||||||
|
*/
|
||||||
|
#define IOPORT_C GPIOC
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GPIO port D identifier.
|
||||||
|
*/
|
||||||
|
#define IOPORT_D GPIOD
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GPIO port E identifier.
|
||||||
|
*/
|
||||||
|
#if !defined(STM32F10X_LD) || defined(__DOXYGEN__)
|
||||||
|
#define IOPORT_E GPIOE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GPIO port F identifier.
|
||||||
|
*/
|
||||||
|
#if defined(STM32F10X_HD) || defined(__DOXYGEN__)
|
||||||
|
#define IOPORT_F GPIOF
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GPIO port G identifier.
|
||||||
|
*/
|
||||||
|
#define IOPORT_G GPIOG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Implementation, some of the following macros could be implemented as */
|
||||||
|
/* functions, please put them in a file named ioports_lld.c if so. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GPIO ports subsystem initialization.
|
||||||
|
*/
|
||||||
|
#define pal_lld_init(config) _pal_lld_init(config)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads an I/O port.
|
||||||
|
* @details This function is implemented by reading the GPIO IDR register, the
|
||||||
|
* implementation has no side effects.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @return the port bits
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
#define pal_lld_readport(port) ((port)->IDR)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads the output latch.
|
||||||
|
* @details This function is implemented by reading the GPIO ODR register, the
|
||||||
|
* implementation has no side effects.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @return The latched logical states.
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
#define pal_lld_readlatch(port) ((port)->ODR)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes on a I/O port.
|
||||||
|
* @details This function is implemented by writing the GPIO ODR register, the
|
||||||
|
* implementation has no side effects.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] bits the bits to be written on the specified port
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
* @note Writing on pads programmed as pull-up or pull-down has the side
|
||||||
|
* effect to modify the resistor setting because the output latched data
|
||||||
|
* is used for the resistor selection.
|
||||||
|
*/
|
||||||
|
#define pal_lld_writeport(port, bits) ((port)->ODR = (bits))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets a bits mask on a I/O port.
|
||||||
|
* @details This function is implemented by writing the GPIO BSRR register, the
|
||||||
|
* implementation has no side effects.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] bits the bits to be ORed on the specified port
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
* @note Writing on pads programmed as pull-up or pull-down has the side
|
||||||
|
* effect to modify the resistor setting because the output latched data
|
||||||
|
* is used for the resistor selection.
|
||||||
|
*/
|
||||||
|
#define pal_lld_setport(port, bits) ((port)->BSRR = (bits))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears a bits mask on a I/O port.
|
||||||
|
* @details This function is implemented by writing the GPIO BRR register, the
|
||||||
|
* implementation has no side effects.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] bits the bits to be cleared on the specified port
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
* @note Writing on pads programmed as pull-up or pull-down has the side
|
||||||
|
* effect to modify the resistor setting because the output latched data
|
||||||
|
* is used for the resistor selection.
|
||||||
|
*/
|
||||||
|
#define pal_lld_clearport(port, bits) ((port)->BRR = (bits))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes a group of bits.
|
||||||
|
* @details This function is implemented by writing the GPIO BSRR register, the
|
||||||
|
* implementation has no side effects.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] mask the group mask
|
||||||
|
* @param[in] offset the group bit offset within the port
|
||||||
|
* @param[in] bits the bits to be written. Values exceeding the group width
|
||||||
|
* are masked.
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
* @note Writing on pads programmed as pull-up or pull-down has the side
|
||||||
|
* effect to modify the resistor setting because the output latched data
|
||||||
|
* is used for the resistor selection.
|
||||||
|
*/
|
||||||
|
#define pal_lld_writegroup(port, mask, offset, bits) { \
|
||||||
|
(port)->BSRR = ((~(bits) & (mask)) << (16 + (offset))) | \
|
||||||
|
(((bits) & (mask)) << (offset)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pads group mode setup.
|
||||||
|
* @details This function programs a pads group belonging to the same port
|
||||||
|
* with the specified mode.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] mask the group mask
|
||||||
|
* @param[in] mode the mode
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
* @note Writing on pads programmed as pull-up or pull-down has the side
|
||||||
|
* effect to modify the resistor setting because the output latched data
|
||||||
|
* is used for the resistor selection.
|
||||||
|
*/
|
||||||
|
#define pal_lld_setgroupmode(port, mask, mode) \
|
||||||
|
_pal_lld_setgroupmode(port, mask, mode)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes a logical state on an output pad.
|
||||||
|
*
|
||||||
|
* @param[in] port the port identifier
|
||||||
|
* @param[in] pad the pad number within the port
|
||||||
|
* @param[out] bit the logical value, the value must be @p 0 or @p 1
|
||||||
|
*
|
||||||
|
* @note This function is not meant to be invoked directly by the application
|
||||||
|
* code.
|
||||||
|
* @note Writing on pads programmed as pull-up or pull-down has the side
|
||||||
|
* effect to modify the resistor setting because the output latched data
|
||||||
|
* is used for the resistor selection.
|
||||||
|
*/
|
||||||
|
#define pal_lld_writepad(port, pad, bit) pal_lld_writegroup(port, 1, pad, bit)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void _pal_lld_init(const STM32GPIOConfig *config);
|
||||||
|
void _pal_lld_setgroupmode(ioportid_t port,
|
||||||
|
ioportmask_t mask,
|
||||||
|
uint_fast8_t mode);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _PAL_LLD_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup STM32F103 STM32F103 Support
|
||||||
|
* @brief STM32F103 specific support.
|
||||||
|
* @details The STM32F103 support includes:
|
||||||
|
* - I/O ports driver.
|
||||||
|
* - Buffered, interrupt driven, serial driver.
|
||||||
|
* - A demo supporting the kernel test suite.
|
||||||
|
* .
|
||||||
|
* @ingroup ARMCM3
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup STM32F103_PAL I/O Ports Support
|
||||||
|
* @brief I/O Ports peripherals support.
|
||||||
|
* @details This module supports the STM32F103 GPIO controller. The controller
|
||||||
|
* supports the following features (see @ref PAL):
|
||||||
|
* - 16 bits wide ports.
|
||||||
|
* - Atomic set/reset functions.
|
||||||
|
* - Atomic set+reset function (atomic bus operations).
|
||||||
|
* - Output latched regardless of the pad setting.
|
||||||
|
* - Direct read of input pads regardless of the pad setting.
|
||||||
|
* .
|
||||||
|
* <h2>Supported Setup Modes</h2>
|
||||||
|
* - @p PAL_MODE_RESET.
|
||||||
|
* - @p PAL_MODE_UNCONNECTED.
|
||||||
|
* - @p PAL_MODE_INPUT.
|
||||||
|
* - @p PAL_MODE_INPUT_PULLUP.
|
||||||
|
* - @p PAL_MODE_INPUT_PULLDOWN.
|
||||||
|
* - @p PAL_MODE_OUTPUT_PUSHPULL.
|
||||||
|
* - @p PAL_MODE_OUTPUT_OPENDRAIN.
|
||||||
|
* .
|
||||||
|
* Any attempt to setup an invalid mode is ignored.
|
||||||
|
*
|
||||||
|
* <h2>Suboptimal Behavior</h2>
|
||||||
|
* Some GPIO features are less than optimal:
|
||||||
|
* - Pad/port toggling operations are not atomic.
|
||||||
|
* - Pad/group mode setup is not atomic.
|
||||||
|
* - Writing on pads/groups/ports programmed as input with pull-up/down
|
||||||
|
* resistor can change the resistor setting because the output latch is
|
||||||
|
* used for resistor selection.
|
||||||
|
* .
|
||||||
|
* @ingroup STM32F103
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup STM32F103_SERIAL USART Support
|
||||||
|
* @brief USART peripherals support.
|
||||||
|
* @details The serial driver supports the STM32F103 USARTs in asynchronous
|
||||||
|
* mode.
|
||||||
|
*
|
||||||
|
* @ingroup STM32F103
|
||||||
|
*/
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARMCM3-STM32F103/stm32_can.c
|
||||||
|
* @brief STM32 CAN driver code
|
||||||
|
* @addtogroup STM32F103_CAN
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARMCM3-STM32F103/stm32_can.h
|
||||||
|
* @brief STM32 CAN driver header file
|
||||||
|
* @addtogroup STM32F103_CAN
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STM32_CAN_H_
|
||||||
|
#define _STM32_CAN_H_
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
} CANConfig;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
} CANMessage;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void canInit(CANConfig *config);
|
||||||
|
bool_t canReceive(CANMessage *canmsg);
|
||||||
|
bool_t canTransmit(CANMessage *canmsg);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _STM32_CAN_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,222 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARMCM3-STM32F103/stm32_serial.c
|
||||||
|
* @brief STM32F103 Serial driver code.
|
||||||
|
* @addtogroup STM32F103_SERIAL
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
|
||||||
|
#include "board.h"
|
||||||
|
#include "nvic.h"
|
||||||
|
#include "stm32_serial.h"
|
||||||
|
|
||||||
|
#if USE_STM32_USART1 || defined(__DOXYGEN__)
|
||||||
|
/** @brief USART1 serial driver identifier.*/
|
||||||
|
FullDuplexDriver COM1;
|
||||||
|
|
||||||
|
static uint8_t ib1[SERIAL_BUFFERS_SIZE];
|
||||||
|
static uint8_t ob1[SERIAL_BUFFERS_SIZE];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_STM32_USART2 || defined(__DOXYGEN__)
|
||||||
|
/** @brief USART2 serial driver identifier.*/
|
||||||
|
FullDuplexDriver COM2;
|
||||||
|
|
||||||
|
static uint8_t ib2[SERIAL_BUFFERS_SIZE];
|
||||||
|
static uint8_t ob2[SERIAL_BUFFERS_SIZE];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_STM32_USART3 || defined(__DOXYGEN__)
|
||||||
|
/** @brief USART3 serial driver identifier.*/
|
||||||
|
FullDuplexDriver COM3;
|
||||||
|
|
||||||
|
static uint8_t ib3[SERIAL_BUFFERS_SIZE];
|
||||||
|
static uint8_t ob3[SERIAL_BUFFERS_SIZE];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Error handling routine.
|
||||||
|
* @param[in] sr USART SR register value
|
||||||
|
* @param[in] com communication channel associated to the USART
|
||||||
|
*/
|
||||||
|
static void SetError(uint16_t sr, FullDuplexDriver *com) {
|
||||||
|
dflags_t sts = 0;
|
||||||
|
|
||||||
|
if (sr & USART_SR_ORE)
|
||||||
|
sts |= SD_OVERRUN_ERROR;
|
||||||
|
if (sr & USART_SR_PE)
|
||||||
|
sts |= SD_PARITY_ERROR;
|
||||||
|
if (sr & USART_SR_FE)
|
||||||
|
sts |= SD_FRAMING_ERROR;
|
||||||
|
if (sr & USART_SR_LBD)
|
||||||
|
sts |= SD_BREAK_DETECTED;
|
||||||
|
chSysLockFromIsr();
|
||||||
|
chFDDAddFlagsI(com, sts);
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Common IRQ handler.
|
||||||
|
* @param[in] u pointer to an USART I/O block
|
||||||
|
* @param[in] com communication channel associated to the USART
|
||||||
|
*/
|
||||||
|
static void ServeInterrupt(USART_TypeDef *u, FullDuplexDriver *com) {
|
||||||
|
uint16_t sr = u->SR;
|
||||||
|
|
||||||
|
if (sr & (USART_SR_ORE | USART_SR_FE | USART_SR_PE | USART_SR_LBD))
|
||||||
|
SetError(sr, com);
|
||||||
|
if (sr & USART_SR_RXNE) {
|
||||||
|
chSysLockFromIsr();
|
||||||
|
chFDDIncomingDataI(com, u->DR);
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
}
|
||||||
|
if (sr & USART_SR_TXE) {
|
||||||
|
chSysLockFromIsr();
|
||||||
|
msg_t b = chFDDRequestDataI(com);
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
if (b < Q_OK)
|
||||||
|
u->CR1 &= ~USART_CR1_TXEIE;
|
||||||
|
else
|
||||||
|
u->DR = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_STM32_USART1 || defined(__DOXYGEN__)
|
||||||
|
CH_IRQ_HANDLER(VectorD4) {
|
||||||
|
|
||||||
|
CH_IRQ_PROLOGUE();
|
||||||
|
|
||||||
|
ServeInterrupt(USART1, &COM1);
|
||||||
|
|
||||||
|
CH_IRQ_EPILOGUE();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OutNotify1(void) {
|
||||||
|
|
||||||
|
USART1->CR1 |= USART_CR1_TXEIE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_STM32_USART2 || defined(__DOXYGEN__)
|
||||||
|
CH_IRQ_HANDLER(VectorD8) {
|
||||||
|
|
||||||
|
CH_IRQ_PROLOGUE();
|
||||||
|
|
||||||
|
ServeInterrupt(USART2, &COM2);
|
||||||
|
|
||||||
|
CH_IRQ_EPILOGUE();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OutNotify2(void) {
|
||||||
|
|
||||||
|
USART2->CR1 |= USART_CR1_TXEIE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_STM32_USART3 || defined(__DOXYGEN__)
|
||||||
|
CH_IRQ_HANDLER(VectorDC) {
|
||||||
|
|
||||||
|
CH_IRQ_PROLOGUE();
|
||||||
|
|
||||||
|
ServeInterrupt(USART3, &COM3);
|
||||||
|
|
||||||
|
CH_IRQ_EPILOGUE();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OutNotify3(void) {
|
||||||
|
|
||||||
|
USART3->CR1 |= USART_CR1_TXEIE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief USART1 setup.
|
||||||
|
* @details This function must be invoked with interrupts disabled.
|
||||||
|
* @param[in] u pointer to an USART I/O block
|
||||||
|
* @param[in] speed serial port speed in bits per second
|
||||||
|
* @param[in] cr1 the value for the @p CR1 register
|
||||||
|
* @param[in] cr2 the value for the @p CR2 register
|
||||||
|
* @param[in] cr3 the value for the @p CR3 register
|
||||||
|
* @note Must be invoked with interrupts disabled.
|
||||||
|
* @note Does not reset the I/O queues.
|
||||||
|
*/
|
||||||
|
void usart_setup(USART_TypeDef *u, uint32_t speed, uint16_t cr1,
|
||||||
|
uint16_t cr2, uint16_t cr3) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Baud rate setting.
|
||||||
|
*/
|
||||||
|
if (u == USART1)
|
||||||
|
u->BRR = APB2CLK / speed;
|
||||||
|
else
|
||||||
|
u->BRR = APB1CLK / speed;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that some bits are enforced.
|
||||||
|
*/
|
||||||
|
u->CR1 = cr1 | USART_CR1_UE | USART_CR1_PEIE | USART_CR1_RXNEIE |
|
||||||
|
USART_CR1_TE | USART_CR1_RE;
|
||||||
|
u->CR2 = cr2;
|
||||||
|
u->CR3 = cr3 | USART_CR3_EIE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Serial driver initialization.
|
||||||
|
* @param[in] prio1 priority to be assigned to the USART1 IRQ
|
||||||
|
* @param[in] prio2 priority to be assigned to the USART2 IRQ
|
||||||
|
* @param[in] prio3 priority to be assigned to the USART3 IRQ
|
||||||
|
* @note Handshake pads are not enabled inside this function because they
|
||||||
|
* may have another use, enable them externally if needed.
|
||||||
|
* RX and TX pads are handled inside.
|
||||||
|
*/
|
||||||
|
void serial_init(uint32_t prio1, uint32_t prio2, uint32_t prio3) {
|
||||||
|
|
||||||
|
#if USE_STM32_USART1
|
||||||
|
chFDDInit(&COM1, ib1, sizeof ib1, NULL, ob1, sizeof ob1, OutNotify1);
|
||||||
|
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
|
||||||
|
usart_setup(USART1, DEFAULT_USART_BITRATE, 0,
|
||||||
|
USART_CR2_STOP1_BITS | USART_CR2_LINEN, 0);
|
||||||
|
GPIOA->CRH = (GPIOA->CRH & 0xFFFFF00F) | 0x000004B0;
|
||||||
|
NVICEnableVector(USART1_IRQn, prio1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_STM32_USART2
|
||||||
|
chFDDInit(&COM2, ib2, sizeof ib2, NULL, ob2, sizeof ob2, OutNotify2);
|
||||||
|
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
|
||||||
|
usart_setup(USART2, DEFAULT_USART_BITRATE, 0,
|
||||||
|
USART_CR2_STOP1_BITS | USART_CR2_LINEN, 0);
|
||||||
|
GPIOA->CRL = (GPIOA->CRL & 0xFFFF00FF) | 0x00004B00;
|
||||||
|
NVICEnableVector(USART2_IRQn, prio2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_STM32_USART3
|
||||||
|
chFDDInit(&COM3, ib3, sizeof ib3, NULL, ob3, sizeof ob3, OutNotify3);
|
||||||
|
RCC->APB1ENR |= RCC_APB1ENR_USART3EN;
|
||||||
|
usart_setup(USART3, DEFAULT_USART_BITRATE, 0,
|
||||||
|
USART_CR2_STOP1_BITS | USART_CR2_LINEN, 0);
|
||||||
|
GPIOB->CRH = (GPIOB->CRH & 0xFFFF00FF) | 0x00004B00;
|
||||||
|
NVICEnableVector(USART3_IRQn, prio3);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARMCM3-STM32F103/stm32_serial.h
|
||||||
|
* @brief STM32F103 Serial driver macros and structures.
|
||||||
|
* @addtogroup STM32F103_SERIAL
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STM32_SERIAL_H_
|
||||||
|
#define _STM32_SERIAL_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tricks required to make the TRUE/FALSE declaration inside the library
|
||||||
|
* compatible.
|
||||||
|
*/
|
||||||
|
#ifndef __STM32F10x_H
|
||||||
|
#undef FALSE
|
||||||
|
#undef TRUE
|
||||||
|
#include <stm32f10x.h>
|
||||||
|
#define FALSE 0
|
||||||
|
#define TRUE (!FALSE)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Serial buffers size.
|
||||||
|
* @details Configuration parameter, you can change the depth of the queue
|
||||||
|
* buffers depending on the requirements of your application.
|
||||||
|
* @note The default is 128 bytes for both the transmission and receive buffers.
|
||||||
|
*/
|
||||||
|
#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
|
||||||
|
#define SERIAL_BUFFERS_SIZE 128
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default bit rate.
|
||||||
|
* @details Configuration parameter, at startup the USARTs are configured at
|
||||||
|
* this speed.
|
||||||
|
* @note It is possible to use @p SetUSART() in order to change the working
|
||||||
|
* parameters at runtime.
|
||||||
|
*/
|
||||||
|
#if !defined(DEFAULT_USART_BITRATE) || defined(__DOXYGEN__)
|
||||||
|
#define DEFAULT_USART_BITRATE 38400
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief USART1 driver enable switch.
|
||||||
|
* @details If set to @p TRUE the support for USART1 is included.
|
||||||
|
* @note The default is @p FALSE.
|
||||||
|
*/
|
||||||
|
#if !defined(USE_STM32_USART1) || defined(__DOXYGEN__)
|
||||||
|
#define USE_STM32_USART1 FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief USART2 driver enable switch.
|
||||||
|
* @details If set to @p TRUE the support for USART2 is included.
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
*/
|
||||||
|
#if !defined(USE_STM32_USART2) || defined(__DOXYGEN__)
|
||||||
|
#define USE_STM32_USART2 TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief USART3 driver enable switch.
|
||||||
|
* @details If set to @p TRUE the support for USART3 is included.
|
||||||
|
* @note The default is @p FALSE.
|
||||||
|
*/
|
||||||
|
#if !defined(USE_STM32_USART3) || defined(__DOXYGEN__)
|
||||||
|
#define USE_STM32_USART3 FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extra USARTs definitions here (missing from the ST header file).
|
||||||
|
*/
|
||||||
|
#define USART_CR2_STOP1_BITS (0 << 12) /**< @brief CR2 1 stop bit value.*/
|
||||||
|
#define USART_CR2_STOP0P5_BITS (1 << 12) /**< @brief CR2 0.5 stop bit value.*/
|
||||||
|
#define USART_CR2_STOP2_BITS (2 << 12) /**< @brief CR2 2 stop bit value.*/
|
||||||
|
#define USART_CR2_STOP1P5_BITS (3 << 12) /**< @brief CR2 1.5 stop bit value.*/
|
||||||
|
|
||||||
|
/** @cond never*/
|
||||||
|
#if USE_STM32_USART1
|
||||||
|
extern FullDuplexDriver COM1;
|
||||||
|
#endif
|
||||||
|
#if USE_STM32_USART2
|
||||||
|
extern FullDuplexDriver COM2;
|
||||||
|
#endif
|
||||||
|
#if USE_STM32_USART3
|
||||||
|
extern FullDuplexDriver COM3;
|
||||||
|
#endif
|
||||||
|
/** @endcond*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void serial_init(uint32_t prio1, uint32_t prio2, uint32_t prio3);
|
||||||
|
void usart_setup(USART_TypeDef *u, uint32_t speed, uint16_t cr1,
|
||||||
|
uint16_t cr2, uint16_t cr3);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _STM32_SERIAL_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,256 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.syntax unified
|
||||||
|
.thumb
|
||||||
|
|
||||||
|
.section vectors
|
||||||
|
_vectors:
|
||||||
|
.word __ram_end__
|
||||||
|
.word ResetHandler
|
||||||
|
.word NMIVector
|
||||||
|
.word HardFaultVector
|
||||||
|
.word MemManageVector
|
||||||
|
.word BusFaultVector
|
||||||
|
.word UsageFaultVector
|
||||||
|
.word Vector1C
|
||||||
|
.word Vector20
|
||||||
|
.word Vector24
|
||||||
|
.word Vector28
|
||||||
|
.word SVCallVector
|
||||||
|
.word DebugMonitorVector
|
||||||
|
.word Vector34
|
||||||
|
.word PendSVVector
|
||||||
|
.word SysTickVector
|
||||||
|
.word Vector40
|
||||||
|
.word Vector44
|
||||||
|
.word Vector48
|
||||||
|
.word Vector4C
|
||||||
|
.word Vector50
|
||||||
|
.word Vector54
|
||||||
|
.word Vector58
|
||||||
|
.word Vector5C
|
||||||
|
.word Vector60
|
||||||
|
.word Vector64
|
||||||
|
.word Vector68
|
||||||
|
.word Vector6C
|
||||||
|
.word Vector70
|
||||||
|
.word Vector74
|
||||||
|
.word Vector78
|
||||||
|
.word Vector7C
|
||||||
|
.word Vector80
|
||||||
|
.word Vector84
|
||||||
|
.word Vector88
|
||||||
|
.word Vector8C
|
||||||
|
.word Vector90
|
||||||
|
.word Vector94
|
||||||
|
.word Vector98
|
||||||
|
.word Vector9C
|
||||||
|
.word VectorA0
|
||||||
|
.word VectorA4
|
||||||
|
.word VectorA8
|
||||||
|
.word VectorAC
|
||||||
|
.word VectorB0
|
||||||
|
.word VectorB4
|
||||||
|
.word VectorB8
|
||||||
|
.word VectorBC
|
||||||
|
.word VectorC0
|
||||||
|
.word VectorC4
|
||||||
|
.word VectorC8
|
||||||
|
.word VectorCC
|
||||||
|
.word VectorD0
|
||||||
|
.word VectorD4
|
||||||
|
.word VectorD8
|
||||||
|
.word VectorDC
|
||||||
|
.word VectorE0
|
||||||
|
.word VectorE4
|
||||||
|
.word VectorE8
|
||||||
|
|
||||||
|
.weak NMIVector
|
||||||
|
NMIVector:
|
||||||
|
|
||||||
|
.weak HardFaultVector
|
||||||
|
HardFaultVector:
|
||||||
|
|
||||||
|
.weak MemManageVector
|
||||||
|
MemManageVector:
|
||||||
|
|
||||||
|
.weak BusFaultVector
|
||||||
|
BusFaultVector:
|
||||||
|
|
||||||
|
.weak UsageFaultVector
|
||||||
|
UsageFaultVector:
|
||||||
|
|
||||||
|
.weak Vector1C
|
||||||
|
Vector1C:
|
||||||
|
|
||||||
|
.weak Vector20
|
||||||
|
Vector20:
|
||||||
|
|
||||||
|
.weak Vector24
|
||||||
|
Vector24:
|
||||||
|
|
||||||
|
.weak Vector28
|
||||||
|
Vector28:
|
||||||
|
|
||||||
|
.weak SVCallVector
|
||||||
|
SVCallVector:
|
||||||
|
|
||||||
|
.weak DebugMonitorVector
|
||||||
|
DebugMonitorVector:
|
||||||
|
|
||||||
|
.weak Vector34
|
||||||
|
Vector34:
|
||||||
|
|
||||||
|
.weak PendSVVector
|
||||||
|
PendSVVector:
|
||||||
|
|
||||||
|
.weak SysTickVector
|
||||||
|
SysTickVector:
|
||||||
|
|
||||||
|
.weak Vector40
|
||||||
|
Vector40:
|
||||||
|
|
||||||
|
.weak Vector44
|
||||||
|
Vector44:
|
||||||
|
|
||||||
|
.weak Vector48
|
||||||
|
Vector48:
|
||||||
|
|
||||||
|
.weak Vector4C
|
||||||
|
Vector4C:
|
||||||
|
|
||||||
|
.weak Vector50
|
||||||
|
Vector50:
|
||||||
|
|
||||||
|
.weak Vector54
|
||||||
|
Vector54:
|
||||||
|
|
||||||
|
.weak Vector58
|
||||||
|
Vector58:
|
||||||
|
|
||||||
|
.weak Vector5C
|
||||||
|
Vector5C:
|
||||||
|
|
||||||
|
.weak Vector60
|
||||||
|
Vector60:
|
||||||
|
|
||||||
|
.weak Vector64
|
||||||
|
Vector64:
|
||||||
|
|
||||||
|
.weak Vector68
|
||||||
|
Vector68:
|
||||||
|
|
||||||
|
.weak Vector6C
|
||||||
|
Vector6C:
|
||||||
|
|
||||||
|
.weak Vector70
|
||||||
|
Vector70:
|
||||||
|
|
||||||
|
.weak Vector74
|
||||||
|
Vector74:
|
||||||
|
|
||||||
|
.weak Vector78
|
||||||
|
Vector78:
|
||||||
|
|
||||||
|
.weak Vector7C
|
||||||
|
Vector7C:
|
||||||
|
|
||||||
|
.weak Vector80
|
||||||
|
Vector80:
|
||||||
|
|
||||||
|
.weak Vector84
|
||||||
|
Vector84:
|
||||||
|
|
||||||
|
.weak Vector88
|
||||||
|
Vector88:
|
||||||
|
|
||||||
|
.weak Vector8C
|
||||||
|
Vector8C:
|
||||||
|
|
||||||
|
.weak Vector90
|
||||||
|
Vector90:
|
||||||
|
|
||||||
|
.weak Vector94
|
||||||
|
Vector94:
|
||||||
|
|
||||||
|
.weak Vector98
|
||||||
|
Vector98:
|
||||||
|
|
||||||
|
.weak Vector9C
|
||||||
|
Vector9C:
|
||||||
|
|
||||||
|
.weak VectorA0
|
||||||
|
VectorA0:
|
||||||
|
|
||||||
|
.weak VectorA4
|
||||||
|
VectorA4:
|
||||||
|
|
||||||
|
.weak VectorA8
|
||||||
|
VectorA8:
|
||||||
|
|
||||||
|
.weak VectorAC
|
||||||
|
VectorAC:
|
||||||
|
|
||||||
|
.weak VectorB0
|
||||||
|
VectorB0:
|
||||||
|
|
||||||
|
.weak VectorB4
|
||||||
|
VectorB4:
|
||||||
|
|
||||||
|
.weak VectorB8
|
||||||
|
VectorB8:
|
||||||
|
|
||||||
|
.weak VectorBC
|
||||||
|
VectorBC:
|
||||||
|
|
||||||
|
.weak VectorC0
|
||||||
|
VectorC0:
|
||||||
|
|
||||||
|
.weak VectorC4
|
||||||
|
VectorC4:
|
||||||
|
|
||||||
|
.weak VectorC8
|
||||||
|
VectorC8:
|
||||||
|
|
||||||
|
.weak VectorCC
|
||||||
|
VectorCC:
|
||||||
|
|
||||||
|
.weak VectorD0
|
||||||
|
VectorD0:
|
||||||
|
|
||||||
|
.weak VectorD4
|
||||||
|
VectorD4:
|
||||||
|
|
||||||
|
.weak VectorD8
|
||||||
|
VectorD8:
|
||||||
|
|
||||||
|
.weak VectorDC
|
||||||
|
VectorDC:
|
||||||
|
|
||||||
|
.weak VectorE0
|
||||||
|
VectorE0:
|
||||||
|
|
||||||
|
.weak VectorE4
|
||||||
|
VectorE4:
|
||||||
|
|
||||||
|
.weak VectorE8
|
||||||
|
VectorE8:
|
||||||
|
|
||||||
|
here: b here
|
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARMCM3/chcore.c
|
||||||
|
* @brief ARM Cortex-M3 architecture port code.
|
||||||
|
* @addtogroup ARMCM3_CORE
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
#include <nvic.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Halts the system.
|
||||||
|
* @note The function is declared as a weak symbol, it is possible to redefine
|
||||||
|
* it in your application code.
|
||||||
|
*/
|
||||||
|
/** @cond never */
|
||||||
|
__attribute__((weak))
|
||||||
|
/** @endcond */
|
||||||
|
void port_halt(void) {
|
||||||
|
|
||||||
|
port_disable();
|
||||||
|
while (TRUE) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !CH_OPTIMIZE_SPEED
|
||||||
|
void _port_lock(void) {
|
||||||
|
register uint32_t tmp asm ("r3") = BASEPRI_KERNEL;
|
||||||
|
asm volatile ("msr BASEPRI, %0" : : "r" (tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _port_unlock(void) {
|
||||||
|
register uint32_t tmp asm ("r3") = BASEPRI_USER;
|
||||||
|
asm volatile ("msr BASEPRI, %0" : : "r" (tmp));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* System Timer vector.
|
||||||
|
* This interrupt is used as system tick.
|
||||||
|
* @note The timer is initialized in the board setup code.
|
||||||
|
*/
|
||||||
|
CH_IRQ_HANDLER(SysTickVector) {
|
||||||
|
|
||||||
|
CH_IRQ_PROLOGUE();
|
||||||
|
|
||||||
|
chSysLockFromIsr();
|
||||||
|
chSysTimerHandlerI();
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
|
||||||
|
CH_IRQ_EPILOGUE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SVC vector is used for commanded context switch.
|
||||||
|
* @param otp the thread to be switched out
|
||||||
|
* @param ntp the thread to be switched it
|
||||||
|
*/
|
||||||
|
/** @cond never */
|
||||||
|
__attribute__((naked))
|
||||||
|
/** @endcond */
|
||||||
|
void SVCallVector(Thread *otp, Thread *ntp) {
|
||||||
|
/* { r0 = otp, r1 = ntp } */
|
||||||
|
/* get the BASEPRI in r3 */
|
||||||
|
/* get the PSP in r12 */
|
||||||
|
/* push the registers on the PSP stack */
|
||||||
|
/* stores the modified PSP into the thread context */
|
||||||
|
/* fetches the PSP position from the new thread context */
|
||||||
|
/* pop the registers from the PSP stack */
|
||||||
|
/* set the PSP from r12 */
|
||||||
|
/* set the BASEPRI from R3 */
|
||||||
|
#ifdef CH_CURRP_REGISTER_CACHE
|
||||||
|
asm volatile ("mrs r3, BASEPRI \n\t" \
|
||||||
|
"mrs r12, PSP \n\t" \
|
||||||
|
"stmdb r12!, {r3-r6,r8-r11, lr} \n\t" \
|
||||||
|
"str r12, [r0, #16] \n\t" \
|
||||||
|
"ldr r12, [r1, #16] \n\t" \
|
||||||
|
"ldmia r12!, {r3-r6,r8-r11, lr} \n\t" \
|
||||||
|
"msr PSP, r12 \n\t" \
|
||||||
|
"msr BASEPRI, r3 \n\t" \
|
||||||
|
"bx lr ");
|
||||||
|
#else
|
||||||
|
asm volatile ("mrs r3, BASEPRI \n\t" \
|
||||||
|
"mrs r12, PSP \n\t" \
|
||||||
|
"stmdb r12!, {r3-r11, lr} \n\t" \
|
||||||
|
"str r12, [r0, #16] \n\t" \
|
||||||
|
"ldr r12, [r1, #16] \n\t" \
|
||||||
|
"ldmia r12!, {r3-r11, lr} \n\t" \
|
||||||
|
"msr PSP, r12 \n\t" \
|
||||||
|
"msr BASEPRI, r3 \n\t" \
|
||||||
|
"bx lr ");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CH_CURRP_REGISTER_CACHE
|
||||||
|
#define PUSH_CONTEXT(sp) { \
|
||||||
|
register uint32_t tmp asm ("r3") = BASEPRI_USER; \
|
||||||
|
asm volatile ("mrs %0, PSP \n\t" \
|
||||||
|
"stmdb %0!, {r3-r6,r8-r11, lr}" : \
|
||||||
|
"=r" (sp) : "r" (sp), "r" (tmp)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define POP_CONTEXT(sp) { \
|
||||||
|
asm volatile ("ldmia %0!, {r3-r6,r8-r11, lr} \n\t" \
|
||||||
|
"msr PSP, %0 \n\t" \
|
||||||
|
"msr BASEPRI, r3 \n\t" \
|
||||||
|
"bx lr" : "=r" (sp) : "r" (sp)); \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define PUSH_CONTEXT(sp) { \
|
||||||
|
register uint32_t tmp asm ("r3") = BASEPRI_USER; \
|
||||||
|
asm volatile ("mrs %0, PSP \n\t" \
|
||||||
|
"stmdb %0!, {r3-r11,lr}" : \
|
||||||
|
"=r" (sp) : "r" (sp), "r" (tmp)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define POP_CONTEXT(sp) { \
|
||||||
|
asm volatile ("ldmia %0!, {r3-r11, lr} \n\t" \
|
||||||
|
"msr PSP, %0 \n\t" \
|
||||||
|
"msr BASEPRI, r3 \n\t" \
|
||||||
|
"bx lr" : "=r" (sp) : "r" (sp)); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preemption invoked context switch.
|
||||||
|
*/
|
||||||
|
/** @cond never */
|
||||||
|
__attribute__((naked))
|
||||||
|
/** @endcond */
|
||||||
|
void PendSVVector(void) {
|
||||||
|
Thread *otp;
|
||||||
|
register struct intctx *sp_thd asm("r12");
|
||||||
|
|
||||||
|
chSysLockFromIsr();
|
||||||
|
asm volatile ("push {lr}");
|
||||||
|
if (!chSchRescRequiredI()) {
|
||||||
|
chSysUnlockFromIsr();
|
||||||
|
asm volatile ("pop {pc}");
|
||||||
|
}
|
||||||
|
asm volatile ("pop {lr}");
|
||||||
|
|
||||||
|
PUSH_CONTEXT(sp_thd);
|
||||||
|
|
||||||
|
(otp = currp)->p_ctx.r13 = sp_thd;
|
||||||
|
(currp = fifo_remove((void *)&rlist))->p_state = PRCURR;
|
||||||
|
chSchReadyI(otp);
|
||||||
|
#if CH_USE_ROUNDROBIN
|
||||||
|
/* set the round-robin time quantum */
|
||||||
|
rlist.r_preempt = CH_TIME_QUANTUM;
|
||||||
|
#endif
|
||||||
|
chDbgTrace(otp, currp);
|
||||||
|
sp_thd = currp->p_ctx.r13;
|
||||||
|
|
||||||
|
POP_CONTEXT(sp_thd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,333 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARMCM3/chcore.h
|
||||||
|
* @brief ARM Cortex-M3 architecture port macros and structures.
|
||||||
|
* @addtogroup ARMCM3_CORE
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CHCORE_H_
|
||||||
|
#define _CHCORE_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Port-related configuration parameters.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables the use of the WFI ins.
|
||||||
|
*/
|
||||||
|
#ifndef ENABLE_WFI_IDLE
|
||||||
|
#define ENABLE_WFI_IDLE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BASEPRI user level, 0 = disabled.
|
||||||
|
*/
|
||||||
|
#ifndef BASEPRI_USER
|
||||||
|
#define BASEPRI_USER 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BASEPRI level within kernel lock.
|
||||||
|
* Priority levels higher than this one (lower values) are unaffected by
|
||||||
|
* the OS activity and can be classified as fast interrupt sources, see
|
||||||
|
* @ref interrupt_classes.
|
||||||
|
*/
|
||||||
|
#ifndef BASEPRI_KERNEL
|
||||||
|
#define BASEPRI_KERNEL 0x40
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SVCALL handler priority.
|
||||||
|
* @note This priority must always be one level above the @p BASEPRI_KERNEL
|
||||||
|
* value.
|
||||||
|
* @note It is recommended to leave this priority level for this handler alone.
|
||||||
|
*/
|
||||||
|
#ifndef PRIORITY_SVCALL
|
||||||
|
#define PRIORITY_SVCALL (BASEPRI_KERNEL - 0x10)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SYSTICK handler priority.
|
||||||
|
*/
|
||||||
|
#ifndef PRIORITY_SYSTICK
|
||||||
|
#define PRIORITY_SYSTICK 0x80
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PENDSV handler priority.
|
||||||
|
* @note It is recommended to leave this priority level for this handler alone.
|
||||||
|
* @note This is a reserved handler and its priority must always be the
|
||||||
|
* lowest priority in the system in order to be always executed last
|
||||||
|
* in the interrupt servicing chain.
|
||||||
|
*/
|
||||||
|
#ifndef PRIORITY_PENDSV
|
||||||
|
#define PRIORITY_PENDSV 0xF0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Macro defining the ARM Cortex-M3 architecture.
|
||||||
|
*/
|
||||||
|
#define CH_ARCHITECTURE_ARMCM3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the implemented architecture.
|
||||||
|
*/
|
||||||
|
#define CH_ARCHITECTURE_NAME "ARM Cortex-M3"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 32 bit stack alignment.
|
||||||
|
*/
|
||||||
|
typedef uint32_t stkalign_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic ARM register.
|
||||||
|
*/
|
||||||
|
typedef void *regarm_t;
|
||||||
|
|
||||||
|
/** @cond never */
|
||||||
|
/**
|
||||||
|
* Interrupt saved context, empty in this architecture.
|
||||||
|
*/
|
||||||
|
struct extctx {
|
||||||
|
};
|
||||||
|
/** @endcond */
|
||||||
|
|
||||||
|
/** @cond never */
|
||||||
|
/**
|
||||||
|
* This structure represents the inner stack frame during a context switching.
|
||||||
|
*/
|
||||||
|
struct intctx {
|
||||||
|
regarm_t basepri;
|
||||||
|
regarm_t r4;
|
||||||
|
regarm_t r5;
|
||||||
|
regarm_t r6;
|
||||||
|
#ifndef CH_CURRP_REGISTER_CACHE
|
||||||
|
regarm_t r7;
|
||||||
|
#endif
|
||||||
|
regarm_t r8;
|
||||||
|
regarm_t r9;
|
||||||
|
regarm_t r10;
|
||||||
|
regarm_t r11;
|
||||||
|
regarm_t lr_exc;
|
||||||
|
regarm_t r0;
|
||||||
|
regarm_t r1;
|
||||||
|
regarm_t r2;
|
||||||
|
regarm_t r3;
|
||||||
|
regarm_t r12;
|
||||||
|
regarm_t lr_thd;
|
||||||
|
regarm_t pc;
|
||||||
|
regarm_t xpsr;
|
||||||
|
};
|
||||||
|
/** @endcond */
|
||||||
|
|
||||||
|
/** @cond never */
|
||||||
|
/**
|
||||||
|
* Cortex-M3 context structure.
|
||||||
|
*/
|
||||||
|
struct context {
|
||||||
|
struct intctx *r13;
|
||||||
|
};
|
||||||
|
/** @endcond */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Platform dependent part of the @p chThdInit() API.
|
||||||
|
* This code usually setup the context switching frame represented by a
|
||||||
|
* @p intctx structure.
|
||||||
|
*/
|
||||||
|
#define SETUP_CONTEXT(workspace, wsize, pf, arg) { \
|
||||||
|
tp->p_ctx.r13 = (struct intctx *)((uint8_t *)workspace + \
|
||||||
|
wsize - \
|
||||||
|
sizeof(struct intctx)); \
|
||||||
|
tp->p_ctx.r13->basepri = BASEPRI_USER; \
|
||||||
|
tp->p_ctx.r13->lr_exc = (regarm_t)0xFFFFFFFD; \
|
||||||
|
tp->p_ctx.r13->r0 = arg; \
|
||||||
|
tp->p_ctx.r13->lr_thd = chThdExit; \
|
||||||
|
tp->p_ctx.r13->pc = pf; \
|
||||||
|
tp->p_ctx.r13->xpsr = (regarm_t)0x01000000; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default idle thread implementation requires no extra stack space in
|
||||||
|
* this port.
|
||||||
|
*/
|
||||||
|
#ifndef IDLE_THREAD_STACK_SIZE
|
||||||
|
#define IDLE_THREAD_STACK_SIZE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This port requires no extra stack space for interrupt handling.
|
||||||
|
*/
|
||||||
|
#ifndef INT_REQUIRED_STACK
|
||||||
|
#define INT_REQUIRED_STACK 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enforces a correct alignment for a stack area size value.
|
||||||
|
*/
|
||||||
|
#define STACK_ALIGN(n) ((((n) - 1) | (sizeof(stkalign_t) - 1)) + 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the thread working area global size.
|
||||||
|
*/
|
||||||
|
#define THD_WA_SIZE(n) STACK_ALIGN(sizeof(Thread) + \
|
||||||
|
sizeof(struct intctx) + \
|
||||||
|
sizeof(struct extctx) + \
|
||||||
|
(n) + (INT_REQUIRED_STACK))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Macro used to allocate a thread working area aligned as both position and
|
||||||
|
* size.
|
||||||
|
*/
|
||||||
|
#define WORKING_AREA(s, n) stkalign_t s[THD_WA_SIZE(n) / sizeof(stkalign_t)];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IRQ prologue code, inserted at the start of all IRQ handlers enabled to
|
||||||
|
* invoke system APIs.
|
||||||
|
*/
|
||||||
|
#define PORT_IRQ_PROLOGUE()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IRQ epilogue code, inserted at the end of all IRQ handlers enabled to
|
||||||
|
* invoke system APIs.
|
||||||
|
*/
|
||||||
|
#define PORT_IRQ_EPILOGUE() { \
|
||||||
|
SCB_ICSR = ICSR_PENDSVSET; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IRQ handler function declaration.
|
||||||
|
*/
|
||||||
|
#define PORT_IRQ_HANDLER(id) void id(void)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is empty in this port.
|
||||||
|
*/
|
||||||
|
#define port_init()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raises the base priority to kernel level.
|
||||||
|
*/
|
||||||
|
#if CH_OPTIMIZE_SPEED
|
||||||
|
#define port_lock() { \
|
||||||
|
register uint32_t tmp asm ("r3") = BASEPRI_KERNEL; \
|
||||||
|
asm volatile ("msr BASEPRI, %0" : : "r" (tmp)); \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define port_lock() { \
|
||||||
|
asm volatile ("bl _port_lock" : : : "r3", "lr"); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lowers the base priority to user level.
|
||||||
|
*/
|
||||||
|
#if CH_OPTIMIZE_SPEED
|
||||||
|
#define port_unlock() { \
|
||||||
|
register uint32_t tmp asm ("r3") = BASEPRI_USER; \
|
||||||
|
asm volatile ("msr BASEPRI, %0" : : "r" (tmp)); \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define port_unlock() { \
|
||||||
|
asm volatile ("bl _port_unlock" : : : "r3", "lr"); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as @p port_lock() in this port.
|
||||||
|
*/
|
||||||
|
#define port_lock_from_isr() port_lock()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as @p port_unlock() in this port.
|
||||||
|
*/
|
||||||
|
#define port_unlock_from_isr() port_unlock()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables all the interrupt sources by raising the priority mask to level 0.
|
||||||
|
*/
|
||||||
|
#define port_disable() asm volatile ("cpsid i")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raises/lowers the base priority to kernel level.
|
||||||
|
*/
|
||||||
|
#define port_suspend() { \
|
||||||
|
register uint32_t tmp asm ("r3") = BASEPRI_KERNEL; \
|
||||||
|
asm volatile ("msr BASEPRI, %0 \n\t" \
|
||||||
|
"cpsie i" : : "r" (tmp)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lowers the base priority to user level.
|
||||||
|
*/
|
||||||
|
#define port_enable() { \
|
||||||
|
register uint32_t tmp asm ("r3") = BASEPRI_USER; \
|
||||||
|
asm volatile ("msr BASEPRI, %0 \n\t" \
|
||||||
|
"cpsie i" : : "r" (tmp)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This port function is implemented as inlined code for performance reasons.
|
||||||
|
*/
|
||||||
|
#if ENABLE_WFI_IDLE || defined(__DOXYGEN__)
|
||||||
|
#define port_wait_for_interrupt() { \
|
||||||
|
asm volatile ("wfi"); \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define port_wait_for_interrupt()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This port function is implemented as inlined code for performance reasons.
|
||||||
|
*/
|
||||||
|
#if CH_DBG_ENABLE_STACK_CHECK
|
||||||
|
#define port_switch(otp, ntp) { \
|
||||||
|
register Thread *_otp asm ("r0") = (otp); \
|
||||||
|
register Thread *_ntp asm ("r1") = (ntp); \
|
||||||
|
register char *sp asm ("sp"); \
|
||||||
|
if (sp - sizeof(struct intctx) - sizeof(Thread) < (char *)_otp) \
|
||||||
|
asm volatile ("movs r0, #0 \n\t" \
|
||||||
|
"b chDbgPanic"); \
|
||||||
|
asm volatile ("svc #0" : : "r" (_otp), "r" (_ntp)); \
|
||||||
|
}
|
||||||
|
#else /* !CH_DBG_ENABLE_STACK_CHECK */
|
||||||
|
#define port_switch(otp, ntp) { \
|
||||||
|
register Thread *_otp asm ("r0") = (otp); \
|
||||||
|
register Thread *_ntp asm ("r1") = (ntp); \
|
||||||
|
asm volatile ("svc #0" : : "r" (_otp), "r" (_ntp)); \
|
||||||
|
}
|
||||||
|
#endif /* !CH_DBG_ENABLE_STACK_CHECK */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void port_halt(void);
|
||||||
|
#if !CH_OPTIMIZE_SPEED
|
||||||
|
void _port_lock(void);
|
||||||
|
void _port_unlock(void);
|
||||||
|
#endif
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _CHCORE_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARMCM3/chtypes.h
|
||||||
|
* @brief ARM Cortex-M3 architecture port system types.
|
||||||
|
* @addtogroup ARMCM3_CORE
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CHTYPES_H_
|
||||||
|
#define _CHTYPES_H_
|
||||||
|
|
||||||
|
#define __need_NULL
|
||||||
|
#define __need_size_t
|
||||||
|
#define __need_ptrdiff_t
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#if !defined(_STDINT_H) && !defined(__STDINT_H_)
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef int32_t bool_t; /**< Fast boolean type. */
|
||||||
|
typedef uint8_t tmode_t; /**< Thread flags. */
|
||||||
|
typedef uint8_t tstate_t; /**< Thread state. */
|
||||||
|
typedef uint32_t tprio_t; /**< Thread priority. */
|
||||||
|
typedef int32_t msg_t; /**< Inter-thread message. */
|
||||||
|
typedef int32_t eventid_t; /**< Event Id. */
|
||||||
|
typedef uint32_t eventmask_t; /**< Events mask. */
|
||||||
|
typedef uint32_t systime_t; /**< System time. */
|
||||||
|
typedef int32_t cnt_t; /**< Resources counter. */
|
||||||
|
|
||||||
|
#define INLINE inline
|
||||||
|
#define PACK_STRUCT_STRUCT __attribute__((packed))
|
||||||
|
#define PACK_STRUCT_BEGIN
|
||||||
|
#define PACK_STRUCT_END
|
||||||
|
|
||||||
|
#endif /* _CHTYPES_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,829 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file: core_cm3.c
|
||||||
|
* @purpose: CMSIS Cortex-M3 Core Peripheral Access Layer Source File
|
||||||
|
* @version: V1.20
|
||||||
|
* @date: 22. May 2009
|
||||||
|
*----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 ARM Limited. All rights reserved.
|
||||||
|
*
|
||||||
|
* ARM Limited (ARM) is supplying this software for use with Cortex-Mx
|
||||||
|
* processor based microcontrollers. This file can be freely distributed
|
||||||
|
* within development tools that are supporting such ARM based processors.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||||
|
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||||
|
* ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* define compiler specific symbols */
|
||||||
|
#if defined ( __CC_ARM )
|
||||||
|
#define __ASM __asm /*!< asm keyword for armcc */
|
||||||
|
#define __INLINE __inline /*!< inline keyword for armcc */
|
||||||
|
|
||||||
|
#elif defined ( __ICCARM__ )
|
||||||
|
#define __ASM __asm /*!< asm keyword for iarcc */
|
||||||
|
#define __INLINE inline /*!< inline keyword for iarcc. Only avaiable in High optimization mode! */
|
||||||
|
|
||||||
|
#elif defined ( __GNUC__ )
|
||||||
|
#define __ASM __asm /*!< asm keyword for gcc */
|
||||||
|
#define __INLINE inline /*!< inline keyword for gcc */
|
||||||
|
|
||||||
|
#elif defined ( __TASKING__ )
|
||||||
|
#define __ASM __asm /*!< asm keyword for TASKING Compiler */
|
||||||
|
#define __INLINE inline /*!< inline keyword for TASKING Compiler */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined ( __CC_ARM ) /*------------------RealView Compiler -----------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the Process Stack Pointer
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
* @return uint32_t ProcessStackPointer
|
||||||
|
*
|
||||||
|
* Return the actual process stack pointer
|
||||||
|
*/
|
||||||
|
__ASM uint32_t __get_PSP(void)
|
||||||
|
{
|
||||||
|
mrs r0, psp
|
||||||
|
bx lr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Process Stack Pointer
|
||||||
|
*
|
||||||
|
* @param uint32_t Process Stack Pointer
|
||||||
|
* @return none
|
||||||
|
*
|
||||||
|
* Assign the value ProcessStackPointer to the MSP
|
||||||
|
* (process stack pointer) Cortex processor register
|
||||||
|
*/
|
||||||
|
__ASM void __set_PSP(uint32_t topOfProcStack)
|
||||||
|
{
|
||||||
|
msr psp, r0
|
||||||
|
bx lr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the Main Stack Pointer
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
* @return uint32_t Main Stack Pointer
|
||||||
|
*
|
||||||
|
* Return the current value of the MSP (main stack pointer)
|
||||||
|
* Cortex processor register
|
||||||
|
*/
|
||||||
|
__ASM uint32_t __get_MSP(void)
|
||||||
|
{
|
||||||
|
mrs r0, msp
|
||||||
|
bx lr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Main Stack Pointer
|
||||||
|
*
|
||||||
|
* @param uint32_t Main Stack Pointer
|
||||||
|
* @return none
|
||||||
|
*
|
||||||
|
* Assign the value mainStackPointer to the MSP
|
||||||
|
* (main stack pointer) Cortex processor register
|
||||||
|
*/
|
||||||
|
__ASM void __set_MSP(uint32_t mainStackPointer)
|
||||||
|
{
|
||||||
|
msr msp, r0
|
||||||
|
bx lr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reverse byte order in unsigned short value
|
||||||
|
*
|
||||||
|
* @param uint16_t value to reverse
|
||||||
|
* @return uint32_t reversed value
|
||||||
|
*
|
||||||
|
* Reverse byte order in unsigned short value
|
||||||
|
*/
|
||||||
|
__ASM uint32_t __REV16(uint16_t value)
|
||||||
|
{
|
||||||
|
rev16 r0, r0
|
||||||
|
bx lr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reverse byte order in signed short value with sign extension to integer
|
||||||
|
*
|
||||||
|
* @param int16_t value to reverse
|
||||||
|
* @return int32_t reversed value
|
||||||
|
*
|
||||||
|
* Reverse byte order in signed short value with sign extension to integer
|
||||||
|
*/
|
||||||
|
__ASM int32_t __REVSH(int16_t value)
|
||||||
|
{
|
||||||
|
revsh r0, r0
|
||||||
|
bx lr
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if (__ARMCC_VERSION < 400000)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Remove the exclusive lock created by ldrex
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
* @return none
|
||||||
|
*
|
||||||
|
* Removes the exclusive lock which is created by ldrex.
|
||||||
|
*/
|
||||||
|
__ASM void __CLREX(void)
|
||||||
|
{
|
||||||
|
clrex
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the Base Priority value
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
* @return uint32_t BasePriority
|
||||||
|
*
|
||||||
|
* Return the content of the base priority register
|
||||||
|
*/
|
||||||
|
__ASM uint32_t __get_BASEPRI(void)
|
||||||
|
{
|
||||||
|
mrs r0, basepri
|
||||||
|
bx lr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Base Priority value
|
||||||
|
*
|
||||||
|
* @param uint32_t BasePriority
|
||||||
|
* @return none
|
||||||
|
*
|
||||||
|
* Set the base priority register
|
||||||
|
*/
|
||||||
|
__ASM void __set_BASEPRI(uint32_t basePri)
|
||||||
|
{
|
||||||
|
msr basepri, r0
|
||||||
|
bx lr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the Priority Mask value
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
* @return uint32_t PriMask
|
||||||
|
*
|
||||||
|
* Return the state of the priority mask bit from the priority mask
|
||||||
|
* register
|
||||||
|
*/
|
||||||
|
__ASM uint32_t __get_PRIMASK(void)
|
||||||
|
{
|
||||||
|
mrs r0, primask
|
||||||
|
bx lr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Priority Mask value
|
||||||
|
*
|
||||||
|
* @param uint32_t PriMask
|
||||||
|
* @return none
|
||||||
|
*
|
||||||
|
* Set the priority mask bit in the priority mask register
|
||||||
|
*/
|
||||||
|
__ASM void __set_PRIMASK(uint32_t priMask)
|
||||||
|
{
|
||||||
|
msr primask, r0
|
||||||
|
bx lr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the Fault Mask value
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
* @return uint32_t FaultMask
|
||||||
|
*
|
||||||
|
* Return the content of the fault mask register
|
||||||
|
*/
|
||||||
|
__ASM uint32_t __get_FAULTMASK(void)
|
||||||
|
{
|
||||||
|
mrs r0, faultmask
|
||||||
|
bx lr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Fault Mask value
|
||||||
|
*
|
||||||
|
* @param uint32_t faultMask value
|
||||||
|
* @return none
|
||||||
|
*
|
||||||
|
* Set the fault mask register
|
||||||
|
*/
|
||||||
|
__ASM void __set_FAULTMASK(uint32_t faultMask)
|
||||||
|
{
|
||||||
|
msr faultmask, r0
|
||||||
|
bx lr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the Control Register value
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
* @return uint32_t Control value
|
||||||
|
*
|
||||||
|
* Return the content of the control register
|
||||||
|
*/
|
||||||
|
__ASM uint32_t __get_CONTROL(void)
|
||||||
|
{
|
||||||
|
mrs r0, control
|
||||||
|
bx lr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Control Register value
|
||||||
|
*
|
||||||
|
* @param uint32_t Control value
|
||||||
|
* @return none
|
||||||
|
*
|
||||||
|
* Set the control register
|
||||||
|
*/
|
||||||
|
__ASM void __set_CONTROL(uint32_t control)
|
||||||
|
{
|
||||||
|
msr control, r0
|
||||||
|
bx lr
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __ARMCC_VERSION */
|
||||||
|
|
||||||
|
|
||||||
|
#elif (defined (__ICCARM__)) /*------------------ ICC Compiler -------------------*/
|
||||||
|
#pragma diag_suppress=Pe940
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the Process Stack Pointer
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
* @return uint32_t ProcessStackPointer
|
||||||
|
*
|
||||||
|
* Return the actual process stack pointer
|
||||||
|
*/
|
||||||
|
uint32_t __get_PSP(void)
|
||||||
|
{
|
||||||
|
__ASM("mrs r0, psp");
|
||||||
|
__ASM("bx lr");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Process Stack Pointer
|
||||||
|
*
|
||||||
|
* @param uint32_t Process Stack Pointer
|
||||||
|
* @return none
|
||||||
|
*
|
||||||
|
* Assign the value ProcessStackPointer to the MSP
|
||||||
|
* (process stack pointer) Cortex processor register
|
||||||
|
*/
|
||||||
|
void __set_PSP(uint32_t topOfProcStack)
|
||||||
|
{
|
||||||
|
__ASM("msr psp, r0");
|
||||||
|
__ASM("bx lr");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the Main Stack Pointer
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
* @return uint32_t Main Stack Pointer
|
||||||
|
*
|
||||||
|
* Return the current value of the MSP (main stack pointer)
|
||||||
|
* Cortex processor register
|
||||||
|
*/
|
||||||
|
uint32_t __get_MSP(void)
|
||||||
|
{
|
||||||
|
__ASM("mrs r0, msp");
|
||||||
|
__ASM("bx lr");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Main Stack Pointer
|
||||||
|
*
|
||||||
|
* @param uint32_t Main Stack Pointer
|
||||||
|
* @return none
|
||||||
|
*
|
||||||
|
* Assign the value mainStackPointer to the MSP
|
||||||
|
* (main stack pointer) Cortex processor register
|
||||||
|
*/
|
||||||
|
void __set_MSP(uint32_t topOfMainStack)
|
||||||
|
{
|
||||||
|
__ASM("msr msp, r0");
|
||||||
|
__ASM("bx lr");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reverse byte order in unsigned short value
|
||||||
|
*
|
||||||
|
* @param uint16_t value to reverse
|
||||||
|
* @return uint32_t reversed value
|
||||||
|
*
|
||||||
|
* Reverse byte order in unsigned short value
|
||||||
|
*/
|
||||||
|
uint32_t __REV16(uint16_t value)
|
||||||
|
{
|
||||||
|
__ASM("rev16 r0, r0");
|
||||||
|
__ASM("bx lr");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reverse bit order of value
|
||||||
|
*
|
||||||
|
* @param uint32_t value to reverse
|
||||||
|
* @return uint32_t reversed value
|
||||||
|
*
|
||||||
|
* Reverse bit order of value
|
||||||
|
*/
|
||||||
|
uint32_t __RBIT(uint32_t value)
|
||||||
|
{
|
||||||
|
__ASM("rbit r0, r0");
|
||||||
|
__ASM("bx lr");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief LDR Exclusive
|
||||||
|
*
|
||||||
|
* @param uint8_t* address
|
||||||
|
* @return uint8_t value of (*address)
|
||||||
|
*
|
||||||
|
* Exclusive LDR command
|
||||||
|
*/
|
||||||
|
uint8_t __LDREXB(uint8_t *addr)
|
||||||
|
{
|
||||||
|
__ASM("ldrexb r0, [r0]");
|
||||||
|
__ASM("bx lr");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief LDR Exclusive
|
||||||
|
*
|
||||||
|
* @param uint16_t* address
|
||||||
|
* @return uint16_t value of (*address)
|
||||||
|
*
|
||||||
|
* Exclusive LDR command
|
||||||
|
*/
|
||||||
|
uint16_t __LDREXH(uint16_t *addr)
|
||||||
|
{
|
||||||
|
__ASM("ldrexh r0, [r0]");
|
||||||
|
__ASM("bx lr");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief LDR Exclusive
|
||||||
|
*
|
||||||
|
* @param uint32_t* address
|
||||||
|
* @return uint32_t value of (*address)
|
||||||
|
*
|
||||||
|
* Exclusive LDR command
|
||||||
|
*/
|
||||||
|
uint32_t __LDREXW(uint32_t *addr)
|
||||||
|
{
|
||||||
|
__ASM("ldrex r0, [r0]");
|
||||||
|
__ASM("bx lr");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief STR Exclusive
|
||||||
|
*
|
||||||
|
* @param uint8_t *address
|
||||||
|
* @param uint8_t value to store
|
||||||
|
* @return uint32_t successful / failed
|
||||||
|
*
|
||||||
|
* Exclusive STR command
|
||||||
|
*/
|
||||||
|
uint32_t __STREXB(uint8_t value, uint8_t *addr)
|
||||||
|
{
|
||||||
|
__ASM("strexb r0, r0, [r1]");
|
||||||
|
__ASM("bx lr");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief STR Exclusive
|
||||||
|
*
|
||||||
|
* @param uint16_t *address
|
||||||
|
* @param uint16_t value to store
|
||||||
|
* @return uint32_t successful / failed
|
||||||
|
*
|
||||||
|
* Exclusive STR command
|
||||||
|
*/
|
||||||
|
uint32_t __STREXH(uint16_t value, uint16_t *addr)
|
||||||
|
{
|
||||||
|
__ASM("strexh r0, r0, [r1]");
|
||||||
|
__ASM("bx lr");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief STR Exclusive
|
||||||
|
*
|
||||||
|
* @param uint32_t *address
|
||||||
|
* @param uint32_t value to store
|
||||||
|
* @return uint32_t successful / failed
|
||||||
|
*
|
||||||
|
* Exclusive STR command
|
||||||
|
*/
|
||||||
|
uint32_t __STREXW(uint32_t value, uint32_t *addr)
|
||||||
|
{
|
||||||
|
__ASM("strex r0, r0, [r1]");
|
||||||
|
__ASM("bx lr");
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma diag_default=Pe940
|
||||||
|
|
||||||
|
|
||||||
|
#elif (defined (__GNUC__)) /*------------------ GNU Compiler ---------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the Process Stack Pointer
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
* @return uint32_t ProcessStackPointer
|
||||||
|
*
|
||||||
|
* Return the actual process stack pointer
|
||||||
|
*/
|
||||||
|
uint32_t __get_PSP(void) __attribute__( ( naked ) );
|
||||||
|
uint32_t __get_PSP(void)
|
||||||
|
{
|
||||||
|
uint32_t result=0;
|
||||||
|
|
||||||
|
__ASM volatile ("MRS %0, psp\n\t"
|
||||||
|
"MOV r0, %0 \n\t"
|
||||||
|
"BX lr \n\t" : "=r" (result) );
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Process Stack Pointer
|
||||||
|
*
|
||||||
|
* @param uint32_t Process Stack Pointer
|
||||||
|
* @return none
|
||||||
|
*
|
||||||
|
* Assign the value ProcessStackPointer to the MSP
|
||||||
|
* (process stack pointer) Cortex processor register
|
||||||
|
*/
|
||||||
|
void __set_PSP(uint32_t topOfProcStack) __attribute__( ( naked ) );
|
||||||
|
void __set_PSP(uint32_t topOfProcStack)
|
||||||
|
{
|
||||||
|
__ASM volatile ("MSR psp, %0\n\t"
|
||||||
|
"BX lr \n\t" : : "r" (topOfProcStack) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the Main Stack Pointer
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
* @return uint32_t Main Stack Pointer
|
||||||
|
*
|
||||||
|
* Return the current value of the MSP (main stack pointer)
|
||||||
|
* Cortex processor register
|
||||||
|
*/
|
||||||
|
uint32_t __get_MSP(void) __attribute__( ( naked ) );
|
||||||
|
uint32_t __get_MSP(void)
|
||||||
|
{
|
||||||
|
uint32_t result=0;
|
||||||
|
|
||||||
|
__ASM volatile ("MRS %0, msp\n\t"
|
||||||
|
"MOV r0, %0 \n\t"
|
||||||
|
"BX lr \n\t" : "=r" (result) );
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Main Stack Pointer
|
||||||
|
*
|
||||||
|
* @param uint32_t Main Stack Pointer
|
||||||
|
* @return none
|
||||||
|
*
|
||||||
|
* Assign the value mainStackPointer to the MSP
|
||||||
|
* (main stack pointer) Cortex processor register
|
||||||
|
*/
|
||||||
|
void __set_MSP(uint32_t topOfMainStack) __attribute__( ( naked ) );
|
||||||
|
void __set_MSP(uint32_t topOfMainStack)
|
||||||
|
{
|
||||||
|
__ASM volatile ("MSR msp, %0\n\t"
|
||||||
|
"BX lr \n\t" : : "r" (topOfMainStack) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the Base Priority value
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
* @return uint32_t BasePriority
|
||||||
|
*
|
||||||
|
* Return the content of the base priority register
|
||||||
|
*/
|
||||||
|
uint32_t __get_BASEPRI(void)
|
||||||
|
{
|
||||||
|
uint32_t result=0;
|
||||||
|
|
||||||
|
__ASM volatile ("MRS %0, basepri_max" : "=r" (result) );
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Base Priority value
|
||||||
|
*
|
||||||
|
* @param uint32_t BasePriority
|
||||||
|
* @return none
|
||||||
|
*
|
||||||
|
* Set the base priority register
|
||||||
|
*/
|
||||||
|
void __set_BASEPRI(uint32_t value)
|
||||||
|
{
|
||||||
|
__ASM volatile ("MSR basepri, %0" : : "r" (value) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the Priority Mask value
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
* @return uint32_t PriMask
|
||||||
|
*
|
||||||
|
* Return the state of the priority mask bit from the priority mask
|
||||||
|
* register
|
||||||
|
*/
|
||||||
|
uint32_t __get_PRIMASK(void)
|
||||||
|
{
|
||||||
|
uint32_t result=0;
|
||||||
|
|
||||||
|
__ASM volatile ("MRS %0, primask" : "=r" (result) );
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Priority Mask value
|
||||||
|
*
|
||||||
|
* @param uint32_t PriMask
|
||||||
|
* @return none
|
||||||
|
*
|
||||||
|
* Set the priority mask bit in the priority mask register
|
||||||
|
*/
|
||||||
|
void __set_PRIMASK(uint32_t priMask)
|
||||||
|
{
|
||||||
|
__ASM volatile ("MSR primask, %0" : : "r" (priMask) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the Fault Mask value
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
* @return uint32_t FaultMask
|
||||||
|
*
|
||||||
|
* Return the content of the fault mask register
|
||||||
|
*/
|
||||||
|
uint32_t __get_FAULTMASK(void)
|
||||||
|
{
|
||||||
|
uint32_t result=0;
|
||||||
|
|
||||||
|
__ASM volatile ("MRS %0, faultmask" : "=r" (result) );
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Fault Mask value
|
||||||
|
*
|
||||||
|
* @param uint32_t faultMask value
|
||||||
|
* @return none
|
||||||
|
*
|
||||||
|
* Set the fault mask register
|
||||||
|
*/
|
||||||
|
void __set_FAULTMASK(uint32_t faultMask)
|
||||||
|
{
|
||||||
|
__ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reverse byte order in integer value
|
||||||
|
*
|
||||||
|
* @param uint32_t value to reverse
|
||||||
|
* @return uint32_t reversed value
|
||||||
|
*
|
||||||
|
* Reverse byte order in integer value
|
||||||
|
*/
|
||||||
|
uint32_t __REV(uint32_t value)
|
||||||
|
{
|
||||||
|
uint32_t result=0;
|
||||||
|
|
||||||
|
__ASM volatile ("rev %0, %1" : "=r" (result) : "r" (value) );
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reverse byte order in unsigned short value
|
||||||
|
*
|
||||||
|
* @param uint16_t value to reverse
|
||||||
|
* @return uint32_t reversed value
|
||||||
|
*
|
||||||
|
* Reverse byte order in unsigned short value
|
||||||
|
*/
|
||||||
|
uint32_t __REV16(uint16_t value)
|
||||||
|
{
|
||||||
|
uint32_t result=0;
|
||||||
|
|
||||||
|
__ASM volatile ("rev16 %0, %1" : "=r" (result) : "r" (value) );
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reverse byte order in signed short value with sign extension to integer
|
||||||
|
*
|
||||||
|
* @param int32_t value to reverse
|
||||||
|
* @return int32_t reversed value
|
||||||
|
*
|
||||||
|
* Reverse byte order in signed short value with sign extension to integer
|
||||||
|
*/
|
||||||
|
int32_t __REVSH(int16_t value)
|
||||||
|
{
|
||||||
|
uint32_t result=0;
|
||||||
|
|
||||||
|
__ASM volatile ("revsh %0, %1" : "=r" (result) : "r" (value) );
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reverse bit order of value
|
||||||
|
*
|
||||||
|
* @param uint32_t value to reverse
|
||||||
|
* @return uint32_t reversed value
|
||||||
|
*
|
||||||
|
* Reverse bit order of value
|
||||||
|
*/
|
||||||
|
uint32_t __RBIT(uint32_t value)
|
||||||
|
{
|
||||||
|
uint32_t result=0;
|
||||||
|
|
||||||
|
__ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) );
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief LDR Exclusive
|
||||||
|
*
|
||||||
|
* @param uint8_t* address
|
||||||
|
* @return uint8_t value of (*address)
|
||||||
|
*
|
||||||
|
* Exclusive LDR command
|
||||||
|
*/
|
||||||
|
uint8_t __LDREXB(uint8_t *addr)
|
||||||
|
{
|
||||||
|
uint8_t result=0;
|
||||||
|
|
||||||
|
__ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) );
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief LDR Exclusive
|
||||||
|
*
|
||||||
|
* @param uint16_t* address
|
||||||
|
* @return uint16_t value of (*address)
|
||||||
|
*
|
||||||
|
* Exclusive LDR command
|
||||||
|
*/
|
||||||
|
uint16_t __LDREXH(uint16_t *addr)
|
||||||
|
{
|
||||||
|
uint16_t result=0;
|
||||||
|
|
||||||
|
__ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) );
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief LDR Exclusive
|
||||||
|
*
|
||||||
|
* @param uint32_t* address
|
||||||
|
* @return uint32_t value of (*address)
|
||||||
|
*
|
||||||
|
* Exclusive LDR command
|
||||||
|
*/
|
||||||
|
uint32_t __LDREXW(uint32_t *addr)
|
||||||
|
{
|
||||||
|
uint32_t result=0;
|
||||||
|
|
||||||
|
__ASM volatile ("ldrex %0, [%1]" : "=r" (result) : "r" (addr) );
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief STR Exclusive
|
||||||
|
*
|
||||||
|
* @param uint8_t *address
|
||||||
|
* @param uint8_t value to store
|
||||||
|
* @return uint32_t successful / failed
|
||||||
|
*
|
||||||
|
* Exclusive STR command
|
||||||
|
*/
|
||||||
|
uint32_t __STREXB(uint8_t value, uint8_t *addr)
|
||||||
|
{
|
||||||
|
uint32_t result=0;
|
||||||
|
|
||||||
|
__ASM volatile ("strexb %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief STR Exclusive
|
||||||
|
*
|
||||||
|
* @param uint16_t *address
|
||||||
|
* @param uint16_t value to store
|
||||||
|
* @return uint32_t successful / failed
|
||||||
|
*
|
||||||
|
* Exclusive STR command
|
||||||
|
*/
|
||||||
|
uint32_t __STREXH(uint16_t value, uint16_t *addr)
|
||||||
|
{
|
||||||
|
uint32_t result=0;
|
||||||
|
|
||||||
|
__ASM volatile ("strexh %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief STR Exclusive
|
||||||
|
*
|
||||||
|
* @param uint32_t *address
|
||||||
|
* @param uint32_t value to store
|
||||||
|
* @return uint32_t successful / failed
|
||||||
|
*
|
||||||
|
* Exclusive STR command
|
||||||
|
*/
|
||||||
|
uint32_t __STREXW(uint32_t value, uint32_t *addr)
|
||||||
|
{
|
||||||
|
uint32_t result=0;
|
||||||
|
|
||||||
|
__ASM volatile ("strex %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the Control Register value
|
||||||
|
*
|
||||||
|
* @param none
|
||||||
|
* @return uint32_t Control value
|
||||||
|
*
|
||||||
|
* Return the content of the control register
|
||||||
|
*/
|
||||||
|
uint32_t __get_CONTROL(void)
|
||||||
|
{
|
||||||
|
uint32_t result=0;
|
||||||
|
|
||||||
|
__ASM volatile ("MRS %0, control" : "=r" (result) );
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Control Register value
|
||||||
|
*
|
||||||
|
* @param uint32_t Control value
|
||||||
|
* @return none
|
||||||
|
*
|
||||||
|
* Set the control register
|
||||||
|
*/
|
||||||
|
void __set_CONTROL(uint32_t control)
|
||||||
|
{
|
||||||
|
__ASM volatile ("MSR control, %0" : : "r" (control) );
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif (defined (__TASKING__)) /*------------------ TASKING Compiler ---------------------*/
|
||||||
|
/* TASKING carm specific functions */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The CMSIS functions have been implemented as intrinsics in the compiler.
|
||||||
|
* Please use "carm -?i" to get an up to date list of all instrinsics,
|
||||||
|
* Including the CMSIS ones.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,128 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARMCM3/crt0.s
|
||||||
|
* @brief Generic ARM Cortex-M3 startup file for ChibiOS/RT.
|
||||||
|
* @addtogroup ARMCM3_CORE
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/** @cond never */
|
||||||
|
|
||||||
|
.set CONTROL_MODE_PRIVILEGED, 0
|
||||||
|
.set CONTROL_MODE_UNPRIVILEGED, 1
|
||||||
|
.set CONTROL_USE_MSP, 0
|
||||||
|
.set CONTROL_USE_PSP, 2
|
||||||
|
|
||||||
|
.text
|
||||||
|
.balign 2
|
||||||
|
.syntax unified
|
||||||
|
.thumb
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset handler.
|
||||||
|
*/
|
||||||
|
.thumb_func
|
||||||
|
.global ResetHandler
|
||||||
|
.weak ResetHandler
|
||||||
|
ResetHandler:
|
||||||
|
/* Interrupts globally masked. */
|
||||||
|
cpsid i
|
||||||
|
/*
|
||||||
|
* Stack pointers initialization.
|
||||||
|
*/
|
||||||
|
ldr r0, =__ram_end__
|
||||||
|
ldr r1, =__main_stack_size__
|
||||||
|
sub r0, r0, r1
|
||||||
|
/* { r0 = main stack low address } */
|
||||||
|
msr PSP, r0
|
||||||
|
/* Early initialization. */
|
||||||
|
bl hwinit0
|
||||||
|
/*
|
||||||
|
* Data initialization.
|
||||||
|
* NOTE: It assumes that the DATA size is a multiple of 4.
|
||||||
|
*/
|
||||||
|
ldr r1, =_textdata
|
||||||
|
ldr r2, =_data
|
||||||
|
ldr r3, =_edata
|
||||||
|
dloop:
|
||||||
|
cmp r2, r3
|
||||||
|
ittt lo
|
||||||
|
ldrlo r0, [r1], #4
|
||||||
|
strlo r0, [r2], #4
|
||||||
|
blo dloop
|
||||||
|
/*
|
||||||
|
* BSS initialization.
|
||||||
|
* NOTE: It assumes that the BSS size is a multiple of 4.
|
||||||
|
*/
|
||||||
|
movs r0, #0
|
||||||
|
ldr r1, =_bss_start
|
||||||
|
ldr r2, =_bss_end
|
||||||
|
bloop:
|
||||||
|
cmp r1, r2
|
||||||
|
itt lo
|
||||||
|
strlo r0, [r1], #4
|
||||||
|
blo bloop
|
||||||
|
/* Switches to the Process Stack. */
|
||||||
|
movs r0, #CONTROL_MODE_PRIVILEGED | CONTROL_USE_PSP
|
||||||
|
msr CONTROL, r0
|
||||||
|
isb
|
||||||
|
/* Late initialization. */
|
||||||
|
bl hwinit1
|
||||||
|
movs r0, #0
|
||||||
|
mov r1, r0
|
||||||
|
bl main
|
||||||
|
b MainExitHandler
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default main exit code, just a loop.
|
||||||
|
* It is a weak symbol, the application code can redefine the behavior.
|
||||||
|
*/
|
||||||
|
.thumb_func
|
||||||
|
.global MainExitHandler
|
||||||
|
.weak MainExitHandler
|
||||||
|
MainExitHandler:
|
||||||
|
.loop: b .loop
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default early initialization code. It is declared weak in order to be
|
||||||
|
* replaced by the real initialization code.
|
||||||
|
* Early initialization is performed just after reset before BSS and DATA
|
||||||
|
* segments initialization.
|
||||||
|
*/
|
||||||
|
.thumb_func
|
||||||
|
.global hwinit0
|
||||||
|
.weak hwinit0
|
||||||
|
hwinit0:
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default late initialization code. It is declared weak in order to be
|
||||||
|
* replaced by the real initialization code.
|
||||||
|
* Late initialization is performed after BSS and DATA segments initialization
|
||||||
|
* and before invoking the main() function.
|
||||||
|
*/
|
||||||
|
.thumb_func
|
||||||
|
.global hwinit1
|
||||||
|
.weak hwinit1
|
||||||
|
hwinit1:
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
/** @endcond */
|
||||||
|
/** @} */
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARMCM3/nvic.c
|
||||||
|
* @brief Cortex-M3 NVIC support code.
|
||||||
|
* @addtogroup ARMCM3_NVIC
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
#include <nvic.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the priority of an interrupt handler and enables it.
|
||||||
|
*
|
||||||
|
* @param n the interrupt number
|
||||||
|
* @param prio the interrupt priority
|
||||||
|
* @note The parameters are not tested for correctness.
|
||||||
|
*/
|
||||||
|
void NVICEnableVector(uint32_t n, uint32_t prio) {
|
||||||
|
unsigned sh = (n & 3) << 3;
|
||||||
|
|
||||||
|
NVIC_IPR(n >> 2) = (NVIC_IPR(n >> 2) & ~(0xFF << sh)) | (prio << sh);
|
||||||
|
NVIC_ISER(n >> 5) = 1 << (n & 0x1F);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Changes the priority of a system handler.
|
||||||
|
*
|
||||||
|
* @param handler the system handler number
|
||||||
|
* @param prio the system handler priority
|
||||||
|
* @note The parameters are not tested for correctness.
|
||||||
|
*/
|
||||||
|
void NVICSetSystemHandlerPriority(uint32_t handler, uint32_t prio) {
|
||||||
|
unsigned sh = (handler & 3) * 8;
|
||||||
|
|
||||||
|
SCB_SHPR(handler >> 2) = (SCB_SHPR(handler >> 2) & ~(0xFF << sh)) | (prio << sh);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,190 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ports/ARMCM3/nvic.h
|
||||||
|
* @brief Cortex-M3 NVIC support macros and structures.
|
||||||
|
* @addtogroup ARMCM3_NVIC
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _NVIC_H_
|
||||||
|
#define _NVIC_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* System vector constants for @p NVICSetSystemHandlerPriority().
|
||||||
|
*/
|
||||||
|
#define HANDLER_MEM_MANAGE 0 /**< MEM MANAGE vector id.*/
|
||||||
|
#define HANDLER_BUS_FAULT 1 /**< BUS FAULT vector id.*/
|
||||||
|
#define HANDLER_USAGE_FAULT 2 /**< USAGE FAULT vector id.*/
|
||||||
|
#define HANDLER_RESERVED_3 3
|
||||||
|
#define HANDLER_RESERVED_4 4
|
||||||
|
#define HANDLER_RESERVED_5 5
|
||||||
|
#define HANDLER_RESERVED_6 6
|
||||||
|
#define HANDLER_SVCALL 7 /**< SVCALL vector id.*/
|
||||||
|
#define HANDLER_DEBUG_MONITOR 8 /**< DEBUG MONITOR vector id.*/
|
||||||
|
#define HANDLER_RESERVED_9 9
|
||||||
|
#define HANDLER_PENDSV 10 /**< PENDSV vector id.*/
|
||||||
|
#define HANDLER_SYSTICK 11 /**< SYS TCK vector id.*/
|
||||||
|
|
||||||
|
typedef volatile unsigned char IOREG8; /**< 8 bits I/O register type.*/
|
||||||
|
typedef volatile unsigned int IOREG32; /**< 32 bits I/O register type.*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief NVIC ITCR register.
|
||||||
|
*/
|
||||||
|
#define NVIC_ITCR (*((IOREG32 *)0xE000E004))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief NVIC STIR register.
|
||||||
|
*/
|
||||||
|
#define NVIC_STIR (*((IOREG32 *)0xE000EF00))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Structure representing the SYSTICK I/O space.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
IOREG32 CSR;
|
||||||
|
IOREG32 RVR;
|
||||||
|
IOREG32 CVR;
|
||||||
|
IOREG32 CBVR;
|
||||||
|
} CM3_ST;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SYSTICK peripheral base address.
|
||||||
|
*/
|
||||||
|
#define STBase ((CM3_ST *)0xE000E010)
|
||||||
|
#define ST_CSR (STBase->CSR)
|
||||||
|
#define ST_RVR (STBase->RVR)
|
||||||
|
#define ST_CVR (STBase->CVR)
|
||||||
|
#define ST_CBVR (STBase->CBVR)
|
||||||
|
|
||||||
|
#define CSR_ENABLE_MASK (0x1 << 0)
|
||||||
|
#define ENABLE_OFF_BITS (0 << 0)
|
||||||
|
#define ENABLE_ON_BITS (1 << 0)
|
||||||
|
#define CSR_TICKINT_MASK (0x1 << 1)
|
||||||
|
#define TICKINT_DISABLED_BITS (0 << 1)
|
||||||
|
#define TICKINT_ENABLED_BITS (1 << 1)
|
||||||
|
#define CSR_CLKSOURCE_MASK (0x1 << 2)
|
||||||
|
#define CLKSOURCE_EXT_BITS (0 << 2)
|
||||||
|
#define CLKSOURCE_CORE_BITS (1 << 2)
|
||||||
|
#define CSR_COUNTFLAG_MASK (0x1 << 16)
|
||||||
|
|
||||||
|
#define RVR_RELOAD_MASK (0xFFFFFF << 0)
|
||||||
|
|
||||||
|
#define CVR_CURRENT_MASK (0xFFFFFF << 0)
|
||||||
|
|
||||||
|
#define CBVR_TENMS_MASK (0xFFFFFF << 0)
|
||||||
|
#define CBVR_SKEW_MASK (0x1 << 30)
|
||||||
|
#define CBVR_NOREF_MASK (0x1 << 31)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Structure representing the NVIC I/O space.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
IOREG32 ISER[8];
|
||||||
|
IOREG32 unused1[24];
|
||||||
|
IOREG32 ICER[8];
|
||||||
|
IOREG32 unused2[24];
|
||||||
|
IOREG32 ISPR[8];
|
||||||
|
IOREG32 unused3[24];
|
||||||
|
IOREG32 ICPR[8];
|
||||||
|
IOREG32 unused4[24];
|
||||||
|
IOREG32 IABR[8];
|
||||||
|
IOREG32 unused5[56];
|
||||||
|
IOREG32 IPR[60];
|
||||||
|
} CM3_NVIC;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief NVIC peripheral base address.
|
||||||
|
*/
|
||||||
|
#define NVICBase ((CM3_NVIC *)0xE000E100)
|
||||||
|
#define NVIC_ISER(n) (NVICBase->ISER[n])
|
||||||
|
#define NVIC_ICER(n) (NVICBase->ICER[n])
|
||||||
|
#define NVIC_ISPR(n) (NVICBase->ISPR[n])
|
||||||
|
#define NVIC_ICPR(n) (NVICBase->ICPR[n])
|
||||||
|
#define NVIC_IABR(n) (NVICBase->IABR[n])
|
||||||
|
#define NVIC_IPR(n) (NVICBase->IPR[n])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Structure representing the System Control Block I/O space.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
IOREG32 CPUID;
|
||||||
|
IOREG32 ICSR;
|
||||||
|
IOREG32 VTOR;
|
||||||
|
IOREG32 AIRCR;
|
||||||
|
IOREG32 SCR;
|
||||||
|
IOREG32 CCR;
|
||||||
|
IOREG32 SHPR[3];
|
||||||
|
IOREG32 SHCSR;
|
||||||
|
IOREG32 CFSR;
|
||||||
|
IOREG32 HFSR;
|
||||||
|
IOREG32 DFSR;
|
||||||
|
IOREG32 MMFAR;
|
||||||
|
IOREG32 BFAR;
|
||||||
|
IOREG32 AFSR;
|
||||||
|
} CM3_SCB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SCB peripheral base address.
|
||||||
|
*/
|
||||||
|
#define SCBBase ((CM3_SCB *)0xE000ED00)
|
||||||
|
#define SCB_CPUID (SCBBase->CPUID)
|
||||||
|
#define SCB_ICSR (SCBBase->ICSR)
|
||||||
|
#define SCB_VTOR (SCBBase->VTOR)
|
||||||
|
#define SCB_AIRCR (SCBBase->AIRCR)
|
||||||
|
#define SCB_SCR (SCBBase->SCR)
|
||||||
|
#define SCB_CCR (SCBBase->CCR)
|
||||||
|
#define SCB_SHPR(n) (SCBBase->SHPR[n])
|
||||||
|
#define SCB_SHCSR (SCBBase->SHCSR)
|
||||||
|
#define SCB_CFSR (SCBBase->CFSR)
|
||||||
|
#define SCB_HFSR (SCBBase->HFSR)
|
||||||
|
#define SCB_DFSR (SCBBase->DFSR)
|
||||||
|
#define SCB_MMFAR (SCBBase->MMFAR)
|
||||||
|
#define SCB_BFAR (SCBBase->BFAR)
|
||||||
|
#define SCB_AFSR (SCBBase->AFSR)
|
||||||
|
|
||||||
|
#define ICSR_VECTACTIVE_MASK (0x1FF << 0)
|
||||||
|
#define ICSR_RETTOBASE (0x1 << 11)
|
||||||
|
#define ICSR_VECTPENDING_MASK (0x1FF << 12)
|
||||||
|
#define ICSR_ISRPENDING (0x1 << 22)
|
||||||
|
#define ICSR_ISRPREEMPT (0x1 << 23)
|
||||||
|
#define ICSR_PENDSTCLR (0x1 << 25)
|
||||||
|
#define ICSR_PENDSTSET (0x1 << 26)
|
||||||
|
#define ICSR_PENDSVCLR (0x1 << 27)
|
||||||
|
#define ICSR_PENDSVSET (0x1 << 28)
|
||||||
|
#define ICSR_NMIPENDSET (0x1 << 31)
|
||||||
|
|
||||||
|
#define AIRCR_VECTKEY 0x05FA0000
|
||||||
|
#define AIRCR_PRIGROUP_MASK (0x7 << 8)
|
||||||
|
#define AIRCR_PRIGROUP(n) ((n) << 8)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void NVICEnableVector(uint32_t n, uint32_t prio);
|
||||||
|
void NVICSetSystemHandlerPriority(uint32_t handler, uint32_t prio);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _NVIC_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,170 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup ARMCM3 ARM Cortex-M3
|
||||||
|
* @details The ARM Cortex-M3 architecture is quite complex for a
|
||||||
|
* microcontroller and some explanations are required about the port choices.
|
||||||
|
*
|
||||||
|
* @section ARMCM3_STATES Mapping of the System States in the ARM Cortex-M3 port
|
||||||
|
* The ChibiOS/RT logical @ref system_states are mapped as follow in the ARM
|
||||||
|
* Cortex-M3 port:
|
||||||
|
* - <b>Init</b>. This state is represented by the startup code and the
|
||||||
|
* initialization code before @p chSysInit() is executed. It has not a
|
||||||
|
* special hardware state associated.
|
||||||
|
* - <b>Normal</b>. This is the state the system has after executing
|
||||||
|
* @p chSysInit(). In this state the ARM Cortex-M3 has the BASEPRI register
|
||||||
|
* set at @p BASEPRI_USER level, interrupts are not masked. The processor
|
||||||
|
* is running in thread-privileged mode.
|
||||||
|
* - <b>Suspended</b>. In this state the interrupt sources are not globally
|
||||||
|
* masked but the BASEPRI register is set to @p BASEPRI_KERNEL thus masking
|
||||||
|
* any interrupt source with lower or equal priority. The processor
|
||||||
|
* is running in thread-privileged mode.
|
||||||
|
* - <b>Disabled</b>. Interrupt sources are globally masked. The processor
|
||||||
|
* is running in thread-privileged mode.
|
||||||
|
* - <b>Sleep</b>. This state is entered with the execution of the specific
|
||||||
|
* instruction @p <b>wfi</b>.
|
||||||
|
* - <b>S-Locked</b>. In this state the interrupt sources are not globally
|
||||||
|
* masked but the BASEPRI register is set to @p BASEPRI_KERNEL thus masking
|
||||||
|
* any interrupt source with lower or equal priority. The processor
|
||||||
|
* is running in thread-privileged mode.
|
||||||
|
* - <b>I-Locked</b>. In this state the interrupt sources are not globally
|
||||||
|
* masked but the BASEPRI register is set to @p BASEPRI_KERNEL thus masking
|
||||||
|
* any interrupt source with lower or equal priority. The processor
|
||||||
|
* is running in exception-privileged mode.
|
||||||
|
* - <b>Serving Regular Interrupt</b>. In this state the interrupt sources are
|
||||||
|
* not globally masked but only interrupts with higher priority can preempt
|
||||||
|
* the current handler. The processor is running in exception-privileged mode.
|
||||||
|
* - <b>Serving Fast Interrupt</b>. It is basically the same of the SRI state
|
||||||
|
* but it is not possible to switch to the I-Locked state because fast
|
||||||
|
* interrupts can preempt the kernel critical zone.
|
||||||
|
* - <b>Serving Non-Maskable Interrupt</b>. The Cortex-M3 has a specific
|
||||||
|
* asynchronous NMI vector and several synchronous fault vectors that can
|
||||||
|
* be considered to be in this category.
|
||||||
|
* - <b>Halted</b>. Implemented as an infinite loop after globally masking all
|
||||||
|
* the maskable interrupt sources. The ARM state is whatever the processor
|
||||||
|
* was running when @p chSysHalt() was invoked.
|
||||||
|
* .
|
||||||
|
* @section ARMCM3_NOTES The ARM Cortex-M3 port notes
|
||||||
|
* The ARM Cortex-M3 port is organized as follow:
|
||||||
|
* - The @p main() function is invoked in thread-privileged mode.
|
||||||
|
* - Each thread has a private process stack, the system has a single main
|
||||||
|
* stack where all the interrupts and exceptions are processed.
|
||||||
|
* - Only the 4 MSb of the priority level are used, the 4 LSb are assumed
|
||||||
|
* to be zero.
|
||||||
|
* - The threads are started in thread-privileged mode with BASEPRI level
|
||||||
|
* 0x00 (disabled).
|
||||||
|
* - The kernel raises its BASEPRI level to @p BASEPRI_KERNEL in order to
|
||||||
|
* protect the kernel data structures.
|
||||||
|
* - Interrupt nesting and the other advanced NVIC features are supported.
|
||||||
|
* - The SVC instruction and vector, with parameter #0, is internally used
|
||||||
|
* for commanded context switching.<br>
|
||||||
|
* It is possible to share the SVC handler at the cost of slower context
|
||||||
|
* switching.
|
||||||
|
* - The PendSV vector is internally used for preemption context switching.
|
||||||
|
* .
|
||||||
|
* @ingroup Ports
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup ARMCM3_CONF Configuration Options
|
||||||
|
* @brief ARM Cortex-M3 Configuration Options.
|
||||||
|
* @details The ARMCM3 port allows some architecture-specific configurations
|
||||||
|
* settings that can be specified externally, as example on the compiler
|
||||||
|
* command line:
|
||||||
|
* - @p INT_REQUIRED_STACK, this value represent the amount of stack space used
|
||||||
|
* by an interrupt handler between the @p extctx and @p intctx
|
||||||
|
* structures.<br>
|
||||||
|
* In the current implementation this value is guaranteed to be zero so
|
||||||
|
* there is no need to modify this value unless changes are done at the
|
||||||
|
* interrupts handling code.
|
||||||
|
* - @p BASEPRI_USER, this is the @p BASEPRI value for the user threads. The
|
||||||
|
* default value is @p 0 (disabled).<br>
|
||||||
|
* Usually there is no need to change this value, please refer to the
|
||||||
|
* Cortex-M3 technical reference manual for a detailed description.
|
||||||
|
* - @p BASEPRI_KERNEL, this is the @p BASEPRI value for the kernel lock code.
|
||||||
|
* The default value is 0x40.<br>
|
||||||
|
* Code running at higher priority levels must not invoke any OS API.<br>
|
||||||
|
* Usually there is no need to change this value, please refer to the
|
||||||
|
* Cortex-M3 technical reference manual for a detailed description.
|
||||||
|
* - @p ENABLE_WFI_IDLE, if set to @p 1 enables the use of the @p <b>wfi</b>
|
||||||
|
* instruction from within the idle loop. This is defaulted to 0 because
|
||||||
|
* it can create problems with some debuggers. Setting this option to 1
|
||||||
|
* reduces the system power requirements.
|
||||||
|
* .
|
||||||
|
* @ingroup ARMCM3
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup ARMCM3_CORE Core Port Implementation
|
||||||
|
* @brief ARM Cortex-M3 specific port code, structures and macros.
|
||||||
|
*
|
||||||
|
* @ingroup ARMCM3
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup ARMCM3_STARTUP Startup Support
|
||||||
|
* @brief ARM Cortex-M3 startup code support.
|
||||||
|
* @details ChibiOS/RT provides its own generic startup file for the ARM
|
||||||
|
* Cortex-M3 port.
|
||||||
|
* Of course it is not mandatory to use it but care should be taken about the
|
||||||
|
* startup phase details.
|
||||||
|
*
|
||||||
|
* <h2>Startup Process</h2>
|
||||||
|
* The startup process, as implemented, is the following:
|
||||||
|
* -# Interrupts are masked globally.
|
||||||
|
* -# The two stacks are initialized by assigning them the sizes defined in the
|
||||||
|
* linker script (usually named @p ch.ld). Stack areas are allocated from
|
||||||
|
* the highest RAM location downward.
|
||||||
|
* -# An early initialization routine @p hwinit0 is invoked, if the symbol is
|
||||||
|
* not defined then an empty default routine is executed (weak symbol).
|
||||||
|
* -# DATA and BSS segments are initialized.
|
||||||
|
* -# The CPU state is switched to Privileged and the PSP stack is used.
|
||||||
|
* -# A late initialization routine @p hwinit1 is invoked, if the symbol not
|
||||||
|
* defined then an empty default routine is executed (weak symbol).<br>
|
||||||
|
* This late initialization function is also the proper place for a
|
||||||
|
* @a bootloader, if your application requires one.
|
||||||
|
* -# The @p main() function is invoked with the parameters @p argc and @p argv
|
||||||
|
* set to zero.
|
||||||
|
* -# Should the @p main() function return a branch is performed to the weak
|
||||||
|
* symbol MainExitHandler. The default code is an endless empty loop.
|
||||||
|
* .
|
||||||
|
* <h2>Expected linker symbols</h2>
|
||||||
|
* The startup code starts at the symbol @p ResetHandler and expects the
|
||||||
|
* following symbols to be defined in the linker script:
|
||||||
|
* - @p __ram_end__ RAM end location +1.
|
||||||
|
* - @p __main_stack_size__ Exception stack size.
|
||||||
|
* - @p __process_stack_size__ Process stack size. This is the stack area used
|
||||||
|
* by the @p main() function.
|
||||||
|
* - @p _textdata address of the data segment source read only data.
|
||||||
|
* - @p _data data segment start location.
|
||||||
|
* - @p _edata data segment end location +1.
|
||||||
|
* - @p _bss_start BSS start location.
|
||||||
|
* - @p _bss_end BSS end location +1.
|
||||||
|
* .
|
||||||
|
* @ingroup ARMCM3
|
||||||
|
* @file ports/ARMCM3/crt0.s Startup code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup ARMCM3_NVIC NVIC Support
|
||||||
|
* @brief ARM Cortex-M3 NVIC support.
|
||||||
|
*
|
||||||
|
* @ingroup ARMCM3
|
||||||
|
*/
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue