This commit is contained in:
parent
8b451bd0f1
commit
884da751c3
|
@ -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
|
|
@ -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
|
|
@ -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_ */
|
||||
|
||||
/** @} */
|
|
@ -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
|
|
@ -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__) */
|
||||
|
||||
/** @} */
|
|
@ -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
|
@ -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_ */
|
||||
|
||||
/** @} */
|
|
@ -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_ */
|
||||
|
||||
/** @} */
|
|
@ -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 */
|
||||
|
||||
/** @} */
|
|
@ -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(ÐD1.rdqueue, MSG_RESET);
|
||||
#if MAC_USE_EVENTS
|
||||
osalEventBroadcastFlagsI(ÐD1.rdevent, 0);
|
||||
#endif
|
||||
osalSysUnlockFromISR();
|
||||
}
|
||||
|
||||
if (dmasr & ETH_DMASR_TS) {
|
||||
/* Data Transmitted.*/
|
||||
osalSysLockFromISR();
|
||||
osalThreadDequeueAllI(ÐD1.tdqueue, MSG_RESET);
|
||||
osalSysUnlockFromISR();
|
||||
}
|
||||
|
||||
OSAL_IRQ_EPILOGUE();
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level MAC initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void mac_lld_init(void) {
|
||||
unsigned i;
|
||||
|
||||
macObjectInit(ÐD1);
|
||||
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(ÐD1);
|
||||
#endif
|
||||
|
||||
#if defined(BOARD_PHY_RESET)
|
||||
/* PHY board-specific reset procedure.*/
|
||||
BOARD_PHY_RESET();
|
||||
#else
|
||||
/* PHY soft reset procedure.*/
|
||||
mii_write(ÐD1, MII_BMCR, BMCR_RESET);
|
||||
#if defined(BOARD_PHY_RESET_DELAY)
|
||||
osalSysPolledDelayX(BOARD_PHY_RESET_DELAY);
|
||||
#endif
|
||||
while (mii_read(ÐD1, 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(ÐD1, MII_BMCR, mii_read(ÐD1, 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 */
|
||||
|
||||
/** @} */
|
|
@ -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 */
|
||||
|
||||
/** @} */
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -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 */
|
||||
|
||||
/** @} */
|
|
@ -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();
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -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
|
|
@ -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_ */
|
||||
|
||||
/** @} */
|
|
@ -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();
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -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_ */
|
||||
|
||||
/** @} */
|
|
@ -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 */
|
||||
|
||||
/** @} */
|
|
@ -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
|
||||
*/
|
|
@ -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_ */
|
||||
|
||||
/** @} */
|
|
@ -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, ×pec);
|
||||
return rtcConvertDateTimeToFAT(×pec);
|
||||
#else
|
||||
return ((uint32_t)0 | (1 << 16)) | (1 << 21); /* wrong but valid time */
|
||||
#endif
|
||||
}
|
|
@ -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.
|
Loading…
Reference in New Issue