This commit is contained in:
rusefi 2017-03-22 08:47:53 -04:00
parent 8b451bd0f1
commit 884da751c3
25 changed files with 13199 additions and 0 deletions

View File

@ -0,0 +1,9 @@
# List of the ChibiOS generic LPC214x file.
STARTUPSRC = $(CHIBIOS)/os/common/ports/ARM/compilers/GCC/crt1.c
STARTUPASM = $(CHIBIOS)/os/common/ports/ARM/compilers/GCC/vectors.s \
$(CHIBIOS)/os/common/ports/ARM/compilers/GCC/crt0.s
STARTUPINC = ${CHIBIOS}/os/common/ports/ARM/devices/LPC214x
STARTUPLD = ${CHIBIOS}/os/common/ports/ARM/compilers/GCC/ld

View File

@ -0,0 +1,50 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
* ST32F100xB memory setup.
*/
MEMORY
{
flash : org = 0x08000000, len = 128k
ram0 : org = 0x20000000, len = 8k
ram1 : org = 0x00000000, len = 0
ram2 : org = 0x00000000, len = 0
ram3 : org = 0x00000000, len = 0
ram4 : org = 0x00000000, len = 0
ram5 : org = 0x00000000, len = 0
ram6 : org = 0x00000000, len = 0
ram7 : org = 0x00000000, len = 0
}
/* RAM region to be used for Main stack. This stack accommodates the processing
of all exceptions and interrupts*/
REGION_ALIAS("MAIN_STACK_RAM", ram0);
/* RAM region to be used for the process stack. This is the stack used by
the main() function.*/
REGION_ALIAS("PROCESS_STACK_RAM", ram0);
/* RAM region to be used for data segment.*/
REGION_ALIAS("DATA_RAM", ram0);
/* RAM region to be used for BSS segment.*/
REGION_ALIAS("BSS_RAM", ram0);
/* RAM region to be used for the default heap.*/
REGION_ALIAS("HEAP_RAM", ram0);
INCLUDE rules.ld

View File

@ -0,0 +1,78 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file vectors.h
* @brief ISR vector module header.
*
* @addtogroup PPC_CW_CORE
* @{
*/
#ifndef _VECTORS_H_
#define _VECTORS_H_
#include "ppcparams.h"
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
/* The following code is not processed when the file is included from an
asm module.*/
#if !defined(_FROM_ASM_)
#if !defined(__DOXYGEN__)
extern uint32_t _vectors[PPC_NUM_VECTORS];
#endif
#ifdef __cplusplus
extern "C" {
#endif
void _unhandled_irq(void);
#ifdef __cplusplus
}
#endif
#endif /* !defined(_FROM_ASM_) */
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
#endif /* _VECTORS_H_ */
/** @} */

View File

@ -0,0 +1,11 @@
# List of the ChibiOS e200z0 SPC560Pxx startup files.
STARTUPSRC =
STARTUPASM = $(CHIBIOS)/os/common/ports/e200/devices/SPC560Pxx/boot.s \
$(CHIBIOS)/os/common/ports/e200/compilers/GCC/vectors.s \
$(CHIBIOS)/os/common/ports/e200/compilers/GCC/crt0.s
STARTUPINC = ${CHIBIOS}/os/common/ports/e200/compilers/GCC \
${CHIBIOS}/os/common/ports/e200/devices/SPC560Pxx
STARTUPLD = ${CHIBIOS}/os/common/ports/e200/compilers/GCC/ld

View File

@ -0,0 +1,214 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file SPC560Dxx/boot.s
* @brief SPC560Dxx boot-related code.
*
* @addtogroup PPC_BOOT
* @{
*/
#include "boot.h"
#if !defined(__DOXYGEN__)
/* BAM record.*/
.section .boot, "ax"
.long 0x015A0000
.long _reset_address
.align 2
.globl _reset_address
.type _reset_address, @function
_reset_address:
#if BOOT_PERFORM_CORE_INIT
bl _coreinit
#endif
bl _ivinit
#if BOOT_RELOCATE_IN_RAM
/*
* Image relocation in RAM.
*/
lis r4, __ram_reloc_start__@h
ori r4, r4, __ram_reloc_start__@l
lis r5, __ram_reloc_dest__@h
ori r5, r5, __ram_reloc_dest__@l
lis r6, __ram_reloc_end__@h
ori r6, r6, __ram_reloc_end__@l
.relloop:
cmpl cr0, r4, r6
bge cr0, .relend
lwz r7, 0(r4)
addi r4, r4, 4
stw r7, 0(r5)
addi r5, r5, 4
b .relloop
.relend:
lis r3, _boot_address@h
ori r3, r3, _boot_address@l
mtctr r3
bctrl
#else
b _boot_address
#endif
#if BOOT_PERFORM_CORE_INIT
.align 2
_coreinit:
/*
* RAM clearing, this device requires a write to all RAM location in
* order to initialize the ECC detection hardware, this is going to
* slow down the startup but there is no way around.
*/
xor r0, r0, r0
xor r1, r1, r1
xor r2, r2, r2
xor r3, r3, r3
xor r4, r4, r4
xor r5, r5, r5
xor r6, r6, r6
xor r7, r7, r7
xor r8, r8, r8
xor r9, r9, r9
xor r10, r10, r10
xor r11, r11, r11
xor r12, r12, r12
xor r13, r13, r13
xor r14, r14, r14
xor r15, r15, r15
xor r16, r16, r16
xor r17, r17, r17
xor r18, r18, r18
xor r19, r19, r19
xor r20, r20, r20
xor r21, r21, r21
xor r22, r22, r22
xor r23, r23, r23
xor r24, r24, r24
xor r25, r25, r25
xor r26, r26, r26
xor r27, r27, r27
xor r28, r28, r28
xor r29, r29, r29
xor r30, r30, r30
xor r31, r31, r31
lis r4, __ram_start__@h
ori r4, r4, __ram_start__@l
lis r5, __ram_end__@h
ori r5, r5, __ram_end__@l
.cleareccloop:
cmpl cr0, r4, r5
bge cr0, .cleareccend
stmw r16, 0(r4)
addi r4, r4, 64
b .cleareccloop
.cleareccend:
/*
* Branch prediction enabled.
*/
li r3, BOOT_BUCSR_DEFAULT
mtspr 1013, r3 /* BUCSR */
blr
#endif /* BOOT_PERFORM_CORE_INIT */
/*
* Exception vectors initialization.
*/
.align 2
_ivinit:
/* MSR initialization.*/
lis r3, BOOT_MSR_DEFAULT@h
ori r3, r3, BOOT_MSR_DEFAULT@l
mtMSR r3
/* IVPR initialization.*/
lis r3, __ivpr_base__@h
ori r3, r3, __ivpr_base__@l
mtIVPR r3
blr
.section .ivors, "ax"
.globl IVORS
IVORS:
b _IVOR0
.align 4
b _IVOR1
.align 4
b _IVOR2
.align 4
b _IVOR3
.align 4
b _IVOR4
.align 4
b _IVOR5
.align 4
b _IVOR6
.align 4
b _IVOR7
.align 4
b _IVOR8
.align 4
b _IVOR9
.align 4
b _IVOR10
.align 4
b _IVOR11
.align 4
b _IVOR12
.align 4
b _IVOR13
.align 4
b _IVOR14
.align 4
b _IVOR15
.section .handlers, "ax"
/*
* Default IVOR handlers.
*/
.align 2
.weak _IVOR0, _IVOR1, _IVOR2, _IVOR3, _IVOR4, _IVOR5
.weak _IVOR6, _IVOR7, _IVOR8, _IVOR9, _IVOR10, _IVOR11
.weak _IVOR12, _IVOR13, _IVOR14, _IVOR15
_IVOR0:
_IVOR1:
_IVOR2:
_IVOR3:
_IVOR5:
_IVOR6:
_IVOR7:
_IVOR8:
_IVOR9:
_IVOR11:
_IVOR12:
_IVOR13:
_IVOR14:
_IVOR15:
.global _unhandled_exception
_unhandled_exception:
b _unhandled_exception
#endif /* !defined(__DOXYGEN__) */
/** @} */

View File

@ -0,0 +1,248 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file boot.h
* @brief Boot parameters for the SPC56ECxx.
* @{
*/
#ifndef _BOOT_H_
#define _BOOT_H_
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/**
* @name MASx registers definitions
* @{
*/
#define MAS0_TBLMAS_TBL 0x10000000
#define MAS0_ESEL_MASK 0x000F0000
#define MAS0_ESEL(n) ((n) << 16)
#define MAS1_VALID 0x80000000
#define MAS1_IPROT 0x40000000
#define MAS1_TID_MASK 0x00FF0000
#define MAS1_TS 0x00001000
#define MAS1_TSISE_MASK 0x00000F80
#define MAS1_TSISE_1K 0x00000000
#define MAS1_TSISE_2K 0x00000080
#define MAS1_TSISE_4K 0x00000100
#define MAS1_TSISE_8K 0x00000180
#define MAS1_TSISE_16K 0x00000200
#define MAS1_TSISE_32K 0x00000280
#define MAS1_TSISE_64K 0x00000300
#define MAS1_TSISE_128K 0x00000380
#define MAS1_TSISE_256K 0x00000400
#define MAS1_TSISE_512K 0x00000480
#define MAS1_TSISE_1M 0x00000500
#define MAS1_TSISE_2M 0x00000580
#define MAS1_TSISE_4M 0x00000600
#define MAS1_TSISE_8M 0x00000680
#define MAS1_TSISE_16M 0x00000700
#define MAS1_TSISE_32M 0x00000780
#define MAS1_TSISE_64M 0x00000800
#define MAS1_TSISE_128M 0x00000880
#define MAS1_TSISE_256M 0x00000900
#define MAS1_TSISE_512M 0x00000980
#define MAS1_TSISE_1G 0x00000A00
#define MAS1_TSISE_2G 0x00000A80
#define MAS1_TSISE_4G 0x00000B00
#define MAS2_EPN_MASK 0xFFFFFC00
#define MAS2_EPN(n) ((n) & MAS2_EPN_MASK)
#define MAS2_EBOOK 0x00000000
#define MAS2_VLE 0x00000020
#define MAS2_W 0x00000010
#define MAS2_I 0x00000008
#define MAS2_M 0x00000004
#define MAS2_G 0x00000002
#define MAS2_E 0x00000001
#define MAS3_RPN_MASK 0xFFFFFC00
#define MAS3_RPN(n) ((n) & MAS3_RPN_MASK)
#define MAS3_U0 0x00000200
#define MAS3_U1 0x00000100
#define MAS3_U2 0x00000080
#define MAS3_U3 0x00000040
#define MAS3_UX 0x00000020
#define MAS3_SX 0x00000010
#define MAS3_UW 0x00000008
#define MAS3_SW 0x00000004
#define MAS3_UR 0x00000002
#define MAS3_SR 0x00000001
/** @} */
/**
* @name BUCSR registers definitions
* @{
*/
#define BUCSR_BPEN 0x00000001
#define BUCSR_BPRED_MASK 0x00000006
#define BUCSR_BPRED_0 0x00000000
#define BUCSR_BPRED_1 0x00000002
#define BUCSR_BPRED_2 0x00000004
#define BUCSR_BPRED_3 0x00000006
#define BUCSR_BALLOC_MASK 0x00000030
#define BUCSR_BALLOC_0 0x00000000
#define BUCSR_BALLOC_1 0x00000010
#define BUCSR_BALLOC_2 0x00000020
#define BUCSR_BALLOC_3 0x00000030
#define BUCSR_BALLOC_BFI 0x00000200
/** @} */
/**
* @name LICSR1 registers definitions
* @{
*/
#define LICSR1_ICE 0x00000001
#define LICSR1_ICINV 0x00000002
#define LICSR1_ICORG 0x00000010
/** @} */
/**
* @name MSR register definitions
* @{
*/
#define MSR_UCLE 0x04000000
#define MSR_SPE 0x02000000
#define MSR_WE 0x00040000
#define MSR_CE 0x00020000
#define MSR_EE 0x00008000
#define MSR_PR 0x00004000
#define MSR_FP 0x00002000
#define MSR_ME 0x00001000
#define MSR_FE0 0x00000800
#define MSR_DE 0x00000200
#define MSR_FE1 0x00000100
#define MSR_IS 0x00000020
#define MSR_DS 0x00000010
#define MSR_RI 0x00000002
/** @} */
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/*
* TLB default settings.
*/
#define TLB0_MAS0 (MAS0_TBLMAS_TBL | MAS0_ESEL(0))
#define TLB0_MAS1 (MAS1_VALID | MAS1_IPROT | MAS1_TSISE_4M)
#define TLB0_MAS2 (MAS2_EPN(0x00000000) | MAS2_VLE)
#define TLB0_MAS3 (MAS3_RPN(0x00000000) | \
MAS3_UX | MAS3_SX | MAS3_UW | MAS3_SW | \
MAS3_UR | MAS3_SR)
#define TLB1_MAS0 (MAS0_TBLMAS_TBL | MAS0_ESEL(1))
#define TLB1_MAS1 (MAS1_VALID | MAS1_IPROT | MAS1_TSISE_256K)
#define TLB1_MAS2 (MAS2_EPN(0x40000000) | MAS2_VLE)
#define TLB1_MAS3 (MAS3_RPN(0x40000000) | \
MAS3_UX | MAS3_SX | MAS3_UW | MAS3_SW | \
MAS3_UR | MAS3_SR)
#define TLB2_MAS0 (MAS0_TBLMAS_TBL | MAS0_ESEL(2))
#define TLB2_MAS1 (MAS1_VALID | MAS1_IPROT | MAS1_TSISE_1M)
#define TLB2_MAS2 (MAS2_EPN(0xC3F00000) | MAS2_I)
#define TLB2_MAS3 (MAS3_RPN(0xC3F00000) | \
MAS3_UW | MAS3_SW | MAS3_UR | MAS3_SR)
#define TLB3_MAS0 (MAS0_TBLMAS_TBL | MAS0_ESEL(3))
#define TLB3_MAS1 (MAS1_VALID | MAS1_IPROT | MAS1_TSISE_1M)
#define TLB3_MAS2 (MAS2_EPN(0xFFE00000) | MAS2_I)
#define TLB3_MAS3 (MAS3_RPN(0xFFE00000) | \
MAS3_UW | MAS3_SW | MAS3_UR | MAS3_SR)
#define TLB4_MAS0 (MAS0_TBLMAS_TBL | MAS0_ESEL(4))
#define TLB4_MAS1 (MAS1_VALID | MAS1_IPROT | MAS1_TSISE_1M)
#define TLB4_MAS2 (MAS2_EPN(0x8FF00000) | MAS2_I)
#define TLB4_MAS3 (MAS3_RPN(0x8FF00000) | \
MAS3_UW | MAS3_SW | MAS3_UR | MAS3_SR)
#define TLB5_MAS0 (MAS0_TBLMAS_TBL | MAS0_ESEL(5))
#define TLB5_MAS1 (MAS1_VALID | MAS1_IPROT | MAS1_TSISE_1M)
#define TLB5_MAS2 (MAS2_EPN(0xFFF00000) | MAS2_I)
#define TLB5_MAS3 (MAS3_RPN(0xFFF00000) | \
MAS3_UW | MAS3_SW | MAS3_UR | MAS3_SR)
/*
* BUCSR default settings.
*/
#if !defined(BOOT_BUCSR_DEFAULT) || defined(__DOXYGEN__)
#define BOOT_BUCSR_DEFAULT (BUCSR_BPEN | BUCSR_BPRED_0 | \
BUCSR_BALLOC_0 | BUCSR_BALLOC_BFI)
#endif
/*
* LICSR1 default settings.
*/
#if !defined(BOOT_LICSR1_DEFAULT) || defined(__DOXYGEN__)
#define BOOT_LICSR1_DEFAULT (LICSR1_ICE | LICSR1_ICORG)
#endif
/*
* MSR default settings.
*/
#if !defined(BOOT_MSR_DEFAULT) || defined(__DOXYGEN__)
#define BOOT_MSR_DEFAULT (MSR_SPE | MSR_WE | MSR_CE | MSR_ME)
#endif
/*
* Boot default settings.
*/
#if !defined(BOOT_PERFORM_CORE_INIT) || defined(__DOXYGEN__)
#define BOOT_PERFORM_CORE_INIT 1
#endif
/*
* VLE mode default settings.
*/
#if !defined(BOOT_USE_VLE) || defined(__DOXYGEN__)
#define BOOT_USE_VLE 1
#endif
/*
* RAM relocation flag.
*/
#if !defined(BOOT_RELOCATE_IN_RAM) || defined(__DOXYGEN__)
#define BOOT_RELOCATE_IN_RAM 0
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
#endif /* _BOOT_H_ */
/** @} */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,238 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file hal_files.h
* @brief Data files.
* @details This header defines abstract interfaces useful to access generic
* data files in a standardized way.
*
* @addtogroup HAL_FILES
* @details This module define an abstract interface for generic data files by
* extending the @p BaseSequentialStream interface. Note that no code
* is present, data files are just abstract interface-like structures,
* you should look at the systems as to a set of abstract C++ classes
* (even if written in C). This system has the advantage to make the
* access to streams independent from the implementation logic.<br>
* The data files interface can be used as base class for high level
* object types such as an API for a File System implementation.
* @{
*/
#ifndef _HAL_FILES_H_
#define _HAL_FILES_H_
/**
* @name Files return codes
* @{
*/
/**
* @brief No error return code.
*/
#define FILE_OK STM_OK
/**
* @brief Error code from the file stream methods.
*/
#define FILE_ERROR STM_TIMEOUT
/**
* @brief End-of-file condition for file get/put methods.
*/
#define FILE_EOF STM_RESET
/** @} */
/**
* @brief File offset type.
*/
typedef uint32_t fileoffset_t;
/**
* @brief FileStream specific methods.
*/
#define _file_stream_methods \
_base_sequential_stream_methods \
/* File close method.*/ \
msg_t (*close)(void *instance); \
/* Get last error code method.*/ \
msg_t (*geterror)(void *instance); \
/* File get size method.*/ \
msg_t (*getsize)(void *instance); \
/* File get current position method.*/ \
msg_t (*getposition)(void *instance); \
/* File seek method.*/ \
msg_t (*lseek)(void *instance, fileoffset_t offset);
/**
* @brief @p FileStream specific data.
* @note It is empty because @p FileStream is only an interface
* without implementation.
*/
#define _file_stream_data \
_base_sequential_stream_data
/**
* @extends BaseSequentialStreamVMT
*
* @brief @p FileStream virtual methods table.
*/
struct FileStreamVMT {
_file_stream_methods
};
/**
* @extends BaseSequentialStream
*
* @brief Base file stream class.
* @details This class represents a generic file data stream.
*/
typedef struct {
/** @brief Virtual Methods Table.*/
const struct FileStreamVMT *vmt;
_file_stream_data
} FileStream;
/**
* @name Macro Functions (FileStream)
* @{
*/
/**
* @brief File stream write.
* @details The function writes data from a buffer to a file stream.
*
* @param[in] ip pointer to a @p FileStream or derived class
* @param[in] bp pointer to the data buffer
* @param[in] n the maximum amount of data to be transferred
* @return The number of bytes transferred. The return value can
* be less than the specified number of bytes if an
* end-of-file condition has been met.
* @retval FILE_ERROR operation failed.
*
* @api
*/
#define fileStreamWrite(ip, bp, n) streamWrite(ip, bp, n)
/**
* @brief File stream read.
* @details The function reads data from a file stream into a buffer.
*
* @param[in] ip pointer to a @p FileStream or derived class
* @param[out] bp pointer to the data buffer
* @param[in] n the maximum amount of data to be transferred
* @return The number of bytes transferred. The return value can
* be less than the specified number of bytes if an
* end-of-file condition has been met.
* @retval FILE_ERROR operation failed.
*
* @api
*/
#define fileStreamRead(ip, bp, n) streamRead(ip, bp, n)
/**
* @brief File stream 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 FileStream or derived class
* @param[in] b the byte value to be written to the channel
*
* @return The operation status.
* @retval FILE_OK if the operation succeeded.
* @retval FILE_ERROR operation failed.
* @retval FILE_EOF if an end-of-file condition has been met.
*
* @api
*/
#define fileStreamPut(ip, b) streamPut(ip, b)
/**
* @brief File stream 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 FileStream or derived class
*
* @return A byte value from the queue.
* @retval FILE_ERROR operation failed.
* @retval FILE_EOF if an end-of-file condition has been met.
*
* @api
*/
#define fileStreamGet(ip) streamGet(ip)
/**
* @brief File Stream close.
* @details The function closes a file stream.
*
* @param[in] ip pointer to a @p FileStream or derived class
* @return The operation status.
* @retval FILE_OK no error.
* @retval FILE_ERROR operation failed.
*
* @api
*/
#define fileStreamClose(ip) ((ip)->vmt->close(ip))
/**
* @brief Returns an implementation dependent error code.
* @pre The previously called function must have returned @p FILE_ERROR.
*
* @param[in] ip pointer to a @p FileStream or derived class
* @return Implementation dependent error code.
*
* @api
*/
#define fileStreamGetError(ip) ((ip)->vmt->geterror(ip))
/**
* @brief Returns the current file size.
*
* @param[in] ip pointer to a @p FileStream or derived class
* @return The file size.
* @retval FILE_ERROR operation failed.
*
* @api
*/
#define fileStreamGetSize(ip) ((ip)->vmt->getsize(ip))
/**
* @brief Returns the current file pointer position.
*
* @param[in] ip pointer to a @p FileStream or derived class
* @return The current position inside the file.
* @retval FILE_ERROR operation failed.
*
* @api
*/
#define fileStreamGetPosition(ip) ((ip)->vmt->getposition(ip))
/**
* @brief Moves the file current pointer to an absolute position.
*
* @param[in] ip pointer to a @p FileStream or derived class
* @param[in] offset new absolute position
* @return The operation status.
* @retval FILE_OK no error.
* @retval FILE_ERROR operation failed.
*
* @api
*/
#define fileStreamSeek(ip, offset) ((ip)->vmt->lseek(ip, offset))
/** @} */
#endif /* _HAL_FILES_H_ */
/** @} */

View File

@ -0,0 +1,570 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file STM32/LLD/ADCv2/adc_lld.h
* @brief STM32 ADC subsystem low level driver header.
*
* @addtogroup ADC
* @{
*/
#ifndef _ADC_LLD_H_
#define _ADC_LLD_H_
#if HAL_USE_ADC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name Absolute Maximum Ratings
* @{
*/
/**
* @brief Minimum ADC clock frequency.
*/
#define STM32_ADCCLK_MIN 600000
/**
* @brief Maximum ADC clock frequency.
*/
#if defined(STM32F4XX) || defined(__DOXYGEN__)
#define STM32_ADCCLK_MAX 36000000
#else
#define STM32_ADCCLK_MAX 30000000
#endif
/** @} */
/**
* @name Triggers selection
* @{
*/
#define ADC_CR2_EXTEN_MASK (3U << 28U)
#define ADC_CR2_EXTEN_DISABLED (0U << 28U)
#define ADC_CR2_EXTEN_RISING (1U << 28U)
#define ADC_CR2_EXTEN_FALLING (2U << 28U)
#define ADC_CR2_EXTEN_BOTH (3U << 28U)
#define ADC_CR2_EXTSEL_MASK (15U << 24U)
#define ADC_CR2_EXTSEL_SRC(n) ((n) << 24U)
/** @} */
/**
* @name ADC clock divider settings
* @{
*/
#define ADC_CCR_ADCPRE_DIV2 0
#define ADC_CCR_ADCPRE_DIV4 1
#define ADC_CCR_ADCPRE_DIV6 2
#define ADC_CCR_ADCPRE_DIV8 3
/** @} */
/**
* @name Available analog channels
* @{
*/
#define ADC_CHANNEL_IN0 0 /**< @brief External analog input 0. */
#define ADC_CHANNEL_IN1 1 /**< @brief External analog input 1. */
#define ADC_CHANNEL_IN2 2 /**< @brief External analog input 2. */
#define ADC_CHANNEL_IN3 3 /**< @brief External analog input 3. */
#define ADC_CHANNEL_IN4 4 /**< @brief External analog input 4. */
#define ADC_CHANNEL_IN5 5 /**< @brief External analog input 5. */
#define ADC_CHANNEL_IN6 6 /**< @brief External analog input 6. */
#define ADC_CHANNEL_IN7 7 /**< @brief External analog input 7. */
#define ADC_CHANNEL_IN8 8 /**< @brief External analog input 8. */
#define ADC_CHANNEL_IN9 9 /**< @brief External analog input 9. */
#define ADC_CHANNEL_IN10 10 /**< @brief External analog input 10. */
#define ADC_CHANNEL_IN11 11 /**< @brief External analog input 11. */
#define ADC_CHANNEL_IN12 12 /**< @brief External analog input 12. */
#define ADC_CHANNEL_IN13 13 /**< @brief External analog input 13. */
#define ADC_CHANNEL_IN14 14 /**< @brief External analog input 14. */
#define ADC_CHANNEL_IN15 15 /**< @brief External analog input 15. */
#define ADC_CHANNEL_SENSOR 16 /**< @brief Internal temperature sensor.
@note Available onADC1 only. */
#define ADC_CHANNEL_VREFINT 17 /**< @brief Internal reference.
@note Available onADC1 only. */
#define ADC_CHANNEL_VBAT 18 /**< @brief VBAT.
@note Available onADC1 only. */
/** @} */
/**
* @name Sampling rates
* @{
*/
#define ADC_SAMPLE_3 0 /**< @brief 3 cycles sampling time. */
#define ADC_SAMPLE_15 1 /**< @brief 15 cycles sampling time. */
#define ADC_SAMPLE_28 2 /**< @brief 28 cycles sampling time. */
#define ADC_SAMPLE_56 3 /**< @brief 56 cycles sampling time. */
#define ADC_SAMPLE_84 4 /**< @brief 84 cycles sampling time. */
#define ADC_SAMPLE_112 5 /**< @brief 112 cycles sampling time. */
#define ADC_SAMPLE_144 6 /**< @brief 144 cycles sampling time. */
#define ADC_SAMPLE_480 7 /**< @brief 480 cycles sampling time. */
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief ADC common clock divider.
* @note This setting is influenced by the VDDA voltage and other
* external conditions, please refer to the datasheet for more
* info.<br>
* See section 5.3.20 "12-bit ADC characteristics".
*/
#if !defined(STM32_ADC_ADCPRE) || defined(__DOXYGEN__)
#define STM32_ADC_ADCPRE ADC_CCR_ADCPRE_DIV2
#endif
/**
* @brief ADC1 driver enable switch.
* @details If set to @p TRUE the support for ADC1 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_ADC_USE_ADC1) || defined(__DOXYGEN__)
#define STM32_ADC_USE_ADC1 FALSE
#endif
/**
* @brief ADC2 driver enable switch.
* @details If set to @p TRUE the support for ADC2 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_ADC_USE_ADC2) || defined(__DOXYGEN__)
#define STM32_ADC_USE_ADC2 FALSE
#endif
/**
* @brief ADC3 driver enable switch.
* @details If set to @p TRUE the support for ADC3 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_ADC_USE_ADC3) || defined(__DOXYGEN__)
#define STM32_ADC_USE_ADC3 FALSE
#endif
/**
* @brief DMA stream used for ADC1 operations.
*/
#if !defined(STM32_ADC_ADC1_DMA_STREAM) || defined(__DOXYGEN__)
#define STM32_ADC_ADC1_DMA_STREAM STM32_DMA_STREAM_ID(2, 4)
#endif
/**
* @brief DMA stream used for ADC2 operations.
*/
#if !defined(STM32_ADC_ADC2_DMA_STREAM) || defined(__DOXYGEN__)
#define STM32_ADC_ADC2_DMA_STREAM STM32_DMA_STREAM_ID(2, 2)
#endif
/**
* @brief DMA stream used for ADC3 operations.
*/
#if !defined(STM32_ADC_ADC3_DMA_STREAM) || defined(__DOXYGEN__)
#define STM32_ADC_ADC3_DMA_STREAM STM32_DMA_STREAM_ID(2, 1)
#endif
/**
* @brief ADC1 DMA priority (0..3|lowest..highest).
*/
#if !defined(STM32_ADC_ADC1_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_ADC_ADC1_DMA_PRIORITY 2
#endif
/**
* @brief ADC2 DMA priority (0..3|lowest..highest).
*/
#if !defined(STM32_ADC_ADC2_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_ADC_ADC2_DMA_PRIORITY 2
#endif
/**
* @brief ADC3 DMA priority (0..3|lowest..highest).
*/
#if !defined(STM32_ADC_ADC3_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_ADC_ADC3_DMA_PRIORITY 2
#endif
/**
* @brief ADC interrupt priority level setting.
* @note This setting is shared among ADC1, ADC2 and ADC3 because
* all ADCs share the same vector.
*/
#if !defined(STM32_ADC_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_ADC_IRQ_PRIORITY 5
#endif
/**
* @brief ADC1 DMA interrupt priority level setting.
*/
#if !defined(STM32_ADC_ADC1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY 5
#endif
/**
* @brief ADC2 DMA interrupt priority level setting.
*/
#if !defined(STM32_ADC_ADC2_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_ADC_ADC2_DMA_IRQ_PRIORITY 5
#endif
/**
* @brief ADC3 DMA interrupt priority level setting.
*/
#if !defined(STM32_ADC_ADC3_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_ADC_ADC3_DMA_IRQ_PRIORITY 5
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if STM32_ADC_USE_ADC1 && !STM32_HAS_ADC1
#error "ADC1 not present in the selected device"
#endif
#if STM32_ADC_USE_ADC2 && !STM32_HAS_ADC2
#error "ADC2 not present in the selected device"
#endif
#if STM32_ADC_USE_ADC3 && !STM32_HAS_ADC3
#error "ADC3 not present in the selected device"
#endif
#if !STM32_ADC_USE_ADC1 && !STM32_ADC_USE_ADC2 && !STM32_ADC_USE_ADC3
#error "ADC driver activated but no ADC peripheral assigned"
#endif
#if STM32_ADC_USE_ADC1 && \
!STM32_DMA_IS_VALID_ID(STM32_ADC_ADC1_DMA_STREAM, STM32_ADC1_DMA_MSK)
#error "invalid DMA stream associated to ADC1"
#endif
#if STM32_ADC_USE_ADC2 && \
!STM32_DMA_IS_VALID_ID(STM32_ADC_ADC2_DMA_STREAM, STM32_ADC2_DMA_MSK)
#error "invalid DMA stream associated to ADC2"
#endif
#if STM32_ADC_USE_ADC3 && \
!STM32_DMA_IS_VALID_ID(STM32_ADC_ADC3_DMA_STREAM, STM32_ADC3_DMA_MSK)
#error "invalid DMA stream associated to ADC3"
#endif
/* ADC clock related settings and checks.*/
#if STM32_ADC_ADCPRE == ADC_CCR_ADCPRE_DIV2
#define STM32_ADCCLK (STM32_PCLK2 / 2)
#elif STM32_ADC_ADCPRE == ADC_CCR_ADCPRE_DIV4
#define STM32_ADCCLK (STM32_PCLK2 / 4)
#elif STM32_ADC_ADCPRE == ADC_CCR_ADCPRE_DIV6
#define STM32_ADCCLK (STM32_PCLK2 / 6)
#elif STM32_ADC_ADCPRE == ADC_CCR_ADCPRE_DIV8
#define STM32_ADCCLK (STM32_PCLK2 / 8)
#else
#error "invalid STM32_ADC_ADCPRE value specified"
#endif
#if (STM32_ADCCLK < STM32_ADCCLK_MIN) || (STM32_ADCCLK > STM32_ADCCLK_MAX)
#error "STM32_ADCCLK outside acceptable range (STM32_ADCCLK_MIN...STM32_ADCCLK_MAX)"
#endif
#if !defined(STM32_DMA_REQUIRED)
#define STM32_DMA_REQUIRED
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief ADC sample data type.
*/
typedef uint16_t adcsample_t;
/**
* @brief Channels number in a conversion group.
*/
typedef uint16_t adc_channels_num_t;
/**
* @brief Possible ADC failure causes.
* @note Error codes are architecture dependent and should not relied
* upon.
*/
typedef enum {
ADC_ERR_DMAFAILURE = 0, /**< DMA operations failure. */
ADC_ERR_OVERFLOW = 1 /**< ADC overflow condition. */
} adcerror_t;
/**
* @brief Type of a structure representing an ADC driver.
*/
typedef struct ADCDriver ADCDriver;
/**
* @brief ADC notification callback type.
*
* @param[in] adcp pointer to the @p ADCDriver object triggering the
* callback
* @param[in] buffer pointer to the most recent samples data
* @param[in] n number of buffer rows available starting from @p buffer
*/
typedef void (*adccallback_t)(ADCDriver *adcp, adcsample_t *buffer, size_t n);
/**
* @brief ADC error callback type.
*
* @param[in] adcp pointer to the @p ADCDriver object triggering the
* callback
* @param[in] err ADC error code
*/
typedef void (*adcerrorcallback_t)(ADCDriver *adcp, adcerror_t err);
/**
* @brief Conversion group configuration structure.
* @details This implementation-dependent structure describes a conversion
* operation.
* @note The use of this configuration structure requires knowledge of
* STM32 ADC cell registers interface, please refer to the STM32
* reference manual for details.
*/
typedef struct {
/**
* @brief Enables the circular buffer mode for the group.
*/
bool circular;
/**
* @brief Number of the analog channels belonging to the conversion group.
*/
adc_channels_num_t num_channels;
/**
* @brief Callback function associated to the group or @p NULL.
*/
adccallback_t end_cb;
/**
* @brief Error callback or @p NULL.
*/
adcerrorcallback_t error_cb;
/* End of the mandatory fields.*/
/**
* @brief ADC CR1 register initialization data.
* @note All the required bits must be defined into this field except
* @p ADC_CR1_SCAN that is enforced inside the driver.
*/
uint32_t cr1;
/**
* @brief ADC CR2 register initialization data.
* @note All the required bits must be defined into this field except
* @p ADC_CR2_DMA, @p ADC_CR2_CONT and @p ADC_CR2_ADON that are
* enforced inside the driver.
*/
uint32_t cr2;
/**
* @brief ADC SMPR1 register initialization data.
* @details In this field must be specified the sample times for channels
* 10...18.
*/
uint32_t smpr1;
/**
* @brief ADC SMPR2 register initialization data.
* @details In this field must be specified the sample times for channels
* 0...9.
*/
uint32_t smpr2;
/**
* @brief ADC SQR1 register initialization data.
* @details Conversion group sequence 13...16 + sequence length.
*/
uint32_t sqr1;
/**
* @brief ADC SQR2 register initialization data.
* @details Conversion group sequence 7...12.
*/
uint32_t sqr2;
/**
* @brief ADC SQR3 register initialization data.
* @details Conversion group sequence 1...6.
*/
uint32_t sqr3;
} ADCConversionGroup;
/**
* @brief Driver configuration structure.
* @note It could be empty on some architectures.
*/
typedef struct {
uint32_t dummy;
} ADCConfig;
/**
* @brief Structure representing an ADC driver.
*/
struct ADCDriver {
/**
* @brief Driver state.
*/
adcstate_t state;
/**
* @brief Current configuration data.
*/
const ADCConfig *config;
/**
* @brief Current samples buffer pointer or @p NULL.
*/
adcsample_t *samples;
/**
* @brief Current samples buffer depth or @p 0.
*/
size_t depth;
/**
* @brief Current conversion group pointer or @p NULL.
*/
const ADCConversionGroup *grpp;
#if ADC_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
thread_reference_t thread;
#endif
#if ADC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the peripheral.
*/
mutex_t mutex;
#endif /* ADC_USE_MUTUAL_EXCLUSION */
#if defined(ADC_DRIVER_EXT_FIELDS)
ADC_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Pointer to the ADCx registers block.
*/
ADC_TypeDef *adc;
/**
* @brief Pointer to associated DMA channel.
*/
const stm32_dma_stream_t *dmastp;
/**
* @brief DMA mode bit mask.
*/
uint32_t dmamode;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Sequences building helper macros
* @{
*/
/**
* @brief Number of channels in a conversion sequence.
*/
#define ADC_SQR1_NUM_CH(n) (((n) - 1) << 20)
#define ADC_SQR3_SQ1_N(n) ((n) << 0) /**< @brief 1st channel in seq. */
#define ADC_SQR3_SQ2_N(n) ((n) << 5) /**< @brief 2nd channel in seq. */
#define ADC_SQR3_SQ3_N(n) ((n) << 10) /**< @brief 3rd channel in seq. */
#define ADC_SQR3_SQ4_N(n) ((n) << 15) /**< @brief 4th channel in seq. */
#define ADC_SQR3_SQ5_N(n) ((n) << 20) /**< @brief 5th channel in seq. */
#define ADC_SQR3_SQ6_N(n) ((n) << 25) /**< @brief 6th channel in seq. */
#define ADC_SQR2_SQ7_N(n) ((n) << 0) /**< @brief 7th channel in seq. */
#define ADC_SQR2_SQ8_N(n) ((n) << 5) /**< @brief 8th channel in seq. */
#define ADC_SQR2_SQ9_N(n) ((n) << 10) /**< @brief 9th channel in seq. */
#define ADC_SQR2_SQ10_N(n) ((n) << 15) /**< @brief 10th channel in seq.*/
#define ADC_SQR2_SQ11_N(n) ((n) << 20) /**< @brief 11th channel in seq.*/
#define ADC_SQR2_SQ12_N(n) ((n) << 25) /**< @brief 12th channel in seq.*/
#define ADC_SQR1_SQ13_N(n) ((n) << 0) /**< @brief 13th channel in seq.*/
#define ADC_SQR1_SQ14_N(n) ((n) << 5) /**< @brief 14th channel in seq.*/
#define ADC_SQR1_SQ15_N(n) ((n) << 10) /**< @brief 15th channel in seq.*/
#define ADC_SQR1_SQ16_N(n) ((n) << 15) /**< @brief 16th channel in seq.*/
/** @} */
/**
* @name Sampling rate settings helper macros
* @{
*/
#define ADC_SMPR2_SMP_AN0(n) ((n) << 0) /**< @brief AN0 sampling time. */
#define ADC_SMPR2_SMP_AN1(n) ((n) << 3) /**< @brief AN1 sampling time. */
#define ADC_SMPR2_SMP_AN2(n) ((n) << 6) /**< @brief AN2 sampling time. */
#define ADC_SMPR2_SMP_AN3(n) ((n) << 9) /**< @brief AN3 sampling time. */
#define ADC_SMPR2_SMP_AN4(n) ((n) << 12) /**< @brief AN4 sampling time. */
#define ADC_SMPR2_SMP_AN5(n) ((n) << 15) /**< @brief AN5 sampling time. */
#define ADC_SMPR2_SMP_AN6(n) ((n) << 18) /**< @brief AN6 sampling time. */
#define ADC_SMPR2_SMP_AN7(n) ((n) << 21) /**< @brief AN7 sampling time. */
#define ADC_SMPR2_SMP_AN8(n) ((n) << 24) /**< @brief AN8 sampling time. */
#define ADC_SMPR2_SMP_AN9(n) ((n) << 27) /**< @brief AN9 sampling time. */
#define ADC_SMPR1_SMP_AN10(n) ((n) << 0) /**< @brief AN10 sampling time. */
#define ADC_SMPR1_SMP_AN11(n) ((n) << 3) /**< @brief AN11 sampling time. */
#define ADC_SMPR1_SMP_AN12(n) ((n) << 6) /**< @brief AN12 sampling time. */
#define ADC_SMPR1_SMP_AN13(n) ((n) << 9) /**< @brief AN13 sampling time. */
#define ADC_SMPR1_SMP_AN14(n) ((n) << 12) /**< @brief AN14 sampling time. */
#define ADC_SMPR1_SMP_AN15(n) ((n) << 15) /**< @brief AN15 sampling time. */
#define ADC_SMPR1_SMP_SENSOR(n) ((n) << 18) /**< @brief Temperature Sensor
sampling time. */
#define ADC_SMPR1_SMP_VREF(n) ((n) << 21) /**< @brief Voltage Reference
sampling time. */
#define ADC_SMPR1_SMP_VBAT(n) ((n) << 24) /**< @brief VBAT sampling time. */
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if STM32_ADC_USE_ADC1 && !defined(__DOXYGEN__)
extern ADCDriver ADCD1;
#endif
#if STM32_ADC_USE_ADC2 && !defined(__DOXYGEN__)
extern ADCDriver ADCD2;
#endif
#if STM32_ADC_USE_ADC3 && !defined(__DOXYGEN__)
extern ADCDriver ADCD3;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void adc_lld_init(void);
void adc_lld_start(ADCDriver *adcp);
void adc_lld_stop(ADCDriver *adcp);
void adc_lld_start_conversion(ADCDriver *adcp);
void adc_lld_stop_conversion(ADCDriver *adcp);
void adcSTM32EnableTSVREFE(void);
void adcSTM32DisableTSVREFE(void);
void adcSTM32EnableVBATE(void);
void adcSTM32DisableVBATE(void);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_ADC */
#endif /* _ADC_LLD_H_ */
/** @} */

View File

@ -0,0 +1,522 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file DMAv2/stm32_dma.c
* @brief Enhanced DMA helper driver code.
*
* @addtogroup STM32_DMA
* @details DMA sharing helper driver. In the STM32 the DMA streams are a
* shared resource, this driver allows to allocate and free DMA
* streams at runtime in order to allow all the other device
* drivers to coordinate the access to the resource.
* @note The DMA ISR handlers are all declared into this module because
* sharing, the various device drivers can associate a callback to
* ISRs when allocating streams.
* @{
*/
#include "hal.h"
/* The following macro is only defined if some driver requiring DMA services
has been enabled.*/
#if defined(STM32_DMA_REQUIRED) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/**
* @brief Mask of the DMA1 streams in @p dma_streams_mask.
*/
#define STM32_DMA1_STREAMS_MASK 0x000000FFU
/**
* @brief Mask of the DMA2 streams in @p dma_streams_mask.
*/
#define STM32_DMA2_STREAMS_MASK 0x0000FF00U
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief DMA streams descriptors.
* @details This table keeps the association between an unique stream
* identifier and the involved physical registers.
* @note Don't use this array directly, use the appropriate wrapper macros
* instead: @p STM32_DMA1_STREAM0, @p STM32_DMA1_STREAM1 etc.
*/
const stm32_dma_stream_t _stm32_dma_streams[STM32_DMA_STREAMS] = {
{DMA1_Stream0, &DMA1->LIFCR, 0, 0, STM32_DMA1_CH0_NUMBER},
{DMA1_Stream1, &DMA1->LIFCR, 6, 1, STM32_DMA1_CH1_NUMBER},
{DMA1_Stream2, &DMA1->LIFCR, 16, 2, STM32_DMA1_CH2_NUMBER},
{DMA1_Stream3, &DMA1->LIFCR, 22, 3, STM32_DMA1_CH3_NUMBER},
{DMA1_Stream4, &DMA1->HIFCR, 0, 4, STM32_DMA1_CH4_NUMBER},
{DMA1_Stream5, &DMA1->HIFCR, 6, 5, STM32_DMA1_CH5_NUMBER},
{DMA1_Stream6, &DMA1->HIFCR, 16, 6, STM32_DMA1_CH6_NUMBER},
{DMA1_Stream7, &DMA1->HIFCR, 22, 7, STM32_DMA1_CH7_NUMBER},
{DMA2_Stream0, &DMA2->LIFCR, 0, 8, STM32_DMA2_CH0_NUMBER},
{DMA2_Stream1, &DMA2->LIFCR, 6, 9, STM32_DMA2_CH1_NUMBER},
{DMA2_Stream2, &DMA2->LIFCR, 16, 10, STM32_DMA2_CH2_NUMBER},
{DMA2_Stream3, &DMA2->LIFCR, 22, 11, STM32_DMA2_CH3_NUMBER},
{DMA2_Stream4, &DMA2->HIFCR, 0, 12, STM32_DMA2_CH4_NUMBER},
{DMA2_Stream5, &DMA2->HIFCR, 6, 13, STM32_DMA2_CH5_NUMBER},
{DMA2_Stream6, &DMA2->HIFCR, 16, 14, STM32_DMA2_CH6_NUMBER},
{DMA2_Stream7, &DMA2->HIFCR, 22, 15, STM32_DMA2_CH7_NUMBER},
};
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/**
* @brief DMA ISR redirector type.
*/
typedef struct {
stm32_dmaisr_t dma_func; /**< @brief DMA callback function. */
void *dma_param; /**< @brief DMA callback parameter. */
} dma_isr_redir_t;
/**
* @brief Mask of the allocated streams.
*/
static uint32_t dma_streams_mask;
/**
* @brief DMA IRQ redirectors.
*/
static dma_isr_redir_t dma_isr_redir[STM32_DMA_STREAMS];
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/**
* @brief DMA1 stream 0 shared interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(STM32_DMA1_CH0_HANDLER) {
uint32_t flags;
OSAL_IRQ_PROLOGUE();
flags = (DMA1->LISR >> 0U) & STM32_DMA_ISR_MASK;
DMA1->LIFCR = flags << 0U;
if (dma_isr_redir[0].dma_func)
dma_isr_redir[0].dma_func(dma_isr_redir[0].dma_param, flags);
OSAL_IRQ_EPILOGUE();
}
/**
* @brief DMA1 stream 1 shared interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(STM32_DMA1_CH1_HANDLER) {
uint32_t flags;
OSAL_IRQ_PROLOGUE();
flags = (DMA1->LISR >> 6U) & STM32_DMA_ISR_MASK;
DMA1->LIFCR = flags << 6U;
if (dma_isr_redir[1].dma_func)
dma_isr_redir[1].dma_func(dma_isr_redir[1].dma_param, flags);
OSAL_IRQ_EPILOGUE();
}
/**
* @brief DMA1 stream 2 shared interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(STM32_DMA1_CH2_HANDLER) {
uint32_t flags;
OSAL_IRQ_PROLOGUE();
flags = (DMA1->LISR >> 16U) & STM32_DMA_ISR_MASK;
DMA1->LIFCR = flags << 16U;
if (dma_isr_redir[2].dma_func)
dma_isr_redir[2].dma_func(dma_isr_redir[2].dma_param, flags);
OSAL_IRQ_EPILOGUE();
}
/**
* @brief DMA1 stream 3 shared interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(STM32_DMA1_CH3_HANDLER) {
uint32_t flags;
OSAL_IRQ_PROLOGUE();
flags = (DMA1->LISR >> 22U) & STM32_DMA_ISR_MASK;
DMA1->LIFCR = flags << 22U;
if (dma_isr_redir[3].dma_func)
dma_isr_redir[3].dma_func(dma_isr_redir[3].dma_param, flags);
OSAL_IRQ_EPILOGUE();
}
/**
* @brief DMA1 stream 4 shared interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(STM32_DMA1_CH4_HANDLER) {
uint32_t flags;
OSAL_IRQ_PROLOGUE();
flags = (DMA1->HISR >> 0U) & STM32_DMA_ISR_MASK;
DMA1->HIFCR = flags << 0U;
if (dma_isr_redir[4].dma_func)
dma_isr_redir[4].dma_func(dma_isr_redir[4].dma_param, flags);
OSAL_IRQ_EPILOGUE();
}
/**
* @brief DMA1 stream 5 shared interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(STM32_DMA1_CH5_HANDLER) {
uint32_t flags;
OSAL_IRQ_PROLOGUE();
flags = (DMA1->HISR >> 6U) & STM32_DMA_ISR_MASK;
DMA1->HIFCR = flags << 6U;
if (dma_isr_redir[5].dma_func)
dma_isr_redir[5].dma_func(dma_isr_redir[5].dma_param, flags);
OSAL_IRQ_EPILOGUE();
}
/**
* @brief DMA1 stream 6 shared interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(STM32_DMA1_CH6_HANDLER) {
uint32_t flags;
OSAL_IRQ_PROLOGUE();
flags = (DMA1->HISR >> 16U) & STM32_DMA_ISR_MASK;
DMA1->HIFCR = flags << 16U;
if (dma_isr_redir[6].dma_func)
dma_isr_redir[6].dma_func(dma_isr_redir[6].dma_param, flags);
OSAL_IRQ_EPILOGUE();
}
/**
* @brief DMA1 stream 7 shared interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(STM32_DMA1_CH7_HANDLER) {
uint32_t flags;
OSAL_IRQ_PROLOGUE();
flags = (DMA1->HISR >> 22U) & STM32_DMA_ISR_MASK;
DMA1->HIFCR = flags << 22U;
if (dma_isr_redir[7].dma_func)
dma_isr_redir[7].dma_func(dma_isr_redir[7].dma_param, flags);
OSAL_IRQ_EPILOGUE();
}
/**
* @brief DMA2 stream 0 shared interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(STM32_DMA2_CH0_HANDLER) {
uint32_t flags;
OSAL_IRQ_PROLOGUE();
flags = (DMA2->LISR >> 0U) & STM32_DMA_ISR_MASK;
DMA2->LIFCR = flags << 0U;
if (dma_isr_redir[8].dma_func)
dma_isr_redir[8].dma_func(dma_isr_redir[8].dma_param, flags);
OSAL_IRQ_EPILOGUE();
}
/**
* @brief DMA2 stream 1 shared interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(STM32_DMA2_CH1_HANDLER) {
uint32_t flags;
OSAL_IRQ_PROLOGUE();
flags = (DMA2->LISR >> 6U) & STM32_DMA_ISR_MASK;
DMA2->LIFCR = flags << 6U;
if (dma_isr_redir[9].dma_func)
dma_isr_redir[9].dma_func(dma_isr_redir[9].dma_param, flags);
OSAL_IRQ_EPILOGUE();
}
/**
* @brief DMA2 stream 2 shared interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(STM32_DMA2_CH2_HANDLER) {
uint32_t flags;
OSAL_IRQ_PROLOGUE();
flags = (DMA2->LISR >> 16U) & STM32_DMA_ISR_MASK;
DMA2->LIFCR = flags << 16U;
if (dma_isr_redir[10].dma_func)
dma_isr_redir[10].dma_func(dma_isr_redir[10].dma_param, flags);
OSAL_IRQ_EPILOGUE();
}
/**
* @brief DMA2 stream 3 shared interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(STM32_DMA2_CH3_HANDLER) {
uint32_t flags;
OSAL_IRQ_PROLOGUE();
flags = (DMA2->LISR >> 22U) & STM32_DMA_ISR_MASK;
DMA2->LIFCR = flags << 22U;
if (dma_isr_redir[11].dma_func)
dma_isr_redir[11].dma_func(dma_isr_redir[11].dma_param, flags);
OSAL_IRQ_EPILOGUE();
}
/**
* @brief DMA2 stream 4 shared interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(STM32_DMA2_CH4_HANDLER) {
uint32_t flags;
OSAL_IRQ_PROLOGUE();
flags = (DMA2->HISR >> 0U) & STM32_DMA_ISR_MASK;
DMA2->HIFCR = flags << 0U;
if (dma_isr_redir[12].dma_func)
dma_isr_redir[12].dma_func(dma_isr_redir[12].dma_param, flags);
OSAL_IRQ_EPILOGUE();
}
/**
* @brief DMA2 stream 5 shared interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(STM32_DMA2_CH5_HANDLER) {
uint32_t flags;
OSAL_IRQ_PROLOGUE();
flags = (DMA2->HISR >> 6U) & STM32_DMA_ISR_MASK;
DMA2->HIFCR = flags << 6U;
if (dma_isr_redir[13].dma_func)
dma_isr_redir[13].dma_func(dma_isr_redir[13].dma_param, flags);
OSAL_IRQ_EPILOGUE();
}
/**
* @brief DMA2 stream 6 shared interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(STM32_DMA2_CH6_HANDLER) {
uint32_t flags;
OSAL_IRQ_PROLOGUE();
flags = (DMA2->HISR >> 16U) & STM32_DMA_ISR_MASK;
DMA2->HIFCR = flags << 16U;
if (dma_isr_redir[14].dma_func)
dma_isr_redir[14].dma_func(dma_isr_redir[14].dma_param, flags);
OSAL_IRQ_EPILOGUE();
}
/**
* @brief DMA2 stream 7 shared interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(STM32_DMA2_CH7_HANDLER) {
uint32_t flags;
OSAL_IRQ_PROLOGUE();
flags = (DMA2->HISR >> 22U) & STM32_DMA_ISR_MASK;
DMA2->HIFCR = flags << 22U;
if (dma_isr_redir[15].dma_func)
dma_isr_redir[15].dma_func(dma_isr_redir[15].dma_param, flags);
OSAL_IRQ_EPILOGUE();
}
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief STM32 DMA helper initialization.
*
* @init
*/
void dmaInit(void) {
unsigned i;
dma_streams_mask = 0U;
for (i = 0U; i < STM32_DMA_STREAMS; i++) {
_stm32_dma_streams[i].stream->CR = 0U;
dma_isr_redir[i].dma_func = NULL;
}
DMA1->LIFCR = 0xFFFFFFFFU;
DMA1->HIFCR = 0xFFFFFFFFU;
DMA2->LIFCR = 0xFFFFFFFFU;
DMA2->HIFCR = 0xFFFFFFFFU;
}
/**
* @brief Allocates a DMA stream.
* @details The stream is allocated and, if required, the DMA clock enabled.
* The function also enables the IRQ vector associated to the stream
* and initializes its priority.
* @pre The stream must not be already in use or an error is returned.
* @post The stream is allocated and the default ISR handler redirected
* to the specified function.
* @post The stream ISR vector is enabled and its priority configured.
* @post The stream must be freed using @p dmaStreamRelease() before it can
* be reused with another peripheral.
* @post The stream is in its post-reset state.
* @note This function can be invoked in both ISR or thread context.
*
* @param[in] dmastp pointer to a stm32_dma_stream_t structure
* @param[in] priority IRQ priority mask for the DMA stream
* @param[in] func handling function pointer, can be @p NULL
* @param[in] param a parameter to be passed to the handling function
* @return The operation status.
* @retval false no error, stream taken.
* @retval true error, stream already taken.
*
* @special
*/
bool dmaStreamAllocate(const stm32_dma_stream_t *dmastp,
uint32_t priority,
stm32_dmaisr_t func,
void *param) {
osalDbgCheck(dmastp != NULL);
/* Checks if the stream is already taken.*/
if ((dma_streams_mask & (1U << dmastp->selfindex)) != 0U)
return true;
/* Marks the stream as allocated.*/
dma_isr_redir[dmastp->selfindex].dma_func = func;
dma_isr_redir[dmastp->selfindex].dma_param = param;
dma_streams_mask |= (1U << dmastp->selfindex);
/* Enabling DMA clocks required by the current streams set.*/
if ((dma_streams_mask & STM32_DMA1_STREAMS_MASK) != 0U) {
rccEnableDMA1(false);
}
if ((dma_streams_mask & STM32_DMA2_STREAMS_MASK) != 0U) {
rccEnableDMA2(false);
}
/* Putting the stream in a safe state.*/
dmaStreamDisable(dmastp);
dmastp->stream->CR = STM32_DMA_CR_RESET_VALUE;
dmastp->stream->FCR = STM32_DMA_FCR_RESET_VALUE;
/* Enables the associated IRQ vector if a callback is defined.*/
if (func != NULL) {
nvicEnableVector(dmastp->vector, priority);
}
return false;
}
/**
* @brief Releases a DMA stream.
* @details The stream is freed and, if required, the DMA clock disabled.
* Trying to release a unallocated stream is an illegal operation
* and is trapped if assertions are enabled.
* @pre The stream must have been allocated using @p dmaStreamAllocate().
* @post The stream is again available.
* @note This function can be invoked in both ISR or thread context.
*
* @param[in] dmastp pointer to a stm32_dma_stream_t structure
*
* @special
*/
void dmaStreamRelease(const stm32_dma_stream_t *dmastp) {
osalDbgCheck(dmastp != NULL);
/* Check if the streams is not taken.*/
osalDbgAssert((dma_streams_mask & (1U << dmastp->selfindex)) != 0U,
"not allocated");
/* Disables the associated IRQ vector.*/
nvicDisableVector(dmastp->vector);
/* Marks the stream as not allocated.*/
dma_streams_mask &= ~(1U << dmastp->selfindex);
/* Shutting down clocks that are no more required, if any.*/
if ((dma_streams_mask & STM32_DMA1_STREAMS_MASK) == 0U) {
rccDisableDMA1(false);
}
if ((dma_streams_mask & STM32_DMA2_STREAMS_MASK) == 0U) {
rccDisableDMA2(false);
}
}
#endif /* STM32_DMA_REQUIRED */
/** @} */

View File

@ -0,0 +1,757 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file STM32/mac_lld.c
* @brief STM32 low level MAC driver code.
*
* @addtogroup MAC
* @{
*/
#include <string.h>
#include "hal.h"
#if HAL_USE_MAC || defined(__DOXYGEN__)
#include "mii.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
#define BUFFER_SIZE ((((STM32_MAC_BUFFERS_SIZE - 1) | 3) + 1) / 4)
/* Fixing inconsistencies in ST headers.*/
#if !defined(ETH_MACMIIAR_CR_Div102) && defined(ETH_MACMIIAR_CR_DIV102)
#define ETH_MACMIIAR_CR_Div102 ETH_MACMIIAR_CR_DIV102
#endif
#if !defined(ETH_MACMIIAR_CR_Div62) && defined(ETH_MACMIIAR_CR_DIV62)
#define ETH_MACMIIAR_CR_Div62 ETH_MACMIIAR_CR_DIV62
#endif
#if !defined(ETH_MACMIIAR_CR_Div42) && defined(ETH_MACMIIAR_CR_DIV42)
#define ETH_MACMIIAR_CR_Div42 ETH_MACMIIAR_CR_DIV42
#endif
#if !defined(ETH_MACMIIAR_CR_Div26) && defined(ETH_MACMIIAR_CR_DIV26)
#define ETH_MACMIIAR_CR_Div26 ETH_MACMIIAR_CR_DIV26
#endif
#if !defined(ETH_MACMIIAR_CR_Div16) && defined(ETH_MACMIIAR_CR_DIV16)
#define ETH_MACMIIAR_CR_Div16 ETH_MACMIIAR_CR_DIV16
#endif
/* MII divider optimal value.*/
#if (STM32_HCLK >= 150000000)
#define MACMIIDR_CR ETH_MACMIIAR_CR_Div102
#elif (STM32_HCLK >= 100000000)
#define MACMIIDR_CR ETH_MACMIIAR_CR_Div62
#elif (STM32_HCLK >= 60000000)
#define MACMIIDR_CR ETH_MACMIIAR_CR_Div42
#elif (STM32_HCLK >= 35000000)
#define MACMIIDR_CR ETH_MACMIIAR_CR_Div26
#elif (STM32_HCLK >= 20000000)
#define MACMIIDR_CR ETH_MACMIIAR_CR_Div16
#else
#error "STM32_HCLK below minimum frequency for ETH operations (20MHz)"
#endif
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief Ethernet driver 1.
*/
MACDriver ETHD1;
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
static const uint8_t default_mac_address[] = {0xAA, 0x55, 0x13,
0x37, 0x01, 0x10};
static stm32_eth_rx_descriptor_t __eth_rd[STM32_MAC_RECEIVE_BUFFERS];
static stm32_eth_tx_descriptor_t __eth_td[STM32_MAC_TRANSMIT_BUFFERS];
static uint32_t __eth_rb[STM32_MAC_RECEIVE_BUFFERS][BUFFER_SIZE];
static uint32_t __eth_tb[STM32_MAC_TRANSMIT_BUFFERS][BUFFER_SIZE];
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Writes a PHY register.
*
* @param[in] macp pointer to the @p MACDriver object
* @param[in] reg register number
* @param[in] value new register value
*
* @notapi
*/
void mii_write(MACDriver *macp, uint32_t reg, uint32_t value) {
ETH->MACMIIDR = value;
ETH->MACMIIAR = macp->phyaddr | (reg << 6) | MACMIIDR_CR |
ETH_MACMIIAR_MW | ETH_MACMIIAR_MB;
while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) != 0)
;
}
/**
* @brief Reads a PHY register.
*
* @param[in] macp pointer to the @p MACDriver object
* @param[in] reg register number
*
* @return The PHY register content.
*
* @notapi
*/
uint32_t mii_read(MACDriver *macp, uint32_t reg) {
ETH->MACMIIAR = macp->phyaddr | (reg << 6) | MACMIIDR_CR | ETH_MACMIIAR_MB;
while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) != 0)
;
return ETH->MACMIIDR;
}
#if !defined(BOARD_PHY_ADDRESS)
/**
* @brief PHY address detection.
*
* @param[in] macp pointer to the @p MACDriver object
*/
static void mii_find_phy(MACDriver *macp) {
uint32_t i;
#if STM32_MAC_PHY_TIMEOUT > 0
unsigned n = STM32_MAC_PHY_TIMEOUT;
do {
#endif
for (i = 0U; i < 31U; i++) {
macp->phyaddr = i << 11U;
ETH->MACMIIDR = (i << 6U) | MACMIIDR_CR;
if ((mii_read(macp, MII_PHYSID1) == (BOARD_PHY_ID >> 16U)) &&
((mii_read(macp, MII_PHYSID2) & 0xFFF0U) == (BOARD_PHY_ID & 0xFFF0U))) {
return;
}
}
#if STM32_MAC_PHY_TIMEOUT > 0
n--;
} while (n > 0U);
#endif
/* Wrong or defective board.*/
osalSysHalt("MAC failure");
}
#endif
/**
* @brief MAC address setup.
*
* @param[in] p pointer to a six bytes buffer containing the MAC
* address
*/
static void mac_lld_set_address(const uint8_t *p) {
/* MAC address configuration, only a single address comparator is used,
hash table not used.*/
ETH->MACA0HR = ((uint32_t)p[5] << 8) |
((uint32_t)p[4] << 0);
ETH->MACA0LR = ((uint32_t)p[3] << 24) |
((uint32_t)p[2] << 16) |
((uint32_t)p[1] << 8) |
((uint32_t)p[0] << 0);
ETH->MACA1HR = 0x0000FFFF;
ETH->MACA1LR = 0xFFFFFFFF;
ETH->MACA2HR = 0x0000FFFF;
ETH->MACA2LR = 0xFFFFFFFF;
ETH->MACA3HR = 0x0000FFFF;
ETH->MACA3LR = 0xFFFFFFFF;
ETH->MACHTHR = 0;
ETH->MACHTLR = 0;
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
OSAL_IRQ_HANDLER(STM32_ETH_HANDLER) {
uint32_t dmasr;
OSAL_IRQ_PROLOGUE();
dmasr = ETH->DMASR;
ETH->DMASR = dmasr; /* Clear status bits.*/
if (dmasr & ETH_DMASR_RS) {
/* Data Received.*/
osalSysLockFromISR();
osalThreadDequeueAllI(&ETHD1.rdqueue, MSG_RESET);
#if MAC_USE_EVENTS
osalEventBroadcastFlagsI(&ETHD1.rdevent, 0);
#endif
osalSysUnlockFromISR();
}
if (dmasr & ETH_DMASR_TS) {
/* Data Transmitted.*/
osalSysLockFromISR();
osalThreadDequeueAllI(&ETHD1.tdqueue, MSG_RESET);
osalSysUnlockFromISR();
}
OSAL_IRQ_EPILOGUE();
}
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level MAC initialization.
*
* @notapi
*/
void mac_lld_init(void) {
unsigned i;
macObjectInit(&ETHD1);
ETHD1.link_up = false;
/* Descriptor tables are initialized in chained mode, note that the first
word is not initialized here but in mac_lld_start().*/
for (i = 0; i < STM32_MAC_RECEIVE_BUFFERS; i++) {
__eth_rd[i].rdes1 = STM32_RDES1_RCH | STM32_MAC_BUFFERS_SIZE;
__eth_rd[i].rdes2 = (uint32_t)__eth_rb[i];
__eth_rd[i].rdes3 = (uint32_t)&__eth_rd[(i + 1) % STM32_MAC_RECEIVE_BUFFERS];
}
for (i = 0; i < STM32_MAC_TRANSMIT_BUFFERS; i++) {
__eth_td[i].tdes1 = 0;
__eth_td[i].tdes2 = (uint32_t)__eth_tb[i];
__eth_td[i].tdes3 = (uint32_t)&__eth_td[(i + 1) % STM32_MAC_TRANSMIT_BUFFERS];
}
/* Selection of the RMII or MII mode based on info exported by board.h.*/
#if defined(STM32F10X_CL)
#if defined(BOARD_PHY_RMII)
AFIO->MAPR |= AFIO_MAPR_MII_RMII_SEL;
#else
AFIO->MAPR &= ~AFIO_MAPR_MII_RMII_SEL;
#endif
#elif defined(STM32F2XX) || defined(STM32F4XX) || defined(STM32F7XX)
#if defined(BOARD_PHY_RMII)
SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL;
#else
SYSCFG->PMC &= ~SYSCFG_PMC_MII_RMII_SEL;
#endif
#else
#error "unsupported STM32 platform for MAC driver"
#endif
/* Reset of the MAC core.*/
rccResetETH();
/* MAC clocks temporary activation.*/
rccEnableETH(false);
/* PHY address setup.*/
#if defined(BOARD_PHY_ADDRESS)
ETHD1.phyaddr = BOARD_PHY_ADDRESS << 11;
#else
mii_find_phy(&ETHD1);
#endif
#if defined(BOARD_PHY_RESET)
/* PHY board-specific reset procedure.*/
BOARD_PHY_RESET();
#else
/* PHY soft reset procedure.*/
mii_write(&ETHD1, MII_BMCR, BMCR_RESET);
#if defined(BOARD_PHY_RESET_DELAY)
osalSysPolledDelayX(BOARD_PHY_RESET_DELAY);
#endif
while (mii_read(&ETHD1, MII_BMCR) & BMCR_RESET)
;
#endif
#if STM32_MAC_ETH1_CHANGE_PHY_STATE
/* PHY in power down mode until the driver will be started.*/
mii_write(&ETHD1, MII_BMCR, mii_read(&ETHD1, MII_BMCR) | BMCR_PDOWN);
#endif
/* MAC clocks stopped again.*/
rccDisableETH(false);
}
/**
* @brief Configures and activates the MAC peripheral.
*
* @param[in] macp pointer to the @p MACDriver object
*
* @notapi
*/
void mac_lld_start(MACDriver *macp) {
unsigned i;
/* Resets the state of all descriptors.*/
for (i = 0; i < STM32_MAC_RECEIVE_BUFFERS; i++)
__eth_rd[i].rdes0 = STM32_RDES0_OWN;
macp->rxptr = (stm32_eth_rx_descriptor_t *)__eth_rd;
for (i = 0; i < STM32_MAC_TRANSMIT_BUFFERS; i++)
__eth_td[i].tdes0 = STM32_TDES0_TCH;
macp->txptr = (stm32_eth_tx_descriptor_t *)__eth_td;
/* MAC clocks activation and commanded reset procedure.*/
rccEnableETH(false);
#if defined(STM32_MAC_DMABMR_SR)
ETH->DMABMR |= ETH_DMABMR_SR;
while(ETH->DMABMR & ETH_DMABMR_SR)
;
#endif
/* ISR vector enabled.*/
nvicEnableVector(STM32_ETH_NUMBER, STM32_MAC_ETH1_IRQ_PRIORITY);
#if STM32_MAC_ETH1_CHANGE_PHY_STATE
/* PHY in power up mode.*/
mii_write(macp, MII_BMCR, mii_read(macp, MII_BMCR) & ~BMCR_PDOWN);
#endif
/* MAC configuration.*/
ETH->MACFFR = 0;
ETH->MACFCR = 0;
ETH->MACVLANTR = 0;
/* MAC address setup.*/
if (macp->config->mac_address == NULL)
mac_lld_set_address(default_mac_address);
else
mac_lld_set_address(macp->config->mac_address);
/* Transmitter and receiver enabled.
Note that the complete setup of the MAC is performed when the link
status is detected.*/
#if STM32_MAC_IP_CHECKSUM_OFFLOAD
ETH->MACCR = ETH_MACCR_IPCO | ETH_MACCR_RE | ETH_MACCR_TE;
#else
ETH->MACCR = ETH_MACCR_RE | ETH_MACCR_TE;
#endif
/* DMA configuration:
Descriptor chains pointers.*/
ETH->DMARDLAR = (uint32_t)__eth_rd;
ETH->DMATDLAR = (uint32_t)__eth_td;
/* Enabling required interrupt sources.*/
ETH->DMASR = ETH->DMASR;
ETH->DMAIER = ETH_DMAIER_NISE | ETH_DMAIER_RIE | ETH_DMAIER_TIE;
/* DMA general settings.*/
ETH->DMABMR = ETH_DMABMR_AAB | ETH_DMABMR_RDP_1Beat | ETH_DMABMR_PBL_1Beat;
/* Transmit FIFO flush.*/
ETH->DMAOMR = ETH_DMAOMR_FTF;
while (ETH->DMAOMR & ETH_DMAOMR_FTF)
;
/* DMA final configuration and start.*/
ETH->DMAOMR = ETH_DMAOMR_DTCEFD | ETH_DMAOMR_RSF | ETH_DMAOMR_TSF |
ETH_DMAOMR_ST | ETH_DMAOMR_SR;
}
/**
* @brief Deactivates the MAC peripheral.
*
* @param[in] macp pointer to the @p MACDriver object
*
* @notapi
*/
void mac_lld_stop(MACDriver *macp) {
if (macp->state != MAC_STOP) {
#if STM32_MAC_ETH1_CHANGE_PHY_STATE
/* PHY in power down mode until the driver will be restarted.*/
mii_write(macp, MII_BMCR, mii_read(macp, MII_BMCR) | BMCR_PDOWN);
#endif
/* MAC and DMA stopped.*/
ETH->MACCR = 0;
ETH->DMAOMR = 0;
ETH->DMAIER = 0;
ETH->DMASR = ETH->DMASR;
/* MAC clocks stopped.*/
rccDisableETH(false);
/* ISR vector disabled.*/
nvicDisableVector(STM32_ETH_NUMBER);
}
}
/**
* @brief Returns a transmission descriptor.
* @details One of the available transmission descriptors is locked and
* returned.
*
* @param[in] macp pointer to the @p MACDriver object
* @param[out] tdp pointer to a @p MACTransmitDescriptor structure
* @return The operation status.
* @retval MSG_OK the descriptor has been obtained.
* @retval MSG_TIMEOUT descriptor not available.
*
* @notapi
*/
msg_t mac_lld_get_transmit_descriptor(MACDriver *macp,
MACTransmitDescriptor *tdp) {
stm32_eth_tx_descriptor_t *tdes;
if (!macp->link_up)
return MSG_TIMEOUT;
osalSysLock();
/* Get Current TX descriptor.*/
tdes = macp->txptr;
/* Ensure that descriptor isn't owned by the Ethernet DMA or locked by
another thread.*/
if (tdes->tdes0 & (STM32_TDES0_OWN | STM32_TDES0_LOCKED)) {
osalSysUnlock();
return MSG_TIMEOUT;
}
/* Marks the current descriptor as locked using a reserved bit.*/
tdes->tdes0 |= STM32_TDES0_LOCKED;
/* Next TX descriptor to use.*/
macp->txptr = (stm32_eth_tx_descriptor_t *)tdes->tdes3;
osalSysUnlock();
/* Set the buffer size and configuration.*/
tdp->offset = 0;
tdp->size = STM32_MAC_BUFFERS_SIZE;
tdp->physdesc = tdes;
return MSG_OK;
}
/**
* @brief Releases a transmit descriptor and starts the transmission of the
* enqueued data as a single frame.
*
* @param[in] tdp the pointer to the @p MACTransmitDescriptor structure
*
* @notapi
*/
void mac_lld_release_transmit_descriptor(MACTransmitDescriptor *tdp) {
osalDbgAssert(!(tdp->physdesc->tdes0 & STM32_TDES0_OWN),
"attempt to release descriptor already owned by DMA");
osalSysLock();
/* Unlocks the descriptor and returns it to the DMA engine.*/
tdp->physdesc->tdes1 = tdp->offset;
tdp->physdesc->tdes0 = STM32_TDES0_CIC(STM32_MAC_IP_CHECKSUM_OFFLOAD) |
STM32_TDES0_IC | STM32_TDES0_LS | STM32_TDES0_FS |
STM32_TDES0_TCH | STM32_TDES0_OWN;
/* If the DMA engine is stalled then a restart request is issued.*/
if ((ETH->DMASR & ETH_DMASR_TPS) == ETH_DMASR_TPS_Suspended) {
ETH->DMASR = ETH_DMASR_TBUS;
ETH->DMATPDR = ETH_DMASR_TBUS; /* Any value is OK.*/
}
osalSysUnlock();
}
/**
* @brief Returns a receive descriptor.
*
* @param[in] macp pointer to the @p MACDriver object
* @param[out] rdp pointer to a @p MACReceiveDescriptor structure
* @return The operation status.
* @retval MSG_OK the descriptor has been obtained.
* @retval MSG_TIMEOUT descriptor not available.
*
* @notapi
*/
msg_t mac_lld_get_receive_descriptor(MACDriver *macp,
MACReceiveDescriptor *rdp) {
stm32_eth_rx_descriptor_t *rdes;
osalSysLock();
/* Get Current RX descriptor.*/
rdes = macp->rxptr;
/* Iterates through received frames until a valid one is found, invalid
frames are discarded.*/
while (!(rdes->rdes0 & STM32_RDES0_OWN)) {
if (!(rdes->rdes0 & (STM32_RDES0_AFM | STM32_RDES0_ES))
#if STM32_MAC_IP_CHECKSUM_OFFLOAD
&& (rdes->rdes0 & STM32_RDES0_FT)
&& !(rdes->rdes0 & (STM32_RDES0_IPHCE | STM32_RDES0_PCE))
#endif
&& (rdes->rdes0 & STM32_RDES0_FS) && (rdes->rdes0 & STM32_RDES0_LS)) {
/* Found a valid one.*/
rdp->offset = 0;
rdp->size = ((rdes->rdes0 & STM32_RDES0_FL_MASK) >> 16) - 4;
rdp->physdesc = rdes;
macp->rxptr = (stm32_eth_rx_descriptor_t *)rdes->rdes3;
osalSysUnlock();
return MSG_OK;
}
/* Invalid frame found, purging.*/
rdes->rdes0 = STM32_RDES0_OWN;
rdes = (stm32_eth_rx_descriptor_t *)rdes->rdes3;
}
/* Next descriptor to check.*/
macp->rxptr = rdes;
osalSysUnlock();
return MSG_TIMEOUT;
}
/**
* @brief Releases a receive descriptor.
* @details The descriptor and its buffer are made available for more incoming
* frames.
*
* @param[in] rdp the pointer to the @p MACReceiveDescriptor structure
*
* @notapi
*/
void mac_lld_release_receive_descriptor(MACReceiveDescriptor *rdp) {
osalDbgAssert(!(rdp->physdesc->rdes0 & STM32_RDES0_OWN),
"attempt to release descriptor already owned by DMA");
osalSysLock();
/* Give buffer back to the Ethernet DMA.*/
rdp->physdesc->rdes0 = STM32_RDES0_OWN;
/* If the DMA engine is stalled then a restart request is issued.*/
if ((ETH->DMASR & ETH_DMASR_RPS) == ETH_DMASR_RPS_Suspended) {
ETH->DMASR = ETH_DMASR_RBUS;
ETH->DMARPDR = ETH_DMASR_RBUS; /* Any value is OK.*/
}
osalSysUnlock();
}
/**
* @brief Updates and returns the link status.
*
* @param[in] macp pointer to the @p MACDriver object
* @return The link status.
* @retval true if the link is active.
* @retval false if the link is down.
*
* @notapi
*/
bool mac_lld_poll_link_status(MACDriver *macp) {
uint32_t maccr, bmsr, bmcr;
maccr = ETH->MACCR;
/* PHY CR and SR registers read.*/
(void)mii_read(macp, MII_BMSR);
bmsr = mii_read(macp, MII_BMSR);
bmcr = mii_read(macp, MII_BMCR);
/* Check on auto-negotiation mode.*/
if (bmcr & BMCR_ANENABLE) {
uint32_t lpa;
/* Auto-negotiation must be finished without faults and link established.*/
if ((bmsr & (BMSR_LSTATUS | BMSR_RFAULT | BMSR_ANEGCOMPLETE)) !=
(BMSR_LSTATUS | BMSR_ANEGCOMPLETE))
return macp->link_up = false;
/* Auto-negotiation enabled, checks the LPA register.*/
lpa = mii_read(macp, MII_LPA);
/* Check on link speed.*/
if (lpa & (LPA_100HALF | LPA_100FULL | LPA_100BASE4))
maccr |= ETH_MACCR_FES;
else
maccr &= ~ETH_MACCR_FES;
/* Check on link mode.*/
if (lpa & (LPA_10FULL | LPA_100FULL))
maccr |= ETH_MACCR_DM;
else
maccr &= ~ETH_MACCR_DM;
}
else {
/* Link must be established.*/
if (!(bmsr & BMSR_LSTATUS))
return macp->link_up = false;
/* Check on link speed.*/
if (bmcr & BMCR_SPEED100)
maccr |= ETH_MACCR_FES;
else
maccr &= ~ETH_MACCR_FES;
/* Check on link mode.*/
if (bmcr & BMCR_FULLDPLX)
maccr |= ETH_MACCR_DM;
else
maccr &= ~ETH_MACCR_DM;
}
/* Changes the mode in the MAC.*/
ETH->MACCR = maccr;
/* Returns the link status.*/
return macp->link_up = true;
}
/**
* @brief Writes to a transmit descriptor's stream.
*
* @param[in] tdp pointer to a @p MACTransmitDescriptor structure
* @param[in] buf pointer to the buffer containing the data to be
* written
* @param[in] size number of bytes to be written
* @return The number of bytes written into the descriptor's
* stream, this value can be less than the amount
* specified in the parameter @p size if the maximum
* frame size is reached.
*
* @notapi
*/
size_t mac_lld_write_transmit_descriptor(MACTransmitDescriptor *tdp,
uint8_t *buf,
size_t size) {
osalDbgAssert(!(tdp->physdesc->tdes0 & STM32_TDES0_OWN),
"attempt to write descriptor already owned by DMA");
if (size > tdp->size - tdp->offset)
size = tdp->size - tdp->offset;
if (size > 0) {
memcpy((uint8_t *)(tdp->physdesc->tdes2) + tdp->offset, buf, size);
tdp->offset += size;
}
return size;
}
/**
* @brief Reads from a receive descriptor's stream.
*
* @param[in] rdp pointer to a @p MACReceiveDescriptor structure
* @param[in] buf pointer to the buffer that will receive the read data
* @param[in] size number of bytes to be read
* @return The number of bytes read from the descriptor's
* stream, this value can be less than the amount
* specified in the parameter @p size if there are
* no more bytes to read.
*
* @notapi
*/
size_t mac_lld_read_receive_descriptor(MACReceiveDescriptor *rdp,
uint8_t *buf,
size_t size) {
osalDbgAssert(!(rdp->physdesc->rdes0 & STM32_RDES0_OWN),
"attempt to read descriptor already owned by DMA");
if (size > rdp->size - rdp->offset)
size = rdp->size - rdp->offset;
if (size > 0) {
memcpy(buf, (uint8_t *)(rdp->physdesc->rdes2) + rdp->offset, size);
rdp->offset += size;
}
return size;
}
#if MAC_USE_ZERO_COPY || defined(__DOXYGEN__)
/**
* @brief Returns a pointer to the next transmit buffer in the descriptor
* chain.
* @note The API guarantees that enough buffers can be requested to fill
* a whole frame.
*
* @param[in] tdp pointer to a @p MACTransmitDescriptor structure
* @param[in] size size of the requested buffer. Specify the frame size
* on the first call then scale the value down subtracting
* the amount of data already copied into the previous
* buffers.
* @param[out] sizep pointer to variable receiving the buffer size, it is
* zero when the last buffer has already been returned.
* Note that a returned size lower than the amount
* requested means that more buffers must be requested
* in order to fill the frame data entirely.
* @return Pointer to the returned buffer.
* @retval NULL if the buffer chain has been entirely scanned.
*
* @notapi
*/
uint8_t *mac_lld_get_next_transmit_buffer(MACTransmitDescriptor *tdp,
size_t size,
size_t *sizep) {
if (tdp->offset == 0) {
*sizep = tdp->size;
tdp->offset = size;
return (uint8_t *)tdp->physdesc->tdes2;
}
*sizep = 0;
return NULL;
}
/**
* @brief Returns a pointer to the next receive buffer in the descriptor
* chain.
* @note The API guarantees that the descriptor chain contains a whole
* frame.
*
* @param[in] rdp pointer to a @p MACReceiveDescriptor structure
* @param[out] sizep pointer to variable receiving the buffer size, it is
* zero when the last buffer has already been returned.
* @return Pointer to the returned buffer.
* @retval NULL if the buffer chain has been entirely scanned.
*
* @notapi
*/
const uint8_t *mac_lld_get_next_receive_buffer(MACReceiveDescriptor *rdp,
size_t *sizep) {
if (rdp->size > 0) {
*sizep = rdp->size;
rdp->offset = rdp->size;
rdp->size = 0;
return (uint8_t *)rdp->physdesc->rdes2;
}
*sizep = 0;
return NULL;
}
#endif /* MAC_USE_ZERO_COPY */
#endif /* HAL_USE_MAC */
/** @} */

View File

@ -0,0 +1,635 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file STM32/SPIv1/spi_lld.c
* @brief STM32 SPI subsystem low level driver source.
*
* @addtogroup SPI
* @{
*/
#include "hal.h"
#if HAL_USE_SPI || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
#define SPI1_RX_DMA_CHANNEL \
STM32_DMA_GETCHANNEL(STM32_SPI_SPI1_RX_DMA_STREAM, \
STM32_SPI1_RX_DMA_CHN)
#define SPI1_TX_DMA_CHANNEL \
STM32_DMA_GETCHANNEL(STM32_SPI_SPI1_TX_DMA_STREAM, \
STM32_SPI1_TX_DMA_CHN)
#define SPI2_RX_DMA_CHANNEL \
STM32_DMA_GETCHANNEL(STM32_SPI_SPI2_RX_DMA_STREAM, \
STM32_SPI2_RX_DMA_CHN)
#define SPI2_TX_DMA_CHANNEL \
STM32_DMA_GETCHANNEL(STM32_SPI_SPI2_TX_DMA_STREAM, \
STM32_SPI2_TX_DMA_CHN)
#define SPI3_RX_DMA_CHANNEL \
STM32_DMA_GETCHANNEL(STM32_SPI_SPI3_RX_DMA_STREAM, \
STM32_SPI3_RX_DMA_CHN)
#define SPI3_TX_DMA_CHANNEL \
STM32_DMA_GETCHANNEL(STM32_SPI_SPI3_TX_DMA_STREAM, \
STM32_SPI3_TX_DMA_CHN)
#define SPI4_RX_DMA_CHANNEL \
STM32_DMA_GETCHANNEL(STM32_SPI_SPI4_RX_DMA_STREAM, \
STM32_SPI4_RX_DMA_CHN)
#define SPI4_TX_DMA_CHANNEL \
STM32_DMA_GETCHANNEL(STM32_SPI_SPI4_TX_DMA_STREAM, \
STM32_SPI4_TX_DMA_CHN)
#define SPI5_RX_DMA_CHANNEL \
STM32_DMA_GETCHANNEL(STM32_SPI_SPI5_RX_DMA_STREAM, \
STM32_SPI5_RX_DMA_CHN)
#define SPI5_TX_DMA_CHANNEL \
STM32_DMA_GETCHANNEL(STM32_SPI_SPI5_TX_DMA_STREAM, \
STM32_SPI5_TX_DMA_CHN)
#define SPI6_RX_DMA_CHANNEL \
STM32_DMA_GETCHANNEL(STM32_SPI_SPI6_RX_DMA_STREAM, \
STM32_SPI6_RX_DMA_CHN)
#define SPI6_TX_DMA_CHANNEL \
STM32_DMA_GETCHANNEL(STM32_SPI_SPI6_TX_DMA_STREAM, \
STM32_SPI6_TX_DMA_CHN)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/** @brief SPI1 driver identifier.*/
#if STM32_SPI_USE_SPI1 || defined(__DOXYGEN__)
SPIDriver SPID1;
#endif
/** @brief SPI2 driver identifier.*/
#if STM32_SPI_USE_SPI2 || defined(__DOXYGEN__)
SPIDriver SPID2;
#endif
/** @brief SPI3 driver identifier.*/
#if STM32_SPI_USE_SPI3 || defined(__DOXYGEN__)
SPIDriver SPID3;
#endif
/** @brief SPI4 driver identifier.*/
#if STM32_SPI_USE_SPI4 || defined(__DOXYGEN__)
SPIDriver SPID4;
#endif
/** @brief SPI5 driver identifier.*/
#if STM32_SPI_USE_SPI5 || defined(__DOXYGEN__)
SPIDriver SPID5;
#endif
/** @brief SPI6 driver identifier.*/
#if STM32_SPI_USE_SPI6 || defined(__DOXYGEN__)
SPIDriver SPID6;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
static uint16_t dummytx;
static uint16_t dummyrx;
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Shared end-of-rx service routine.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] flags pre-shifted content of the ISR register
*/
static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags) {
/* DMA errors handling.*/
#if defined(STM32_SPI_DMA_ERROR_HOOK)
if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
STM32_SPI_DMA_ERROR_HOOK(spip);
}
#else
(void)flags;
#endif
/* Stop everything.*/
dmaStreamDisable(spip->dmatx);
dmaStreamDisable(spip->dmarx);
/* Portable SPI ISR code defined in the high level driver, note, it is
a macro.*/
_spi_isr_code(spip);
}
/**
* @brief Shared end-of-tx service routine.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] flags pre-shifted content of the ISR register
*/
static void spi_lld_serve_tx_interrupt(SPIDriver *spip, uint32_t flags) {
/* DMA errors handling.*/
#if defined(STM32_SPI_DMA_ERROR_HOOK)
(void)spip;
if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
STM32_SPI_DMA_ERROR_HOOK(spip);
}
#else
(void)spip;
(void)flags;
#endif
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level SPI driver initialization.
*
* @notapi
*/
void spi_lld_init(void) {
dummytx = 0xFFFF;
#if STM32_SPI_USE_SPI1
spiObjectInit(&SPID1);
SPID1.spi = SPI1;
SPID1.dmarx = STM32_DMA_STREAM(STM32_SPI_SPI1_RX_DMA_STREAM);
SPID1.dmatx = STM32_DMA_STREAM(STM32_SPI_SPI1_TX_DMA_STREAM);
SPID1.rxdmamode = STM32_DMA_CR_CHSEL(SPI1_RX_DMA_CHANNEL) |
STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) |
STM32_DMA_CR_DIR_P2M |
STM32_DMA_CR_TCIE |
STM32_DMA_CR_DMEIE |
STM32_DMA_CR_TEIE;
SPID1.txdmamode = STM32_DMA_CR_CHSEL(SPI1_TX_DMA_CHANNEL) |
STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) |
STM32_DMA_CR_DIR_M2P |
STM32_DMA_CR_DMEIE |
STM32_DMA_CR_TEIE;
#endif
#if STM32_SPI_USE_SPI2
spiObjectInit(&SPID2);
SPID2.spi = SPI2;
SPID2.dmarx = STM32_DMA_STREAM(STM32_SPI_SPI2_RX_DMA_STREAM);
SPID2.dmatx = STM32_DMA_STREAM(STM32_SPI_SPI2_TX_DMA_STREAM);
SPID2.rxdmamode = STM32_DMA_CR_CHSEL(SPI2_RX_DMA_CHANNEL) |
STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) |
STM32_DMA_CR_DIR_P2M |
STM32_DMA_CR_TCIE |
STM32_DMA_CR_DMEIE |
STM32_DMA_CR_TEIE;
SPID2.txdmamode = STM32_DMA_CR_CHSEL(SPI2_TX_DMA_CHANNEL) |
STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) |
STM32_DMA_CR_DIR_M2P |
STM32_DMA_CR_DMEIE |
STM32_DMA_CR_TEIE;
#endif
#if STM32_SPI_USE_SPI3
spiObjectInit(&SPID3);
SPID3.spi = SPI3;
SPID3.dmarx = STM32_DMA_STREAM(STM32_SPI_SPI3_RX_DMA_STREAM);
SPID3.dmatx = STM32_DMA_STREAM(STM32_SPI_SPI3_TX_DMA_STREAM);
SPID3.rxdmamode = STM32_DMA_CR_CHSEL(SPI3_RX_DMA_CHANNEL) |
STM32_DMA_CR_PL(STM32_SPI_SPI3_DMA_PRIORITY) |
STM32_DMA_CR_DIR_P2M |
STM32_DMA_CR_TCIE |
STM32_DMA_CR_DMEIE |
STM32_DMA_CR_TEIE;
SPID3.txdmamode = STM32_DMA_CR_CHSEL(SPI3_TX_DMA_CHANNEL) |
STM32_DMA_CR_PL(STM32_SPI_SPI3_DMA_PRIORITY) |
STM32_DMA_CR_DIR_M2P |
STM32_DMA_CR_DMEIE |
STM32_DMA_CR_TEIE;
#endif
#if STM32_SPI_USE_SPI4
spiObjectInit(&SPID4);
SPID4.spi = SPI4;
SPID4.dmarx = STM32_DMA_STREAM(STM32_SPI_SPI4_RX_DMA_STREAM);
SPID4.dmatx = STM32_DMA_STREAM(STM32_SPI_SPI4_TX_DMA_STREAM);
SPID4.rxdmamode = STM32_DMA_CR_CHSEL(SPI4_RX_DMA_CHANNEL) |
STM32_DMA_CR_PL(STM32_SPI_SPI4_DMA_PRIORITY) |
STM32_DMA_CR_DIR_P2M |
STM32_DMA_CR_TCIE |
STM32_DMA_CR_DMEIE |
STM32_DMA_CR_TEIE;
SPID4.txdmamode = STM32_DMA_CR_CHSEL(SPI4_TX_DMA_CHANNEL) |
STM32_DMA_CR_PL(STM32_SPI_SPI4_DMA_PRIORITY) |
STM32_DMA_CR_DIR_M2P |
STM32_DMA_CR_DMEIE |
STM32_DMA_CR_TEIE;
#endif
#if STM32_SPI_USE_SPI5
spiObjectInit(&SPID5);
SPID5.spi = SPI5;
SPID5.dmarx = STM32_DMA_STREAM(STM32_SPI_SPI5_RX_DMA_STREAM);
SPID5.dmatx = STM32_DMA_STREAM(STM32_SPI_SPI5_TX_DMA_STREAM);
SPID5.rxdmamode = STM32_DMA_CR_CHSEL(SPI5_RX_DMA_CHANNEL) |
STM32_DMA_CR_PL(STM32_SPI_SPI5_DMA_PRIORITY) |
STM32_DMA_CR_DIR_P2M |
STM32_DMA_CR_TCIE |
STM32_DMA_CR_DMEIE |
STM32_DMA_CR_TEIE;
SPID5.txdmamode = STM32_DMA_CR_CHSEL(SPI5_TX_DMA_CHANNEL) |
STM32_DMA_CR_PL(STM32_SPI_SPI5_DMA_PRIORITY) |
STM32_DMA_CR_DIR_M2P |
STM32_DMA_CR_DMEIE |
STM32_DMA_CR_TEIE;
#endif
#if STM32_SPI_USE_SPI6
spiObjectInit(&SPID6);
SPID6.spi = SPI6;
SPID6.dmarx = STM32_DMA_STREAM(STM32_SPI_SPI6_RX_DMA_STREAM);
SPID6.dmatx = STM32_DMA_STREAM(STM32_SPI_SPI6_TX_DMA_STREAM);
SPID6.rxdmamode = STM32_DMA_CR_CHSEL(SPI6_RX_DMA_CHANNEL) |
STM32_DMA_CR_PL(STM32_SPI_SPI6_DMA_PRIORITY) |
STM32_DMA_CR_DIR_P2M |
STM32_DMA_CR_TCIE |
STM32_DMA_CR_DMEIE |
STM32_DMA_CR_TEIE;
SPID6.txdmamode = STM32_DMA_CR_CHSEL(SPI6_TX_DMA_CHANNEL) |
STM32_DMA_CR_PL(STM32_SPI_SPI6_DMA_PRIORITY) |
STM32_DMA_CR_DIR_M2P |
STM32_DMA_CR_DMEIE |
STM32_DMA_CR_TEIE;
#endif
}
/**
* @brief Configures and activates the SPI peripheral.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_start(SPIDriver *spip) {
/* If in stopped state then enables the SPI and DMA clocks.*/
if (spip->state == SPI_STOP) {
#if STM32_SPI_USE_SPI1
if (&SPID1 == spip) {
bool b;
b = dmaStreamAllocate(spip->dmarx,
STM32_SPI_SPI1_IRQ_PRIORITY,
(stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
(void *)spip);
osalDbgAssert(!b, "stream already allocated");
b = dmaStreamAllocate(spip->dmatx,
STM32_SPI_SPI1_IRQ_PRIORITY,
(stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
(void *)spip);
osalDbgAssert(!b, "stream already allocated");
rccEnableSPI1(FALSE);
}
#endif
#if STM32_SPI_USE_SPI2
if (&SPID2 == spip) {
bool b;
b = dmaStreamAllocate(spip->dmarx,
STM32_SPI_SPI2_IRQ_PRIORITY,
(stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
(void *)spip);
osalDbgAssert(!b, "stream already allocated");
b = dmaStreamAllocate(spip->dmatx,
STM32_SPI_SPI2_IRQ_PRIORITY,
(stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
(void *)spip);
osalDbgAssert(!b, "stream already allocated");
rccEnableSPI2(FALSE);
}
#endif
#if STM32_SPI_USE_SPI3
if (&SPID3 == spip) {
bool b;
b = dmaStreamAllocate(spip->dmarx,
STM32_SPI_SPI3_IRQ_PRIORITY,
(stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
(void *)spip);
osalDbgAssert(!b, "stream already allocated");
b = dmaStreamAllocate(spip->dmatx,
STM32_SPI_SPI3_IRQ_PRIORITY,
(stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
(void *)spip);
osalDbgAssert(!b, "stream already allocated");
rccEnableSPI3(FALSE);
}
#endif
#if STM32_SPI_USE_SPI4
if (&SPID4 == spip) {
bool b;
b = dmaStreamAllocate(spip->dmarx,
STM32_SPI_SPI4_IRQ_PRIORITY,
(stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
(void *)spip);
osalDbgAssert(!b, "stream already allocated");
b = dmaStreamAllocate(spip->dmatx,
STM32_SPI_SPI4_IRQ_PRIORITY,
(stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
(void *)spip);
osalDbgAssert(!b, "stream already allocated");
rccEnableSPI4(FALSE);
}
#endif
#if STM32_SPI_USE_SPI5
if (&SPID5 == spip) {
bool b;
b = dmaStreamAllocate(spip->dmarx,
STM32_SPI_SPI5_IRQ_PRIORITY,
(stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
(void *)spip);
osalDbgAssert(!b, "stream already allocated");
b = dmaStreamAllocate(spip->dmatx,
STM32_SPI_SPI5_IRQ_PRIORITY,
(stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
(void *)spip);
osalDbgAssert(!b, "stream already allocated");
rccEnableSPI5(FALSE);
}
#endif
#if STM32_SPI_USE_SPI6
if (&SPID6 == spip) {
bool b;
b = dmaStreamAllocate(spip->dmarx,
STM32_SPI_SPI6_IRQ_PRIORITY,
(stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
(void *)spip);
osalDbgAssert(!b, "stream already allocated");
b = dmaStreamAllocate(spip->dmatx,
STM32_SPI_SPI6_IRQ_PRIORITY,
(stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
(void *)spip);
osalDbgAssert(!b, "stream already allocated");
rccEnableSPI6(FALSE);
}
#endif
/* DMA setup.*/
dmaStreamSetPeripheral(spip->dmarx, &spip->spi->DR);
dmaStreamSetPeripheral(spip->dmatx, &spip->spi->DR);
}
/* Configuration-specific DMA setup.*/
if ((spip->config->cr1 & SPI_CR1_DFF) == 0) {
/* Frame width is 8 bits or smaller.*/
spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) |
STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE;
spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) |
STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE;
}
else {
/* Frame width is larger than 8 bits.*/
spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) |
STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) |
STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
}
/* SPI setup and enable.*/
spip->spi->CR1 = 0;
spip->spi->CR1 = spip->config->cr1 | SPI_CR1_MSTR | SPI_CR1_SSM |
SPI_CR1_SSI;
spip->spi->CR2 = SPI_CR2_SSOE | SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN;
spip->spi->CR1 |= SPI_CR1_SPE;
}
/**
* @brief Deactivates the SPI peripheral.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_stop(SPIDriver *spip) {
/* If in ready state then disables the SPI clock.*/
if (spip->state == SPI_READY) {
/* SPI disable.*/
spip->spi->CR1 = 0;
spip->spi->CR2 = 0;
dmaStreamRelease(spip->dmarx);
dmaStreamRelease(spip->dmatx);
#if STM32_SPI_USE_SPI1
if (&SPID1 == spip)
rccDisableSPI1(FALSE);
#endif
#if STM32_SPI_USE_SPI2
if (&SPID2 == spip)
rccDisableSPI2(FALSE);
#endif
#if STM32_SPI_USE_SPI3
if (&SPID3 == spip)
rccDisableSPI3(FALSE);
#endif
#if STM32_SPI_USE_SPI4
if (&SPID4 == spip)
rccDisableSPI4(FALSE);
#endif
#if STM32_SPI_USE_SPI5
if (&SPID5 == spip)
rccDisableSPI5(FALSE);
#endif
#if STM32_SPI_USE_SPI6
if (&SPID6 == spip)
rccDisableSPI6(FALSE);
#endif
}
}
/**
* @brief Asserts the slave select signal and prepares for transfers.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_select(SPIDriver *spip) {
palClearPad(spip->config->ssport, spip->config->sspad);
}
/**
* @brief Deasserts the slave select signal.
* @details The previously selected peripheral is unselected.
*
* @param[in] spip pointer to the @p SPIDriver object
*
* @notapi
*/
void spi_lld_unselect(SPIDriver *spip) {
palSetPad(spip->config->ssport, spip->config->sspad);
}
/**
* @brief Ignores data on the SPI bus.
* @details This asynchronous function starts the transmission of a series of
* idle words on the SPI bus and ignores the received data.
* @post At the end of the operation the configured callback is invoked.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to be ignored
*
* @notapi
*/
void spi_lld_ignore(SPIDriver *spip, size_t n) {
dmaStreamSetMemory0(spip->dmarx, &dummyrx);
dmaStreamSetTransactionSize(spip->dmarx, n);
dmaStreamSetMode(spip->dmarx, spip->rxdmamode);
dmaStreamSetMemory0(spip->dmatx, &dummytx);
dmaStreamSetTransactionSize(spip->dmatx, n);
dmaStreamSetMode(spip->dmatx, spip->txdmamode);
dmaStreamEnable(spip->dmarx);
dmaStreamEnable(spip->dmatx);
}
/**
* @brief Exchanges data on the SPI bus.
* @details This asynchronous function starts a simultaneous transmit/receive
* operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to be exchanged
* @param[in] txbuf the pointer to the transmit buffer
* @param[out] rxbuf the pointer to the receive buffer
*
* @notapi
*/
void spi_lld_exchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf) {
dmaStreamSetMemory0(spip->dmarx, rxbuf);
dmaStreamSetTransactionSize(spip->dmarx, n);
dmaStreamSetMode(spip->dmarx, spip->rxdmamode| STM32_DMA_CR_MINC);
dmaStreamSetMemory0(spip->dmatx, txbuf);
dmaStreamSetTransactionSize(spip->dmatx, n);
dmaStreamSetMode(spip->dmatx, spip->txdmamode | STM32_DMA_CR_MINC);
dmaStreamEnable(spip->dmarx);
dmaStreamEnable(spip->dmatx);
}
/**
* @brief Sends data over the SPI bus.
* @details This asynchronous function starts a transmit operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to send
* @param[in] txbuf the pointer to the transmit buffer
*
* @notapi
*/
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
dmaStreamSetMemory0(spip->dmarx, &dummyrx);
dmaStreamSetTransactionSize(spip->dmarx, n);
dmaStreamSetMode(spip->dmarx, spip->rxdmamode);
dmaStreamSetMemory0(spip->dmatx, txbuf);
dmaStreamSetTransactionSize(spip->dmatx, n);
dmaStreamSetMode(spip->dmatx, spip->txdmamode | STM32_DMA_CR_MINC);
dmaStreamEnable(spip->dmarx);
dmaStreamEnable(spip->dmatx);
}
/**
* @brief Receives data from the SPI bus.
* @details This asynchronous function starts a receive operation.
* @post At the end of the operation the configured callback is invoked.
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to receive
* @param[out] rxbuf the pointer to the receive buffer
*
* @notapi
*/
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
dmaStreamSetMemory0(spip->dmarx, rxbuf);
dmaStreamSetTransactionSize(spip->dmarx, n);
dmaStreamSetMode(spip->dmarx, spip->rxdmamode | STM32_DMA_CR_MINC);
dmaStreamSetMemory0(spip->dmatx, &dummytx);
dmaStreamSetTransactionSize(spip->dmatx, n);
dmaStreamSetMode(spip->dmatx, spip->txdmamode);
dmaStreamEnable(spip->dmarx);
dmaStreamEnable(spip->dmatx);
}
/**
* @brief Exchanges one frame using a polled wait.
* @details This synchronous function exchanges one frame using a polled
* synchronization method. This function is useful when exchanging
* small amount of data on high speed channels, usually in this
* situation is much more efficient just wait for completion using
* polling than suspending the thread waiting for an interrupt.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] frame the data frame to send over the SPI bus
* @return The received data frame from the SPI bus.
*/
uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) {
spip->spi->DR = frame;
while ((spip->spi->SR & SPI_SR_RXNE) == 0)
;
return spip->spi->DR;
}
#endif /* HAL_USE_SPI */
/** @} */

View File

@ -0,0 +1,114 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file common/ARMCMx/nvic.c
* @brief Cortex-Mx NVIC support code.
*
* @addtogroup COMMON_ARMCMx_NVIC
* @{
*/
#include "hal.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Sets the priority of an interrupt handler and enables it.
*
* @param[in] n the interrupt number
* @param[in] prio the interrupt priority
*/
void nvicEnableVector(uint32_t n, uint32_t prio) {
#if defined(__CORE_CM0_H_GENERIC)
NVIC->IP[_IP_IDX(n)] = (NVIC->IP[_IP_IDX(n)] & ~(0xFFU << _BIT_SHIFT(n))) |
(NVIC_PRIORITY_MASK(prio) << _BIT_SHIFT(n));
#else
NVIC->IP[n] = NVIC_PRIORITY_MASK(prio);
#endif
NVIC->ICPR[n >> 5U] = 1U << (n & 0x1FU);
NVIC->ISER[n >> 5U] = 1U << (n & 0x1FU);
}
/**
* @brief Disables an interrupt handler.
*
* @param[in] n the interrupt number
*/
void nvicDisableVector(uint32_t n) {
NVIC->ICER[n >> 5U] = 1U << (n & 0x1FU);
#if defined(__CORE_CM0_H_GENERIC)
NVIC->IP[_IP_IDX(n)] = NVIC->IP[_IP_IDX(n)] & ~(0xFFU << _BIT_SHIFT(n));
#else
NVIC->IP[n] = 0U;
#endif
}
/**
* @brief Changes the priority of a system handler.
*
* @param[in] handler the system handler number
* @param[in] prio the system handler priority
*/
void nvicSetSystemHandlerPriority(uint32_t handler, uint32_t prio) {
osalDbgCheck(handler < 12U);
#if defined(__CORE_CM0_H_GENERIC)
SCB->SHP[_SHP_IDX(handler)] = (SCB->SHP[_SHP_IDX(handler)] & ~(0xFFU << _BIT_SHIFT(handler))) |
(NVIC_PRIORITY_MASK(prio) << _BIT_SHIFT(handler));
#elif defined(__CORE_CM7_H_GENERIC)
SCB->SHPR[handler] = NVIC_PRIORITY_MASK(prio);
#else
SCB->SHP[handler] = NVIC_PRIORITY_MASK(prio);
#endif
}
/**
* @brief Clears a pending interrupt source.
*
* @param[in] n the interrupt number
*/
void nvicClearPending(uint32_t n) {
NVIC->ICPR[n >> 5] = 1 << (n & 0x1F);
}
/** @} */

View File

@ -0,0 +1,191 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file uart_lld.c
* @brief PLATFORM UART subsystem low level driver source.
*
* @addtogroup UART
* @{
*/
#include "hal.h"
#if (HAL_USE_UART == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief UART1 driver identifier.
*/
#if (PLATFORM_UART_USE_UART1 == TRUE) || defined(__DOXYGEN__)
UARTDriver UARTD1;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level UART driver initialization.
*
* @notapi
*/
void uart_lld_init(void) {
#if PLATFORM_UART_USE_UART1 == TRUE
/* Driver initialization.*/
uartObjectInit(&UARTD1);
#endif
}
/**
* @brief Configures and activates the UART peripheral.
*
* @param[in] uartp pointer to the @p UARTDriver object
*
* @notapi
*/
void uart_lld_start(UARTDriver *uartp) {
if (uartp->state == UART_STOP) {
/* Enables the peripheral.*/
#if PLATFORM_UART_USE_UART1 == TRUE
if (&UARTD1 == uartp) {
}
#endif
}
/* Configures the peripheral.*/
}
/**
* @brief Deactivates the UART peripheral.
*
* @param[in] uartp pointer to the @p UARTDriver object
*
* @notapi
*/
void uart_lld_stop(UARTDriver *uartp) {
if (uartp->state == UART_READY) {
/* Resets the peripheral.*/
/* Disables the peripheral.*/
#if PLATFORM_UART_USE_UART1 == TRUE
if (&UARTD1 == uartp) {
}
#endif
}
}
/**
* @brief Starts a transmission on the UART peripheral.
* @note The buffers are organized as uint8_t arrays for data sizes below
* or equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] uartp pointer to the @p UARTDriver object
* @param[in] n number of data frames to send
* @param[in] txbuf the pointer to the transmit buffer
*
* @notapi
*/
void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf) {
(void)uartp;
(void)n;
(void)txbuf;
}
/**
* @brief Stops any ongoing transmission.
* @note Stopping a transmission also suppresses the transmission callbacks.
*
* @param[in] uartp pointer to the @p UARTDriver object
*
* @return The number of data frames not transmitted by the
* stopped transmit operation.
*
* @notapi
*/
size_t uart_lld_stop_send(UARTDriver *uartp) {
(void)uartp;
return 0;
}
/**
* @brief Starts a receive operation on the UART peripheral.
* @note The buffers are organized as uint8_t arrays for data sizes below
* or equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] uartp pointer to the @p UARTDriver object
* @param[in] n number of data frames to send
* @param[out] rxbuf the pointer to the receive buffer
*
* @notapi
*/
void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf) {
(void)uartp;
(void)n;
(void)rxbuf;
}
/**
* @brief Stops any ongoing receive operation.
* @note Stopping a receive operation also suppresses the receive callbacks.
*
* @param[in] uartp pointer to the @p UARTDriver object
*
* @return The number of data frames not received by the
* stopped receive operation.
*
* @notapi
*/
size_t uart_lld_stop_receive(UARTDriver *uartp) {
(void)uartp;
return 0;
}
#endif /* HAL_USE_UART == TRUE */
/** @} */

View File

@ -0,0 +1,165 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
This file is part of ChibiOS.
ChibiOS 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 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 nilcore_v7m.c
* @brief ARMv7-M architecture port code.
*
* @addtogroup ARMCMx_V7M_CORE
* @{
*/
#include "nil.h"
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module interrupt handlers. */
/*===========================================================================*/
#if (CORTEX_SIMPLIFIED_PRIORITY == FALSE) || defined(__DOXYGEN__)
/**
* @brief SVC vector.
* @details The SVC vector is used for exception mode re-entering after a
* context switch.
* @note The PendSV vector is only used in advanced kernel mode.
*/
/*lint -save -e9075 [8.4] All symbols are invoked from asm context.*/
void SVC_Handler(void) {
/*lint -restore*/
struct port_extctx *ctxp;
#if CORTEX_USE_FPU == TRUE
/* Enforcing unstacking of the FP part of the context.*/
FPU->FPCCR &= ~FPU_FPCCR_LSPACT_Msk;
#endif
/* The port_extctx structure is pointed by the PSP register.*/
ctxp = (struct port_extctx *)__get_PSP();
/* Discarding the current exception context and positioning the stack to
point to the real one.*/
ctxp++;
/* Restoring real position of the original stack frame.*/
__set_PSP((uint32_t)ctxp);
/* Restoring the normal interrupts status.*/
port_unlock_from_isr();
}
#endif /* CORTEX_SIMPLIFIED_PRIORITY == FALSE */
#if (CORTEX_SIMPLIFIED_PRIORITY == TRUE) || defined(__DOXYGEN__)
/**
* @brief PendSV vector.
* @details The PendSV vector is used for exception mode re-entering after a
* context switch.
* @note The PendSV vector is only used in compact kernel mode.
*/
/*lint -save -e9075 [8.4] All symbols are invoked from asm context.*/
void PendSV_Handler(void) {
/*lint -restore*/
struct port_extctx *ctxp;
#if CORTEX_USE_FPU == TRUE
/* Enforcing unstacking of the FP part of the context.*/
FPU->FPCCR &= ~FPU_FPCCR_LSPACT_Msk;
#endif
/* The port_extctx structure is pointed by the PSP register.*/
ctxp = (struct port_extctx *)__get_PSP();
/* Discarding the current exception context and positioning the stack to
point to the real one.*/
ctxp++;
/* Writing back the modified PSP value.*/
__set_PSP((uint32_t)ctxp);
}
#endif /* CORTEX_SIMPLIFIED_PRIORITY == TRUE */
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/**
* @brief Exception exit redirection to _port_switch_from_isr().
*/
void _port_irq_epilogue(void) {
port_lock_from_isr();
if ((SCB->ICSR & SCB_ICSR_RETTOBASE_Msk) != 0U) {
struct port_extctx *ctxp;
#if CORTEX_USE_FPU == TRUE
/* Enforcing a lazy FPU state save by accessing the FPCSR register.*/
(void) __get_FPSCR();
#endif
/* The port_extctx structure is pointed by the PSP register.*/
ctxp = (struct port_extctx *)__get_PSP();
/* Adding an artificial exception return context, there is no need to
populate it fully.*/
ctxp--;
/* Setting up a fake XPSR register value.*/
ctxp->xpsr = (regarm_t)0x01000000;
/* Writing back the modified PSP value.*/
__set_PSP((uint32_t)ctxp);
/* The exit sequence is different depending on if a preemption is
required or not.*/
if (chSchIsRescRequiredI()) {
/* Preemption is required we need to enforce a context switch.*/
ctxp->pc = (regarm_t)_port_switch_from_isr;
}
else {
/* Preemption not required, we just need to exit the exception
atomically.*/
ctxp->pc = (regarm_t)_port_exit_from_isr;
}
/* Note, returning without unlocking is intentional, this is done in
order to keep the rest of the context switch atomic.*/
return;
}
port_unlock_from_isr();
}
/** @} */

View File

@ -0,0 +1,137 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
This file is part of ChibiOS.
ChibiOS 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 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 AVR/nilcore.c
* @brief AVR port code.
*
* @addtogroup AVR_CORE
* @{
*/
#include "nil.h"
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/**
* @brief Performs a context switch between two threads.
* @details This is the most critical code in any port, this function
* is responsible for the context switch between 2 threads.
* @note The implementation of this code affects <b>directly</b> the context
* switch performance so optimize here as much as you can.
* @note The function is declared as a weak symbol, it is possible to
* redefine it in your application code.
*
* @param[in] ntp the thread to be switched in
* @param[in] otp the thread to be switched out
*/
#if !defined(__DOXYGEN__)
__attribute__((naked, weak))
#endif
void _port_switch(thread_t *ntp, thread_t *otp) {
asm volatile ("push r2");
asm volatile ("push r3");
asm volatile ("push r4");
asm volatile ("push r5");
asm volatile ("push r6");
asm volatile ("push r7");
asm volatile ("push r8");
asm volatile ("push r9");
asm volatile ("push r10");
asm volatile ("push r11");
asm volatile ("push r12");
asm volatile ("push r13");
asm volatile ("push r14");
asm volatile ("push r15");
asm volatile ("push r16");
asm volatile ("push r17");
asm volatile ("push r28");
asm volatile ("push r29");
asm volatile ("movw r30, r22");
asm volatile ("in r0, 0x3d");
asm volatile ("std Z+0, r0");
asm volatile ("in r0, 0x3e");
asm volatile ("std Z+1, r0");
asm volatile ("movw r30, r24");
asm volatile ("ldd r0, Z+0");
asm volatile ("out 0x3d, r0");
asm volatile ("ldd r0, Z+1");
asm volatile ("out 0x3e, r0");
asm volatile ("pop r29");
asm volatile ("pop r28");
asm volatile ("pop r17");
asm volatile ("pop r16");
asm volatile ("pop r15");
asm volatile ("pop r14");
asm volatile ("pop r13");
asm volatile ("pop r12");
asm volatile ("pop r11");
asm volatile ("pop r10");
asm volatile ("pop r9");
asm volatile ("pop r8");
asm volatile ("pop r7");
asm volatile ("pop r6");
asm volatile ("pop r5");
asm volatile ("pop r4");
asm volatile ("pop r3");
asm volatile ("pop r2");
asm volatile ("ret");
}
/**
* @brief Start a thread by invoking its work function.
* @details If the work function returns @p chThdExit() is automatically
* invoked.
*/
void _port_thread_start(void) {
chSysUnlock();
asm volatile ("movw r24, r4");
asm volatile ("movw r30, r2");
asm volatile ("icall");
chSysHalt(0);
}
/** @} */

View File

@ -0,0 +1,14 @@
# List of the ChibiOS/NIL e200z4 SPC57EMxx port files.
PORTSRC = ${CHIBIOS}/os/nil/ports/e200/nilcore.c
PORTASM = $(CHIBIOS)/os/common/ports/e200/devices/SPC57EMxx/boot.s \
$(CHIBIOS)/os/common/ports/e200/compilers/GCC/vectors.s \
$(CHIBIOS)/os/common/ports/e200/compilers/GCC/crt0.s \
$(CHIBIOS)/os/nil/ports/e200/compilers/GCC/ivor.s
PORTINC = ${CHIBIOS}/os/common/ports/e200/compilers/GCC \
${CHIBIOS}/os/common/ports/e200/devices/SPC57EMxx \
${CHIBIOS}/os/nil/ports/e200 \
${CHIBIOS}/os/nil/ports/e200/compilers/GCC
PORTLD = ${CHIBIOS}/os/common/ports/e200/compilers/GCC/ld

View File

@ -0,0 +1,96 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
This file is part of ChibiOS.
ChibiOS 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 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 chdynamic.h
* @brief Dynamic threads macros and structures.
*
* @addtogroup dynamic_threads
* @{
*/
#ifndef _CHDYNAMIC_H_
#define _CHDYNAMIC_H_
#if (CH_CFG_USE_DYNAMIC == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*
* Module dependencies check.
*/
#if CH_CFG_USE_WAITEXIT == FALSE
#error "CH_CFG_USE_DYNAMIC requires CH_CFG_USE_WAITEXIT"
#endif
#if (CH_CFG_USE_HEAP == FALSE) && (CH_CFG_USE_MEMPOOLS == FALSE)
#error "CH_CFG_USE_DYNAMIC requires CH_CFG_USE_HEAP and/or CH_CFG_USE_MEMPOOLS"
#endif
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
/*
* Dynamic threads APIs.
*/
#ifdef __cplusplus
extern "C" {
#endif
thread_t *chThdAddRef(thread_t *tp);
void chThdRelease(thread_t *tp);
#if CH_CFG_USE_HEAP == TRUE
thread_t *chThdCreateFromHeap(memory_heap_t *heapp, size_t size,
tprio_t prio, tfunc_t pf, void *arg);
#endif
#if CH_CFG_USE_MEMPOOLS == TRUE
thread_t *chThdCreateFromMemoryPool(memory_pool_t *mp, tprio_t prio,
tfunc_t pf, void *arg);
#endif
#ifdef __cplusplus
}
#endif
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
#endif /* CH_CFG_USE_DYNAMIC == TRUE */
#endif /* _CHDYNAMIC_H_ */
/** @} */

View File

@ -0,0 +1,168 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
This file is part of ChibiOS.
ChibiOS 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 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 chcore_v7m.c
* @brief ARMv7-M architecture port code.
*
* @addtogroup ARMCMx_V7M_CORE
* @{
*/
#include "ch.h"
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module interrupt handlers. */
/*===========================================================================*/
#if (CORTEX_SIMPLIFIED_PRIORITY == FALSE) || defined(__DOXYGEN__)
/**
* @brief SVC vector.
* @details The SVC vector is used for exception mode re-entering after a
* context switch.
* @note The PendSV vector is only used in advanced kernel mode.
*/
/*lint -save -e9075 [8.4] All symbols are invoked from asm context.*/
void SVC_Handler(void) {
/*lint -restore*/
struct port_extctx *ctxp;
#if CORTEX_USE_FPU
/* Enforcing unstacking of the FP part of the context.*/
FPU->FPCCR &= ~FPU_FPCCR_LSPACT_Msk;
#endif
/* The port_extctx structure is pointed by the PSP register.*/
ctxp = (struct port_extctx *)__get_PSP();
/* Discarding the current exception context and positioning the stack to
point to the real one.*/
ctxp++;
/* Restoring real position of the original stack frame.*/
__set_PSP((uint32_t)ctxp);
/* Restoring the normal interrupts status.*/
port_unlock_from_isr();
}
#endif /* CORTEX_SIMPLIFIED_PRIORITY == FALSE */
#if (CORTEX_SIMPLIFIED_PRIORITY == TRUE) || defined(__DOXYGEN__)
/**
* @brief PendSV vector.
* @details The PendSV vector is used for exception mode re-entering after a
* context switch.
* @note The PendSV vector is only used in compact kernel mode.
*/
/*lint -save -e9075 [8.4] All symbols are invoked from asm context.*/
void PendSV_Handler(void) {
/*lint -restore*/
struct port_extctx *ctxp;
#if CORTEX_USE_FPU
/* Enforcing unstacking of the FP part of the context.*/
FPU->FPCCR &= ~FPU_FPCCR_LSPACT_Msk;
#endif
/* The port_extctx structure is pointed by the PSP register.*/
ctxp = (struct port_extctx *)__get_PSP();
/* Discarding the current exception context and positioning the stack to
point to the real one.*/
ctxp++;
/* Writing back the modified PSP value.*/
__set_PSP((uint32_t)ctxp);
}
#endif /* CORTEX_SIMPLIFIED_PRIORITY == TRUE */
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/**
* @brief Exception exit redirection to _port_switch_from_isr().
*/
void _port_irq_epilogue(void) {
port_lock_from_isr();
if ((SCB->ICSR & SCB_ICSR_RETTOBASE_Msk) != 0U) {
struct port_extctx *ctxp;
#if CORTEX_USE_FPU == TRUE
/* Enforcing a lazy FPU state save by accessing the FPCSR register.*/
(void) __get_FPSCR();
#endif
/* The port_extctx structure is pointed by the PSP register.*/
ctxp = (struct port_extctx *)__get_PSP();
/* Adding an artificial exception return context, there is no need to
populate it fully.*/
ctxp--;
/* Setting up a fake XPSR register value.*/
ctxp->xpsr = (regarm_t)0x01000000;
#if CORTEX_USE_FPU == TRUE
ctxp->fpscr = (regarm_t)FPU->FPDSCR;
#endif
/* Writing back the modified PSP value.*/
__set_PSP((uint32_t)ctxp);
/* The exit sequence is different depending on if a preemption is
required or not.*/
if (chSchIsPreemptionRequired()) {
/* Preemption is required we need to enforce a context switch.*/
ctxp->pc = (regarm_t)_port_switch_from_isr;
}
else {
/* Preemption not required, we just need to exit the exception
atomically.*/
ctxp->pc = (regarm_t)_port_exit_from_isr;
}
/* Note, returning without unlocking is intentional, this is done in
order to keep the rest of the context switch atomic.*/
return;
}
port_unlock_from_isr();
}
/** @} */

View File

@ -0,0 +1,124 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
This file is part of ChibiOS.
ChibiOS 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 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 AVR/chcore_timer.h
* @brief System timer header file.
*
* @addtogroup AVR_TIMER
* @{
*/
#ifndef _CHCORE_TIMER_H_
#define _CHCORE_TIMER_H_
/* This is the only header in the HAL designed to be include-able alone.*/
#include "st.h"
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
/**
* @brief Starts the alarm.
* @note Makes sure that no spurious alarms are triggered after
* this call.
*
* @param[in] time the time to be set for the first alarm
*
* @notapi
*/
static inline void port_timer_start_alarm(systime_t time) {
stStartAlarm(time);
}
/**
* @brief Stops the alarm interrupt.
*
* @notapi
*/
static inline void port_timer_stop_alarm(void) {
stStopAlarm();
}
/**
* @brief Sets the alarm time.
*
* @param[in] time the time to be set for the next alarm
*
* @notapi
*/
static inline void port_timer_set_alarm(systime_t time) {
stSetAlarm(time);
}
/**
* @brief Returns the system time.
*
* @return The system time.
*
* @notapi
*/
static inline systime_t port_timer_get_time(void) {
return stGetCounter();
}
/**
* @brief Returns the current alarm time.
*
* @return The currently set alarm time.
*
* @notapi
*/
static inline systime_t port_timer_get_alarm(void) {
return stGetAlarm();
}
#endif /* _CHCORE_TIMER_H_ */
/** @} */

View File

@ -0,0 +1,411 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
This file is part of ChibiOS.
ChibiOS 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 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
* @details Semaphores related APIs and services.
* <h2>Operation mode</h2>
* Semaphores are a flexible synchronization primitive, ChibiOS/RT
* implements semaphores in their "counting semaphores" variant as
* defined by Edsger Dijkstra plus several enhancements like:
* - Wait operation with timeout.
* - Reset operation.
* - Atomic wait+signal operation.
* - Return message from the wait operation (OK, RESET, TIMEOUT).
* .
* The binary semaphores variant can be easily implemented using
* counting semaphores.<br>
* Operations defined for semaphores:
* - <b>Signal</b>: The semaphore counter is increased and if the
* result is non-positive then a waiting thread is removed from
* the semaphore queue and made ready for execution.
* - <b>Wait</b>: The semaphore counter is decreased and if the result
* becomes negative the thread is queued in the semaphore and
* suspended.
* - <b>Reset</b>: The semaphore counter is reset to a non-negative
* value and all the threads in the queue are released.
* .
* Semaphores can be used as guards for mutual exclusion zones
* (note that mutexes are recommended for this kind of use) but
* also have other uses, queues guards and counters for example.<br>
* Semaphores usually use a FIFO queuing strategy but it is possible
* to make them order threads by priority by enabling
* @p CH_CFG_USE_SEMAPHORES_PRIORITY in @p chconf.h.
* @pre In order to use the semaphore APIs the @p CH_CFG_USE_SEMAPHORES
* option must be enabled in @p chconf.h.
* @{
*/
#include "ch.h"
#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
#if CH_CFG_USE_SEMAPHORES_PRIORITY == TRUE
#define sem_insert(tp, qp) queue_prio_insert(tp, qp)
#else
#define sem_insert(tp, qp) queue_insert(tp, qp)
#endif
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
/**
* @brief Initializes a semaphore with the specified counter value.
*
* @param[out] sp pointer to a @p semaphore_t structure
* @param[in] n initial value of the semaphore counter. Must be
* non-negative.
*
* @init
*/
void chSemObjectInit(semaphore_t *sp, cnt_t n) {
chDbgCheck((sp != NULL) && (n >= (cnt_t)0));
queue_init(&sp->s_queue);
sp->s_cnt = n;
}
/**
* @brief Performs a reset operation on the semaphore.
* @post After invoking this function all the threads waiting on the
* semaphore, if any, are released and the semaphore counter is set
* to the specified, non negative, value.
* @note The released threads can recognize they were waked up by a reset
* rather than a signal because the @p chSemWait() will return
* @p MSG_RESET instead of @p MSG_OK.
*
* @param[in] sp pointer to a @p semaphore_t structure
* @param[in] n the new value of the semaphore counter. The value must
* be non-negative.
*
* @api
*/
void chSemReset(semaphore_t *sp, cnt_t n) {
chSysLock();
chSemResetI(sp, n);
chSchRescheduleS();
chSysUnlock();
}
/**
* @brief Performs a reset operation on the semaphore.
* @post After invoking this function all the threads waiting on the
* semaphore, if any, are released and the semaphore counter is set
* to the specified, non negative, value.
* @post This function does not reschedule so a call to a rescheduling
* function must be performed before unlocking the kernel. Note that
* interrupt handlers always reschedule on exit so an explicit
* reschedule must not be performed in ISRs.
* @note The released threads can recognize they were waked up by a reset
* rather than a signal because the @p chSemWait() will return
* @p MSG_RESET instead of @p MSG_OK.
*
* @param[in] sp pointer to a @p semaphore_t structure
* @param[in] n the new value of the semaphore counter. The value must
* be non-negative.
*
* @iclass
*/
void chSemResetI(semaphore_t *sp, cnt_t n) {
cnt_t cnt;
chDbgCheckClassI();
chDbgCheck((sp != NULL) && (n >= (cnt_t)0));
chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) ||
((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)),
"inconsistent semaphore");
cnt = sp->s_cnt;
sp->s_cnt = n;
while (++cnt <= (cnt_t)0) {
chSchReadyI(queue_lifo_remove(&sp->s_queue))->p_u.rdymsg = MSG_RESET;
}
}
/**
* @brief Performs a wait operation on a semaphore.
*
* @param[in] sp pointer to a @p semaphore_t structure
* @return A message specifying how the invoking thread has been
* released from the semaphore.
* @retval MSG_OK if the thread has not stopped on the semaphore or the
* semaphore has been signaled.
* @retval MSG_RESET if the semaphore has been reset using @p chSemReset().
*
* @api
*/
msg_t chSemWait(semaphore_t *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_t structure
* @return A message specifying how the invoking thread has been
* released from the semaphore.
* @retval MSG_OK if the thread has not stopped on the semaphore or the
* semaphore has been signaled.
* @retval MSG_RESET if the semaphore has been reset using @p chSemReset().
*
* @sclass
*/
msg_t chSemWaitS(semaphore_t *sp) {
chDbgCheckClassS();
chDbgCheck(sp != NULL);
chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) ||
((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)),
"inconsistent semaphore");
if (--sp->s_cnt < (cnt_t)0) {
currp->p_u.wtsemp = sp;
sem_insert(currp, &sp->s_queue);
chSchGoSleepS(CH_STATE_WTSEM);
return currp->p_u.rdymsg;
}
return MSG_OK;
}
/**
* @brief Performs a wait operation on a semaphore with timeout specification.
*
* @param[in] sp pointer to a @p semaphore_t 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.
* .
* @return A message specifying how the invoking thread has been
* released from the semaphore.
* @retval MSG_OK if the thread has not stopped on the semaphore or the
* semaphore has been signaled.
* @retval MSG_RESET if the semaphore has been reset using @p chSemReset().
* @retval MSG_TIMEOUT if the semaphore has not been signaled or reset within
* the specified timeout.
*
* @api
*/
msg_t chSemWaitTimeout(semaphore_t *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_t 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.
* .
* @return A message specifying how the invoking thread has been
* released from the semaphore.
* @retval MSG_OK if the thread has not stopped on the semaphore or the
* semaphore has been signaled.
* @retval MSG_RESET if the semaphore has been reset using @p chSemReset().
* @retval MSG_TIMEOUT if the semaphore has not been signaled or reset within
* the specified timeout.
*
* @sclass
*/
msg_t chSemWaitTimeoutS(semaphore_t *sp, systime_t time) {
chDbgCheckClassS();
chDbgCheck(sp != NULL);
chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) ||
((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)),
"inconsistent semaphore");
if (--sp->s_cnt < (cnt_t)0) {
if (TIME_IMMEDIATE == time) {
sp->s_cnt++;
return MSG_TIMEOUT;
}
currp->p_u.wtsemp = sp;
sem_insert(currp, &sp->s_queue);
return chSchGoSleepTimeoutS(CH_STATE_WTSEM, time);
}
return MSG_OK;
}
/**
* @brief Performs a signal operation on a semaphore.
*
* @param[in] sp pointer to a @p semaphore_t structure
*
* @api
*/
void chSemSignal(semaphore_t *sp) {
chDbgCheck(sp != NULL);
chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) ||
((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)),
"inconsistent semaphore");
chSysLock();
if (++sp->s_cnt <= (cnt_t)0) {
chSchWakeupS(queue_fifo_remove(&sp->s_queue), MSG_OK);
}
chSysUnlock();
}
/**
* @brief Performs a signal operation on a semaphore.
* @post This function does not reschedule so a call to a rescheduling
* function must be performed before unlocking the kernel. Note that
* interrupt handlers always reschedule on exit so an explicit
* reschedule must not be performed in ISRs.
*
* @param[in] sp pointer to a @p semaphore_t structure
*
* @iclass
*/
void chSemSignalI(semaphore_t *sp) {
chDbgCheckClassI();
chDbgCheck(sp != NULL);
chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) ||
((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)),
"inconsistent semaphore");
if (++sp->s_cnt <= (cnt_t)0) {
/* Note, it is done this way in order to allow a tail call on
chSchReadyI().*/
thread_t *tp = queue_fifo_remove(&sp->s_queue);
tp->p_u.rdymsg = MSG_OK;
(void) chSchReadyI(tp);
}
}
/**
* @brief Adds the specified value to the semaphore counter.
* @post This function does not reschedule so a call to a rescheduling
* function must be performed before unlocking the kernel. Note that
* interrupt handlers always reschedule on exit so an explicit
* reschedule must not be performed in ISRs.
*
* @param[in] sp pointer to a @p semaphore_t structure
* @param[in] n value to be added to the semaphore counter. The value
* must be positive.
*
* @iclass
*/
void chSemAddCounterI(semaphore_t *sp, cnt_t n) {
chDbgCheckClassI();
chDbgCheck((sp != NULL) && (n > (cnt_t)0));
chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) ||
((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)),
"inconsistent semaphore");
while (n > (cnt_t)0) {
if (++sp->s_cnt <= (cnt_t)0) {
chSchReadyI(queue_fifo_remove(&sp->s_queue))->p_u.rdymsg = MSG_OK;
}
n--;
}
}
/**
* @brief Performs atomic signal and wait operations on two semaphores.
*
* @param[in] sps pointer to a @p semaphore_t structure to be signaled
* @param[in] spw pointer to a @p semaphore_t structure to wait on
* @return A message specifying how the invoking thread has been
* released from the semaphore.
* @retval MSG_OK if the thread has not stopped on the semaphore or the
* semaphore has been signaled.
* @retval MSG_RESET if the semaphore has been reset using @p chSemReset().
*
* @api
*/
msg_t chSemSignalWait(semaphore_t *sps, semaphore_t *spw) {
msg_t msg;
chDbgCheck((sps != NULL) && (spw != NULL));
chDbgAssert(((sps->s_cnt >= (cnt_t)0) && queue_isempty(&sps->s_queue)) ||
((sps->s_cnt < (cnt_t)0) && queue_notempty(&sps->s_queue)),
"inconsistent semaphore");
chDbgAssert(((spw->s_cnt >= (cnt_t)0) && queue_isempty(&spw->s_queue)) ||
((spw->s_cnt < (cnt_t)0) && queue_notempty(&spw->s_queue)),
"inconsistent semaphore");
chSysLock();
if (++sps->s_cnt <= (cnt_t)0) {
chSchReadyI(queue_fifo_remove(&sps->s_queue))->p_u.rdymsg = MSG_OK;
}
if (--spw->s_cnt < (cnt_t)0) {
thread_t *ctp = currp;
sem_insert(ctp, &spw->s_queue);
ctp->p_u.wtsemp = spw;
chSchGoSleepS(CH_STATE_WTSEM);
msg = ctp->p_u.rdymsg;
}
else {
chSchRescheduleS();
msg = MSG_OK;
}
chSysUnlock();
return msg;
}
#endif /* CH_CFG_USE_SEMAPHORES == TRUE */
/** @} */

View File

@ -0,0 +1,26 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @defgroup lis302dl Interface module for LIS302DL MEMS
*
* @brief Interface module for LIS302DL MEMS.
* @details This module implements a generic interface for the LIS302DL
* STMicroelectronics MEMS device. The communication is performed
* through a standard SPI driver.
*
* @ingroup accel
*/

View File

@ -0,0 +1,94 @@
/*
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file evtimer.h
* @brief Events Generator Timer structures and macros.
*
* @addtogroup event_timer
* @{
*/
#ifndef _EVTIMER_H_
#define _EVTIMER_H_
/*===========================================================================*/
/* Module constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Module pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*
* Module dependencies check.
*/
#if !CH_CFG_USE_EVENTS
#error "Event Timers require CH_CFG_USE_EVENTS"
#endif
/*===========================================================================*/
/* Module data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a event timer structure.
*/
typedef struct {
virtual_timer_t et_vt;
event_source_t et_es;
systime_t et_interval;
} event_timer_t;
/*===========================================================================*/
/* Module macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void evtObjectInit(event_timer_t *etp, systime_t time);
void evtStart(event_timer_t *etp);
#ifdef __cplusplus
}
#endif
/*===========================================================================*/
/* Module inline functions. */
/*===========================================================================*/
/**
* @brief Stops the timer.
* @details If the timer was already stopped then the function has no effect.
*
* @param[in] etp pointer to an initialized @p event_timer_t structure.
*/
static inline void vevtStop(event_timer_t *etp) {
chVTReset(&etp->et_vt);
}
#endif /* _EVTIMER_H_ */
/** @} */

View File

@ -0,0 +1,254 @@
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */
/*-----------------------------------------------------------------------*/
/* This is a stub disk I/O module that acts as front end of the existing */
/* disk I/O modules and attach it to FatFs module with common interface. */
/*-----------------------------------------------------------------------*/
#include "hal.h"
#include "ffconf.h"
#include "diskio.h"
#if HAL_USE_MMC_SPI && HAL_USE_SDC
#error "cannot specify both MMC_SPI and SDC drivers"
#endif
#if HAL_USE_MMC_SPI
extern MMCDriver MMCD1;
#elif HAL_USE_SDC
extern SDCDriver SDCD1;
#else
#error "MMC_SPI or SDC driver must be specified"
#endif
#if HAL_USE_RTC
extern RTCDriver RTCD1;
#endif
/*-----------------------------------------------------------------------*/
/* Correspondence between physical drive number and physical drive. */
#define MMC 0
#define SDC 0
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber (0..) */
)
{
DSTATUS stat;
switch (pdrv) {
#if HAL_USE_MMC_SPI
case MMC:
stat = 0;
/* It is initialized externally, just reads the status.*/
if (blkGetDriverState(&MMCD1) != BLK_READY)
stat |= STA_NOINIT;
if (mmcIsWriteProtected(&MMCD1))
stat |= STA_PROTECT;
return stat;
#else
case SDC:
stat = 0;
/* It is initialized externally, just reads the status.*/
if (blkGetDriverState(&SDCD1) != BLK_READY)
stat |= STA_NOINIT;
if (sdcIsWriteProtected(&SDCD1))
stat |= STA_PROTECT;
return stat;
#endif
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Return Disk Status */
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber (0..) */
)
{
DSTATUS stat;
switch (pdrv) {
#if HAL_USE_MMC_SPI
case MMC:
stat = 0;
/* It is initialized externally, just reads the status.*/
if (blkGetDriverState(&MMCD1) != BLK_READY)
stat |= STA_NOINIT;
if (mmcIsWriteProtected(&MMCD1))
stat |= STA_PROTECT;
return stat;
#else
case SDC:
stat = 0;
/* It is initialized externally, just reads the status.*/
if (blkGetDriverState(&SDCD1) != BLK_READY)
stat |= STA_NOINIT;
if (sdcIsWriteProtected(&SDCD1))
stat |= STA_PROTECT;
return stat;
#endif
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address (LBA) */
UINT count /* Number of sectors to read (1..255) */
)
{
switch (pdrv) {
#if HAL_USE_MMC_SPI
case MMC:
if (blkGetDriverState(&MMCD1) != BLK_READY)
return RES_NOTRDY;
if (mmcStartSequentialRead(&MMCD1, sector))
return RES_ERROR;
while (count > 0) {
if (mmcSequentialRead(&MMCD1, buff))
return RES_ERROR;
buff += MMCSD_BLOCK_SIZE;
count--;
}
if (mmcStopSequentialRead(&MMCD1))
return RES_ERROR;
return RES_OK;
#else
case SDC:
if (blkGetDriverState(&SDCD1) != BLK_READY)
return RES_NOTRDY;
if (sdcRead(&SDCD1, sector, buff, count))
return RES_ERROR;
return RES_OK;
#endif
}
return RES_PARERR;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
#if _USE_WRITE
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber (0..) */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address (LBA) */
UINT count /* Number of sectors to write (1..255) */
)
{
switch (pdrv) {
#if HAL_USE_MMC_SPI
case MMC:
if (blkGetDriverState(&MMCD1) != BLK_READY)
return RES_NOTRDY;
if (mmcIsWriteProtected(&MMCD1))
return RES_WRPRT;
if (mmcStartSequentialWrite(&MMCD1, sector))
return RES_ERROR;
while (count > 0) {
if (mmcSequentialWrite(&MMCD1, buff))
return RES_ERROR;
buff += MMCSD_BLOCK_SIZE;
count--;
}
if (mmcStopSequentialWrite(&MMCD1))
return RES_ERROR;
return RES_OK;
#else
case SDC:
if (blkGetDriverState(&SDCD1) != BLK_READY)
return RES_NOTRDY;
if (sdcWrite(&SDCD1, sector, buff, count))
return RES_ERROR;
return RES_OK;
#endif
}
return RES_PARERR;
}
#endif /* _USE_WRITE */
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
#if _USE_IOCTL
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
switch (pdrv) {
#if HAL_USE_MMC_SPI
case MMC:
switch (cmd) {
case CTRL_SYNC:
return RES_OK;
case GET_SECTOR_SIZE:
*((WORD *)buff) = MMCSD_BLOCK_SIZE;
return RES_OK;
#if _USE_ERASE
case CTRL_ERASE_SECTOR:
mmcErase(&MMCD1, *((DWORD *)buff), *((DWORD *)buff + 1));
return RES_OK;
#endif
default:
return RES_PARERR;
}
#else
case SDC:
switch (cmd) {
case CTRL_SYNC:
return RES_OK;
case GET_SECTOR_COUNT:
*((DWORD *)buff) = mmcsdGetCardCapacity(&SDCD1);
return RES_OK;
case GET_SECTOR_SIZE:
*((WORD *)buff) = MMCSD_BLOCK_SIZE;
return RES_OK;
case GET_BLOCK_SIZE:
*((DWORD *)buff) = 256; /* 512b blocks in one erase block */
return RES_OK;
#if _USE_ERASE
case CTRL_ERASE_SECTOR:
sdcErase(&SDCD1, *((DWORD *)buff), *((DWORD *)buff + 1));
return RES_OK;
#endif
default:
return RES_PARERR;
}
#endif
}
return RES_PARERR;
}
#endif /* _USE_IOCTL */
DWORD get_fattime(void) {
#if HAL_USE_RTC
RTCDateTime timespec;
rtcGetTime(&RTCD1, &timespec);
return rtcConvertDateTimeToFAT(&timespec);
#else
return ((uint32_t)0 | (1 << 16)) | (1 << 21); /* wrong but valid time */
#endif
}

View File

@ -0,0 +1,6 @@
This directory contains the ChibiOS/RT "official" bindings with the lwIP
TCP/IP stack: http://savannah.nongnu.org/projects/lwip
In order to use lwIP within ChibiOS/RT project, unzip lwIP under
./ext/lwip-1.4.0 then include $(CHIBIOS)/os/various/lwip_bindings/lwip.mk
in your makefile.